webpack.config.prod.js 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. var autoprefixer = require('autoprefixer');
  2. var webpack = require('webpack');
  3. var HtmlWebpackPlugin = require('html-webpack-plugin');
  4. var ExtractTextPlugin = require('extract-text-webpack-plugin');
  5. var ManifestPlugin = require('webpack-manifest-plugin');
  6. var InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
  7. var url = require('url');
  8. var paths = require('./paths');
  9. var getClientEnvironment = require('./env');
  10. function ensureSlash(path, needsSlash) {
  11. var hasSlash = path.endsWith('/');
  12. if (hasSlash && !needsSlash) {
  13. return path.substr(path, path.length - 1);
  14. } else if (!hasSlash && needsSlash) {
  15. return path + '/';
  16. } else {
  17. return path;
  18. }
  19. }
  20. // We use "homepage" field to infer "public path" at which the app is served.
  21. // Webpack needs to know it to put the right <script> hrefs into HTML even in
  22. // single-page apps that may serve index.html for nested URLs like /todos/42.
  23. // We can't use a relative path in HTML because we don't want to load something
  24. // like /todos/42/static/js/bundle.7289d.js. We have to know the root.
  25. var homepagePath = require(paths.appPackageJson).homepage;
  26. var homepagePathname = homepagePath ? url.parse(homepagePath).pathname : '/';
  27. // Webpack uses `publicPath` to determine where the app is being served from.
  28. // It requires a trailing slash, or the file assets will get an incorrect path.
  29. var publicPath = ensureSlash(homepagePathname, true);
  30. // `publicUrl` is just like `publicPath`, but we will provide it to our app
  31. // as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript.
  32. // Omit trailing slash as %PUBLIC_PATH%/xyz looks better than %PUBLIC_PATH%xyz.
  33. var publicUrl = ensureSlash(homepagePathname, false);
  34. // Get environment variables to inject into our app.
  35. var env = getClientEnvironment(publicUrl);
  36. // Assert this just to be safe.
  37. // Development builds of React are slow and not intended for production.
  38. if (env['process.env'].NODE_ENV !== '"production"') {
  39. throw new Error('Production builds must have NODE_ENV=production.');
  40. }
  41. // This is the production configuration.
  42. // It compiles slowly and is focused on producing a fast and minimal bundle.
  43. // The development configuration is different and lives in a separate file.
  44. module.exports = {
  45. // Don't attempt to continue if there are any errors.
  46. bail: true,
  47. // We generate sourcemaps in production. This is slow but gives good results.
  48. // You can exclude the *.map files from the build during deployment.
  49. devtool: 'source-map',
  50. // In production, we only want to load the polyfills and the app code.
  51. entry: [
  52. require.resolve('./polyfills'),
  53. paths.appIndexJs
  54. ],
  55. output: {
  56. // The build folder.
  57. path: paths.appBuild,
  58. // Generated JS file names (with nested folders).
  59. // There will be one main bundle, and one file per asynchronous chunk.
  60. // We don't currently advertise code splitting but Webpack supports it.
  61. filename: 'static/js/[name].[chunkhash:8].js',
  62. chunkFilename: 'static/js/[name].[chunkhash:8].chunk.js',
  63. // We inferred the "public path" (such as / or /my-project) from homepage.
  64. publicPath: publicPath
  65. },
  66. resolve: {
  67. // This allows you to set a fallback for where Webpack should look for modules.
  68. // We read `NODE_PATH` environment variable in `paths.js` and pass paths here.
  69. // We use `fallback` instead of `root` because we want `node_modules` to "win"
  70. // if there any conflicts. This matches Node resolution mechanism.
  71. // https://github.com/facebookincubator/create-react-app/issues/253
  72. fallback: paths.nodePaths,
  73. // These are the reasonable defaults supported by the Node ecosystem.
  74. // We also include JSX as a common component filename extension to support
  75. // some tools, although we do not recommend using it, see:
  76. // https://github.com/facebookincubator/create-react-app/issues/290
  77. extensions: ['.js', '.json', '.jsx', ''],
  78. alias: {
  79. // Support React Native Web
  80. // https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
  81. 'react-native': 'react-native-web'
  82. }
  83. },
  84. module: {
  85. // First, run the linter.
  86. // It's important to do this before Babel processes the JS.
  87. preLoaders: [
  88. {
  89. test: /\.(js|jsx)$/,
  90. loader: 'eslint',
  91. include: paths.appSrc
  92. }
  93. ],
  94. loaders: [
  95. // Default loader: load all assets that are not handled
  96. // by other loaders with the url loader.
  97. // Note: This list needs to be updated with every change of extensions
  98. // the other loaders match.
  99. // E.g., when adding a loader for a new supported file extension,
  100. // we need to add the supported extension to this loader too.
  101. // Add one new line in `exclude` for each loader.
  102. //
  103. // "file" loader makes sure those assets end up in the `build` folder.
  104. // When you `import` an asset, you get its filename.
  105. // "url" loader works just like "file" loader but it also embeds
  106. // assets smaller than specified size as data URLs to avoid requests.
  107. {
  108. exclude: [
  109. /\.html$/,
  110. /\.(js|jsx)$/,
  111. /\.css$/,
  112. /\.json$/,
  113. /\.woff$/,
  114. /\.woff2$/,
  115. /\.(ttf|svg|eot)$/
  116. ],
  117. loader: 'url',
  118. query: {
  119. limit: 10000,
  120. name: 'static/media/[name].[hash:8].[ext]'
  121. }
  122. },
  123. // Process JS with Babel.
  124. {
  125. test: /\.(js|jsx)$/,
  126. include: paths.appSrc,
  127. loader: 'babel',
  128. },
  129. // The notation here is somewhat confusing.
  130. // "postcss" loader applies autoprefixer to our CSS.
  131. // "css" loader resolves paths in CSS and adds assets as dependencies.
  132. // "style" loader normally turns CSS into JS modules injecting <style>,
  133. // but unlike in development configuration, we do something different.
  134. // `ExtractTextPlugin` first applies the "postcss" and "css" loaders
  135. // (second argument), then grabs the result CSS and puts it into a
  136. // separate file in our build process. This way we actually ship
  137. // a single CSS file in production instead of JS code injecting <style>
  138. // tags. If you use code splitting, however, any async bundles will still
  139. // use the "style" loader inside the async code so CSS from them won't be
  140. // in the main CSS file.
  141. {
  142. test: /\.css$/,
  143. loader: ExtractTextPlugin.extract('style', 'css?importLoaders=1!postcss')
  144. // Note: this won't work without `new ExtractTextPlugin()` in `plugins`.
  145. },
  146. // JSON is not enabled by default in Webpack but both Node and Browserify
  147. // allow it implicitly so we also enable it.
  148. {
  149. test: /\.json$/,
  150. loader: 'json'
  151. },
  152. // "file" loader for svg
  153. {
  154. test: /\.svg$/,
  155. loader: 'file',
  156. query: {
  157. name: 'static/media/[name].[hash:8].[ext]'
  158. }
  159. },
  160. // "file" loader for fonts
  161. {
  162. test: /\.woff$/,
  163. loader: 'file',
  164. query: {
  165. name: 'fonts/[name].[hash].[ext]'
  166. }
  167. },
  168. {
  169. test: /\.woff2$/,
  170. loader: 'file',
  171. query: {
  172. name: 'fonts/[name].[hash].[ext]'
  173. }
  174. },
  175. {
  176. test: /\.(ttf|eot)$/,
  177. loader: 'file',
  178. query: {
  179. name: 'fonts/[name].[hash].[ext]'
  180. }
  181. }
  182. ]
  183. },
  184. // We use PostCSS for autoprefixing only.
  185. postcss: function() {
  186. return [
  187. autoprefixer({
  188. browsers: [
  189. '>1%',
  190. 'last 4 versions',
  191. 'Firefox ESR',
  192. 'not ie < 9', // React doesn't support IE8 anyway
  193. ]
  194. }),
  195. ];
  196. },
  197. plugins: [
  198. // Makes the public URL available as %PUBLIC_URL% in index.html, e.g.:
  199. // <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
  200. // In production, it will be an empty string unless you specify "homepage"
  201. // in `package.json`, in which case it will be the pathname of that URL.
  202. new InterpolateHtmlPlugin({
  203. PUBLIC_URL: publicUrl
  204. }),
  205. // Generates an `index.html` file with the <script> injected.
  206. new HtmlWebpackPlugin({
  207. inject: true,
  208. template: paths.appHtml,
  209. minify: {
  210. removeComments: true,
  211. collapseWhitespace: true,
  212. removeRedundantAttributes: true,
  213. useShortDoctype: true,
  214. removeEmptyAttributes: true,
  215. removeStyleLinkTypeAttributes: true,
  216. keepClosingSlash: true,
  217. minifyJS: true,
  218. minifyCSS: true,
  219. minifyURLs: true
  220. }
  221. }),
  222. // Makes some environment variables available to the JS code, for example:
  223. // if (process.env.NODE_ENV === 'production') { ... }. See `./env.js`.
  224. // It is absolutely essential that NODE_ENV was set to production here.
  225. // Otherwise React will be compiled in the very slow development mode.
  226. new webpack.DefinePlugin(env),
  227. // This helps ensure the builds are consistent if source hasn't changed:
  228. new webpack.optimize.OccurrenceOrderPlugin(),
  229. // Try to dedupe duplicated modules, if any:
  230. new webpack.optimize.DedupePlugin(),
  231. // Minify the code.
  232. new webpack.optimize.UglifyJsPlugin({
  233. compress: {
  234. screw_ie8: true, // React doesn't support IE8
  235. warnings: false
  236. },
  237. mangle: {
  238. screw_ie8: true
  239. },
  240. output: {
  241. comments: false,
  242. screw_ie8: true
  243. }
  244. }),
  245. // Note: this won't work without ExtractTextPlugin.extract(..) in `loaders`.
  246. new ExtractTextPlugin('static/css/[name].[contenthash:8].css'),
  247. // Generate a manifest file which contains a mapping of all asset filenames
  248. // to their corresponding output file so that tools can pick it up without
  249. // having to parse `index.html`.
  250. new ManifestPlugin({
  251. fileName: 'asset-manifest.json'
  252. })
  253. ],
  254. // Some libraries import Node modules but don't use them in the browser.
  255. // Tell Webpack to provide empty mocks for them so importing them works.
  256. node: {
  257. fs: 'empty',
  258. net: 'empty',
  259. tls: 'empty'
  260. }
  261. };