|
| 1 | +// @remove-on-eject-begin |
| 2 | +/** |
| 3 | + * Copyright (c) 2015-present, Facebook, Inc. |
| 4 | + * |
| 5 | + * This source code is licensed under the MIT license found in the |
| 6 | + * LICENSE file in the root directory of this source tree. |
| 7 | + */ |
| 8 | +// @remove-on-eject-end |
| 9 | +'use strict'; |
| 10 | + |
| 11 | +const autoprefixer = require('autoprefixer'); |
| 12 | +const path = require('path'); |
| 13 | +const webpack = require('webpack'); |
| 14 | +const HtmlWebpackPlugin = require('html-webpack-plugin'); |
| 15 | +const ExtractTextPlugin = require('extract-text-webpack-plugin'); |
| 16 | +const ManifestPlugin = require('webpack-manifest-plugin'); |
| 17 | +const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin'); |
| 18 | +const SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin'); |
| 19 | +const eslintFormatter = require('react-dev-utils/eslintFormatter'); |
| 20 | +const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin'); |
| 21 | +const paths = require('./paths'); |
| 22 | +const getClientEnvironment = require('./env'); |
| 23 | + |
| 24 | +// Webpack uses `publicPath` to determine where the app is being served from. |
| 25 | +// It requires a trailing slash, or the file assets will get an incorrect path. |
| 26 | +const publicPath = paths.servedPath; |
| 27 | +// Some apps do not use client-side routing with pushState. |
| 28 | +// For these, "homepage" can be set to "." to enable relative asset paths. |
| 29 | +const shouldUseRelativeAssetPaths = publicPath === './'; |
| 30 | +// Source maps are resource heavy and can cause out of memory issue for large source files. |
| 31 | +const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false'; |
| 32 | +// `publicUrl` is just like `publicPath`, but we will provide it to our app |
| 33 | +// as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript. |
| 34 | +// Omit trailing slash as %PUBLIC_URL%/xyz looks better than %PUBLIC_URL%xyz. |
| 35 | +const publicUrl = publicPath.slice(0, -1); |
| 36 | +// Get environment variables to inject into our app. |
| 37 | +const env = getClientEnvironment(publicUrl); |
| 38 | + |
| 39 | +// Assert this just to be safe. |
| 40 | +// Development builds of React are slow and not intended for production. |
| 41 | +if (env.stringified['process.env'].NODE_ENV !== '"production"') { |
| 42 | + throw new Error('Production builds must have NODE_ENV=production.'); |
| 43 | +} |
| 44 | + |
| 45 | +// Note: defined here because it will be used more than once. |
| 46 | +const cssFilename = 'static/css/[name].[contenthash:8].css'; |
| 47 | + |
| 48 | +// ExtractTextPlugin expects the build output to be flat. |
| 49 | +// (See https://github.com/webpack-contrib/extract-text-webpack-plugin/issues/27) |
| 50 | +// However, our output is structured with css, js and media folders. |
| 51 | +// To have this structure working with relative paths, we have to use custom options. |
| 52 | +const extractTextPluginOptions = shouldUseRelativeAssetPaths |
| 53 | + ? // Making sure that the publicPath goes back to to build folder. |
| 54 | + { publicPath: Array(cssFilename.split('/').length).join('../') } |
| 55 | + : {}; |
| 56 | + |
| 57 | +// This is the production configuration. |
| 58 | +// It compiles slowly and is focused on producing a fast and minimal bundle. |
| 59 | +// The development configuration is different and lives in a separate file. |
| 60 | +module.exports = { |
| 61 | + // Don't attempt to continue if there are any errors. |
| 62 | + bail: true, |
| 63 | + // We generate sourcemaps in production. This is slow but gives good results. |
| 64 | + // You can exclude the *.map files from the build during deployment. |
| 65 | + devtool: shouldUseSourceMap ? 'source-map' : false, |
| 66 | + // In production, we only want to load the polyfills and the app code. |
| 67 | + entry: [require.resolve('./polyfills'), paths.appIndexJs], |
| 68 | + output: { |
| 69 | + // The build folder. |
| 70 | + path: paths.appBuild, |
| 71 | + // Generated JS file names (with nested folders). |
| 72 | + // There will be one main bundle, and one file per asynchronous chunk. |
| 73 | + // We don't currently advertise code splitting but Webpack supports it. |
| 74 | + filename: 'static/js/[name].[chunkhash:8].js', |
| 75 | + chunkFilename: 'static/js/[name].[chunkhash:8].chunk.js', |
| 76 | + // We inferred the "public path" (such as / or /my-project) from homepage. |
| 77 | + publicPath: publicPath, |
| 78 | + // Point sourcemap entries to original disk location (format as URL on Windows) |
| 79 | + devtoolModuleFilenameTemplate: info => |
| 80 | + path |
| 81 | + .relative(paths.appSrc, info.absoluteResourcePath) |
| 82 | + .replace(/\\/g, '/'), |
| 83 | + }, |
| 84 | + resolve: { |
| 85 | + // This allows you to set a fallback for where Webpack should look for modules. |
| 86 | + // We placed these paths second because we want `node_modules` to "win" |
| 87 | + // if there are any conflicts. This matches Node resolution mechanism. |
| 88 | + // https://github.com/facebookincubator/create-react-app/issues/253 |
| 89 | + modules: ['node_modules', paths.appNodeModules].concat( |
| 90 | + // It is guaranteed to exist because we tweak it in `env.js` |
| 91 | + process.env.NODE_PATH.split(path.delimiter).filter(Boolean) |
| 92 | + ), |
| 93 | + // These are the reasonable defaults supported by the Node ecosystem. |
| 94 | + // We also include JSX as a common component filename extension to support |
| 95 | + // some tools, although we do not recommend using it, see: |
| 96 | + // https://github.com/facebookincubator/create-react-app/issues/290 |
| 97 | + // `web` extension prefixes have been added for better support |
| 98 | + // for React Native Web. |
| 99 | + extensions: ['.web.js', '.mjs', '.js', '.json', '.web.jsx', '.jsx'], |
| 100 | + alias: { |
| 101 | + // @remove-on-eject-begin |
| 102 | + // Resolve Babel runtime relative to react-scripts. |
| 103 | + // It usually still works on npm 3 without this but it would be |
| 104 | + // unfortunate to rely on, as react-scripts could be symlinked, |
| 105 | + // and thus babel-runtime might not be resolvable from the source. |
| 106 | + 'babel-runtime': path.dirname( |
| 107 | + require.resolve('babel-runtime/package.json') |
| 108 | + ), |
| 109 | + // @remove-on-eject-end |
| 110 | + // Support React Native Web |
| 111 | + // https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/ |
| 112 | + 'react-native': 'react-native-web', |
| 113 | + }, |
| 114 | + plugins: [ |
| 115 | + // Prevents users from importing files from outside of src/ (or node_modules/). |
| 116 | + // This often causes confusion because we only process files within src/ with babel. |
| 117 | + // To fix this, we prevent you from importing files out of src/ -- if you'd like to, |
| 118 | + // please link the files into your node_modules/ and let module-resolution kick in. |
| 119 | + // Make sure your source files are compiled, as they will not be processed in any way. |
| 120 | + new ModuleScopePlugin(paths.appSrc, [paths.appPackageJson]), |
| 121 | + ], |
| 122 | + }, |
| 123 | + module: { |
| 124 | + strictExportPresence: true, |
| 125 | + rules: [ |
| 126 | + // TODO: Disable require.ensure as it's not a standard language feature. |
| 127 | + // We are waiting for https://github.com/facebookincubator/create-react-app/issues/2176. |
| 128 | + // { parser: { requireEnsure: false } }, |
| 129 | + |
| 130 | + // First, run the linter. |
| 131 | + // It's important to do this before Babel processes the JS. |
| 132 | + { |
| 133 | + test: /\.(js|jsx|mjs)$/, |
| 134 | + enforce: 'pre', |
| 135 | + use: [ |
| 136 | + { |
| 137 | + options: { |
| 138 | + formatter: eslintFormatter, |
| 139 | + eslintPath: require.resolve('eslint'), |
| 140 | + // @remove-on-eject-begin |
| 141 | + // TODO: consider separate config for production, |
| 142 | + // e.g. to enable no-console and no-debugger only in production. |
| 143 | + baseConfig: { |
| 144 | + extends: [require.resolve('eslint-config-react-app')], |
| 145 | + }, |
| 146 | + ignore: false, |
| 147 | + useEslintrc: false, |
| 148 | + // @remove-on-eject-end |
| 149 | + }, |
| 150 | + loader: require.resolve('eslint-loader'), |
| 151 | + }, |
| 152 | + ], |
| 153 | + include: paths.appSrc, |
| 154 | + }, |
| 155 | + { |
| 156 | + // "oneOf" will traverse all following loaders until one will |
| 157 | + // match the requirements. When no loader matches it will fall |
| 158 | + // back to the "file" loader at the end of the loader list. |
| 159 | + oneOf: [ |
| 160 | + // "url" loader works just like "file" loader but it also embeds |
| 161 | + // assets smaller than specified size as data URLs to avoid requests. |
| 162 | + { |
| 163 | + test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/], |
| 164 | + loader: require.resolve('url-loader'), |
| 165 | + options: { |
| 166 | + limit: 10000, |
| 167 | + name: 'static/media/[name].[hash:8].[ext]', |
| 168 | + }, |
| 169 | + }, |
| 170 | + // Process JS with Babel. |
| 171 | + { |
| 172 | + test: /\.(js|jsx|mjs)$/, |
| 173 | + include: paths.appSrc, |
| 174 | + loader: require.resolve('babel-loader'), |
| 175 | + options: { |
| 176 | + // @remove-on-eject-begin |
| 177 | + babelrc: false, |
| 178 | + presets: [require.resolve('babel-preset-react-app')], |
| 179 | + // @remove-on-eject-end |
| 180 | + compact: true, |
| 181 | + }, |
| 182 | + }, |
| 183 | + // The notation here is somewhat confusing. |
| 184 | + // "postcss" loader applies autoprefixer to our CSS. |
| 185 | + // "css" loader resolves paths in CSS and adds assets as dependencies. |
| 186 | + // "style" loader normally turns CSS into JS modules injecting <style>, |
| 187 | + // but unlike in development configuration, we do something different. |
| 188 | + // `ExtractTextPlugin` first applies the "postcss" and "css" loaders |
| 189 | + // (second argument), then grabs the result CSS and puts it into a |
| 190 | + // separate file in our build process. This way we actually ship |
| 191 | + // a single CSS file in production instead of JS code injecting <style> |
| 192 | + // tags. If you use code splitting, however, any async bundles will still |
| 193 | + // use the "style" loader inside the async code so CSS from them won't be |
| 194 | + // in the main CSS file. |
| 195 | + { |
| 196 | + test: /\.css$/, |
| 197 | + loader: ExtractTextPlugin.extract( |
| 198 | + Object.assign( |
| 199 | + { |
| 200 | + fallback: { |
| 201 | + loader: require.resolve('style-loader'), |
| 202 | + options: { |
| 203 | + hmr: false, |
| 204 | + }, |
| 205 | + }, |
| 206 | + use: [ |
| 207 | + { |
| 208 | + loader: require.resolve('css-loader'), |
| 209 | + options: { |
| 210 | + importLoaders: 1, |
| 211 | + minimize: true, |
| 212 | + sourceMap: shouldUseSourceMap, |
| 213 | + }, |
| 214 | + }, |
| 215 | + { |
| 216 | + loader: require.resolve('postcss-loader'), |
| 217 | + options: { |
| 218 | + // Necessary for external CSS imports to work |
| 219 | + // https://github.com/facebookincubator/create-react-app/issues/2677 |
| 220 | + ident: 'postcss', |
| 221 | + plugins: () => [ |
| 222 | + require('postcss-flexbugs-fixes'), |
| 223 | + autoprefixer({ |
| 224 | + browsers: [ |
| 225 | + '>1%', |
| 226 | + 'last 4 versions', |
| 227 | + 'Firefox ESR', |
| 228 | + 'not ie < 9', // React doesn't support IE8 anyway |
| 229 | + ], |
| 230 | + flexbox: 'no-2009', |
| 231 | + }), |
| 232 | + ], |
| 233 | + }, |
| 234 | + }, |
| 235 | + ], |
| 236 | + }, |
| 237 | + extractTextPluginOptions |
| 238 | + ) |
| 239 | + ), |
| 240 | + // Note: this won't work without `new ExtractTextPlugin()` in `plugins`. |
| 241 | + }, |
| 242 | + // "file" loader makes sure assets end up in the `build` folder. |
| 243 | + // When you `import` an asset, you get its filename. |
| 244 | + // This loader doesn't use a "test" so it will catch all modules |
| 245 | + // that fall through the other loaders. |
| 246 | + { |
| 247 | + loader: require.resolve('file-loader'), |
| 248 | + // Exclude `js` files to keep "css" loader working as it injects |
| 249 | + // it's runtime that would otherwise processed through "file" loader. |
| 250 | + // Also exclude `html` and `json` extensions so they get processed |
| 251 | + // by webpacks internal loaders. |
| 252 | + exclude: [/\.(js|jsx|mjs)$/, /\.html$/, /\.json$/], |
| 253 | + options: { |
| 254 | + name: 'static/media/[name].[hash:8].[ext]', |
| 255 | + }, |
| 256 | + }, |
| 257 | + // ** STOP ** Are you adding a new loader? |
| 258 | + // Make sure to add the new loader(s) before the "file" loader. |
| 259 | + ], |
| 260 | + }, |
| 261 | + ], |
| 262 | + }, |
| 263 | + plugins: [ |
| 264 | + // Makes some environment variables available in index.html. |
| 265 | + // The public URL is available as %PUBLIC_URL% in index.html, e.g.: |
| 266 | + // <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico"> |
| 267 | + // In production, it will be an empty string unless you specify "homepage" |
| 268 | + // in `package.json`, in which case it will be the pathname of that URL. |
| 269 | + new InterpolateHtmlPlugin(env.raw), |
| 270 | + // Generates an `index.html` file with the <script> injected. |
| 271 | + new HtmlWebpackPlugin({ |
| 272 | + inject: true, |
| 273 | + template: paths.appHtml, |
| 274 | + minify: { |
| 275 | + removeComments: true, |
| 276 | + collapseWhitespace: true, |
| 277 | + removeRedundantAttributes: true, |
| 278 | + useShortDoctype: true, |
| 279 | + removeEmptyAttributes: true, |
| 280 | + removeStyleLinkTypeAttributes: true, |
| 281 | + keepClosingSlash: true, |
| 282 | + minifyJS: true, |
| 283 | + minifyCSS: true, |
| 284 | + minifyURLs: true, |
| 285 | + }, |
| 286 | + }), |
| 287 | + // Makes some environment variables available to the JS code, for example: |
| 288 | + // if (process.env.NODE_ENV === 'production') { ... }. See `./env.js`. |
| 289 | + // It is absolutely essential that NODE_ENV was set to production here. |
| 290 | + // Otherwise React will be compiled in the very slow development mode. |
| 291 | + new webpack.DefinePlugin(env.stringified), |
| 292 | + // Minify the code. |
| 293 | + /* |
| 294 | + new webpack.optimize.UglifyJsPlugin({ |
| 295 | + compress: { |
| 296 | + warnings: false, |
| 297 | + // Disabled because of an issue with Uglify breaking seemingly valid code: |
| 298 | + // https://github.com/facebookincubator/create-react-app/issues/2376 |
| 299 | + // Pending further investigation: |
| 300 | + // https://github.com/mishoo/UglifyJS2/issues/2011 |
| 301 | + comparisons: false, |
| 302 | + }, |
| 303 | + mangle: { |
| 304 | + safari10: true, |
| 305 | + }, |
| 306 | + output: { |
| 307 | + comments: false, |
| 308 | + // Turned on because emoji and regex is not minified properly using default |
| 309 | + // https://github.com/facebookincubator/create-react-app/issues/2488 |
| 310 | + ascii_only: true, |
| 311 | + }, |
| 312 | + sourceMap: shouldUseSourceMap, |
| 313 | + }), |
| 314 | + */ |
| 315 | + // Note: this won't work without ExtractTextPlugin.extract(..) in `loaders`. |
| 316 | + new ExtractTextPlugin({ |
| 317 | + filename: cssFilename, |
| 318 | + }), |
| 319 | + // Generate a manifest file which contains a mapping of all asset filenames |
| 320 | + // to their corresponding output file so that tools can pick it up without |
| 321 | + // having to parse `index.html`. |
| 322 | + new ManifestPlugin({ |
| 323 | + fileName: 'asset-manifest.json', |
| 324 | + }), |
| 325 | + // Generate a service worker script that will precache, and keep up to date, |
| 326 | + // the HTML & assets that are part of the Webpack build. |
| 327 | + new SWPrecacheWebpackPlugin({ |
| 328 | + // By default, a cache-busting query parameter is appended to requests |
| 329 | + // used to populate the caches, to ensure the responses are fresh. |
| 330 | + // If a URL is already hashed by Webpack, then there is no concern |
| 331 | + // about it being stale, and the cache-busting can be skipped. |
| 332 | + dontCacheBustUrlsMatching: /\.\w{8}\./, |
| 333 | + filename: 'service-worker.js', |
| 334 | + logger(message) { |
| 335 | + if (message.indexOf('Total precache size is') === 0) { |
| 336 | + // This message occurs for every build and is a bit too noisy. |
| 337 | + return; |
| 338 | + } |
| 339 | + if (message.indexOf('Skipping static resource') === 0) { |
| 340 | + // This message obscures real errors so we ignore it. |
| 341 | + // https://github.com/facebookincubator/create-react-app/issues/2612 |
| 342 | + return; |
| 343 | + } |
| 344 | + console.log(message); |
| 345 | + }, |
| 346 | + minify: true, |
| 347 | + // For unknown URLs, fallback to the index page |
| 348 | + navigateFallback: publicUrl + '/index.html', |
| 349 | + // Ignores URLs starting from /__ (useful for Firebase): |
| 350 | + // https://github.com/facebookincubator/create-react-app/issues/2237#issuecomment-302693219 |
| 351 | + navigateFallbackWhitelist: [/^(?!\/__).*/], |
| 352 | + // Don't precache sourcemaps (they're large) and build asset manifest: |
| 353 | + staticFileGlobsIgnorePatterns: [/\.map$/, /asset-manifest\.json$/], |
| 354 | + }), |
| 355 | + // Moment.js is an extremely popular library that bundles large locale files |
| 356 | + // by default due to how Webpack interprets its code. This is a practical |
| 357 | + // solution that requires the user to opt into importing specific locales. |
| 358 | + // https://github.com/jmblog/how-to-optimize-momentjs-with-webpack |
| 359 | + // You can remove this if you don't use Moment.js: |
| 360 | + new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/), |
| 361 | + ], |
| 362 | + // Some libraries import Node modules but don't use them in the browser. |
| 363 | + // Tell Webpack to provide empty mocks for them so importing them works. |
| 364 | + node: { |
| 365 | + dgram: 'empty', |
| 366 | + fs: 'empty', |
| 367 | + net: 'empty', |
| 368 | + tls: 'empty', |
| 369 | + child_process: 'empty', |
| 370 | + }, |
| 371 | +}; |
0 commit comments