webpack packaging optimization solution

bug problem:
When a single page application enters the project for the first time, it will obtain part of the data, then divide the JS package into pieces, go there and load the JS. In this way, CSS does not need to get the JS repeated across pages, and there will be no progress bar across pages. This reduces the waiting time, improves the user experience and saves unnecessary traffic. However, single page applications also have a significant problem: when entering for the first time, too many resources are loaded and the white screen time is too long.

1. Use the plug-in to view all packages and volume of the project. 2webpack external extension 3DLL mode

1, View project packaging

webpack has a plug-in, which can check the total number of packages of the project, the volume of each package and the package in each package. First download the plug-in

npm intall webpack-bundle-analyzer --save-dev

At the same time in webpack config. JS configuration

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

webpackConfig.plugins.push(new BundleAnalyzerPlugin());

In package Add commands to JSON

"script": {
    "analyz": "NODE_ENV=production npm_config_report=true npm run deploy:prod"
}

My webpack is 1 Webpack 2 of X Students of X, please have a look

Then enter from the command line

npm run analyz

Start building, depending on the size of the project and the time. After a while, the output results are as follows:

2, webpack external extensions

Lists the larger packages in the project. The rest is to find ways to reduce the volume of these packages (break a large package into multiple small packages). The reasons for large packages in the project can be considered from two aspects:

The dependency packages introduced in the project are too large; The business code is written in one piece, or the business code is complicated; We can solve these two problems from two aspects:

Pull out the packages that are publicly dependent, infrequently changed and large in size in the project; Split a large business code file into multiple smaller files and load it asynchronously (or optimize the business code). The second item involves changing the business code. The specific situation is different. It is suitable to see how to optimize the JS code. Let's discuss the first method, how to reduce the public dependency without changing the business code.

We should know that these dependencies are what we need, and it is impossible to exclude them from being introduced. However, they are globally dependent and unchanged for ten thousand years. You can use the browser's own cache to realize no repeated loading. The specific method is: take out some public dependent packages that are not often changed in the project, and do not package and compile every time (such as React, Redux, etc.). Instead, CDNs are introduced in the form of script tags, so that when there is a cache, these resources go through the cache and do not have to be loaded.

Specific methods:

Summarize the public dependencies that need to be removed.
These dependencies need to meet certain conditions:

Large volume; Infrequently updated; More dependence; Is pre dependency; Common packages that meet these conditions include:

React react DOM Redux react Redux moment jQuery some other package files, such as the Antd library file. The whole package is large, but the library file will also be loaded on demand every time what is used, so there is no need to take it out separately. In addition, it is not recommended to take out such library files separately, because there may be bug s in them and they need to be updated.

Introducing resources using CDN
Take my demo as an example: the files I need to extract include react, react DOM, react router, redux, react redux, history. Put these files on cnd. Note that these files should be compressed and written in ES5, otherwise the browser will report an error.

<head>
  <title>React Starter Kit</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <!-- Bulky package -->
  <script src="https://cdn.bootcss.com/react/15.0.0/react-with-addons.min.js"></script>
  <script src="https://cdn.bootcss.com/react/15.0.0/react-dom.min.js"></script>
  <script src="https://cdn.bootcss.com/react-router/3.0.0/ReactRouter.min.js"></script>
  <script src="https://cdn.bootcss.com/redux/3.6.0/redux.min.js"></script>
  <script src="https://cdn.bootcss.com/react-redux/5.0.1/react-redux.min.js"></script>
  <script src="https://cdn.bootcss.com/history/4.5.0/history.min.js"></script>
</head>

Configure webpack conf.js
Resources have been introduced. Next, you need to configure webpack so that these resources are not packaged when they are packaged.

const webpackConfig = {
    name: 'client',
    target: 'web',
    devtool: config.compiler_devtool,
    resolve: {
        root: paths.client(),
        extensions: ['', '.js', '.jsx', '.json'],
    },
    externals: {
        'react': 'React',
        'react-dom': 'ReactDOM',
        'react-router': 'ReactRouter',
        'redux': 'Redux',
        'history': 'History'
    },
    module: {},
}

Here externals tells webpack where to find those resources. The key of the object represents the variable in the current environment represented by the string value at the time of require or import. For example, after the introduction of React, React is regarded as a global object, and webpack goes back to find the React object. If one of them cannot be found, the packaging will fail.

Configure vendor js
Next, configure the vendor so that the vendor does not package the JS

compiler_vendors : [
    // 'react',
    // 'react-redux',
    // 'react-router',
    // 'redux',
],

Next, run npm run analyz again

Compared with the first rendering, it is obvious that app JS is reduced from 625kb to 78kb, which is the second largest vendor JS is now very small. However, it should be noted that the smaller the package, the better. The smaller the package, the more links it consumes. You should make the business code in your package account for the majority. Later, I was told that the maximum package volume can be compressed within 80k.

3, DLL mode

The full name of dll is: dynamic link library. The dll method is to tell webpack to specify the location of the library in the project through configuration, so as to import it directly without packaging it. The method described above is to put the package on cdn, and the corresponding package is not introduced during build; dll method is to specify the package in the project. When building, the corresponding package is not packaged, but introduced when using. Webpack through webpack Dllplugin and webpack Dllreferenceplugin two embedded plug-ins realize this function.

Create a new webpack dll. config. js

const webpack = require('webpack');

module.exports = {
    entry: {
        bundle: [
            'react',
            'react-dom',
            //Other libraries
            ],
    },
    output: {
        path: './build',
        filename: '[name].js',
        library: '[name]_library'
    },
    plugins: [
        new webpack.DllPlugin({
            path: './build/bundle.manifest.json',
            name: '[name]_library',
        })
    ]
};

webpack.DllPlugin options:

path: manifest. The output path of JSON file, which will be used for subsequent business code packaging; Name: the name of the object exposed by dll, which should follow output Keep the library consistent; Context: the context of resolving the package path, which is the same as the next configured webpack config. JS consistent.

Run file
Run: webpack -- config webpack dll. config. js
Generate two files, one is the packaged bundle JS and the other is bundle mainifest. JSON, roughly as follows:

{
  "name": "bundle_library",
  "content": {
    "./node_modules/react/react.js": 1,
    "./node_modules/react/lib/React.js": 2,
    "./node_modules/process/browser.js": 3,
    "./node_modules/object-assign/index.js": 4,
    "./node_modules/react/lib/ReactChildren.js": 5,
    "./node_modules/react/lib/PooledClass.js": 6,
    "./node_modules/react/lib/reactProdInvariant.js": 7,
    //Other references
}

Configure webpack config. js

const webpack = require('webpack');
var path = require('path');
module.exports = {
  entry: {
    main: './main.js',
  },
  output: {
    path: path.join(__dirname, "build"),
    publicPath: './',
    filename: '[name].js'
  },
  module: {
    loaders:[
      { test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192'},
      {
        test: /\.jsx?$/,
        loaders: ['babel-loader?presets[]=es2015&presets[]=react'],
        include: path.join(__dirname, '.')
      }
    ]
  },
  plugins: [
     new webpack.DllReferencePlugin({
      context: '.',
      manifest: require("./build/bundle.manifest.json"),
        }),
  ]
};

webpack. In the options of dllreferenceplugin:

context: it needs to be consistent with the previous one. This is used to guide webpack to match manifest The path of the library in JSON; Manifest: used to import the output manifest JSON file.

Tags: Webpack

Posted by dserf on Thu, 14 Apr 2022 07:20:27 +0930