Completed
Push — master ( d771b6...a267a2 )
by Junior
10s
created

config/webpack.config.prod.js   A

Complexity

Total Complexity 7
Complexity/F 2.33

Size

Lines of Code 339
Function Count 3

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

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