UNPKG

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