前面已经把 webpack 的基本配置都了解了一遍,我们已经可以运用基本配置将项目打包成我们想要的包,接下来深入了解一下 webpack 的其他配置和特性。
前面所配置webpack
的项目,文件每一次修改都需要调用webpack-cli
的命令去调用webpack
来进行打包。当我们需要长时间不断地修改项目或者调试项目时。
显然每一次修改文件都需要手动地调用是非常麻烦的,所以,webpack 中有一个HMR(模块热更新)
的功能来帮我们解决这个问题。
HMR
的作用就是:当entry
入口和其依赖的文件发生改变时,就会触发 webpack 的打包,将 entry 和相关依赖重新打包一遍。
webpack 本身不支持 HMR,使用 HMR 需要安装webpack-dev-server或者其他支持HMR
的库。
安装完库后,在 webpack 配置中添加 devServer 字段:
const path = require("path");
const MyPlugin = require("./src/plugin");
module.exports = {
mode: "production",
entry: [
path.resolve(__dirname, "src", "entry.js"),
path.resolve(__dirname, "src", "test2.js"),
],
devServer: {
static: "./dist",
hot: true,
},
output: {
filename: "bundle.js",
},
plugins: [new MyPlugin(path.resolve(__dirname, "src", "test.html"))],
};
配置完后执行webpack-dev-server
命令,就会启动模块监听,并启动一个 web 服务,web 服务中的静态文件为static
路径下的文件。
webpack-dev-server
<i> [webpack-dev-server] Project is running at:
<i> [webpack-dev-server] Loopback: http://localhost:8080/
<i> [webpack-dev-server] On Your Network (IPv4): http://192.168.3.3:8080/
<i> [webpack-dev-server] On Your Network (IPv6): http://[fe80::1]:8080/
<i> [webpack-dev-server] Content not from webpack is served from './dist' directory
<i> [webpack-dev-middleware] wait until bundle finished: /
asset bundle.js 115 KiB [emitted] [minimized] (name: main) 1 related asset
懒加载是指:将模块文件将他们逻辑地分开,当触发某个事件时再重新调用这些分开的模块。这样做的目的是减少初始打包文件打大小,加载网页加载速度。
懒加载在项目庞大的时候非常有用。
使用懒加载的原理很简单,就是利用动态导入的方式,当触发某个事件时,动态导入模块代码。下面就来看一下我们在业务代码中如何调用懒加载
首先定义一个模块函数和一个主函数
// test.js 模块函数
function test2() {
console.log("test2");
}
export default test2;
// entry.js 主函数
window.onload = () => {
var btn = document.querySelector("#btn");
if (btn) {
btn.onclick = async function () {
const module = await import(/* webpackChunkName: "test" */ "./test2");
module.default();
};
}
};
webpack 配置
const path = require("path");
const htmlPlugin = require("html-webpack-plugin");
module.exports = {
mode: "production",
entry: [path.resolve(__dirname, "src", "entry.js")],
devServer: {
static: "./dist",
hot: true,
},
output: {
filename: "[name].bundle.js",
clean: true,
},
plugins: [
new htmlPlugin({
template: path.resolve(__dirname, "src", "test.html"),
}),
],
};
执行打包后会将动态引入的test2.js
文件从 entry 中分离出来独立打包成一个文件,等待调用。
$ webpack
// asset main.bundle.js 2.64 KiB [emitted] [minimized] (name: main)
// asset index.html 214 bytes [emitted]
// asset test.bundle.js 164 bytes [emitted] [minimized] (name: test)
Tree Shaking
描述的是我们在项目中上下文都未使用的代码,在打包过程中会将它“优化”掉。
那么如何判断代码块在上下文都未使用呢?
在纯ES Module
的代码中,webpack 中已经在内部帮我们做好了判断,很容易就能判断到哪些代码是有side effect(副作用)
的。
"side effect(副作用)" 的定义是,在导入时会执行特殊行为的代码,
而不是仅仅暴露一个 export 或多个 export。
举例说明,例如 polyfill,它影响全局作用域,并且通常不提供 export。
比如 css 在 JS 文件中引入,因为该文件没有在 js 文件中被使用,webpack 很可能会优化掉它,这是我们可以手动地标记一下,让 webpack 知道这个模块是有副作用的。标记的方法就是在package.json
中定义sideEffects
。
// package.json
{
"name": "test",
"sideEffects": ["*.css"]
}
标记了之后,webpack 会认为这些模块都是有副作用的,在打包的时候会被保留。
可以手动标记文件的副作用,当然也可以标记为无副作用
// package.json
{
"name": "test",
"sideEffects": false
}
除了将文件模块标记副作用,还可以针对某个方法来标记它无副作用。使用/*#__PURE__*/
标记
// 标记无副作用函数
/*#__PURE__*/ test2();
webpack 的mode:"production"
内置了Tree Shaking
,设置之后在打包的时候会自动地使用。
本小节主要介绍了
HMR
: 模块热更新懒加载
: 用于优化初始文件的大小,降低初始文件大小,提高首屏加载速度Tree Shaking
: 打包过程中会将它“优化”掉未被使用的模块