webpack4.X 5.X-- 打包结果优化

本文介绍了如何通过webpack-bundle-analyzer分析打包结果,优化CSS和JS体积,使用terser-webpack-plugin进行代码压缩,以及启用treeshaking以移除未使用的代码。还讨论了ScopeHoisting的作用和删除无用代码的配置,如移除console.log和debugger。
摘要由CSDN通过智能技术生成
目录
  • 打印体积分析
  • 压缩css
  • 压缩js
  • 清除无用css
  • tree shaking
  • scope hosting
  • 删除无用代码
打印体积分析

借助插件 webpack-bundle-analyzer 我们可以直观的看到打包结果中,文件的体积大小、各模块依赖关系、文件是否重复等问题,极大的方便我们在进行项目优化的时候,进行问题诊断。

安装
$ npm i -D webpack-bundle-analyze
配置插件
// 引入插件
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin

const config = {
  // ...
  plugins:[ 
    // ...
    // 配置插件 
    new BundleAnalyzerPlugin({
      // analyzerMode: 'disabled',  // 不启动展示打包报告的http服务器
      // generateStatsFile: true, // 是否生成stats.json文件
    })
  ],
};
结果分析

每次打包结束后,会自行启动地址为 http://127.0.0.1:8888 的 web 服务,访问地址就可以看到

图片.png

鼠标hover上去可以看到每个依赖的体积大小,从上往下,表示依赖的嵌套关系

如果,我们只想保留数据不想启动 web 服务,这个时候,我们可以加上两个配置

new BundleAnalyzerPlugin({
   analyzerMode: 'disabled',  // 不启动展示打包报告的http服务器
   generateStatsFile: true, // 是否生成stats.json文件
})

这样再次执行打包的时候就只会产生 state.json 的文件了,state.json文件会静态的展示打包之后的体积信息

图片.png

压缩css

安装 optimize-css-assets-webpack-plugin

$ npm install -D optimize-css-assets-webpack-plugin 

修改 webapck.config.js 配置

// 压缩css
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin')

const config = {
  optimization: {
    minimize: true,
    minimizer: [
      // 添加 css 压缩配置
      new OptimizeCssAssetsPlugin({}),
    ]
  },
}
压缩js

uglifyjs-webpack-plugin插件在webpack4之后已经不再维护了,现在已经弃用了,取而代之的是具有相同功能的terser-webpack-plugin插件

而webpack5 内置了terser-webpack-plugin 插件,所以我们不需重复安装,直接引用就可以了

const TerserPlugin = require('terser-webpack-plugin');

const config = {
  // ...
  optimization: {
    minimize: true, // 开启最小化
    minimizer: [
      // ...
      new TerserPlugin({})
    ]
  },
  // ...
}

在生成环境下打包默认会开启 js 压缩,但是当我们手动配置 optimization 选项之后,就不再默认对 js 进行压缩,需要我们手动去配置。

当minimize设置为true,他会告知 webpack 使用 TerserPlugin 或其它在 optimization.minimizer定义的插件压缩 bundle。

删除无用的css

purgecss-webpack-plugin 会单独提取 CSS 并清除用不到的 CSS

安装插件

$ npm i -D purgecss-webpack-plugin

添加配置

// ...
const PurgecssWebpackPlugin = require('purgecss-webpack-plugin')
const glob = require('glob'); // 文件匹配模式

// ...
function resolve(dir){
  return path.join(__dirname, dir);
}

const PATHS = {
  src: resolve('src')
}

const config = {
  plugins:[ // 配置插件
    // ...
    new PurgecssPlugin({
      paths: glob.sync(`${PATHS.src}/**/*`, {nodir: true}) // nodir表示不匹配文件夹
    }),
  ]
}

注意:PurgecssWebpackPlugin不能单独使用,必须先安装配置分离css

tree shaking

Tree-shaking意为摇树,作用是剔除没有使用的代码,以降低包的体积,它是基于ES Module 规范来实现的,所以**Tree Shaking 只支持 ESM 的引入方式,不支持其他的引入方式。**

原理

在 CommonJs、AMD、CMD 等旧版本的 JavaScript 模块化方案中,导入导出行为是高度动态,难以预测的,例如:

if(process.env.NODE_ENV === 'development'){
  require('./bar');
  exports.foo = 'foo';
}

而 ESM 方案则从规范层面规避这一行为,它要求所有的导入导出语句只能出现在模块顶层,且导入导出的模块名必须为字符串常量,这意味着下述代码在 ESM 方案下是非法的:

