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