Created
October 5, 2017 15:37
-
-
Save TechnotronicOz/dcd3622d38b96f4a4c82eb7793581b9c 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
| import path from 'path'; | |
| import webpack from 'webpack'; | |
| import AssetsPlugin from 'assets-webpack-plugin'; | |
| import nodeExternals from 'webpack-node-externals'; | |
| import {BundleAnalyzerPlugin} from 'webpack-bundle-analyzer'; | |
| import overrideRules from './lib/overrideRules'; | |
| import pkg from '../package.json'; | |
| const isDebug = !process.argv.includes('--release'); | |
| const isVerbose = process.argv.includes('--verbose'); | |
| const isAnalyze = | |
| process.argv.includes('--analyze') || process.argv.includes('--analyse'); | |
| const reScript = /\.jsx?$/; | |
| const reStyle = /\.(css|less|scss|sss)$/; | |
| const reImage = /\.(bmp|gif|jpe?g|png|svg)$/; | |
| const staticAssetName = isDebug | |
| ? '[path][name].[ext]?[hash:8]' | |
| : '[hash:8].[ext]'; | |
| // | |
| // Common configuration chunk to be used for both | |
| // client-side (client.js) and server-side (server.js) bundles | |
| // ----------------------------------------------------------------------------- | |
| const config = { | |
| context: path.resolve(__dirname, '..'), | |
| output: { | |
| path: path.resolve(__dirname, '../build/public/assets'), | |
| publicPath: '/assets/', | |
| pathinfo: isVerbose, | |
| filename: isDebug ? '[name].js' : '[name].[chunkhash:8].js', | |
| chunkFilename: isDebug | |
| ? '[name].chunk.js' | |
| : '[name].[chunkhash:8].chunk.js', | |
| devtoolModuleFilenameTemplate: info => | |
| path.resolve(info.absoluteResourcePath) | |
| }, | |
| resolve: { | |
| // Allow absolute paths in imports, e.g. import Button from 'components/Button' | |
| // Keep in sync with .flowconfig and .eslintrc | |
| modules: ['node_modules', 'src'] | |
| }, | |
| module: { | |
| // Make missing exports an error instead of warning | |
| strictExportPresence: true, | |
| rules: [ | |
| // Rules for JS / JSX | |
| { | |
| test: reScript, | |
| include: path.resolve(__dirname, '../src'), | |
| loader: 'babel-loader', | |
| options: { | |
| // https://github.com/babel/babel-loader#options | |
| cacheDirectory: isDebug, | |
| // https://babeljs.io/docs/usage/options/ | |
| babelrc: false, | |
| presets: [ | |
| // A Babel preset that can automatically determine the Babel plugins and polyfills | |
| // https://github.com/babel/babel-preset-env | |
| [ | |
| 'env', | |
| { | |
| targets: { | |
| browsers: pkg.browserslist, | |
| uglify: true | |
| }, | |
| modules: false, | |
| useBuiltIns: false, | |
| debug: false | |
| } | |
| ], | |
| // Experimental ECMAScript proposals | |
| // https://babeljs.io/docs/plugins/#presets-stage-x-experimental-presets- | |
| 'stage-2', | |
| // JSX, Flow | |
| // https://github.com/babel/babel/tree/master/packages/babel-preset-react | |
| 'react', | |
| // Optimize React code for the production build | |
| // https://github.com/thejameskyle/babel-react-optimize | |
| ...(isDebug ? [] : ['react-optimize']) | |
| ], | |
| plugins: [ | |
| // Adds component stack to warning messages | |
| // https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-react-jsx-source | |
| ...(isDebug ? ['transform-react-jsx-source'] : []), | |
| // Adds __self attribute to JSX which React will use for some warnings | |
| // https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-react-jsx-self | |
| ...(isDebug ? ['transform-react-jsx-self'] : []) | |
| ] | |
| } | |
| }, | |
| // Rules for Style Sheets | |
| { | |
| test: reStyle, | |
| rules: [ | |
| // Convert CSS into JS module | |
| { | |
| issuer: {not: [reStyle]}, | |
| use: 'isomorphic-style-loader' | |
| }, | |
| // Process external/third-party styles | |
| { | |
| exclude: path.resolve(__dirname, '../src'), | |
| loader: 'css-loader', | |
| options: { | |
| sourceMap: isDebug, | |
| minimize: !isDebug, | |
| discardComments: {removeAll: true} | |
| } | |
| }, | |
| // Process internal/project styles (from src folder) | |
| { | |
| include: path.resolve(__dirname, '../src'), | |
| loader: 'css-loader', | |
| options: { | |
| // CSS Loader https://github.com/webpack/css-loader | |
| importLoaders: 1, | |
| sourceMap: isDebug, | |
| // CSS Modules https://github.com/css-modules/css-modules | |
| modules: true, | |
| localIdentName: isDebug | |
| ? '[name]-[local]-[hash:base64:5]' | |
| : '[hash:base64:5]', | |
| // CSS Nano http://cssnano.co/options/ | |
| minimize: !isDebug, | |
| discardComments: {removeAll: true} | |
| } | |
| }, | |
| // Apply PostCSS plugins including autoprefixer | |
| { | |
| loader: 'postcss-loader', | |
| options: { | |
| config: { | |
| path: './tools/postcss.config.js' | |
| } | |
| } | |
| } | |
| // Compile Less to CSS | |
| // https://github.com/webpack-contrib/less-loader | |
| // Install dependencies before uncommenting: yarn add --dev less-loader less | |
| // { | |
| // test: /\.less$/, | |
| // loader: 'less-loader', | |
| // }, | |
| // Compile Sass to CSS | |
| // https://github.com/webpack-contrib/sass-loader | |
| // Install dependencies before uncommenting: yarn add --dev sass-loader node-sass | |
| // { | |
| // test: /\.scss$/, | |
| // loader: 'sass-loader', | |
| // }, | |
| ] | |
| }, | |
| // Rules for images | |
| { | |
| test: reImage, | |
| oneOf: [ | |
| // Inline lightweight images into CSS | |
| { | |
| issuer: reStyle, | |
| oneOf: [ | |
| // Inline lightweight SVGs as UTF-8 encoded DataUrl string | |
| { | |
| test: /\.svg$/, | |
| loader: 'svg-url-loader', | |
| options: { | |
| name: staticAssetName, | |
| limit: 4096 // 4kb | |
| } | |
| }, | |
| // Inline lightweight images as Base64 encoded DataUrl string | |
| { | |
| loader: 'url-loader', | |
| options: { | |
| name: staticAssetName, | |
| limit: 4096 // 4kb | |
| } | |
| } | |
| ] | |
| }, | |
| // Or return public URL to image resource | |
| { | |
| loader: 'file-loader', | |
| options: { | |
| name: staticAssetName | |
| } | |
| } | |
| ] | |
| }, | |
| // Convert plain text into JS module | |
| { | |
| test: /\.txt$/, | |
| loader: 'raw-loader' | |
| }, | |
| // Convert Markdown into HTML | |
| { | |
| test: /\.md$/, | |
| loader: path.resolve(__dirname, './lib/markdown-loader.js') | |
| }, | |
| // Web fonts | |
| { | |
| test: /\.eot/, | |
| loader: 'url-loader?mimetype=application/vnd.ms-fontobject' | |
| }, | |
| { | |
| test: /\.ttf/, | |
| loader: 'url-loader?mimetype=application/x-font-ttf' | |
| }, | |
| { | |
| test: /\.woff/, | |
| loader: 'url-loader?mimetype=application/font-woff' | |
| }, | |
| { | |
| test: /\.woff2/, | |
| loader: 'url-loader?mimetype=application/font-woff2' | |
| }, | |
| // Return public URL for all assets unless explicitly excluded | |
| // DO NOT FORGET to update `exclude` list when you adding a new loader | |
| { | |
| exclude: [reScript, reStyle, reImage, /\.json$/, /\.txt$/, /\.md$/, /\.eot/, /\.ttf/, /\.woff/, /\.woff2/], | |
| loader: 'file-loader', | |
| options: { | |
| name: staticAssetName | |
| } | |
| }, | |
| // Exclude dev modules from production build | |
| ...(isDebug | |
| ? [] | |
| : [ | |
| { | |
| test: path.resolve( | |
| __dirname, | |
| '../node_modules/react-deep-force-update/lib/index.js' | |
| ), | |
| loader: 'null-loader' | |
| } | |
| ]) | |
| ] | |
| }, | |
| // Don't attempt to continue if there are any errors. | |
| bail: !isDebug, | |
| cache: isDebug, | |
| // Specify what bundle information gets displayed | |
| // https://webpack.js.org/configuration/stats/ | |
| stats: { | |
| cached: isVerbose, | |
| cachedAssets: isVerbose, | |
| chunks: isVerbose, | |
| chunkModules: isVerbose, | |
| colors: true, | |
| hash: isVerbose, | |
| modules: isVerbose, | |
| reasons: isDebug, | |
| timings: true, | |
| version: isVerbose | |
| }, | |
| // Choose a developer tool to enhance debugging | |
| // https://webpack.js.org/configuration/devtool/#devtool | |
| devtool: isDebug ? 'cheap-module-inline-source-map' : 'source-map' | |
| }; | |
| // | |
| // Configuration for the client-side bundle (client.js) | |
| // ----------------------------------------------------------------------------- | |
| const clientConfig = { | |
| ...config, | |
| name: 'client', | |
| target: 'web', | |
| entry: { | |
| client: ['babel-polyfill', './src/client.js'] | |
| }, | |
| plugins: [ | |
| // Define free variables | |
| // https://webpack.js.org/plugins/define-plugin/ | |
| new webpack.DefinePlugin({ | |
| 'process.env.NODE_ENV': isDebug ? '"development"' : '"production"', | |
| 'process.env.BROWSER': true, | |
| __DEV__: isDebug | |
| }), | |
| // Emit a file with assets paths | |
| // https://github.com/sporto/assets-webpack-plugin#options | |
| new AssetsPlugin({ | |
| path: path.resolve(__dirname, '../build'), | |
| filename: 'assets.json', | |
| prettyPrint: true | |
| }), | |
| // Move modules that occur in multiple entry chunks to a new entry chunk (the commons chunk). | |
| // https://webpack.js.org/plugins/commons-chunk-plugin/ | |
| new webpack.optimize.CommonsChunkPlugin({ | |
| name: 'vendor', | |
| minChunks: module => /node_modules/.test(module.resource) | |
| }), | |
| ...(isDebug | |
| ? [] | |
| : [ | |
| // Decrease script evaluation time | |
| // https://github.com/webpack/webpack/blob/master/examples/scope-hoisting/README.md | |
| new webpack.optimize.ModuleConcatenationPlugin(), | |
| // Minimize all JavaScript output of chunks | |
| // https://github.com/mishoo/UglifyJS2#compressor-options | |
| new webpack.optimize.UglifyJsPlugin({ | |
| sourceMap: true, | |
| compress: { | |
| screw_ie8: true, // React doesn't support IE8 | |
| warnings: isVerbose, | |
| unused: true, | |
| dead_code: true | |
| }, | |
| mangle: { | |
| screw_ie8: true | |
| }, | |
| output: { | |
| comments: false, | |
| screw_ie8: true | |
| } | |
| }) | |
| ]), | |
| // Webpack Bundle Analyzer | |
| // https://github.com/th0r/webpack-bundle-analyzer | |
| ...(isAnalyze ? [new BundleAnalyzerPlugin()] : []) | |
| ], | |
| // Some libraries import Node modules but don't use them in the browser. | |
| // Tell Webpack to provide empty mocks for them so importing them works. | |
| // https://webpack.js.org/configuration/node/ | |
| // https://github.com/webpack/node-libs-browser/tree/master/mock | |
| node: { | |
| fs: 'empty', | |
| net: 'empty', | |
| tls: 'empty' | |
| } | |
| }; | |
| // | |
| // Configuration for the server-side bundle (server.js) | |
| // ----------------------------------------------------------------------------- | |
| const serverConfig = { | |
| ...config, | |
| name: 'server', | |
| target: 'node', | |
| entry: { | |
| server: ['babel-polyfill', './src/server.js'] | |
| }, | |
| output: { | |
| ...config.output, | |
| path: path.resolve(__dirname, '../build'), | |
| filename: '[name].js', | |
| chunkFilename: 'chunks/[name].js', | |
| libraryTarget: 'commonjs2' | |
| }, | |
| // Webpack mutates resolve object, so clone it to avoid issues | |
| // https://github.com/webpack/webpack/issues/4817 | |
| resolve: { | |
| ...config.resolve | |
| }, | |
| module: { | |
| ...config.module, | |
| rules: overrideRules(config.module.rules, rule => { | |
| // Override babel-preset-env configuration for Node.js | |
| if (rule.loader === 'babel-loader') { | |
| return { | |
| ...rule, | |
| options: { | |
| ...rule.options, | |
| presets: rule.options.presets.map( | |
| preset => | |
| preset[0] !== 'env' | |
| ? preset | |
| : [ | |
| 'env', | |
| { | |
| targets: { | |
| node: pkg.engines.node.match(/(\d+\.?)+/)[0] | |
| }, | |
| modules: false, | |
| useBuiltIns: false, | |
| debug: false | |
| } | |
| ] | |
| ) | |
| } | |
| }; | |
| } | |
| // Override paths to static assets | |
| if ( | |
| rule.loader === 'file-loader' || | |
| rule.loader === 'url-loader' || | |
| rule.loader === 'svg-url-loader' | |
| ) { | |
| return { | |
| ...rule, | |
| options: { | |
| ...rule.options, | |
| name: `public/assets/${rule.options.name}`, | |
| publicPath: url => url.replace(/^public/, '') | |
| } | |
| }; | |
| } | |
| return rule; | |
| }) | |
| }, | |
| externals: [ | |
| './assets.json', | |
| nodeExternals({ | |
| whitelist: [reStyle, reImage] | |
| }) | |
| ], | |
| plugins: [ | |
| // Define free variables | |
| // https://webpack.js.org/plugins/define-plugin/ | |
| new webpack.DefinePlugin({ | |
| 'process.env.NODE_ENV': isDebug ? '"development"' : '"production"', | |
| 'process.env.BROWSER': false, | |
| __DEV__: isDebug | |
| }), | |
| // Adds a banner to the top of each generated chunk | |
| // https://webpack.js.org/plugins/banner-plugin/ | |
| new webpack.BannerPlugin({ | |
| banner: 'require("source-map-support").install();', | |
| raw: true, | |
| entryOnly: false | |
| }) | |
| ], | |
| // Do not replace node globals with polyfills | |
| // https://webpack.js.org/configuration/node/ | |
| node: { | |
| console: false, | |
| global: false, | |
| process: false, | |
| Buffer: false, | |
| __filename: false, | |
| __dirname: false | |
| } | |
| }; | |
| export default [clientConfig, serverConfig]; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment