|
| 1 | +// @remove-on-eject-begin |
| 2 | +/** |
| 3 | + * Copyright (c) 2015-present, Facebook, Inc. |
| 4 | + * All rights reserved. |
| 5 | + * |
| 6 | + * This source code is licensed under the BSD-style license found in the |
| 7 | + * LICENSE file in the root directory of this source tree. An additional grant |
| 8 | + * of patent rights can be found in the PATENTS file in the same directory. |
| 9 | + */ |
| 10 | +// @remove-on-eject-end |
| 11 | + |
| 12 | +var autoprefixer = require("autoprefixer"); |
| 13 | +var webpack = require("webpack"); |
| 14 | +var HtmlWebpackPlugin = require("html-webpack-plugin"); |
| 15 | +var ExtractTextPlugin = require("extract-text-webpack-plugin"); |
| 16 | +var ManifestPlugin = require("webpack-manifest-plugin"); |
| 17 | +var InterpolateHtmlPlugin = require("react-dev-utils/InterpolateHtmlPlugin"); |
| 18 | +var url = require("url"); |
| 19 | +var paths = require("./paths"); |
| 20 | +var getClientEnvironment = require("./env"); |
| 21 | +var isProduction = require("react-dev-utils/isProduction"); |
| 22 | + |
| 23 | +// @remove-on-eject-begin |
| 24 | +// `path` is not used after eject - see https://github.com/facebookincubator/create-react-app/issues/1174 |
| 25 | +var path = require("path"); |
| 26 | +// @remove-on-eject-end |
| 27 | + |
| 28 | +// Webpack uses `publicPath` to determine where the app is being served from. |
| 29 | +// It requires a trailing slash, or the file assets will get an incorrect path. |
| 30 | +var publicPath = paths.servedPath; |
| 31 | +// Some apps do not use client-side routing with pushState. |
| 32 | +// For these, "homepage" can be set to "." to enable relative asset paths. |
| 33 | +var shouldUseRelativeAssetPaths = publicPath === "./"; |
| 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. |
| 37 | +var publicUrl = publicPath.slice(0, -1); |
| 38 | +// Get environment variables to inject into our app. |
| 39 | +var env = getClientEnvironment(publicUrl); |
| 40 | + |
| 41 | +// Assert this just to be safe. |
| 42 | +// Development builds of React are slow and not intended for production. |
| 43 | +if (env.stringified["process.env"].NODE_ENV !== '"production"') { |
| 44 | + process.env.NODE_ENV = "development"; |
| 45 | +} |
| 46 | + |
| 47 | +// Note: defined here because it will be used more than once. |
| 48 | +const cssFilename = "static/css/" + |
| 49 | + process.env.NODE_ENV + |
| 50 | + ".[name].[contenthash:8].css"; |
| 51 | + |
| 52 | +// ExtractTextPlugin expects the build output to be flat. |
| 53 | +// (See https://github.com/webpack-contrib/extract-text-webpack-plugin/issues/27) |
| 54 | +// However, our output is structured with css, js and media folders. |
| 55 | +// To have this structure working with relative paths, we have to use custom options. |
| 56 | +const extractTextPluginOptions = shouldUseRelativeAssetPaths |
| 57 | + ? // Making sure that the publicPath goes back to to build folder. |
| 58 | + { publicPath: Array(cssFilename.split("/").length).join("../") } |
| 59 | + : {}; |
| 60 | + |
| 61 | +// This is the production configuration. |
| 62 | +// It compiles slowly and is focused on producing a fast and minimal bundle. |
| 63 | +// The development configuration is different and lives in a separate file. |
| 64 | +module.exports = { |
| 65 | + watch: true, |
| 66 | + context: paths.appSrc, |
| 67 | + // We generate sourcemaps in production. This is slow but gives good results. |
| 68 | + // You can exclude the *.map files from the build during deployment. |
| 69 | + devtool: isProduction() ? "source-map" : "cheap-module-source-map", |
| 70 | + // In production, we only want to load the polyfills and the app code. |
| 71 | + entry: [require.resolve("./polyfills"), paths.appIndexJs], |
| 72 | + output: { |
| 73 | + // The build folder. |
| 74 | + path: paths.appBuild, |
| 75 | + // Generated JS file names (with nested folders). |
| 76 | + // There will be one main bundle, and one file per asynchronous chunk. |
| 77 | + // We don't currently advertise code splitting but Webpack supports it. |
| 78 | + filename: "static/js/" + process.env.NODE_ENV + ".[name].[chunkhash:8].js", |
| 79 | + chunkFilename: ( |
| 80 | + "static/js/" + process.env.NODE_ENV + ".[name].[chunkhash:8].chunk.js" |
| 81 | + ), |
| 82 | + // We inferred the "public path" (such as / or /my-project) from homepage. |
| 83 | + publicPath: publicPath |
| 84 | + }, |
| 85 | + resolve: { |
| 86 | + // This allows you to set a fallback for where Webpack should look for modules. |
| 87 | + // We read `NODE_PATH` environment variable in `paths.js` and pass paths here. |
| 88 | + // We placed these paths second because we want `node_modules` to "win" |
| 89 | + // if there are any conflicts. This matches Node resolution mechanism. |
| 90 | + // https://github.com/facebookincubator/create-react-app/issues/253 |
| 91 | + modules: ["node_modules"].concat(paths.nodePaths), |
| 92 | + // These are the reasonable defaults supported by the Node ecosystem. |
| 93 | + // We also include JSX as a common component filename extension to support |
| 94 | + // some tools, although we do not recommend using it, see: |
| 95 | + // https://github.com/facebookincubator/create-react-app/issues/290 |
| 96 | + extensions: [".js", ".json", ".jsx"], |
| 97 | + alias: { |
| 98 | + // Support React Native Web |
| 99 | + // https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/ |
| 100 | + "react-native": "react-native-web" |
| 101 | + } |
| 102 | + }, |
| 103 | + // @remove-on-eject-begin |
| 104 | + // Resolve loaders (webpack plugins for CSS, images, transpilation) from the |
| 105 | + // directory of `react-scripts` itself rather than the project directory. |
| 106 | + resolveLoader: { |
| 107 | + modules: [ |
| 108 | + paths.ownNodeModules, |
| 109 | + // Lerna hoists everything, so we need to look in our app directory |
| 110 | + paths.appNodeModules |
| 111 | + ] |
| 112 | + }, |
| 113 | + // @remove-on-eject-end |
| 114 | + module: { |
| 115 | + rules: [ |
| 116 | + // Disable require.ensure as it's not a standard language feature. |
| 117 | + { parser: { requireEnsure: false } }, |
| 118 | + // First, run the linter. |
| 119 | + // It's important to do this before Babel processes the JS. |
| 120 | + { |
| 121 | + test: /\.(js|jsx)$/, |
| 122 | + enforce: "pre", |
| 123 | + use: [ |
| 124 | + { |
| 125 | + // @remove-on-eject-begin |
| 126 | + // Point ESLint to our predefined config. |
| 127 | + options: { |
| 128 | + // TODO: consider separate config for production, |
| 129 | + // e.g. to enable no-console and no-debugger only in production. |
| 130 | + configFile: path.join(__dirname, "../.eslintrc"), |
| 131 | + useEslintrc: false |
| 132 | + }, |
| 133 | + // @remove-on-eject-end |
| 134 | + loader: "eslint-loader" |
| 135 | + } |
| 136 | + ], |
| 137 | + include: paths.appSrc |
| 138 | + }, |
| 139 | + // ** ADDING/UPDATING LOADERS ** |
| 140 | + // The "url" loader handles all assets unless explicitly excluded. |
| 141 | + // The `exclude` list *must* be updated with every change to loader extensions. |
| 142 | + // When adding a new loader, you must add its `test` |
| 143 | + // as a new entry in the `exclude` list in the "url" loader. |
| 144 | + |
| 145 | + // "url" loader embeds assets smaller than specified size as data URLs to avoid requests. |
| 146 | + // Otherwise, it acts like the "file" loader. |
| 147 | + { |
| 148 | + exclude: [/\.html$/, /\.(js|jsx)$/, /\.css$/, /\.json$/, /\.svg$/], |
| 149 | + loader: "url-loader", |
| 150 | + options: { |
| 151 | + limit: 10000, |
| 152 | + name: ( |
| 153 | + "static/media/" + process.env.NODE_ENV + ".[name].[hash:8].[ext]" |
| 154 | + ) |
| 155 | + } |
| 156 | + }, |
| 157 | + // Process JS with Babel. |
| 158 | + { |
| 159 | + test: /\.(js|jsx)$/, |
| 160 | + include: paths.appSrc, |
| 161 | + loader: "babel-loader", |
| 162 | + // @remove-on-eject-begin |
| 163 | + options: { |
| 164 | + babelrc: false, |
| 165 | + presets: [require.resolve("babel-preset-react-app")] |
| 166 | + } |
| 167 | + // @remove-on-eject-end |
| 168 | + }, |
| 169 | + // The notation here is somewhat confusing. |
| 170 | + // "postcss" loader applies autoprefixer to our CSS. |
| 171 | + // "css" loader resolves paths in CSS and adds assets as dependencies. |
| 172 | + // "style" loader normally turns CSS into JS modules injecting <style>, |
| 173 | + // but unlike in development configuration, we do something different. |
| 174 | + // `ExtractTextPlugin` first applies the "postcss" and "css" loaders |
| 175 | + // (second argument), then grabs the result CSS and puts it into a |
| 176 | + // separate file in our build process. This way we actually ship |
| 177 | + // a single CSS file in production instead of JS code injecting <style> |
| 178 | + // tags. If you use code splitting, however, any async bundles will still |
| 179 | + // use the "style" loader inside the async code so CSS from them won't be |
| 180 | + // in the main CSS file. |
| 181 | + { |
| 182 | + test: /\.css$/, |
| 183 | + loader: ExtractTextPlugin.extract( |
| 184 | + Object.assign( |
| 185 | + { |
| 186 | + fallback: "style-loader", |
| 187 | + use: [ |
| 188 | + { |
| 189 | + loader: "css-loader", |
| 190 | + options: { |
| 191 | + importLoaders: 1 |
| 192 | + } |
| 193 | + }, |
| 194 | + { |
| 195 | + loader: "postcss-loader", |
| 196 | + options: { |
| 197 | + ident: "postcss", // https://webpack.js.org/guides/migrating/#complex-options |
| 198 | + plugins: function() { |
| 199 | + return [ |
| 200 | + autoprefixer({ |
| 201 | + browsers: [ |
| 202 | + ">1%", |
| 203 | + "last 4 versions", |
| 204 | + "Firefox ESR", |
| 205 | + "not ie < 9" // React doesn't support IE8 anyway |
| 206 | + ] |
| 207 | + }) |
| 208 | + ]; |
| 209 | + } |
| 210 | + } |
| 211 | + } |
| 212 | + ] |
| 213 | + }, |
| 214 | + extractTextPluginOptions |
| 215 | + ) |
| 216 | + ) |
| 217 | + // Note: this won't work without `new ExtractTextPlugin()` in `plugins`. |
| 218 | + }, |
| 219 | + // "file" loader for svg |
| 220 | + { |
| 221 | + test: /\.svg$/, |
| 222 | + loader: "file-loader", |
| 223 | + options: { |
| 224 | + name: ( |
| 225 | + "static/media/" + process.env.NODE_ENV + ".[name].[hash:8].[ext]" |
| 226 | + ) |
| 227 | + } |
| 228 | + } |
| 229 | + |
| 230 | + // ** STOP ** Are you adding a new loader? |
| 231 | + // Remember to add the new extension(s) to the "url" loader exclusion list. |
| 232 | + ] |
| 233 | + }, |
| 234 | + plugins: [ |
| 235 | + // Makes some environment variables available in index.html. |
| 236 | + // The public URL is available as %PUBLIC_URL% in index.html, e.g.: |
| 237 | + // <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico"> |
| 238 | + // In production, it will be an empty string unless you specify "homepage" |
| 239 | + // in `package.json`, in which case it will be the pathname of that URL. |
| 240 | + new InterpolateHtmlPlugin(env.raw), |
| 241 | + // Generates an `index.html` file with the <script> injected. |
| 242 | + new HtmlWebpackPlugin({ |
| 243 | + inject: true, |
| 244 | + template: paths.appHtml, |
| 245 | + minify: ( |
| 246 | + isProduction() |
| 247 | + ? { |
| 248 | + removeComments: true, |
| 249 | + collapseWhitespace: true, |
| 250 | + removeRedundantAttributes: true, |
| 251 | + useShortDoctype: true, |
| 252 | + removeEmptyAttributes: true, |
| 253 | + removeStyleLinkTypeAttributes: true, |
| 254 | + keepClosingSlash: true, |
| 255 | + minifyJS: true, |
| 256 | + minifyCSS: true, |
| 257 | + minifyURLs: true |
| 258 | + } |
| 259 | + : false |
| 260 | + ) |
| 261 | + }), |
| 262 | + // Makes some environment variables available to the JS code, for example: |
| 263 | + // if (process.env.NODE_ENV === 'production') { ... }. See `./env.js`. |
| 264 | + // It is absolutely essential that NODE_ENV was set to production here. |
| 265 | + // Otherwise React will be compiled in the very slow development mode. |
| 266 | + new webpack.DefinePlugin(env.stringified), |
| 267 | + // Minify the code. |
| 268 | + isProduction() |
| 269 | + ? new webpack.optimize.UglifyJsPlugin({ |
| 270 | + compress: { |
| 271 | + screw_ie8: true, // React doesn't support IE8 |
| 272 | + warnings: false |
| 273 | + }, |
| 274 | + mangle: { |
| 275 | + screw_ie8: true |
| 276 | + }, |
| 277 | + output: { |
| 278 | + comments: false, |
| 279 | + screw_ie8: true |
| 280 | + }, |
| 281 | + sourceMap: true |
| 282 | + }) |
| 283 | + : false, |
| 284 | + // Note: this won't work without ExtractTextPlugin.extract(..) in `loaders`. |
| 285 | + new ExtractTextPlugin({ |
| 286 | + filename: cssFilename |
| 287 | + }), |
| 288 | + // Generate a manifest file which contains a mapping of all asset filenames |
| 289 | + // to their corresponding output file so that tools can pick it up without |
| 290 | + // having to parse `index.html`. |
| 291 | + new ManifestPlugin({ |
| 292 | + fileName: "asset-manifest.json" |
| 293 | + }) |
| 294 | + ].filter(Boolean), |
| 295 | + // Some libraries import Node modules but don't use them in the browser. |
| 296 | + // Tell Webpack to provide empty mocks for them so importing them works. |
| 297 | + node: { |
| 298 | + fs: "empty", |
| 299 | + net: "empty", |
| 300 | + tls: "empty" |
| 301 | + } |
| 302 | +}; |
0 commit comments