打包过程优化:基于命令行参数的打包过程
在上一节中,我们创建了基础的构建脚本。现在的问题是:每次打包时手动修改 .swcrc 配置文件(如关闭 sourceMap、开启 minify)既不方便,也容易遗漏。本节将通过命令行参数来控制 SWC 的构建配置,实现一键生产环境构建。
问题场景
开发环境中需要 sourceMap 方便调试,但生产环境不需要。手动切换容易出现以下问题:
- 忘记关闭 sourceMap,导致生产包体积增大
- 忘记恢复配置,影响后续开发体验
- 多个配置项(sourceMap、minify 等)需要反复手动切换
解决方案:minimist 解析命令行参数
使用 minimist 库解析命令行参数,动态修改 .swcrc 配置文件。
pnpm add -D minimist
bash
命令行参数传递方式
在 package.json 中配置构建脚本:
{
"scripts": {
"build": "nest build",
"build:prod": "node scripts/build.mjs --sourceMaps=false --minify=true"
}
}
json
参数解析
import minimist from 'minimist'
// 解析命令行参数,从第三个元素开始(跳过 node 和脚本路径)
const argv = minimist(process.argv.slice(2))
console.log(argv) // { _: [], sourceMaps: 'false', minify: 'true' }
javascript
构建 swcBuild 函数
核心逻辑:读取配置 -> 合并参数 -> 写入配置 -> 执行构建 -> 恢复配置。
// 读取 JSON 文件
function readJsonFile(filePath) {
const data = fs.readFileSync(filePath, 'utf8')
return JSON.parse(data)
}
// 写入 JSON 文件
function writeJsonFile(filePath, data) {
const content = JSON.stringify(data, null, 2)
fs.writeFileSync(filePath, content, 'utf8')
}
// SWC 构建主流程
async function swcBuild(argv) {
// 1. 读取 .swcrc 配置文件
const swcPath = path.join(__dirname, '..', '.swcrc')
const swcJson = readJsonFile(swcPath)
// 2. 清理 argv 中不需要的属性
delete argv._
// 3. 将命令行参数中的字符串转换为布尔值
const parsedArgv = parseArgv(argv)
// 4. 合并配置(命令行参数覆盖默认配置)
const newData = { ...swcJson, ...parsedArgv }
// 5. 写入临时配置
writeJsonFile(swcPath, newData)
// 6. 执行构建
const { stdout } = await $`npm run build`
console.log(stdout)
// 7. 恢复原始配置
writeJsonFile(swcPath, swcJson)
}
javascript
类型转换工具函数
命令行参数解析后都是字符串类型(如 "false" 而不是 false),需要进行类型转换:
// utils/parseArgv.mjs
export function parseArgv(argv) {
const result = {}
for (const [key, value] of Object.entries(argv)) {
if (value === 'true') {
result[key] = true
} else if (value === 'false') {
result[key] = false
} else {
result[key] = value
}
}
return result
}
javascript
使用方式:
import { parseArgv } from './utils/parseArgv.mjs'
const parsedArgv = parseArgv(argv)
// { sourceMaps: false, minify: true } -- 布尔值,而非字符串
javascript
完整构建脚本整合
将 Prisma Client 生成和 SWC 构建整合为一个完整的流程:
// scripts/build.mjs
import dotenv from 'dotenv-flow'
import fs from 'fs'
import path from 'path'
import { fileURLToPath } from 'url'
import { execSync } from 'child_process'
import minimist from 'minimist'
import { parseArgv } from './utils/parseArgv.mjs'
const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
const argv = minimist(process.argv.slice(2))
// 生成 Prisma Clients(上一节实现的函数)
async function generatePrismaClients() { /* ... */ }
// SWC 构建
async function swcBuild() {
const swcPath = path.join(__dirname, '..', '.swcrc')
const swcJson = JSON.parse(fs.readFileSync(swcPath, 'utf8'))
delete argv._
const parsedArgv = parseArgv(argv)
const newData = { ...swcJson, ...parsedArgv }
// 写入临时配置
fs.writeFileSync(swcPath, JSON.stringify(newData, null, 2), 'utf8')
// 执行构建
const result = execSync('npm run build', {
cwd: path.join(__dirname, '..'),
})
console.log(result.toString())
// 恢复原始配置
fs.writeFileSync(swcPath, JSON.stringify(swcJson, null, 2), 'utf8')
}
// 主流程
async function run() {
await generatePrismaClients()
await swcBuild()
}
run().catch(console.error)
javascript
验证流程
# 执行生产构建
pnpm build:prod
# 输出过程:
# 1. 生成 PostgreSQL Client...
# 2. 生成 MySQL Client...
# 3. 开始 SWC 构建(sourceMaps=false)...
# 4. 构建完成
# 5. 恢复 .swcrc 配置
# 验证 dist 目录中无 .map 文件
ls dist/ | grep '.map' # 应为空
# 验证 .swcrc 配置已恢复
cat .swcrc # sourceMaps 应恢复为 true(开发值)
bash
.swcrc 配置文件说明
SWC 配置文件 .swcrc 的典型结构:
{
"$schema": "https://swc.rs/schema.json",
"sourceMaps": true,
"minify": false,
"jsc": {
"parser": {
"syntax": "typescript",
"decorators": true,
"dynamicImport": true
},
"transform": {
"legacyDecorator": true,
"decoratorMetadata": true
},
"target": "es2020"
},
"module": {
"type": "commonjs"
}
}
json
小结
本节通过命令行参数驱动构建配置,实现了以下目标:
| 目标 | 实现方式 |
|---|---|
| 参数化构建配置 | minimist 解析命令行参数 |
| 自动类型转换 | parseArgv 工具函数处理字符串到布尔值 |
| 配置安全恢复 | 构建完成后自动恢复 .swcrc 原始配置 |
| 流程整合 | Prisma Client 生成 + SWC 构建一体化 |
下一节将介绍如何使用 execa 库来替代 child_process,使命令执行的代码更加简洁和可读。
↑