webpack 5 如何配置 experiments.lazyCompilation 实现按需编译并保留 HMR
【免费下载链接】webpackA bundler for javascript and friends. Packs many modules into a few bundled assets. Code Splitting allows for loading parts of the application on demand. Through "loaders", modules can be CommonJs, AMD, ES6 modules, CSS, Images, JSON, Coffeescript, LESS, ... and your custom stuff.项目地址: https://gitcode.com/GitHub_Trending/web/webpack
开发一个包含多个入口和大量import()动态分片的 webpack 5 应用时,webpack serve启动后的首次编译会把所有分片全部构建一遍,即使开发时只访问其中一小部分。experiments.lazyCompilation(5.17.0 起可用,官方标注为实验性选项)可以让 webpack 只在入口或import()模块被实际访问时才编译它们。本文基于仓库内的 lazy-compilation 示例 与 类型声明,给出配置方法、验证方式和 HMR 共存的做法。
适用前提:
- webpack 5(
lazyCompilation自 5.17.0 引入,@experimental); - 开发服务器环境:示例 README 明确要求安装
webpack-dev-server并运行webpack serve; - 浏览器端访问页面,模块通过用户操作触发
import()加载。
准备:示例项目结构与运行方式
示例位于examples/lazy-compilation/,其中 example.js 是应用代码:页面生成一组按钮,每个按钮对应一个import()调用(react、acorn、lodash等),点击后加载对应库;public/index.html 中页面加载构建产物dist/main.js。
运行方式按 README 的说明:安装webpack-dev-server依赖(例如npm install --save-dev webpack-dev-server),然后运行:
npx webpack serve配置 experiments.lazyCompilation
最小开启方式是布尔形式:
experiments: { lazyCompilation: true }示例配置文件 的完整写法如下(示例中require("../../")指向仓库根的 webpack 本体;在你自己的项目里应写require("webpack"),entry按你的项目填写):
"use strict"; const { HotModuleReplacementPlugin } = require("webpack"); /** @type {import("webpack").Configuration & { devServer: Record<string, EXPECTED_ANY> }} */ const config = { mode: "development", entry: "./example.js", cache: { type: "filesystem", idleTimeout: 5000 }, experiments: { lazyCompilation: true }, devServer: { hot: true, devMiddleware: { publicPath: "/dist/" } }, plugins: [new HotModuleReplacementPlugin()] }; module.exports = config;devServer.hot: true与HotModuleReplacementPlugin是示例中保留 HMR 的两个组成部分,不要省略;devMiddleware.publicPath: "/dist/"与页面引用dist/main.js的路径对应;cache的 filesystem 配置来自示例原样,可按项目情况调整。
对象形式的选项
lazyCompilation也接受对象,字段定义见 declarations/WebpackOptions.d.ts 中的LazyCompilationOptions:
| 字段 | 文档说明(原文摘要) |
|---|---|
entries | Enable/disable lazy compilation for entries(是否对入口启用) |
imports | Enable/disable lazy compilation for import() modules(是否对import()模块启用) |
test | Specify which entrypoints or import()ed modules should be lazily compiled。注意文档明确:它匹配的是被导入的模块(the imported module),而不是入口名 |
backend | Specifies the backend that should be used for handling client keep alive,可传入LazyCompilationDefaultBackendOptions |
例如只对特定模块启用:
experiments: { lazyCompilation: { entries: true, imports: true, test: /react|lodash/ } }backend用于自定义默认后端的连接方式,LazyCompilationDefaultBackendOptions的字段:client(自定义客户端)、listen(服务端监听地址)、protocol("http" | "https")、server(createServer的 ServerOptions 或自定义创建函数)。默认后端的工作机制见 lazyCompilationBackend.js:浏览器通过EventSource保持到后端/lazy-compilation-using-前缀端点的长连接,该端点返回text/event-stream;默认协议为http,除非配置了protocol: "https"或server带key/pfx。
运行与验证按需编译
npx webpack serve启动后打开页面,验证信号有三处:
页面行为。示例页面初始文案为 “Click on a button to load the library with import(). The first click triggers a lazy compilation of the module.”(首次点击触发该模块的按需编译)。点击某个库按钮后,
<pre>区域先显示Loading <key>...,该模块在本次编译中被懒编译,随后显示该模块导出的键名列表;示例中还有一个 “Load more...” 按钮通过import("./more")动态追加更多库。终端日志。lazyCompilationBackend.js 中后端以
LazyCompilationBackend日志器输出模块激活与释放信息,示例日志(key为模块标识,以下引自源码中的logger.log调用):<key> is now in use and will be compiled. <key> is no longer in use. Next compilation will skip this module.重新编译行为。模块被激活且处于 watch 状态时,后端调用
compiler.watching.invalidate()触发一次重新编译,随后该模块才会真正产出;浏览器端长连接关闭后,源码中的空闲计时器(120000 ms)会递减该模块的引用计数,降为 0 时输出上面的 “no longer in use” 日志,之后的编译将跳过该模块。
保留 HMR 的做法
示例配置中 HMR 与 lazy compilation 同时启用:devServer: { hot: true }加new HotModuleReplacementPlugin()(见 webpack.config.js)。也就是说,入口和未访问的模块先被代理占位,HMR runtime 照常注入;某个懒编译模块首次被激活、真正参与构建后,它的文件变更同样走 HMR 更新流程,不需要为 lazy compilation 单独关闭或降级热更新。
排查时如果模块点击后一直停在 “Loading”,可先确认终端是否出现<key> is now in use and will be compiled.日志,以及浏览器能否连通 lazy compilation 后端(默认http协议;跨环境部署时用backend.listen/backend.protocol调整,见上一节字段表)。
限制与已知边界
- 该选项在 schemas/WebpackOptions.json 与类型声明中均标记为
experimental,生产可用性以官方发布说明为准,本文不展开。 test匹配的是被导入模块而非入口名,按入口名过滤时容易配错(文档原文明确了这一点)。- 一个源码中记录的边界:UMD / AMD / System 这类以闭包参数传递 externals 的库封装(
umd、umd2、amd、amd-require、system)在懒编译代理首次激活时可能因闭包标识符未定义而运行时报错,LazyCompilationPlugin.js 中针对静态可枚举的 externals 做了预占位处理,使用这类库封装时留意该场景。
参考文件
- examples/lazy-compilation/README.md:运行前提(安装
webpack-dev-server、运行webpack serve) - examples/lazy-compilation/webpack.config.js:完整示例配置
- examples/lazy-compilation/example.js:示例入口代码
- declarations/WebpackOptions.d.ts:
LazyCompilationOptions字段定义 - lib/hmr/LazyCompilationPlugin.js、lib/hmr/lazyCompilationBackend.js:插件与默认后端实现
【免费下载链接】webpackA bundler for javascript and friends. Packs many modules into a few bundled assets. Code Splitting allows for loading parts of the application on demand. Through "loaders", modules can be CommonJs, AMD, ES6 modules, CSS, Images, JSON, Coffeescript, LESS, ... and your custom stuff.项目地址: https://gitcode.com/GitHub_Trending/web/webpack
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考