打包器基础
打包资源处理
加载非 js 资源
前端浏览器 js
中只能加载 js
资源, node
中也只能加载 js
和 json
, 所以打包工具中加载 json
和 图片 等资源的时候就得使用不同的方式去加载不同类型的文件,例如 webpack
中的 loader
, webpack
中一切皆为 module
。
加载 json
例如
{
id: 1,
name: 'lafen'
}
项目中使用时,打包器将其当作 module
,可以直接通过 import
引入
import user from './user.json'
实际上,在 webpack
和 rollup
中,帮我们做了转换,将 user.json
的内容转换成了普通的 js
// 实际上 user.json 被编译成以下内容
export default {
id: 1,
name: 'lafen'
}
webpack
中通过 loader
来处理非 js
资源,例如 json-loader
module.exports = function (source) {
const json = typeof source === "string" ? source : JSON.stringify(source);
return `module.exports = ${json}`;
};
加载图片
图片资源则更简单,直接替换成图片路径即可
export default `$PUBLIC_URL/assets/image/logo.png`;
使用的时候实际上引入的只是图片路径
<template>
<img :src="logo" />
</template>
<script>
import logo from 'logo.png'
</script>
加载 css
加载 css
需要处理两个关键点
css-loader
: 借助postcss
的postcss-value-parser
解析处理 成AST
, 并将css
中的url
和@import
视为 模块导入style-loader
: 将处理完的css
插入dom
中。 即使用js
手动创建style
标签并填充css
内容,然后将style
标签插入dom
将 css
资源插入 dom
示例
module.exports = function (source) {
return `
function injectCss(css) {
const style = document.createElement('style')
style.appendChild(document.createTextNode(css))
document.head.appendChild(style)
}
injectCss(\`${source}\`)
`;
};
打包基础优化
提升 webpack 构建速度
使用 speed-measure-webpack-plugin 可评估每个 loader/plugin 的执行耗时。
使用更快的 loader: SWC
webpack
中最耗时的是负责 AST
转换的 loader
,当 loader
进行编译时的 AST
操作均为 CPU
密集型任务,使用 javascript
性能低下,此时可采用高性能语言 rust
编写的 swc
。
比如 javascript
转化由 babel
转化为更快的 swc
module.exports = {
module: {
rules: [
{
test: /\.m?js$/,
exclude: /(node_modules)/,
use: {
loader: "swc-loader",
},
},
];
}
}
持久化缓存: cache
webpack5
内置了关于缓存的插件,可通过 cache 字段配置开启。
它将 Module
、Chunk
、ModuleChunk
等信息序列化到磁盘中,二次构建避免重复编译计算,编译速度得到很大提升。
{
cache: {
type: "filesystem";
}
}
如对一个 JS
文件配置了 eslint
、typescript
、babel
等 loader
,他将有可能执行五次编译,被五次解析为 AST
acorn
: 用以依赖分析,解析为acorn
的AST
eslint-parser
: 用以lint
,解析为espree
的AST
typescript
: 用以ts
,解析为typescript
的AST
babel
: 用以转化为低版本,解析为@babel/parser
的AST
terser
: 用以压缩混淆,解析为acorn
的AST
而当开启了持久化缓存功能,最耗时的 AST
解析将能够从磁盘的缓存中获取,再次编译时无需再次进行解析 AST
。
得益于持久化缓存,二次编译甚至可得到与 Unbundle 的 vite 等相近的开发体验
在 webpack4
中,可使用 cache-loader 仅仅对 loader
进行缓存。需要注意的是该 loader
目前已是 @deprecated
状态。
module.exports = {
module: {
rules: [
{
test: /\.ext$/,
use: ["cache-loader", ...loaders],
include: path.resolve("src"),
},
],
},
};
多进程 thread-loader
thread-loader 为官方推荐的开启多进程的 loader
,可对 babel
解析 AST
时开启多线程处理,提升编译的性能。
module.exports = {
module: {
rules: [
{
test: /\.js$/,
use: [
{
loader: "thread-loader",
options: {
workers: 8,
},
},
"babel-loader",
],
},
],
},
};
在 webpack4
中,可使用 happypack plugin ,但需要注意的是 happypack
已经久不维护了