打包器基础
打包资源处理
加载非 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的ASTeslint-parser: 用以lint,解析为espree的ASTtypescript: 用以ts,解析为typescript的ASTbabel: 用以转化为低版本,解析为@babel/parser的ASTterser: 用以压缩混淆,解析为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 已经久不维护了