if(process.env.NODE_ENV === 'development'){
  import bar from 'bar';
  export const foo = 'foo';

所以,ESM 下模块之间的依赖关系是高度确定的,鉴于此,webpack可以在运行过程中静态分析模块之间的导入导出,确定 ESM 模块中哪些导出值未曾其它模块使用,并将其删除,以此实现打包产物的优化。

配置

生产环境(production)会默认开启tree-shaking,如果想在测试环境开启tree-shaking的话,需要设置

  optimization: {
    usedExports: true,
  }

除此之外还需要在package.json中设置 sideEffects

{
"sideEffects": false,
}
sideEffects

sideEffects的值可以为boolean,也可以是一个数组

  • sideEffects 默认为 true, 告诉 Webpack ,所有文件都有副作用,他们不能被 Tree Shaking。
  • sideEffects 为 false 时,告诉 Webpack ,没有文件是有副作用的,他们都可以 Tree Shaking。
  • sideEffects 为一个数组时,告诉 Webpack ,数组中那些文件不要进行 Tree Shaking,其他的可以 Tree Shaking。
sideEffects 对全局 CSS 的影响

当我们将sideEffects设置为false之后,被引入的全局css文件会被treeShaking掉

原因在于:上面我们将 sideEffects 设置为 false 后,所有的文件都会被 Tree Shaking,通过 import 这样的形式引入的 CSS 就会被当作无用代码处理掉。

例如这样的代码,在打包后,打开页面,你就会发现样式并没有应用上,

reset.css

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
html,
body {
  background-color: #eaeaea;
}
// main.js
import "./styles/reset.css"

为了解决这个问题,可以在 loader 的规则配置中,添加 sideEffects: true ,告诉 Webpack 这些文件不要 Tree Shaking。

rules: [

    // 支持加载css文件
    {
      test: /.css/,
      use: [{ loader: MiniCssExtractPlugin.loader }, 'css-loader'],
      exclude: /node_modules/,
      include: path.resolve(__dirname, 'src'),
      sideEffects: true,
    },
    {
      test: /.less/,
      use: [{ loader: MiniCssExtractPlugin.loader }, 'css-loader', 'less-loader'],
      exclude: /node_modules/,
      include: path.resolve(__dirname, 'src'),
      sideEffects: true,
    }
]

或者指定package.json中的数组

"sideEffects": ["./src/\*\*/\*.less"],
scope hosting

Scope Hoisting开启之前,webpack打包的代码像这样

/\*\*\*\*\*\*/     /\* webpack/runtime/compat get default export \*/
/\*\*\*\*\*\*/     (() => {
/\*\*\*\*\*\*/         // getDefaultExport function for compatibility with non-harmony modules
/\*\*\*\*\*\*/         \_\_webpack\_require\_\_.n = (module) => {
/\*\*\*\*\*\*/             var getter = module && module.\_\_esModule ?
/\*\*\*\*\*\*/                 () => (module['default']) :
/\*\*\*\*\*\*/                 () => (module);
/\*\*\*\*\*\*/             \_\_webpack\_require\_\_.d(getter, { a: getter });
/\*\*\*\*\*\*/             return getter;
/\*\*\*\*\*\*/         };
/\*\*\*\*\*\*/     })();

webpack打包出来是一根匿名闭包,modules是一个加载模块数组,webpack_require用来加载模块,当代码量比较多时会生成大量的函数闭包,体积增大,运行时作用域的定义变多,更消耗内存

原因

  • 被webpack转换之后的模块会带上一层包裹
  • import会被转化成 _webpack_require
  • 主要是为了兼容不同的浏览器
开启Scope Hoisting

Scope Hoisting即作用域提升,将所有的模块按照引用顺序排列在一个函数作用域里面,再适当重命名一些函数,通过这种方式可以减少函数声明和内存开销,在生产环境下已经默认开启

删除无用代码

前面说到,使用TerserWebpackPlugin插件我们可以压缩js代码,除此之外,通过配置TerserWebpackPlugin插件,我们可以在打包时删除如console.log这种代码

minimizer: [
    new TerserWebpackPlugin({
      terserOptions: {
        compress: {
          drop\_console: true, //传true就是干掉所有的console.\*这些函数的调用.
          drop\_debugger: true, //干掉那些debugger;
          //     pure\_funcs: ['console.log'], // 如果你要干掉特定的函数比如console.info ,又想删掉后保留其参数中的副作用,那用pure\_funcs来处理   }  }
        },
      },
    }),
]
  • 14
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值