zhangdizhangdi

webpack

基础

参考

核心概念

  • entry:入口,Webpack 执行构建的第一步将从 Entry 开始,可抽象成输入
  • module:模块,在 Webpack 里一切皆模块,一个模块对应着一个文件。Webpack 会从配置的 Entry 开始递归找出所有依赖的模块
  • chunk:代码块,一个 Chunk 由多个模块组合而成,用于代码合并与分割
  • loader:文件转换器
  • plugin:插件,执行特定任务
  • output:输出结果,在 Webpack 经过一系列处理并得出最终想要的代码后输出结果

Loaders

从右往左,从下往上执行

pitch:拦截 loader 的执行,预处理

js
// 自己写个,style-loader
// 作用:将css内容,通过style标签插入到页面中
// source为要处理的css源文件
function loader(source) {
  let style = `
    let style = document.createElement('style');
    style.setAttribute("type", "text/css");
    style.innerHTML = ${source};
    document.head.appendChild(style)`
  return style
}
module.exports = loader

Plugins

区别

  • loader 运行在打包文件之前

    对于 loader,实质是一个转换器,将 A 文件进行编译形成 B 文件,操作的是文件,比如将 A.scss 或 A.less 转变为 B.css,单纯的文件转换过程

  • plugin 在整个编译周期都起作用

    在 Webpack 运行的生命周期中会广播出许多事件,plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果

source map

tree-shaking

V5

参考

Asset Modules

Long Term Caching

cache

URIs

TreeShaking 和 SideEffects

模块联邦

使 JavaScript 应用,得以从另一个 JavaScript 应用中动态的加载代码,实现共享依赖,用于前端的微服务化

比如项目 A 和项目 B,公用项目 C 组件,以往这种情况,可以将 C 组件发布到 npm 上,然后 A 和 B 再具体引入。当 C 组件发生变化后,需要重新发布到 npm 上,A 和 B 也需要重新下载安装

使用模块联邦后,可以在远程模块的 Webpack 配置中,将 C 组件模块暴露出去,项目 A 和项目 B 就可以远程进行依赖引用。当 C 组件发生变化后,A 和 B 无需重新引用

PackageExports

核心流程

参考




流程

webpack-cli 是要安装的,webpack 命令执行时会先查找其是否安装

Webpack 的构建流程可以分为以下三大阶段:

  • 初始化:启动构建,读取与合并配置参数,加载 Plugin,实例化 Compiler。
  • 编译:从 Entry 发出,针对每个 Module 串行调用对应的 Loader 去翻译文件内容,再找到该 Module 依赖的 Module,递归地进行编译处理。
  • 输出:对编译后的 Module 组合成 Chunk,把 Chunk 转换成文件,输出到文件系统。

以下来自万字总结文章

初始化

  • 初始化参数:从配置文件、 配置对象、Shell 参数中读取,与默认配置结合得出最终的参数
  • 创建编译器对象:用上一步得到的参数创建 Compiler 对象
  • 初始化编译环境:包括注入内置插件、注册各种模块工厂、初始化 RuleSet 集合、加载配置的插件等
  • 开始编译:执行 compiler 对象的 run 方法
  • 确定入口:根据配置中的 entry 找出所有的入口文件,调用 compilition.addEntry 将入口文件转换为 dependence 对象

webpack core
图:webpack core

构建

  • 编译模块(make):根据 entry 对应的 dependence 创建 module 对象,调用 loader 将模块转译为标准 JS 内容,调用 JS 解释器将内容转换为 AST 对象,从中找出该模块依赖的模块,再 递归 本步骤直到所有入口依赖的文件都经过了本步骤的处理
  • 完成模块编译:上一步递归处理所有能触达到的模块后,得到了每个模块被翻译后的内容以及它们之间的 依赖关系图

webpack build
图:webpack build

生成

  • 输出资源(seal):根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会
  • 写入文件系统(emitAssets):在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统

webpack build
图:webpack build

HMR

参考



不同

  • webpack-dev-server 自动安装配置 webpack-dev-middleware,使用 WebSocket
  • webpack-dev-middleware 搭配 webpack-hot-middleware,手动配置,使用 SSE

流程

webpack-dev-server
图:webpack-dev-server

webpack hmr
图:webpack hmr

  • webpack-dev-server 提供 http server 服务和 socket server 服务,在 webpack-dev-middleware 中间件中启用 webpack 的 watch 模式。
  • 当文件系统中某一个文件发生修改,webpack 监听到文件变化,根据配置文件对模块重新编译打包,并将打包后的代码保存在文件系统中。
  • webpack-dev-server/client/index.js 在浏览器端和服务端之间建立一个 websocket 长连接,将 webpack 编译打包的状态信息告知浏览器端。
  • 浏览器端通过 webpack/hot/dev-server.js 接收到最新的编译信息,从而触发 module.hot.check 方法来开始热更新检查。
  • 执行 webpack/lib/hmr/HotModuleReplacement.runtime.js 中的 hotCheck 方法,通过 hmrDownloadManifest 以 fetch 方式请求 hot-update.json 文件,然后执行 loadScript 以 jsonp 的方式加载 hot-update.js 文件。
  • 执行 hot-update.js 文件中的 self[‘webpackHotUpdate’]方法,在 webpack/lib/web/JsonpChunkLoadingRuntimeModule.js 文件的 self[‘webpackHotUpdate’] 方法定义中去收集到需要更新的模块依赖。
  • 调用 internalApply 方法,用新模块替换掉旧模块,然后执行 module.hot._acceptedDependencies 中的回调函数,从而实现模块替换的效果。

构建性能

参考

分类

查找并诊断性能瓶颈:

  • 构建速度分析:影响构建性能和开发效率
  • 构建体积分析:影响页面访问性能

构建性能优化常用方法:

  • 通过多进程加快构建速度
  • 通过分包减少构建目标容量
  • 减少构建目标加快构建速度

构建速度优化

优化 loader 配置

优化正则匹配,使用 includ、exclude、test 指定需要处理的文件,忽略不需要处理的文件

对于 loader 来说,影响打包效率首当其冲必属 Babel 了。因为 Babel 会将代码转为字符串生成 AST,然后对 AST 继续进行转变最后再生成新的代码,项目越大,转换代码越多,效率就越低。

js
module: {
   rules: [{
      test: /\.js$/,
      use: ['babel-loader?cacheDirectory'],
      include: path.resolve(__dirname, 'src'),
   }]
},

减少 loader、plugin

每个的 loader、plugin 都有其启动时间。尽量少地使用工具,将非必须的 loader、plugin 删除。

优化 resolve 配置

多进程/多线程

开启缓存

DLL

使用:

  • 分包:定义 webpack.dll.config.js,使用 DllPlugin 配置分包,定义 scripts 命令,执行命令,完成分包
  • 排除分包:在 vue.config.js 中使用 DllReferencePlugin 引用 manifest 文件排除分包
  • 拷贝 dll:将 dll 拷贝到项目目录下
  • 引用 dll:使用 add-asset-html-webpack-plugin 引用分包文件

构建体积优化

代码压缩

对 js 文件进行压缩,从而减小 js 文件的体积,还可以压缩 html 、css 代码。

代码分离

Tree Shaking

生产环境关闭 sourcemap

图片处理

按需加载

CDN