The front-end project of the company uses Vue framework, which is constructed by Webpack. With the continuous iteration of the project, the project gradually becomes huge, but the construction speed of the project becomes slow, so the optimization of Webpack construction becomes urgent. After continuous exploration and practice, the construction speed of the project increased by 50% after optimization by the following methods. Now the relevant optimization methods are summarized and shared.

The github address is github.com/fengshi123/… , if you like or have some inspiration, please help to give a Star ~, to the author is also a kind of encouragement.

1. Narrow your search for files

1.1. Optimize 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. We can optimize the Loader configuration by (1) optimizing regular matching (2) enabling caching with cacheDirectory (3) reducing the number of files to be processed by include and exclude. The practice is as follows:

Original project configuration:

{
  test: /\.js$/,
  loader: 'babel-loader',
  include: [resolve('src'), resolve('test')]},Copy the code

Optimized configuration:

{// 1, if the project source only js file, do not write /\.jsx? $/ to improve the regular expression performancetest: /\.js$/, //'babel-loader? cacheDirectory'Babel-loader include: [resolve(resolve)'src')]},Copy the code

1.2. Optimize the resolve.modules configuration

Resolve. modules is used to configure which directories Webpack goes to find third-party modules. Resolve. Modules defaults to [node modules], which means to find the module in the /node modules directory of the current directory. If not, go to the upper directory.. /node modules, if there is no more, go to.. /.. /node modules, and so on. This is similar to node.js’s module finding mechanism. When installed third-party modules are placed in the./node modules directory at the root of the project, there is no need to follow the default path of layer by layer search. You can specify the absolute path to store third-party modules to reduce the search.

Optimized configuration:

resolve: {
// Use an absolute path to specify where third-party modules are stored to reduce search steps
modules: [path.resolve(__dirname,'node_modules')]},Copy the code

1.3. Optimize the resolve. Alias configuration

The resolve.alias configuration item maps the original import path to a new one using an alias.

As the configuration in the project uses:

alias: {
  The '@': resolve('src'}, // With the above configuration, we can write import common from directly by referring to common.js under SRC'@/common.js';
Copy the code

1.4. Optimize the resolve. Extensions configuration

When an import statement does not have a file suffix, Webpack will try to ask if the file exists after it is automatically suffixed. The default is: Extensions :[‘.js’, ‘.json ‘]. That is, when an import statement such as require (‘. /data ‘) is encountered, Webpack will first look for the./data.js file, and if it doesn’t exist, it will look for the./data.json file, and if it still can’t find it, it will report an error. The longer the list is, or the later the correct suffix is, the more attempts will be made, so the configuration of the resolve.extensions will also affect the performance of the build.

Optimization measures:

• Keep the list of postfix attempts as small as possible, and do not include impossible situations in the project.

• File suffixes with the highest frequency should be placed first in order to exit the search process as quickly as possible.

• When writing import statements in source code, use suffixes whenever possible to avoid the search process. For example, when working with certainty, write require(‘. /data ‘) as require(‘. /data.json ‘), when enforceExtension and enforceModuleExtension are enabled, the developer can enforce compliance with this optimization

1.5. Optimize the resolve.noparse configuration

The noParse configuration allows Webpack to ignore recursive parsing and processing of parts of the file that are not modularized, which has the benefit of improving build performance. The reason for this is that some libraries such as jQuery and ChartJS are huge and do not adopt modular standards, making it time-consuming and pointless for Webpack to parse these files. NoParse is an optional configuration item whose type must be RegExp, [RegExp], or function. For example, if you want to ignore jQuery and ChartJS, optimize the configuration as follows:

// Use the regular expression noParse: / jquerylChartjs // use the function, which supports noParse: (content)=> {// returnstrueorfalse 
return /jquery|chartjs/.test(content); 
}
Copy the code

2. Reduce redundant code

Babel-plugin-transform-runtime is an add-on to reduce redundant code. When Babel converts ES6 code to ES5 code, it usually requires some auxiliary functions written by ES5 to implement the new syntax. For example, when converting the class extent syntax, the auxiliary functions are injected into the converted ES5 code to implement inheritance. The babel-plugin-transform-Runtime reduces the file size of the code compiled by Babel by replacing relevant helper functions with import statements.

3. Use HappyPack to parse and process files

Since there are a lot of files to parse and process, building is a file read and write and computation-intensive operation, especially as the number of files increases, the problem of Webpack building slowly becomes more serious. Webpack running on Node. Has a single-threaded model, meaning that Webpack needs to process tasks one by one, not multiple tasks at a time. Happy Pack (https://github.com/amireh/happypack) Webpack can do this, it will give more child processes to concurrent execution task decomposition, the child process after processing and then send the result to the main process.

The HappyPack project uses the following configuration:

$NPM I -d HappyPack (2) webpack.base.conf.js to configure module.rules module: {rules: [{test: /\.js$/, // Transfers processing of.js files to the HappyPack instance with id Babel use:['happypack/loader? id=babel'],
          include: [resolve('src'), resolve('test'),   
            resolve('node_modules/webpack-dev-server/client'// Exclude :path.resolve(__dirname,'node_modules'),}, {test: /\.vue$/,
          use: ['happypack/loader? id=vue'},}, (3) webpack.prod.conf.js const HappyPack = require()'happypack'); Const HappyPackThreadPool = happypack.threadPool ({size:5}); const HappyPackThreadPool = happypack.threadpool ({size:5}); Plugins: [new HappyPack ({/ / with a unique identifier id, to represent the current HappyPack is used to handle a specific file id:'vue',
         loaders:[
           {
             loader:'vue-loader', options: vueLoaderConfig } ], threadPool: HappyPackThreadPool,}), new HappyPack({// use a unique identifier id to indicate that the current HappyPack is used to handle a particular class of file ids:'babel'Loaders :[loaders:[loaders:[loaders:[loaders:['babel-loader? cacheDirectory'],
         threadPool: HappyPackThreadPool,
       }),
    ]
Copy the code

ParallelUglifyPlugin is used to compress code files

When compressing JavaScript code, the code needs to be parsed into the AST syntax tree represented by Object abstraction, and then various rules are applied to analyze and process the AST. As a result, this process takes a huge amount of calculation and time consuming. Paralleluglifyjs is used to compress JavaScript files one by one in Webpack, but ParallelUglifyPlugin enables multiple sub-processes to compress files and distribute the compression work among them. Each child process actually uses UglifyJS to compress the code, but executes in parallel. So the ParallelUglify Plugin can compress multiple files more quickly.

ParallelUglifyPlugin in the project uses the configuration:

(1) ParallelUglifyPlugin plugin installation: $NPM I -d webpack-parallel-uglify-plugin (2) webpack.prod.conf.js const ParallelUglifyPlugin =require('webpack-parallel-uglify-plugin');
    plugins: [
    new ParallelUglifyPlugin({
      cacheDir: '.cache/',
      uglifyJs:{
        compress: {
          warnings: false
        },
        sourceMap: true}}),]Copy the code

5. Use automatic refresh

By means of automation, when listening for changes in local source files, automatically rebuild the running code and then control the browser refresh. Webpack has all of these capabilities built in and offers a variety of options.

Configurations that automatically refresh in the project:

DevServer: {watchOptions: {// ignore: /node_modules/ regular match for files or folders that are not listened to. AggregateTimeout: // wait 300ms to listen to changes. 300, // default 1000 poll per second poll: 1000}},Copy the code

Related optimization measures:

(1) The configuration ignores some files that are not listened on, such as node_modules.

. (2) watchOptions aggregateTirneout the greater the value of the performance, the better, because it can reduce the frequency of the reconstructed.

(3) The smaller the value of watchOptions. Poll, the better, because it reduces the frequency of checks.

6. Enable hot replacement

DevServer also supports a technique called Hot Module Replacement for ultra-sensitive real-time previews without refreshing the entire web page. The principle is that when a source code changes, you only need to recompile the changed module and replace the corresponding old module in the browser with the new output module. Module hot replacement technology greatly improves development efficiency and experience.

Configuration of module hot replacement in the project:

devServer: {
  hot: true, }, plugins: [new webpack HotModuleReplacementPlugin (), is replaced / / display module. The name of the new webpack NamedModulesPlugin (), // HMR shows correct file names ]Copy the code

7. Extract common code

If the code for every page includes these common parts, it can cause the following problems:

• The same resources are loaded repeatedly, wasting user traffic and server costs.

• Too many resources need to be loaded on each page. As a result, the first screen of a web page loads slowly, affecting user experience.

This can be optimized by separating common code from multiple pages into separate files. Webpack comes with the CommonsChunkPlugin, a plug-in specifically designed to extract the common parts of multiple chunks.

CommonsChunkPlugin configuration in the project:

// All packages that depend on package.json are packaged into vendor.js. new webpack.optimize.CommonsChunkPlugin({ name:'vendor',
  minChunks: function(module, count) {
    return (
      module.resource &&
      /\.js$/.test(module.resource) &&
      module.resource.indexOf(
        path.join(__dirname, '.. /node_modules') === 0; }}), / / extract code module mapping new webpack.optimize.Com monsChunkPlugin ({name:'manifest',
  chunks: ['vendor']}),Copy the code

Load code on demand

Single-page applications written through VUE may have many routes imported. When packaging builds, javascript packages can become very large and affect loading. It would be much more efficient if we could split the components corresponding to different routes into different code blocks and then load the components only when the routes are accessed. This will greatly speed up the first screen, but may slow down the rest of the page.

Configuration of route load on demand (lazy load) in project:

const Foo = () => import('./Foo.vue')
const router = new VueRouter({
  routes: [
    { path: '/foo', component: Foo }
  ]
})Copy the code

Optimize SourceMap

We are after the package of the project, will develop multiple files in the code package to a file, and compressed, remove Spaces, and Babel after the compilation, will eventually be used in an online environment, so that after processing code and source code can have very big difference, when there are bugs, we can only after positioning to compression processing code position, The inability to locate code in the development environment is bad for development, hence sourceMap, which is designed to solve bad code problems.

The optional values of SourceMap are as follows:



Cheap -module-eval-source-map

Recommended production environment: cheap-module-source-map

Here’s why:

1. The column information in the source code is useless, so we do not want to include column information in the packaged file. Only the row information can establish the dependencies before and after the package. Therefore, in both development and production environments, we want to add the base type of Cheap to ignore the column information before and after packaging.

2. In both the development environment and the formal environment, we want to locate the specific source code of the bug. For example, a vUE file reported an error.

3. We need to generate the map file form, so we need to add the source-map attribute.

4. When we introduced eval packaging code, we know that eval is very fast after packaging, because it does not generate map files, but we can use eval-source-map for the eval combination, which will store the map file in the packaged JS file as DataURL. Do not use eval-source-map in a formal environment because it increases the file size, but in a development environment, try it out because they pack quickly.

10. Output analysis of construction results

The code output from Webpack was very unreadable and the files were very large, which gave us a headache. In order to analyze the output more easily and intuitively, a number of visual analysis tools have emerged in the community. These tools graphically present the results more visually, allowing us to quickly understand the problem. Next, we’ll look at the analysis tool used in the VUE project: Webpack-bundle-Analyzer.

Configure webpack.prod.conf.js in the project:

if (config.build.bundleAnalyzerReport) {
  var BundleAnalyzerPlugin =   require('webpack-bundle-analyzer').BundleAnalyzerPlugin; webpackConfig.plugins.push(new BundleAnalyzerPlugin()); } $NPM run build --reportCopy the code



The github address is github.com/fengshi123/… , if you like or have some inspiration, please help to give a Star ~, to the author is also a kind of encouragement.