Webpack is a mainstream modular packaging tool with powerful functions. When using Webpack, if you do not pay attention to performance optimization, there is a great possibility of performance problems. Performance problems are mainly divided into slow packaging and construction speed during development, repetitive work during development and debugging, and low output file quality. Therefore, performance optimization is mainly analyzed from these aspects. This article is mainly based on their own understanding of the “simple Webpack” book summary, covering most of the optimization methods, can be used as a reference and check list of Webpack performance optimization. Based on Webpack3.4, this article requires that you be familiar with the basic usage of Webpack. Let’s take some time to master webPack performance optimization.
Webpack, Wu Haolin
First, optimize the construction speed
Webpack starts up and recursively parses the dependent files based on the Entry configuration. This process is divided into two processes: searching for files and analyzing and converting matched files. Therefore, you can optimize the configuration from these two perspectives.
1.1 Narrowing the file search scope
1.1.1 Optimized Loader configuration:
Because Loader’s file conversion operation is time-consuming, it is necessary to keep as few files as possible to be processed by Loader
module.export = {
modeule: {
rules: [{// Do not write /\.jsx? If only js files exist in the project source code. $/ to improve the regular expression performance
test: /\.js$/.// babel-loader supports caching of converted results, enabled by cacheDirectory
use: ['babel-loader? cacheDirectory'].// Use babel-loader only for files in the SRC directory under the project root directory
include: path.resolve(__dirname, 'src'),}]}}Copy the code
1.1.2 The resolve field tells Webpack how to search for files, resolve.modules:
resolve.modules:[path.resolve(__dirname, 'node_modules')]
Copy the code
Avoid layers of lookup.
Resolve. modules tells Webpack which directories to look for third-party modules. The default is [‘node_modules’], which looks for./node_modules,.. / node_modules,.. /.. / node_modules.
1.1.3 Resolve. MainFields:
resolve.mainFields:['main']
Copy the code
Set the value of the less as far as possible can reduce the entry file search steps The use of third-party modules in order to adapt to different environment, can define multiple entry documents, mainFields defined using third-party modules which entry files, because most third-party modules using the main fields to describe the location of the entrance to the file, so you can set a main value alone, To reduce the search
1.1.4 Resolve. Alias:
Resolve. Alias for large third-party modules to make Webpack use the library’s min file directly, avoiding in-library resolution like with React:
resolve.alias:{
'react':patch.resolve(__dirname,'./node_modules/react/dist/react.min.js')}Copy the code
This will affect Tree-shaking. It is best for libraries that are more holistic, but for libraries that are more fragmented like LoDash. Avoid this approach.
1.1.5 Resolve. Extensions:, reduce file lookup
Default: Extensions :[‘.js’, ‘.json’], Webpack will look up files from the extensions list if the import statement does not have a file suffix.
- Keep the list values to a minimum
- High frequency file types are suffixed first
- Import statements in source code as far as possible write file suffixes, such as
require(./data)
To be writtenrequire(./data.json)
1.1.6 module.noParse
The fields tell Webpack which files do not have to be parsed and can be used to exclude parsing of modular library files
If resolve. Alias is used to configure react.min.js, parsing should also be ruled out. React.min.js is built to run directly in the browser, and is modular. The noParse values can be RegExp, [RegExp], or function
module:{ noParse:[/jquery|chartjs/, /react\.min\.js$/] }
1.1.7 When configuring the Loader, use test, exclude, and include to narrow the search scope
1.2 Use DllPlugin to reduce the compilation times of basic modules
DllPlugin is a dynamic link library plug-in whose principle is to extract the basic modules that web pages depend on and package them into A DLL file. When a module to be imported exists in a DLL, the module is no longer packaged, but obtained from the DLL. Why does this increase build speed? The reason is that most DLLS contain common third-party modules such as React and React-dom, so as long as these modules are not upgraded, they only need to be compiled once. I think doing this has the same effect as configuring resolve.alias and module.noParse.
Usage:
-
Use DllPlugin to configure a webpack_dll.config.js to build the DLL file:
// webpack_dll.config.js const path = require('path'); const DllPlugin = require('webpack/lib/DllPlugin'); module.exports = { entry: {// Put the React related modules into a separate dynamic link library react:['react'.'react-dom'].polyfill: ['core-js/fn/promise'.'whatwg-fetch']},output: {filename:'[name].dll.js'.path:path.resolve(__dirname, 'dist'), library:'_dll_[name]'.// The global variable name of the DLL }, plugins: [new DllPlugin({ name:'_dll_[name]'.// The global variable name of the DLL path:path.join(__dirname,'dist'.'[name].manifest.json'),// Describe the generated manifest file}})]Copy the code
The name value of the DllPlugin parameter must be the same as the output.library value, and the generated manifest file will reference the output.library value.
The resulting file:
| - polyfill. DLL. Js | -- polyfill. Manifest. Json | -- the react. DLL. Js └ ─ ─ the react. The manifest. JsonCopy the code
Xx.dll. js contains a package of n modules, which are stored in an array with the array index as ID. These modules are exposed globally by a variable named _xx_DLL and can be accessed through window._xx_DLL. The xx.manifest.json file describes which modules the DLL file contains, and the path and ID of each module. The xx.manifest.json file is then imported using the DllReferencePlugin in the project’s main config file.
-
Use the DllReferencePlugin in the main config file to import xx.manifest.json:
//webpack.config.json const path = require('path'); const DllReferencePlugin = require('webpack/lib/DllReferencePlugin'); const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin'); module.exports = { entry: {main:'./main.js' }, / /... Omit configuration of output, loader, etc plugins:[ new DllReferencePlugin({ manifest:require('./dist/react.manifest.json')}),new DllReferenctPlugin({ manifest:require('./dist/polyfill.manifest.json')}),// You need to manually import react.dll new AddAssetHtmlWebpackPlugin( { filepath: path.resolve(__dirname,'dll/react.dll.js')})]}Copy the code
The final build generates main.js
-
Execute a build
webpack --config webpack_dll.config.js Copy the code
1.3 Using HappyPack to Enable Multi-process Loader Conversion
In the whole construction process, the most time-consuming is the Loader’s file conversion operation, and the Webpack running on Node.js is a single-threaded model, that is, it can only be processed one file at a time, not in parallel. HappyPack can split tasks into child processes and send results to the main process. JS is a single-threaded model and can only be improved in this multi-process manner.
The core principle of HappyPack is to break up these tasks into multiple processes to execute them in parallel, reducing the total build time.
HappyPack uses the following:
npm i -D happypack
// webpack.config.json
const path = require('path');
const HappyPack = require('happypack');
// Create a shared process pool. All HappyPack instances use the same process pool to handle tasks
// const happyThreadPool = HappyPack.ThreadPool({size: 5});
module.exports = {
/ /...
module: {rules: [{test:/\.js$/.// pass processing of.js files to an instance of HappyPack with id Babel
use:['happypack/loader? id=babel']
exclude:path.resolve(__dirname, 'node_modules')
},{
test:/\.css/.// Pass the processing of the.css file to the HappyPack instance with the id CSS
use:['happypack/loader? id=css']}],plugins: [new HappyPack({
id:'babel'.loaders: ['babel-loader? cacheDirectory'].//threads: 3,// Start several sub-processes to handle this type of file. Default is 3
Verbose: true,// Whether to allow happyPack to output logs. The default value is true
//threadPool: happyThreadPool// represents a shared process pool
}),
new HappyPack({
id:'css'.loaders: ['css-loader'})]}}Copy the code
1.4 Enable multi-process compressed JS files using ParallelUglifyPlugin
When using UglifyJS plug-in to compress JS code, it is necessary to parse the code into the AST (abstract syntax tree) represented by Object, and then apply various rules to analyze and process the AST. Therefore, this process takes a lot of calculation and time. ParallelUglifyPlugin enables multiple sub-processes, each of which uses UglifyJS compression code and can be executed in parallel, significantly reducing compression time.
It is also very simple to use. Replace the original UglifyJS plug-in with a cost plug-in, and use it as follows:
npm i -D webpack-parallel-uglify-plugin
// webpack.config.json
const ParallelUglifyPlugin = require('wbepack-parallel-uglify-plugin');
/ /...
plugins: [
new ParallelUglifyPlugin({
uglifyJS: {/ /... So this is uglifyJS
},
/ /... Other ParallelUglifyPlugin parameters, setting cacheDir to enable caching and speed up builds})]Copy the code
When instantiated with new ParallelUglifyPlugin(), the following parameters are supported:
- test
- include
- exclude
- cacheDir
- workerCount
- sourceMap
- uglifyES
- uglifyJS
2. Optimize development experience
After you modify the source code during development, you need to automatically build and refresh the browser to see the effect. This process can be automated using Webpack, which listens for changes to files, and DevServer, which refreshes the browser.
2.1 Using Automatic Refresh
2.1.1 Webpack listens for files
Webpack can enable listening in two ways: 1. Start Webpack with the –watch parameter; 2. Set watch:true in the configuration file. In addition, the following configuration parameters are available. Setting watchOptions properly can optimize the listening experience.
module.exports = {
watch: true.watchOptions: {
ignored: /node_modules/.aggregateTimeout: 300.// How long after the file changes to initiate a build, the larger the better
poll: 1000.// The number of queries per second, the smaller the better}}Copy the code
Ignored: Set the directory that you don’t listen to. Ignoring node_modules can significantly reduce Webpack memory consumption
AggregateTimeout: how long after the file is changed to initiate the build, so as to avoid frequent compilation and deadlock caused by the file updating too fast. The larger the better, so as to reduce the reconstruction frequency
Poll: determines whether a file has changed by polling the system for file changes. Poll indicates the number of query times per second. The smaller the poll, the lower the check frequency
2.1.2 DevServer Refreshes the browser
DevServer refreshes the browser in two ways:
- Inject proxy client code into the web page and initiate a refresh through the client
- Load an iframe into the web page and refresh the iframe to achieve the refresh effect
By default, and devServer: {inline:true} refresh the page in the first way. In the first way, DevServer does not know which chunks the web page depends on, so it injects client code into each Chunk, causing a slow build when many chunks are exported. Since only one client is required for a page, disabling inline mode reduces build time and improves with more chunks. Closing mode:
- Start with webpack-dev-server –inline false
- configuration
devserver:{inline:false}
After closing the inline entrance website http://localhost:8080/webpack-dev-server/
In addition, you can set devServer.compress to whether to use Gzip compression. The default value is false
2.2 Enabling the MODULE hot replacement HMR
Module hot replacement does not refresh the entire page, but only recompiles the changed module, and replaces the old module with the new module, so the preview reaction is faster, the wait time is less, and the current page can be preserved without refreshing the page. The principle is to inject proxy clients into each chunk to connect to DevServer and web pages. Opening mode:
- webpack-dev-server –hot
- Use HotModuleReplacementPlugin, more troublesome
After this function is enabled, if the submodule is modified, partial refresh can be realized. However, if the root JS file is modified, the whole page will be refreshed. The reason is that when the submodule is updated, the event is passed up one layer until the file of one layer receives the currently changed module, and then the callback function is executed. If layers are tossed out until no file is received at the outermost layer, the entire page is refreshed.
Using the NamedModulesPlugin allows the console to print out the name of the replaced module instead of the numeric ID, listens with Webpack, and ignores files in the node_modules directory to improve performance.
const NamedModulesPlugin = require('webpack/lib/NamedModulesPlugin');
modules.export = {
plugins: [
// Displays the name of the module to be replaced
new NamedModulesPlugin()
]
}
Copy the code
Optimize output quality – compress file volume
3.1 Environment differentiation – Reduce the production environment code volume
The code operation environment is divided into development environment and production environment. The code needs to do different operations according to different environments. Many third-party libraries also have a large amount of if and else code judged according to the development environment. Differentiating environments can reduce the size of the code in the output production environment. The DefinePlugin plugin is used in Webpack to define the environment for which the configuration file applies.
const DefinePlugin = require('webpack/lib/DefinePlugin');// Only for code that WebPack needs to process
/ /...
plugins:[
new DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production')}})]Copy the code
Note that the reason for json.stringify (‘production’) is that the value of the environment variable requires a double-quoted string, and the value after stringify is ‘”production”‘
You can then use the defined environment in the source code:
if(process.env.NODE_ENV === 'production') {
console.log('You are in production')
// TODO
}else {
console.log('You are using the development environment')
// TODO
}
Copy the code
When process is used in code, Webpack is automatically packaged into the code of the Process module, which emulates the process in Node.js, to support non-Node.js runtime environments. To support the process.env.node_env === ‘production’ statement.
3.2 Compressed code -JS, ES, CSS
-
Compressed JS: Webpack built-in UglifyJS plug-in, ParallelUglifyPlugin
Can analyze THE JS code syntax tree, understand the meaning of the code, so as to eliminate invalid code, remove the log input code, shorten the variable name optimization. Common configuration parameters are as follows:
const UglifyJSPlugin = require('webpack/lib/optimize/UglifyJsPlugin'); / /... plugins: [ new UglifyJSPlugin({ compress: { warnings: false.// Delete useless code without warning drop_console: true.// Delete all console statements, compatible with IE collapse_vars: true.// Embed variables that are defined but used only once reduce_vars: true.// Extract static values used multiple times but not defined into variables }, output: { beautify: false.// The most compact output, with no Spaces and tabs reserved comments: false.// Delete all comments}})]Copy the code
Starting webpack with webpack — optimize-Minimize can inject the default configuration of UglifyJSPlugin
-
Compressed ES6: third-party UglifyJS plug-in
As more and more browsers support direct ES6 code execution, you should run native ES6 as much as possible, with less code and better performance than converted ES5 code. When you run ES6 code directly, you also need to compress it. The third-party Uglip-webpack-plugin provides the ability to compress ES6 code:
npm i -D uglify-webpack-plugin@beta // Use the latest version of the plug-in //webpack.config.json const UglifyESPlugin = require('uglify-webpack-plugin'); / /... plugins:[ new UglifyESPlugin({ uglifyOptions: { // One more layer is nested than UglifyJS compress: { warnings: false.drop_console: true.collapse_vars: true.reduce_vars: true }, output: { beautify: false.comments: false}}})]Copy the code
Also to prevent babel-loader from switching to ES6 code, remove babel-preset-env in. Babelrc since it is babel-preset-env that is responsible for switching TO ES6 to ES5.
-
Compressed CSS: CSS-loader? Minimize, PurifyCSSPlugin
Cssnano is based on PostCSS, and can not only delete Spaces, but also understand the code meaning, such as color:#ff0000 to color:red, csS-loader built-in CSSNano, only need to use CSS-loader? It turns on CS Nano compression.
Another way to compress CSS is to use the PurifyCSSPlugin, which needs to be used in conjunction with the extract-text-webpack-plugin. Its main function is to remove unused CSS code, like JS Tree Shaking.
Removing DEAD JS code using Tree Shaking
Tree Shaking can weed out dead code that you don’t need. It relies on ES6’s modular import and export syntax, first seen in Rollup and introduced in Webpack 2.0. Suitable for Lodash, utils.js and other scattered utility class files. It only works if the code follows ES6’s modularity syntax, which is static (paths in import and export statements must be static strings and cannot be placed in other code blocks). If you use modularity in ES5, for example, module.export = {… }, require(x+y), if (x) {require(‘./util’)}, Webpack cannot figure out which code can be removed.
Enable Tree Shaking:
-
Modify. Babelrc to preserve ES6 modular statements:
{ "presets": [["env", { "module": false}, // turn off Babel module conversion, preserve ES6 modularity syntax]]}Copy the code
-
Starting webpack with –display-used-exports prints a prompt for code culling in the shell
-
Use UglifyJSPlugin, or boot up with –optimize — minimize
-
When using third-party libraries, resolve. MainFields: [‘ jsNext :main’, ‘main’] needs to be configured to specify ES6 modularized code entry when parsing third-party library code
Optimize output quality — speed up network requests
4.1 Use CDN to accelerate static resource loading
-
The principle of CND acceleration
By deploying resources around the world, CDN enables users to access resources nearby and speeds up access. To access the CDN, you need to upload static resources of web pages to the CDN service. When accessing these resources, the URL provided by the CDN service is used.
CDN will enable caching for resources for a long time. For example, if a user obtains index. HTML from the CDN, the user will still use the previous version until the cache expires, even if the index. HTML is replaced later. Industry practice:
- HTML files: store them on your own server with cache disabled and do not access CDN
- Static JS, CSS, images and other resources: enable CDN and cache, and file name with Hash value calculated by the content, so that the Hash will change as the content changes, the file name will change, and it will be re-downloaded regardless of how long the cache time.
In addition, under the HTTP1.x protocol, browsers limit the number of concurrent requests to the same domain name to 4 to 8. Therefore, all static resources can be placed on different CDN services, such as JS files under js.cdn.com and CSS files under css.cdn.com. This brings a new problem: increased domain resolution time, which can be solved by dns-prefetch to reduce domain resolution time. A URL such as **//xx.com omits the protocol **. The advantage of this is that the browser automatically determines whether to use HTTP or HTTPS when accessing resources based on the mode of the current URL.
-
In summary, the build needs to satisfy the following points:
- The STATIC resource import URL is changed to the absolute path to the CDN service
- The file name of a static resource must have a Hash value calculated based on the content
- Different types of resources are stored on CDN of different domain names
-
Final configuration:
const ExtractTextPlugin = require('extract-text-webpack-plugin'); const {WebPlugin} = require('web-webpack-plugin'); / /... output:{ filename: '[name]_[chunkhash:8].js'.path: path.resolve(__dirname, 'dist'), publicPatch: '//js.cdn.com/id/'.// Specify the CDN address for storing JS files }, module: {rules: [{test: /\.css/.use: ExtractTextPlugin.extract({ use: ['css-loader? minimize'].publicPatch: '//img.cdn.com/id/'.// Specify the CDN address for storing resources such as images imported from the CSS file}, {}),test: /\.png/.use: ['file-loader? name=[name]_[hash:8].[ext]'].// Hash the output PNG file name}},plugins: [new WebPlugin({ template: './template.html'.filename: 'index.html'.stylePublicPath: '//css.cdn.com/id/'.// Specify the CDN address for storing CSS files }), new ExtractTextPlugin({ filename:`[name]_[contenthash:8].css`.// Hash the output CSS file})]Copy the code
We want to introduce resources through CDN
const AddAssetHtmlCdnPlugin = require('add-asset-html-cdn-webpack-plugin')
new AddAssetHtmlCdnPlugin(true, {'jquery':'https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js'
})
Copy the code
But you also want to introduce jquery in your code to get hints
import $ from 'jquery'
console.log('$', $)Copy the code
But jquery is still packaged
externals:{
'jquery':'$'
}
Copy the code
Note that jquery is external in the configuration file so that jquery is not packaged
4.2 Multi-page applications extract common code between pages to take advantage of caching
-
The principle of
Large websites are usually composed of multiple pages, each of which is an independent, single-page application, relying on the same style files, technology stacks, etc. If these common files are not extracted, each chunk packed with a single page contains the common code, which is equivalent to n duplicate code transfers. If the public file is extracted from a file, then when the user visits a web page, loads the public file, and then visits other pages that rely on the public file, the file is directly used in the browser’s cache, and the public file is transferred only once.
-
Application methods
-
Extract common code that multiple pages depend on into common.js, where common.js contains the code for the base library
const CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin'); / /... plugins:[ new CommonsChunkPlugin({ chunks: ['a'.'b'].// From which chunks name:'common'.// The extracted common part forms a new chunk})]Copy the code
-
Find the base libraries you depend on, write a base.js file, and extract the common code from common.js into the base. Common.js removes the base library code, while Base.js remains unchanged
//base.js import 'react'; import 'react-dom'; import './base.css'; //webpack.config.json entry:{ base: './base.js' }, plugins: [new CommonsChunkPlugin({ chunks: ['base'.'common'].name:'base'.//minChunks:2, which indicates the minimum number of chunks that a file must have in order to be extracted, in case there is no code in common.js})]Copy the code
-
You get base library code base.js, common. Js without the base library, and the page’s own code file xx.js.
The pages are referenced in the following order: base.js–> common.js–> xx.js
Base.js is for long-term caching
-
4.3 Split code to load on demand
-
The principle of
One of the problems of single-page applications is that a single page is used to host complex functions, and the file volume to be loaded is large. If not optimized, the first screen will take too long to load, affecting the user experience. Doing on-demand loading can solve this problem. Specific methods are as follows:
- Categorize site features into relevant categories
- Each category is merged into a Chunk and the corresponding Chunk is loaded on demand
- For example, put only the first screen related features in the Chunk where the execution portal is located, so that a small amount of code is loaded first and the rest of the code is loaded when it needs to be used. It is best to anticipate what the user will do next and load the corresponding code in advance so that the user does not feel the network load
-
practice
The simplest example is: the first time a page loads main.js, the page displays a button, when the button is clicked, the split show.js will be loaded, and functions in show.js will be executed
//main.js document.getElementById('btn').addEventListener('click'.function(){ import(/* webpackChunkName:"show" */ './show').then((show) = >{ show('Webpack'); })})//show.js module.exports = function (content) { window.alert('Hello ' + content); } Copy the code
Import (/* webpackChunkName:show */ ‘./show’).then() is the key to implementing on-demand loading. Webpack has built-in support for import(*) statements. Webpack will regenerate a Chunk with a./show.js entry. When the code runs in the browser, it will only start loading show.js when the button is clicked, and the import statement returns a Promise that the loaded content can be retrieved in the then method. This requires browsers to support the Promise API, and for those that don’t, inject the Promise Polyfill. /* webpackChunkName:show */ is the name of the Chunk that is dynamically generated. The default name is [id].js. To output the configured ChunkName correctly, Webpack also needs to be configured:
/ /... output:{ filename:'[name].js'.chunkFilename:'[name].js'.// Specify the file name of dynamically generated Chunk when it is exported } Copy the code
The book also provides a more complex scenario for asynchronously loading components in ReactRouter. P212
Optimize output quality — improve code execution efficiency
5.1 Use Prepack to evaluate in advance
-
Principle:
Prepack is a partial evaluator that compiles code ahead of time by putting the results into the compiled code instead of evaluating the code at run time. Get the results by pre-executing the source code at compile time, and output the results directly to improve performance. But Prepack is not mature enough to be used in an online environment.
-
Method of use
const PrepackWebpackPlugin = require('prepack-webpack-plugin').default; module.exports = { plugins: [new PrepackWebpackPlugin() ] } Copy the code
5.2 Use the Scope collieries
-
The principle of
“Scope promotion” is a feature introduced in Webpack3. It analyzes the dependencies between modules and merges the separated modules into a function as far as possible, but does not cause code redundancy, so only the modules referenced once can be merged. Due to the need to analyze the dependencies between modules, so the source must be ES6 modular, otherwise Webpack will degrade processing without Scope.
-
Method of use
const ModuleConcatenationPlugin = require('webpack/lib/optimize/ModuleConcatenationPlugin'); / /... plugins:[ // Start the Scope collieries newModuleConcatenationPlugin(); ] .resolve: {// Es6 modular syntax files pointed out in jsNext :main are preferred for third-party modules in NPM mainFields:['jsnext:main'.'browser'.'main'] Copy the code
}
The 'webpack --display-optimization-bailout' output log will indicate which file caused the degradationlet a = 1;
let b = 2;
let c = 3;
let d = a+b+c
exportdefault d; // import d from'./d';
console.log(d)
Copy the code
The final result will be console.log(6)
- The amount of code is significantly reduced
- Reducing the number of functions also reduces the memory footprint
Use output analysis tools
Starting Webpack with these two parameters generates a JSON file that output analysis tools mostly rely on for analysis:
Webpack –profile –json >stats.json where –profile records the build time, –json outputs the build result in JSON format, >stats.json is a pipe command in UNIX/Linux, The meaning is to pipe the content to a stats.json file.
-
Official tool Webpack Analyse
Open the tool’s website webpack. Making. IO/anal… , the analysis results can be obtained
-
webpack-bundle-analyzer
Visual analysis tool, more intuitive than Webapck Analyse. It’s also easy to use:
- NPM I-g webpack-bundle-Analyzer installed globally
- Generate the stats.json file as described above
- Execute in the project root directory
webpack-bundle-analyzer
, the browser automatically opens the result analysis page.
npm install --save-dev webpack-bundle-analyzer
Copy the code
The use of plug-in
const {BundleAnalyzerPlugin} = require('webpack-bundle-analyzer'); mode ! = ="development" && new BundleAnalyzerPlugin()
Copy the code
By default, an analysis chart of the current application is displayed
7. Configuration file webpack.config.js that focuses on optimizing the development experience
const path = require('path');
const CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin');
const {AutoWebPlugin} = require('web-webpack-plugin');
const HappyPack = require('happypack');
// Automatically find all directories in the Pages directory and treat each directory as a single page application
const autoWebPlugin = new AutoWebPlugin('./src/pages', {
// Path to the HTML template file
template: './template.html'.// Extract the code common to all pages
commonsChunk: {
// Extract the name of the common code Chunk
name: 'common',}});module.exports = {
// AutoWebPlugin will find all the single page applications it finds and generate the corresponding entry configuration.
// The autowebplugin. entry method gets the build entry configuration
entry: autoWebPlugin.entry({
// Here you can add the extra Chunk entry you need
base: './src/base.js',}).output: {
filename: '[name].js',},resolve: {
// Use an absolute path to specify where third-party modules are stored to reduce search steps
// __dirname represents the current working directory, that is, the project root directory
modules: [path.resolve(__dirname, 'node_modules')].// For third party modules in Npm, use the ES6 modularity syntax pointed at in JsNext: Main
// Use only the main field as the entry file description field to reduce search steps
mainFields: ['jsnext:main'.'main'],},module: {
rules: [{// Do not write /\.jsx if only js files are in the project source code. $/ to improve regular expression performance
test: /\.js$/.// Use HappyPack to speed up builds
use: ['happypack/loader? id=babel'].// Use babel-loader only for files in the SRC directory under the project root directory
include: path.resolve(__dirname, 'src'),}, {test: /\.js$/.use: ['happypack/loader? id=ui-component'].include: path.resolve(__dirname, 'src'),}, {// Add support for CSS files
test: /\.css$/.use: ['happypack/loader? id=css'],},]},plugins: [
autoWebPlugin,
// Use HappyPack to speed up builds
new HappyPack({
id: 'babel'.// babel-loader supports caching of converted results, enabled by cacheDirectory
loaders: ['babel-loader? cacheDirectory'],}).new HappyPack({
// UI component load split
id: 'ui-component'.loaders: [{
loader: 'ui-component-loader'.options: {
lib: 'antd'.style: 'style/index.css'.camel2: The '-'}}]}),new HappyPack({
id: 'css'.// How to handle the.css file as in Loader configuration
loaders: ['style-loader'.'css-loader'],}).// Extract the common code
new CommonsChunkPlugin({
// Extract the common parts from two ready-made chunks, common and Base
chunks: ['common'.'base'].// Put the public part in base
name: 'base'}),].watchOptions: {
// Use auto-refresh: files in node_modules directory that are not listened on
ignored: /node_modules/,}};Copy the code
Webpack-dist. Config.js: webpack-dist.
const path = require('path');
const DefinePlugin = require('webpack/lib/DefinePlugin');
const ModuleConcatenationPlugin = require('webpack/lib/optimize/ModuleConcatenationPlugin');
const CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const {AutoWebPlugin} = require('web-webpack-plugin');
const HappyPack = require('happypack');
const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');
// Automatically find all directories in the Pages directory and treat each directory as a single page application
const autoWebPlugin = new AutoWebPlugin('./src/pages', {
// Path to the HTML template file
template: './template.html'.// Extract the code common to all pages
commonsChunk: {
// Extract the name of the common code Chunk
name: 'common',},// Specify the URL of the CDN directory where the CSS files are stored
stylePublicPath: '//css.cdn.com/id/'});module.exports = {
// AutoWebPlugin will find all the single page applications it finds and generate the corresponding entry configuration.
// The autowebplugin. entry method gets the build entry configuration
entry: autoWebPlugin.entry({
// Here you can add the extra Chunk entry you need
base: './src/base.js',}).output: {
// Hash the output file name
filename: '[name]_[chunkhash:8].js'.path: path.resolve(__dirname, './dist'),
// Specify the URL of the CDN directory where the JavaScript files are stored
publicPath: '//js.cdn.com/id/',},resolve: {
// Use an absolute path to specify where third-party modules are stored to reduce search steps
// __dirname represents the current working directory, that is, the project root directory
modules: [path.resolve(__dirname, 'node_modules')].// Use only the main field as the entry file description field to reduce search steps
mainFields: ['jsnext:main'.'main'],},module: {
rules: [{// Do not write /\.jsx if only js files are in the project source code. $/ to improve regular expression performance
test: /\.js$/.// Use HappyPack to speed up builds
use: ['happypack/loader? id=babel'].// Use babel-loader only for files in the SRC directory under the project root directory
include: path.resolve(__dirname, 'src'),}, {test: /\.js$/.use: ['happypack/loader? id=ui-component'].include: path.resolve(__dirname, 'src'),}, {// Add support for CSS files
test: /\.css$/.// Extract the Chunk CSS code into a separate file
use: ExtractTextPlugin.extract({
use: ['happypack/loader? id=css'].// Specify the URL of the CDN directory that stores the resources (such as images) imported from the CSS
publicPath: '//img.cdn.com/id/'}})},],plugins: [
autoWebPlugin,
/ / open ScopeHoisting
new ModuleConcatenationPlugin(),
/ / use HappyPack
new HappyPack({
// Use a unique identifier id to indicate that the current HappyPack is used to process a specific class of files
id: 'babel'.// babel-loader supports caching of converted results, enabled by cacheDirectory
loaders: ['babel-loader? cacheDirectory'],}).new HappyPack({
// UI component load split
id: 'ui-component'.loaders: [{
loader: 'ui-component-loader'.options: {
lib: 'antd'.style: 'style/index.css'.camel2: The '-'}}]}),new HappyPack({
id: 'css'.// How to handle the.css file as in Loader configuration
// Compress CSS code with the minimize option
loaders: ['css-loader? minimize'],}).new ExtractTextPlugin({
// Add a Hash value to the output CSS file name
filename: `[name]_[contenthash:8].css`,}).// Extract the common code
new CommonsChunkPlugin({
// Extract the common parts from two ready-made chunks, common and Base
chunks: ['common'.'base'].// Put the public part in base
name: 'base'
}),
new DefinePlugin({
// Define the NODE_ENV environment variable as production to remove parts of the React code that are needed for development
'process.env': {
NODE_ENV: JSON.stringify('production')}}),ParallelUglifyPlugin is used to compress the output JS code in parallel
new ParallelUglifyPlugin({
// The argument passed to UglifyJS
uglifyJS: {
output: {
// Most compact output
beautify: false.// Delete all comments
comments: false,},compress: {
// UglifyJs deletes unused code without warning
warnings: false.// Delete all 'console' statements, compatible with Internet Explorer
drop_console: true.// Inline variables that are defined but used only once
collapse_vars: true.// Extract static values that occur multiple times but are not defined as variables to reference
reduce_vars: true,}},}),]};Copy the code
Nine, afterword.
As a result of the limitation of words, some contents can’t write, the nuggets a hole o | | -_ –