Created
July 19, 2016 15:31
-
-
Save davidpfahler/3e5b0f9bc76421545c12d92cd92da747 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const fs = require('fs') | |
const path = require('path') | |
const colors = require('colors/safe') | |
const webpack = require('webpack') | |
const WebpackBuildNotifierPlugin = require('webpack-build-notifier') | |
const HtmlWebpackPlugin = require('html-webpack-plugin') | |
const compact = require('lodash.compact') | |
const without = require('lodash.without') | |
// This webpack config does not only support two different entry points | |
// (see below), but also production and development bundling. | |
// This works for both entry points! This config defaults to development. | |
// Set the environment variable `NODE_ENV=production` to optimize the bundle. | |
const isProd = process.env.NODE_ENV === 'production' | |
const isDev = !isProd | |
// This webpack config can build both vendor files or the remaining app. | |
// This helps decrease build time as vendor files are seldom changed. | |
// The config defaults to the entry for the remaining app. | |
// Note that we can not use two entry points in the same config at any time, | |
// because the DLLPlugin/DLLReferencePlugin cannot work inside the same config. | |
// But we can dynamically change the value of the one and only entry point, | |
// which is what we do here. | |
// Note that it would be the job of a build script to first call webpack with the | |
// vendor config and then with the remaining app config. | |
// Set the environment variable `ENTRY=vendor` to build vendor.js. | |
const { ENTRY = 'app' } = process.env | |
const isApp = ENTRY === 'app' | |
const isVendor = ENTRY === 'vendor' | |
let entry = compact([ | |
isDev && isApp && 'react-hot-loader/patch', | |
isDev && isApp && 'webpack-dev-server/client?http://localhost:3000', | |
isDev && isApp && 'webpack/hot/only-dev-server', | |
isApp && './src/index', | |
]) | |
// In production builds, we use react and react-dom from the facebook cdn | |
if (isVendor) { | |
const dependencies = Object.keys(require('./package.json').dependencies) | |
entry = entry.concat((isProd | |
? without(dependencies, 'react', 'react-dom') | |
: dependencies | |
)) | |
} | |
const externals = isProd | |
? ({ | |
react: 'React', | |
'react-dom': 'ReactDOM', | |
}) | |
: null | |
// Check if vendor bundle exists, when building the remaining app. If not, panic. | |
// TODO: This should probably be done in separate builds/make file. | |
if (ENTRY === 'app') { | |
try { | |
fs.accessSync(path.join(__dirname, 'dist', 'vendor.js')) | |
} catch (_) { | |
const cmd = isProd | |
? 'NODE_ENV=production ENTRY=vendor ./node_modules/.bin/webpack' | |
: 'npm run dev:vendor' | |
throw console.error(colors.red( | |
`Error: You must first build \`vendor\` before you can build \`app\`. | |
Use \`${cmd}\` to build the \`vendor\` bundle.` | |
)) | |
} | |
} | |
// shared between devServer and output properties: | |
const publicPath = isDev ? '/static/' : null | |
module.exports = { | |
cache: true, | |
devtool: isProd ? 'source-map' : 'eval', | |
devServer: { | |
host: '0.0.0.0', | |
port: 3000, | |
publicPath, | |
hot: true, | |
historyApiFallback: true, | |
stats: { | |
colors: true, | |
}, | |
}, | |
entry: { | |
[ENTRY]: entry, | |
}, | |
externals, | |
output: { | |
path: path.join(__dirname, 'dist'), | |
pathinfo: isDev, | |
filename: '[name].js', | |
publicPath, | |
devtoolModuleFilenameTemplate: '/[absolute-resource-path]', | |
library: isVendor && '[name]_lib', | |
}, | |
plugins: compact([ | |
isVendor && new webpack.DllPlugin({ | |
path: path.join(__dirname, 'dist', '[name]-manifest.json'), | |
name: '[name]_lib', | |
}), | |
isApp && new webpack.DllReferencePlugin({ | |
context: '.', | |
manifest: require('./dist/vendor-manifest.json'), | |
}), | |
isProd && new webpack.optimize.OccurrenceOrderPlugin(true), | |
isProd && new webpack.optimize.DedupePlugin(), | |
isProd && new webpack.DefinePlugin({ | |
'process.env': { | |
'NODE_ENV': JSON.stringify('production'), | |
}, | |
}), | |
isProd && new webpack.optimize.UglifyJsPlugin({ | |
output: { | |
comments: false, | |
}, | |
compress: { | |
warnings: false, | |
screw_ie8: true, | |
}, | |
}), | |
isProd && isApp && new HtmlWebpackPlugin({ | |
template: './src/index.prod.ejs', | |
}), | |
isDev && isApp && new webpack.HotModuleReplacementPlugin(), | |
isDev && new webpack.NoErrorsPlugin(), | |
isDev && new WebpackBuildNotifierPlugin({ | |
suppressSuccess: true, | |
}), | |
]), | |
resolve: { | |
extensions: ['', '.js'], | |
}, | |
modules: [path.resolve(__dirname, 'src'), 'node_modules'], | |
module: { | |
preLoaders: [{ | |
test: /\.js$/, | |
loader: 'eslint-loader', | |
exclude: /node_modules/, | |
query: { | |
fix: true, | |
}, | |
}], | |
loaders: [{ | |
test: /\.(js)$/, | |
loader: 'babel', | |
include: path.resolve(__dirname, 'src'), | |
query: { | |
cacheDirectory: true, | |
presets: ['es2015-webpack', 'react'], | |
plugins: [ | |
'react-hot-loader/babel', | |
'transform-object-rest-spread', | |
'transform-class-properties', | |
'react-require', | |
], | |
}, | |
}, { | |
test: /\.json$/, | |
loader: 'json', | |
include: [ | |
/node_modules/, | |
], | |
}], | |
}, | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment