1. 概述
build.js
是 Vue 项目中的生产构建脚本,其主要作用是生成优化的生产版本构建文件并拼接 TypeScript 类型定义文件。该脚本是 Vue 项目构建系统的核心组件,负责协调多个包的构建过程。
2. 功能与特性
build.js
主要提供以下功能:
- 多包并行构建:利用 CPU 多核能力并行构建多个包,提高构建效率
- 多种输出格式支持:支持生成 ESM、CJS、IIFE 等多种模块格式
- 构建选项灵活配置:通过命令行参数控制构建行为
- 文件大小分析:构建后自动计算并显示文件大小、gzip 和 brotli 压缩后的大小
- 枚举内联优化:优化代码中的枚举值使用
- 版本信息注入:将 Git 提交信息和版本号注入构建产物
3. 命令行参数解析
build.js
使用 Node.js 的 util.parseArgs
解析命令行参数,支持以下选项:
参数名 | 简写 | 类型 | 说明 |
---|---|---|---|
formats |
-f |
字符串 | 指定构建格式(如 esm,cjs,global ) |
devOnly |
-d |
布尔值 | 仅构建开发版本 |
prodOnly |
-p |
布尔值 | 仅构建生产版本 |
withTypes |
-t |
布尔值 | 同时构建 TypeScript 类型定义 |
sourceMap |
-s |
布尔值 | 生成源码映射文件 |
release |
无 | 布尔值 | 发布模式构建 |
all |
-a |
布尔值 | 构建所有匹配的目标包 |
size |
无 | 布尔值 | 写入构建产物大小信息到文件 |
此外,还支持位置参数指定要构建的目标包名,包名支持模糊匹配。
4. 核心流程
4.1 初始化阶段
javascript
run()
async function run() {
if (writeSize) fs.mkdirSync(sizeDir, { recursive: true })
const removeCache = scanEnums()
try {
const resolvedTargets = targets.length
? fuzzyMatchTarget(targets, buildAllMatching)
: allTargets
await buildAll(resolvedTargets)
await checkAllSizes(resolvedTargets)
if (buildTypes) {
// 构建 TypeScript 类型定义
}
} finally {
removeCache()
}
}
初始化阶段主要完成:
- 创建大小报告目录(如果需要)
- 扫描并内联枚举值
- 解析目标包列表
- 启动构建流程
- 检查构建产物大小
- 构建类型定义(如果需要)
4.2 并行构建机制
javascript
async function buildAll(targets) {
await runParallel(cpus().length, targets, build)
}
buildAll
函数是构建系统的核心,它使用 runParallel
函数实现多目标并行构建。该函数会根据 CPU 核心数限制并发构建数量,避免资源耗尽。
4.3 单包构建流程
javascript
async function build(target) {
const pkgBase = privatePackages.includes(target)
? `packages-private`
: `packages`
const pkgDir = path.resolve(`${pkgBase}/${target}`)
const pkg = JSON.parse(fs.readFileSync(`${pkgDir}/package.json`, 'utf-8'))
// 跳过私有包(全量构建时)
if ((isRelease || !targets.length) && pkg.private) {
return
}
// 清理旧的 dist 目录
if (!formats && fs.existsSync(`${pkgDir}/dist`)) {
fs.rmSync(`${pkgDir}/dist`, { recursive: true })
}
// 确定构建环境
const env = (pkg.buildOptions && pkg.buildOptions.env) ||
(devOnly ? 'development' : 'production')
// 执行 Rollup 构建
await exec(
'rollup',
[
'-c',
'--environment',
[
`COMMIT:${commit}`,
`NODE_ENV:${env}`,
`TARGET:${target}`,
formats ? `FORMATS:${formats}` : ``,
prodOnly ? `PROD_ONLY:true` : ``,
sourceMap ? `SOURCE_MAP:true` : ``,
]
.filter(Boolean)
.join(','),
],
{ stdio: 'inherit' },
)
}
单包构建流程包括:
- 确定包的基础路径(公开包或私有包)
- 读取包的 package.json 配置
- 跳过不应构建的私有包
- 清理旧的构建目录
- 确定构建环境(开发或生产)
- 调用 Rollup 执行实际构建,传递必要的环境变量
4.4 文件大小检查
javascript
async function checkAllSizes(targets) {
if (devOnly || (formats && !formats.includes('global'))) {
return
}
console.log()
for (const target of targets) {
await checkSize(target)
}
console.log()
}
async function checkSize(target) {
const pkgDir = path.resolve(`packages/${target}`)
await checkFileSize(`${pkgDir}/dist/${target}.global.prod.js`)
if (!formats || formats.includes('global-runtime')) {
await checkFileSize(`${pkgDir}/dist/${target}.runtime.global.prod.js`)
}
}
async function checkFileSize(filePath) {
// 计算并显示文件大小、gzip 和 brotli 压缩后的大小
}
文件大小检查功能会:
- 检查全局生产构建文件的大小
- 计算并显示原始大小、gzip 压缩大小和 brotli 压缩大小
- 可选地将大小信息写入文件系统
5. 关键依赖
build.js
依赖以下核心模块:
- Node.js 内置模块 :
fs
,path
,util
,zlib
,os
,child_process
- 第三方工具 :
picocolors
(终端颜色输出),pretty-bytes
(文件大小格式化) - 自定义工具模块 :
./utils.js
(工具函数),./inline-enums.js
(枚举内联优化) - 构建工具 :
rollup
(实际执行构建)
6. 输入输出示例
6.1 输入输出示例
示例 1: 构建特定包
输入:
bash
node scripts/build.js vue
输出: 构建 vue
包,生成所有默认格式的构建产物(esm-bundler, cjs, global 等),并显示构建产物的大小信息。
示例 2: 构建匹配的多个包
输入:
bash
node scripts/build.js dom -a
输出: 构建所有名称包含 "dom" 的包(如 compiler-dom
, runtime-dom
)。
示例 3: 指定构建格式
输入:
bash
node scripts/build.js core --formats cjs
输出: 构建 core
包,仅生成 CJS 格式的构建产物。
示例 4: 同时构建类型定义
输入:
bash
node scripts/build.js vue -t
输出: 构建 vue
包,并同时构建其 TypeScript 类型定义文件。
7. 构建产物
build.js
在每个包的 dist
目录下生成以下类型的构建产物:
- ESM Bundler 版本:用于现代打包工具的 ESM 格式
- ESM Browser 版本:可直接在浏览器中使用的 ESM 格式
- CJS 版本:用于 Node.js 环境的 CommonJS 格式
- Global/IIFE 版本 :可通过
<script>
标签直接在浏览器中使用的格式 - Runtime 版本:不包含编译器的轻量级版本(各种格式都有对应的 runtime 版本)
- 生产优化版本:经过压缩和优化的生产环境版本
每个构建产物都注入了版本信息、Git 提交哈希等元数据,并根据构建环境设置了正确的特性标志。
8. 总结
build.js
是 Vue 项目的核心构建脚本,它通过灵活的参数配置和高效的并行构建机制,确保了 Vue 库能够以多种格式和优化级别输出,满足不同场景的使用需求。该脚本不仅负责构建 JavaScript 代码,还集成了类型定义生成、文件大小分析等功能,是 Vue 开发工作流中不可或缺的工具。