webpack性能优化(二):减少打包体积

当优化webpack性能时,主要集中在两个方面:优化构建后的结果优化构建时的速度。前一篇文章已经介绍了如何通过webpack的分包来优化构建后的结果。而在本篇文章中,我们将从减少打包体积的角度来探讨。

第三方库引入CDN链接

大家都知道CDN是指通过相互连接的网络系统,利用最靠近每个用户的服务器,以更快、更可靠的方式将音乐、图片、视频、应用程序以及其他文件发送给用户,从而实现高性能、可扩展性和低成本的网络内容传递。

平时在开发中我们使用CDN主要有两种方式:

  1. 将打包的所有静态资源,放到CDN服务器。让用户所有资源都是通过CDN服务器加载。
  2. 通过利用知名第三方库的CDN,我们可以避免将这些库打包到我们的项目中,从而降低打包体积。

本文的重点是减少打包体积,因此我们将重点讨论第二种方式。

① 首先通过在webpack.config.js中的配置排除对这些库的打包

js 复制代码
  // webpack.config.js
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { resolve } = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  entry: './src/main.js',
  output: {
    filename: 'bundle.js',
    path: resolve(__dirname, 'build'),
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin(
      {
        template: './index.html'
      }
    ),
  ],
  // 排除打包dayjs
  externals: {
    lodash: '_',
  },
};

强调:在externals这个对象中

  1. lodash 作为属性名(key): 这表示当你在代码中导入 lodash 时,实际上不会将 lodash 包含在你的输出文件中,而是期望它在运行时从外部引入。
  2. '_' 作为属性值(value): 假定在运行环境中已经有一个全局的 _ 对象或者模块

② 在html模块中,加入第三方库的CDN服务器地址

推荐一个国内比较好用的CDN是 bootcdn

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- 导入第三方库的CDN -->
    <script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script></script>
</head>
<body>
    
</body>
</html>

代码压缩

JS压缩

压缩JavaScripte文件可以使用Terser压缩工具,webpack v5 开箱即带有最新版本的 terser-webpack-plugin

在Webpack中,有一个名为minimizer属性,它在生产模式下默认使用TerserPlugin来处理代码。这意味着Webpack会自动使用TerserPlugin来压缩和优化JavaScript代码,以减小文件大小并提高性能。

如果你不满意默认配置,你可以自己创建TerserPlugin的实例,并覆盖相关配置。这允许你根据项目的需求自定义代码压缩和优化,使Webpack配置变得灵活而适应各种场景。总之,minimizer属性允许你控制生产模式下的代码压缩,提供了定制化的选项以满足你的需求。

js 复制代码
  optimization: {
    minimize: true,
    minimizer: [new TerserPlugin({
      extractComments: true,
      terserOptions: {
        compress:{
          ecma: 5,  // 设置输出所需的EcmaScript标准版本
          unused: false // 是否删除未引用的函数和变量
        },
        toplevel: true, // 是否在顶级作用域中声明的名称。
        keep_classnames: true, // 防止丢失类名,
        keep_fnames: true // 防止丢失函数名
      }
    })],
  },

这里面的配置非常多,具体可以看terser文档

CSS压缩

压缩CSS通常是去除无用的空格,压缩CSS可以使用另外一个插件:css-minimizer-webpack-plugin

安装css-minimizer-webpack-plugin

在optimization.minimizer中配置

js 复制代码
  optimization: {
    minimizer: [new cssMinimizerPlugin({
           parallel: true
       }
      )],
  },

被压缩后的代码

Tree Shaking

Tree Shaking,又称为"树摇",是一项用于优化项目打包的技术,其核心目标是在构建过程中自动删除未被引用的函数或变量,从而减小最终生成的文件大小,提高应用程序的性能和加载速度。

JS

usedExports

在生产环境下webpack默认会将usedExports设置为true,在usedExports设置为true时,会有一段注释:unused harmony export mul,这段注释意味着Terser在优化(上面讲到了Terser压缩)时,可以删除掉这段代码.所以我们还得讲minimize设置true

js 复制代码
optimization: {
  // 在生产环境下都帮我们配置了
  minimize: true,
  usedExports: true
}

sideEffects

如果只使用usedExports会出现一个问题,如下:

以下需要tree Sharking的模块

js 复制代码
// format.js
export function formatUTC(date) {
  return date;
}

export function formatPrice(price) {
  return price.toFixed(2);
}

window.effect = "我是一个副作用代码";

以下是主入口文件

js 复制代码
// main.js
// 由于只对模块进行导入,但是未用到内部函数,按理来说format.js整个模块不应该被打包
import "./utils/format";

console.log("main");

以下是打包后的产物

js 复制代码
// build/bundle.js
(()=>{"use strict";window.effect="我是一个副作用代码",console.log("main")})();

我们发现window.effect="我是一个副作用代码"的副作用代码被打包进去了,那么我们应该如何解决这个问题?

可以通过 package.json 的 "sideEffects" 属性,来实现这种方式。

json 复制代码
// package.json
{
  "sideEffects": false,
}

sideEffects设置为false,就是告知webpack可以安全的删除未用到的exports;

如果有一些我们希望保留,可以设置为数组;

json 复制代码
{
    // package.json
    "sideEffects": [
    // 打包后的文件就不会保留format中的如何代码
    "./src/utils/format.js"
  ],
}

CSS

上述我们学习的都是关于JS的Tree Shaking,同样我们也要对CSS代码做Tree Shaking

CSS的Tree Shaking需要借助于一些其他的插件purgecss-webpack-plugin

npm install purgecss-webpack-plugin -D

js 复制代码
    // webpack.config.js
    new PurgeCSSPlugin({
      paths: glob.sync(path.join(__dirname, "src/**/*"), { nodir: true }),
    }),

总结

在实际开发中,上述许多配置不需要手动配置(比如:代码压缩Tree Sharking),因为在生产环境下已经默认为我们配置好了。尽管如此,我们仍然需要了解这些配置的原理。

相关推荐
dream_ready40 分钟前
linux安装nginx+前端部署vue项目(实际测试react项目也可以)
前端·javascript·vue.js·nginx·react·html5
编写美好前程40 分钟前
ruoyi-vue若依前端是如何防止接口重复请求
前端·javascript·vue.js
flytam42 分钟前
ES5 在 Web 上的现状
前端·javascript
喵喵酱仔__42 分钟前
阻止冒泡事件
前端·javascript·vue.js
GISer_Jing43 分钟前
前端面试CSS常见题目
前端·css·面试
八了个戒1 小时前
【TypeScript入坑】什么是TypeScript?
开发语言·前端·javascript·面试·typescript
不悔哥1 小时前
vue 案例使用
前端·javascript·vue.js
anyup_前端梦工厂2 小时前
Vuex 入门与实战
前端·javascript·vue.js
你挚爱的强哥2 小时前
【sgCreateCallAPIFunctionParam】自定义小工具:敏捷开发→调用接口方法参数生成工具
前端·javascript·vue.js
米老鼠的摩托车日记3 小时前
【vue element-ui】关于删除按钮的提示框,可一键复制
前端·javascript·vue.js