webpack.config.js (9369B)
1 /** 2 * React Starter Kit (https://www.reactstarterkit.com/) 3 * 4 * Copyright © 2014-present Kriasoft, LLC. All rights reserved. 5 * 6 * This source code is licensed under the MIT license found in the 7 * LICENSE.txt file in the root directory of this source tree. 8 */ 9 10 import path from 'path'; 11 import webpack from 'webpack'; 12 import AssetsPlugin from 'assets-webpack-plugin'; 13 import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; 14 import pkg from '../package.json'; 15 16 const isDebug = !process.argv.includes('--release'); 17 const isVerbose = process.argv.includes('--verbose'); 18 const isAnalyze = process.argv.includes('--analyze') || process.argv.includes('--analyse'); 19 20 // 21 // Common configuration chunk to be used for both 22 // client-side (client.js) and server-side (server.js) bundles 23 // ----------------------------------------------------------------------------- 24 25 const config = { 26 context: path.resolve(__dirname, '..'), 27 28 output: { 29 path: path.resolve(__dirname, '../build/public/assets'), 30 publicPath: '/assets/', 31 pathinfo: isVerbose, 32 }, 33 34 module: { 35 rules: [ 36 { 37 test: /\.jsx?$/, 38 loader: 'babel-loader', 39 include: [ 40 path.resolve(__dirname, '../src'), 41 ], 42 query: { 43 // https://github.com/babel/babel-loader#options 44 cacheDirectory: isDebug, 45 46 // https://babeljs.io/docs/usage/options/ 47 babelrc: false, 48 presets: [ 49 // A Babel preset that can automatically determine the Babel plugins and polyfills 50 // https://github.com/babel/babel-preset-env 51 ['env', { 52 targets: { 53 browsers: pkg.browserslist, 54 }, 55 modules: false, 56 useBuiltIns: false, 57 debug: false, 58 }], 59 // Experimental ECMAScript proposals 60 // https://babeljs.io/docs/plugins/#presets-stage-x-experimental-presets- 61 'stage-2', 62 // JSX, Flow 63 // https://github.com/babel/babel/tree/master/packages/babel-preset-react 64 'react', 65 // Optimize React code for the production build 66 // https://github.com/thejameskyle/babel-react-optimize 67 ...isDebug ? [] : ['react-optimize'], 68 ], 69 plugins: [ 70 // Adds component stack to warning messages 71 // https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-react-jsx-source 72 ...isDebug ? ['transform-react-jsx-source'] : [], 73 // Adds __self attribute to JSX which React will use for some warnings 74 // https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-react-jsx-self 75 ...isDebug ? ['transform-react-jsx-self'] : [], 76 ], 77 }, 78 }, 79 { 80 test: /\.css/, 81 use: [ 82 { 83 loader: 'isomorphic-style-loader', 84 }, 85 { 86 loader: 'css-loader', 87 options: { 88 // CSS Loader https://github.com/webpack/css-loader 89 importLoaders: 1, 90 sourceMap: isDebug, 91 // CSS Modules https://github.com/css-modules/css-modules 92 modules: true, 93 localIdentName: isDebug ? '[name]-[local]-[hash:base64:5]' : '[hash:base64:5]', 94 // CSS Nano http://cssnano.co/options/ 95 minimize: !isDebug, 96 discardComments: { removeAll: true }, 97 }, 98 }, 99 { 100 loader: 'postcss-loader', 101 options: { 102 config: './tools/postcss.config.js', 103 }, 104 }, 105 ], 106 }, 107 { 108 test: /\.md$/, 109 loader: path.resolve(__dirname, './lib/markdown-loader.js'), 110 }, 111 { 112 test: /\.txt$/, 113 loader: 'raw-loader', 114 }, 115 { 116 test: /\.(ico|jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2)(\?.*)?$/, 117 loader: 'file-loader', 118 query: { 119 name: isDebug ? '[path][name].[ext]?[hash:8]' : '[hash:8].[ext]', 120 }, 121 }, 122 { 123 test: /\.(mp4|webm|wav|mp3|m4a|aac|oga)(\?.*)?$/, 124 loader: 'url-loader', 125 query: { 126 name: isDebug ? '[path][name].[ext]?[hash:8]' : '[hash:8].[ext]', 127 limit: 10000, 128 }, 129 }, 130 ], 131 }, 132 133 // Don't attempt to continue if there are any errors. 134 bail: !isDebug, 135 136 cache: isDebug, 137 138 stats: { 139 colors: true, 140 reasons: isDebug, 141 hash: isVerbose, 142 version: isVerbose, 143 timings: true, 144 chunks: isVerbose, 145 chunkModules: isVerbose, 146 cached: isVerbose, 147 cachedAssets: isVerbose, 148 }, 149 }; 150 151 // 152 // Configuration for the client-side bundle (client.js) 153 // ----------------------------------------------------------------------------- 154 155 const clientConfig = { 156 ...config, 157 158 name: 'client', 159 target: 'web', 160 161 entry: { 162 client: ['babel-polyfill', './src/client.js'], 163 }, 164 165 output: { 166 ...config.output, 167 filename: isDebug ? '[name].js' : '[name].[chunkhash:8].js', 168 chunkFilename: isDebug ? '[name].chunk.js' : '[name].[chunkhash:8].chunk.js', 169 }, 170 171 plugins: [ 172 // Define free variables 173 // https://webpack.github.io/docs/list-of-plugins.html#defineplugin 174 new webpack.DefinePlugin({ 175 'process.env.NODE_ENV': isDebug ? '"development"' : '"production"', 176 'process.env.BROWSER': true, 177 __DEV__: isDebug, 178 }), 179 180 // Emit a file with assets paths 181 // https://github.com/sporto/assets-webpack-plugin#options 182 new AssetsPlugin({ 183 path: path.resolve(__dirname, '../build'), 184 filename: 'assets.json', 185 prettyPrint: true, 186 }), 187 188 // Move modules that occur in multiple entry chunks to a new entry chunk (the commons chunk). 189 // http://webpack.github.io/docs/list-of-plugins.html#commonschunkplugin 190 new webpack.optimize.CommonsChunkPlugin({ 191 name: 'vendor', 192 minChunks: module => /node_modules/.test(module.resource), 193 }), 194 195 ...isDebug ? [] : [ 196 // Minimize all JavaScript output of chunks 197 // https://github.com/mishoo/UglifyJS2#compressor-options 198 new webpack.optimize.UglifyJsPlugin({ 199 sourceMap: true, 200 compress: { 201 screw_ie8: true, // React doesn't support IE8 202 warnings: isVerbose, 203 unused: true, 204 dead_code: true, 205 }, 206 mangle: { 207 screw_ie8: true, 208 }, 209 output: { 210 comments: false, 211 screw_ie8: true, 212 }, 213 }), 214 ], 215 216 // Webpack Bundle Analyzer 217 // https://github.com/th0r/webpack-bundle-analyzer 218 ...isAnalyze ? [new BundleAnalyzerPlugin()] : [], 219 ], 220 221 // Choose a developer tool to enhance debugging 222 // http://webpack.github.io/docs/configuration.html#devtool 223 devtool: isDebug ? 'cheap-module-source-map' : false, 224 225 // Some libraries import Node modules but don't use them in the browser. 226 // Tell Webpack to provide empty mocks for them so importing them works. 227 // https://webpack.github.io/docs/configuration.html#node 228 // https://github.com/webpack/node-libs-browser/tree/master/mock 229 node: { 230 fs: 'empty', 231 net: 'empty', 232 tls: 'empty', 233 }, 234 }; 235 236 // 237 // Configuration for the server-side bundle (server.js) 238 // ----------------------------------------------------------------------------- 239 240 const serverConfig = { 241 ...config, 242 243 name: 'server', 244 target: 'node', 245 246 entry: { 247 server: ['babel-polyfill', './src/server.js'], 248 }, 249 250 output: { 251 ...config.output, 252 filename: '../../server.js', 253 libraryTarget: 'commonjs2', 254 }, 255 256 module: { 257 ...config.module, 258 259 // Override babel-preset-env configuration for Node.js 260 rules: config.module.rules.map(rule => (rule.loader !== 'babel-loader' ? rule : { 261 ...rule, 262 query: { 263 ...rule.query, 264 presets: rule.query.presets.map(preset => (preset[0] !== 'env' ? preset : ['env', { 265 targets: { 266 node: parseFloat(pkg.engines.node.replace(/^\D+/g, '')), 267 }, 268 modules: false, 269 useBuiltIns: false, 270 debug: false, 271 }])), 272 }, 273 })), 274 }, 275 276 externals: [ 277 /^\.\/assets\.json$/, 278 (context, request, callback) => { 279 const isExternal = 280 request.match(/^[@a-z][a-z/.\-0-9]*$/i) && 281 !request.match(/\.(css|less|scss|sss)$/i); 282 callback(null, Boolean(isExternal)); 283 }, 284 ], 285 286 plugins: [ 287 // Define free variables 288 // https://webpack.github.io/docs/list-of-plugins.html#defineplugin 289 new webpack.DefinePlugin({ 290 'process.env.NODE_ENV': isDebug ? '"development"' : '"production"', 291 'process.env.BROWSER': false, 292 __DEV__: isDebug, 293 }), 294 295 // Do not create separate chunks of the server bundle 296 // https://webpack.github.io/docs/list-of-plugins.html#limitchunkcountplugin 297 new webpack.optimize.LimitChunkCountPlugin({ maxChunks: 1 }), 298 299 // Adds a banner to the top of each generated chunk 300 // https://webpack.github.io/docs/list-of-plugins.html#bannerplugin 301 new webpack.BannerPlugin({ 302 banner: 'require("source-map-support").install();', 303 raw: true, 304 entryOnly: false, 305 }), 306 ], 307 308 node: { 309 console: false, 310 global: false, 311 process: false, 312 Buffer: false, 313 __filename: false, 314 __dirname: false, 315 }, 316 317 devtool: isDebug ? 'cheap-module-source-map' : 'source-map', 318 }; 319 320 export default [clientConfig, serverConfig];