一、webpack配置

  1. 新建项目目录
  2. 下载webpack套件
  3. 编写webpack.config.js
  4. 配置npm script

二、loader、插件

  1. 安装loader预处理资源:HTML、js、css等
  2. 安装插件增强处理能力

三、开发环境优化

构建性能——webpack中文文档

打包优化

主要是对打包速度的优化。
从宏观角度来看,提升性能的方法无非两种:增加资源和缩小范围

多线程打包与HappyPack

原理

webpack是单线程的,必须串行执行转译任务,HappyPack以此为切入点,它的核心特性是开启多个线程,并行对不同模块进行转译。充分利用本地计算机资源提升打包速度。

思想

增加资源,通过投入更多的CPU和内存,用更多的计算能力缩短任务时间。

最佳使用场景

适用于转译任务比较重的工程,当把类似于babel-loader和ts-loader迁移到HappyPack上,效果不错。

缩小打包作用域

思想

缩小范围,从自身出发,比如去掉冗余的过程,尽量不做重复性的工作等。

实现
  1. exclude和include
  2. module.noParse
  3. 插件IngnorePlugin
  4. loader的cache配置项,如babel-loader。减少重复且不必要的转译过程。

动态链接库思想与DullPlugin

原理

对于第三方模块或者一些不常变化的模块,可以将它们先编译和打包,然后在项目实际构建过程中直接取用。

实现

与代码分片(Code Splitting)的区别

主要在于是否“只需一次编译和打包”。
代码分片是制定规则,让webpack打包时根据这些规则来提取一些模块,称之为vendor,它对性能的提高体现在生产环境,如果这些提取出来的公共模块不常改变,就可以长期的缓存在客户端,减少对服务器的资源请求。
而DullPlugin是将vendor分离出来,独立编译和打包,在实际工程构建的时候不需要再次对它做任何处理,这些独立出来的模块在经历过一次打包后就一般不再需要参与后续工程的打包过程,它可以被直接取用。

死代码检测与tree shaking

原理

利用的是ES6 Module的模块依赖关系建立发生在代码编译阶段这一特性。可以预先知道哪些代码不会被使用,从而标记以便在打包时清除。

限制

必须是用ES6 Module语法实现导入导出

实现

tree shaking本身只是标记死代码,真正去除死代码是通过插件,如terser-webpack-plugin。

webpack-dashboard

插件。可视化地显示webpack每次构建结束后在控制台中输出的信息。

  1. npm install --save-dev webpack-dashboard

webpack-merge

插件。用来构建开发环境和生产环境的webpack配置文件。

npm install --save-dev webpack-merge

speed-measure-webpack-plugin

可以分析出webpack整个打包过程中各个loader和plugin上的耗费时间。有助于找出构建过程中的性能瓶颈。

npm install --save-dev speed-measure-webpack-plugin

模块热替换

HMR和live reload

live reload是指检测到代码改动就会自动重新构建,然后触发网页刷新。默认配置下,webpack对js代码进行live reload。
HRM,Hot Module Replacement。使代码在网页不刷新的情况下得到最新的改动,其实就是代码在当前环境下重新执行一遍。

开启HRM

HRM是需要手动开启的,且有一些必要条件。

  1. 项目必须是基于webpack-dev-server或webpack-dev-middle进行开发
  2. 使用插件,配置devServer

    const webpack = require('webpack')
    plugins:[
     new webpack.HotModeleReplacementPlugin()
    ],
    devServer:{
     hot:true,
     ···
    }
    

    上面的配置产生的结果是webpack会给每个模块都绑定module.hot对象,这个对象包含了HRM的API。借助这些特定的API可以实现对特定模块开启或关闭HRM,也可以添加热替换之外的逻辑。

  3. 手动添加代码开启HRM

    //index.js
    if(module.hot){
    module.hot.accept();
    }
    

    上面代码放在入口,则其依赖图上的所有模块的更新都会触发热替换。accept()接收一个开启HRM的模块的白名单,默认是所有依赖的模块。

  4. 最好借助工具来开启HRM:react-hot-loader、vue-loader

  • 热替换的特点是不刷新页面而在当前环境全部重新执行一遍代码,如果是设置了定时器setInterval,就有可能重复设置,就需要对该模块禁用HRM,一有改变只能刷新。
  • 对于用html-webpack-plugin处理的HTML文件,HRM不能作用到,只能通过配置devServer.watchFiles来监视这些类似文件的变化。

