webpack4 优化产物体积实践

前言

随着 Web 前端技术的不断发展,前端工程师的日常开发也变得更加繁琐,特别是当项目规模变大的时候,前端产物的体积也会不断增加。而体积过大不仅会影响页面的加载速度,也会影响用户体验,因此对于企业和前端工程师来说,对前端产物的体积进行优化显得尤为重要。在这篇文章中,将着重介绍如何使用 webpack4 来优化前端产物的体积。

产物体积分析

在进行产物体积优化时,首先需要了解产物的体积结构,这里以 vue-cli 3 项目为例,使用 npm run build 命令生成产物,然后使用 webpack-bundle-analyzer 插件进行体积分析,使用结果如下所示:

从上图可以看出,app.js 这个文件的体积占比过大,这是因为 app.js 为应用入口模块,包含了所有的业务逻辑代码和组件库代码,因此需要将 app.js 进行拆分和按需加载,以此来减少打包后的体积。

代码分离

在前端工程化中,使用模块化开发可以有效地避免代码重复、提高开发效率,Webpack 也提供了多种方式来实现代码分离,其主要有以下几种:

入口起点

entry 中配置多个入口文件,每个入口文件都会生成一个产物,相互之间没有依赖关系,适用于简单的项目,但当项目复杂度增加时,配置多个入口文件将变得困难。

module.exports = {
  entry: {
    app: './src/app.js',
    vendor: './src/vendor.js',
  },
  output: {
    filename: '[name].[hash].js',
  },
};

代码分离 + 动态导入

Webpack 4 推荐使用动态导入来实现代码分离,即使用 import()require.ensure() 来进行代码分离,结合 webpackChunkName 参数可以设置输出文件的名称。

import('./path/to/module')
  .then(module => {
    // do something with the module
  })
  .catch(error => {
    // handle error
  });
require.ensure(['./path/to/module'], () => {
  const module = require('./path/to/module');
  // do something with the module
}, 'myModule');

SplitChunksPlugin 插件

SplitChunksPlugin 插件可以将公共模块提取出来,避免代码重复,并生成一个或多个新的代码块,以此来实现对代码的分离。

module.exports = {
  optimization: {
    splitChunks: {
      chunks: 'all',
      minSize: 30000,
      minChunks: 1,
      maxAsyncRequests: 5,
      maxInitialRequests: 3,
      automaticNameDelimiter: '~',
      name: true,
      cacheGroups: {
        vendors: {
          test: /[\\/]node_modules[\\/]/,
          priority: -10,
        },
        default: {
          minChunks: 2,
          priority: -20,
          reuseExistingChunk: true,
        },
      },
    },
  },
};

动态 Polyfill

随着浏览器标准的不断升级,前端开发中逐渐出现了一些新的语法和 API,为了兼容旧的浏览器,JavaScript 开发人员往往需要使用 polyfill 来填充这些新特性,如果所有的 polyfill 都被打包到了产物中,那么必然会造成产物体积的增加。对此,Webpack 提供了 @babel/plugin-transform-runtime 插件来实现动态加载 polyfill,只有实际需要使用到的才会被加载。

// .babelrc
{
  "plugins": ["@babel/plugin-transform-runtime"]
}

Tree Shaking

Tree Shaking 可以消除产物中未被使用的代码,以此来达到减少产物体积的效果。Webpack 通过静态分析的方式检测代码中未被使用的部分,然后将其删除,而实现这一功能的核心工具是 UglifyJSPlugin

// webpack.config.js
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');

module.exports = {
  //...
  optimization: {
    minimizer: [
      new UglifyJsPlugin({
        uglifyOptions: {
          compress: {
            unused: true,
            drop_debugger: true,
          },
          output: {
            comments: false,
          },
        },
        cache: true,
        parallel: true,
        sourceMap: true,
      }),
    ],
  },
  //...
};

环境变量注入

在前端开发中,我们可能需要针对不同的环境进行不同的操作,比如使用不同的 API 地址、不同的 CDN 链接等等,这时候通过环境变量来进行控制会更加便捷。Webpack 提供了 DefinePlugin 插件来实现环境变量注入:

// webpack.config.js
const webpack = require('webpack');
const env = process.env.NODE_ENV;

module.exports = {
  //...
  plugins: [
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: JSON.stringify(env),
      },
    }),
  ],
  //...
};

总结

通过本文的介绍,我们了解了Webpack 4 的一些常见的产物体积优化技术,其中包括代码分离、动态 Polyfill、Tree Shaking、环境变量注入等等。这些技术虽然很简单,但结合实际项目,可以将产物体积减少至少一半以上。

来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65aefe50add4f0e0ff86aac5