如何利用webpack来优化前端性能?

213 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第9天,点击查看活动详情

前言

webpack作为流行比较久的模块化管理工具和打包工具,适用我们大部分项目的打包。通过 loader 的转换,任何形式的资源都可以视作模块,比如 CommonJs 模块、AMD 模块、ES6 模块、CSS、图片等。它可以将许多松散的模块按照依赖和规则打包成符合生产环境部署的前端资源。

优点:

  • 可以将按需加载的模块进行代码分隔
  • 可以模块化的打包任何资源
  • 适配任何模块系统
  • 适合SPA单页应用的开发

当然它也有比较明显的缺点。比如

  • 配置项太多;
  • 不同的插件有不同的扩展字段;
  • babel编译后打包体积过大;
  • 学习成本也比较高。

如何利用webpack来优化前端性能

1. 准备

pnpm install webpack webpack-cli webpack-dev-server image-webpack-loader mini-css-extract-plugin purgecss-webpack-plugin babel-loader @babel/core @babel/preset-env @babel/preset-react terser-webpack-plugin html-webpack-plugin optimize-css-assets-webpack-plugin mini-css-extract-plugin -D

2. 压缩js,css的配置

optimization: {
    minimize: true,
    minimizer: [
    //压缩JS
        new TerserPlugin({});
    //压缩CSS
        new OptimizeCSSAssetsPlugin({}),
    ]
},

3. 压缩图片的配置

{
    test: /\.(png|svg|jpg|gif|jpeg|ico)$/,
    type: "asset",
    parser: {
        dataUrlCondition: {
        // 小于10kb的图片会被base64处理
            maxSize: 10 * 1024,
        },
    }
}

4.清除无用css

const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const PurgecssPlugin = require("purgecss-webpack-plugin");

plugins: [ 
    new MiniCssExtractPlugin({ 
        filename: "[name].css", 
    }), 
    new PurgecssPlugin({ 
        paths: glob.sync(`${PATHS.src}/**/*`, { nodir: true }), 
    }) 
 ]

5. Tree Shaking

利用es6模块的特点,只能作为模块顶层语句出现,import的模块名只能是字符串常量;webpack默认支持,在.babelrc里设置module:false即可在production mode下默认开启

6. 作用域提升

  • scope hoisting的原理是将所有的模块按照引用顺序放在一个函数作用域里,然后适当地重命名一些变量以防止命名冲突
  • 这个功能在mode为production下默认开启,开发环境要用 webpack.optimize.ModuleConcatenationPlugin插件

7. 代码分割

7.1 入口点分割

entry: { 
    index: "./src/index.js",
    login: "./src/login.js" 
}

7.2 动态导入和懒加载

document.querySelector('#clickBtn')
.addEventListener('click',
    () => {  import('./hello')
    .then(result => { console.log(result.default); });
});

React.lazy(()=>import('./hello'))

8. preload(预先加载)和 prefetch(预先拉取)

import(/* webpackPrefetch: true */ './path/to/LoginModal.js');
import(/* webpackPreload: true */ 'ChartingLibrary');

9. 提取公共代码splitChunks:

从 webpack v4 开始,移除了 CommonsChunkPlugin,取而代之的是 optimization.splitChunks

module.exports = {
  //省略其他代码...
  optimization: {
    splitChunks: {
      chunks: 'async',
      minSize: 20000,
      minRemainingSize: 0,
      minChunks: 1,
      maxAsyncRequests: 30,
      maxInitialRequests: 30,
      enforceSizeThreshold: 50000,
      cacheGroups: {
        defaultVendors: {
          test: /[\/]node_modules[\/]/,
          priority: -10,
          reuseExistingChunk: true,
        },
        default: {
          minChunks: 2,
          priority: -20,
          reuseExistingChunk: true,
        },
      },
    },
  },
};

10. CDN

CDN 又叫内容分发网络。

  • 用户使用浏览器第一次访问我们的站点时,该页面引入了各式各样的静态资源,如果我们能做到持久化缓存的话,可以在 http 响应头加上 Cache-control 或 Expires 字段来设置缓存,浏览器可以将这些资源一一缓存到本地
  • 用户在后续访问的时候,如果需要再次请求同样的静态资源,且静态资源没有过期,那么浏览器可以直接走本地缓存而不用再通过网络请求资源
output: {
    publicPath: "http://cdn.example.com/[fullhash]/",
  },

小结

总结了webpack优化前端网页加载速度的一些技巧,对于webpack打包优化大家可以参考之前的文章webpack打包优化