HRM原理

webpack-dev-server相当于服务器,浏览器相当于客户端。

  1. 基于websocket连接,当资源发生变化时向浏览器推送更新事件
  2. 浏览器向服务器请求获取更改文件的列表,即哪些模块发生了改变,如下

    请求网址: http://172.26.212.61:8888/main.b57da663cec1210ea7fd.hot-update.json
    请求方法: GET
    
  3. 服务器返回需要更新的chunk的chunk name以及版本

    {"c":["main"],"r":[],"m":[]}
    
  4. 知道是谁要更新之后,浏览器继续向webpack-dev-server获取该chunk的增量更新:

    请求网址: http://172.26.212.61:8888/main.b57da663cec1210ea7fd.hot-update.js
    请求方法: GET
    
  5. 增量更新返回值 ```javascript “use strict”; self[“webpackHotUpdatebabel_practice”](“main”,{

// “./src/modules/joinstr.js”: /!**!\ !** ./src/modules/joinstr.js ! ***/ /*/ ((unused_webpack_module, webpackexports, webpackrequire) => {

webpack_require.r(webpack_exports); / harmony export / webpack_require.d(webpack_exports, { / harmony export / “joins”: () => (/ binding / joins) / harmony export / }); var joins = function joins(a, b, seq) { return ‘’ + a + seq + b + ‘2021-10-31’; };

/*/ })

}, /**/ function(webpack_require) { // webpackRuntimeModules /**/ / webpack/runtime/getFullHash / /**/ (() => { /**/ webpack_require.h = () => (“608cbe9379e3c20a43c3”) /**/ })(); /**/ /**/ } ); //# sourceMappingURL=main.b57da663cec1210ea7fd.hot-update.js.map

以上是最基本的过程。



<a name="OAhfF"></a>
## 四、生产环境配置与优化
即线上环境。开发环境我们可能更关注打包速度,而在生产环境中我们关注的则是输出的资源体积以及如何优化客户端缓存来缩短页面渲染时间。

1. 环境配置的封装
1. production模式
1. webpack.DefinePlugin与自定义的全局环境变量
1. 代码切片,按需加载
1. source Map跟踪回溯调用栈
1. 资源压缩
1. 缓存,利用客户端缓存缩短页面加载资源加载时间。而针对需要用户浏览器立即更新资源的情况,有以下处理:<br />a. 资源hash,资源改变时hash值也改变,迫使用户下载最新的资源<br />b. 输出动态HTML。html-webpack-plugin
1. bundle体积监控和分析
   1. VS Code插件:Import Cost
   1. npm插件:webpack-bundle-analyzer
   1. 自动化监控资源体积:bundlesize(已弃用)
   1. 更多bundle分析工具,可查看`webpack官方文档/指南/代码分离/bundle分析`
   1. 处理体积过大的包:
      1. 更小的替代方案
      1. 只引用子模块

<a name="L74FG"></a>
### webpack-bundle-analyzer安装与配置
```shell
 npm install --save-dev webpack-bundle-analyzer

在package.json配置

const Analyzer = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
//···
plugins: [
  new HtmlWebpackPlugin({
    template: './src/index.html',
  }),
  new Analyzer(),
],

然后运行npm run build,插件会在浏览器里打开一个统计的页面。

实现高性能应用其中重要的一点是尽可能地让用户每次只加载必要的资源,优先级不太高的资源则采用延迟加载等技术渐进式地获取。其中就涉及代码切片、客户端缓存和延迟加载等内容。

一条软件工程领域的经验——不要过早优化,在项目初期不要看到任何优化点就拿来加到项目中,这样不但增加了复杂度,优化的效果也不会太理想,一般是当项目发展到一定规模后,性能问题随之而来,这时再去分析然后对症下药,才有可能达到理想的优化效果。

相关文献

【译】Google - 使用 webpack 进行 web 性能优化(三):监控和分析应用
bundle 分析(bundle analysis)
《webpack实战:入门、进阶与调优》[

](https://webpack.docschina.org/guides/code-splitting/#bundle-analysis)