The project I am currently in charge of is the React project without scaffolding and other frames. In the development process, the startup project and hot update speed are not very ideal; Packaging builds are also slow and take a long time to load animations when accessing a single file due to the size of the file. Therefore, some optimization work is planned for it. In order to improve the performance of Webpack, the most direct way is to upgrade the idea of WebPack version. A series of upgrades and optimizations were made to the project. The results of the upgrade and optimization are as follows:Compilation speed:

  • Development startup project speed increased by 1180% (non-modified configuration/initial compilation);
  • During the development process, the code hot update speed does not change much, but the development experience is better, browser update is partial update instead of reload;
  • Production environment package build speed increased by 201% (non-modified configuration/first compilation).

Volume:

  • The size of the two large files in the project was reduced by about 77% and 86%, respectively, greatly speeding up page loading.

View performance-related plug-ins:

  • speed-measure-webpack-pluginMeasure plugin, Loader and other time;
  • webpack-bundle-analyzerPackage analysis tools.

Upgrade according to the official migration document

  1. Upgrade Node.js to at least version 10.13.0.
  2. Update WebPack 4 and its related plugin/loader;
    • Upgrade WebPack 4 to the latest version, upgrade WebPack-CLI to the latest version;
    • The latest plugin and loader versions are used.
// Check NPM outdated // Install the latest version of NPM install package@latestCopy the code
  1. Get deprecation warnings in stack information
/ / if there is no default webpack config. Js configuration, you need to - config node configuration file specified - trace - deprecation node_modules/webpack/bin/webpack. JsCopy the code
  1. Test webpack5 compatibility

Add the following configuration options to check that the build is running properly (remove these configuration options when complete).

module.exports = {
  node: {
    Buffer: false.process: false}},Copy the code
  1. Upgrade to webpack5
npm install webpack@latest -D
Copy the code
  1. Babel upgrade to 7, Upgrade Guide: Link. And corresponding plug-ins.

For details, see the official migration guide To V5 from V4

Adjust and optimize after upgrade

Adjust the

  1. useassetInstead offile-loader url-loader raw-loader.
  2. JavaScript code compression using webpack5 built-interser-webpack-plugin.

Optimize compilation and development speed

  1. cache: filesystemPersistent cache. Can greatly improve the secondary build speed (except for modifying configuration files).
{
	cache: {
        type: "filesystem".buildDependencies: {
            // config is added as buildDependency to get cache invalidation when config is changed
            config: [__filename],
        },
        name: process.env.NODE_ENV,
        version: "1.0.0",}}Copy the code
  1. usethread-loaderDo a multi-process build.
// Worker startup consumes a certain amount of time,
// Can preheat the worker pool
const jsWorkerPool = {
    workerParallelJobs: 80.poolTimeout: 2000};const cssWorkerPool = {
    workerParallelJobs: 10.poolTimeout: 2000}; threadLoader.warmup(jsWorkerPool, ["babel-loader"]);
threadLoader.warmup(cssWorkerPool, ["css-loader"."less-loader"]);
Copy the code
  1. You can enable deferred builds if you don’t want to save your code manually during development and it leads to frequent and error-prone builds.
devServer: {
  ...
  watchOptions: {
    // Delay the build
    aggregateTimeout: 1500.ignored: /node_modules/,}},Copy the code
  1. CSS module hot replacement: CSS withstyle-loader, can realize module hot replacement;
  2. JavaScript module hot replacement: It can be implemented using community libraries or plug-ins, otherwise it will be reload.
    1. It can be used if the following conditions are met[react-refresh-webpack-plugin](https://github.com/pmmmwh/react-refresh-webpack-plugin)Plug-in;

{
	plugins: [
  	new ReactRefreshWebpackPlugin()
  ]
}
Copy the code
  1. If the preceding conditions are not met, use the react-hot-loader library
// .babelrc
{
    "plugins": [..."react-hot-loader/babel"]}// index.js
import { hot } from 'react-hot-loader'; .const App = hot(module) (() = >...). ; render(<App />.document.getElementById('root'));
Copy the code

Optimized compilation volume

Volume optimization after packaging: Gzip compression is used to compress files with large volume. The size of the two large files in the project was reduced by about 77% and 86%, respectively, greatly speeding up page loading.

Gzip compression

Gzip(GNU- ZIP) is a compression technology. Compressed pages can greatly speed up browser loading. To enable Gzip, both the server side and the browser side need to support: server side compression (providing compressed files), and browser side decompression. Note:

  • Pictures/MP3 and so on do not need to compress, the compression rate is small;
  • To use proxy_pass reverse proxy pages, gzip — http_version needs to be changed to 1.0;
  • Static compression: gzip_static on;
  • Dynamic compression: gzip on.

other

Other volume optimization needs to be modified because there are many business-related codes, so it has not been optimized for now.

Potholes encountered and related solutions

  1. DeprecationWarning:[DEP_WEBPACK_COMPILATION_NORMAL_MODULE_LOADER_HOOK] DeprecationWarning: Compilation.hooks.normalModuleLoader was moved to NormalModule.getCompilationHooks(compilation).loader

The speed-measure-webpack-plugin is not fully compatible with Webpack5. You can remove related configurations after optimization.

  1. Error: Cannot find module 'webpack-cli/bin/config-yargs

    4.X version of webpack-CLI removes yargs package, need to start webpack-dev-server with Webpack Serve.

// package.json
{
	"script": {
		"dev": "webpack serve --config webpack.dev.js"}}Copy the code
  1. Support for the experimental syntax 'classProperties' isn't currently enabled

@babel/ PRESET -env does not contain a syntax proposal smaller than Stage 3, and the plugin needs to be installed manually. The plugin @babel/plugin-proposal-class-properties is required.

//.babelrc
{
  "plugin": ["@babel/plugin-proposal-class-properties"]}Copy the code
  1. Support for the experimental syntax 'decorators-legacy' isn't currently enabled

For the same reason, install @babel/plugin-proposal-decorators.

//.babelrc
{
  "plugin":[
  	["@babel/plugin-proposal-decorators", {"legacy": true}}]]Copy the code
  1. expose-loaderAfter upgrade, error:ValidationError: Invalid options object. Expose Loader has been initialized using an options object that does not match the API schema.
// Webpack configuration file
module: {
	rules:[
  	...,
    {
    	use: {
    		loader: "expose-loader".options: {
    				exposes: "videojs"}}}]}/ / * *. Use js
require('videojs');
Copy the code
  1. webpack.HotModuleReplacementPluginandhot: trueHot update is not possible when used together.

hot: trueWill automatically addwebpack.HotModuleReplacementPluginPlug-in, no need to add configuration again. 7.speed-measure-webpack-pluginThe plugin cannot be used during build. 8. Webpack5 no longer provides for Node.js to automatically introduce polyfills.

Modify it according to the error message.

  1. The build is complete in production, but the command does not exit

    The thread-loader plugin causes this problem by preheating the worker pool in a production environment.

  2. After the upgrade, WebPack is more stringent on code and needs to be changed as needed.

reference

  • webpack
  • babel