在现代前端开发中,构建是项目交付前不可或缺的一环。它涵盖了从源代码到生产环境代码的转换过程,主要包括:
虽然许多项目的构建流程已经预先配置好,但理解其背后的原理和考量,对于提升开发效率和解决复杂问题至关重要。
本章将引导你使用 npm script 和命令行工具,从零开始为一个典型的前端项目搭建构建流水线,让你深入理解每个环节的实现细节。
在开始之前,请确保你已具备以下基础:
我们从一个简单的项目结构开始,它代表了典型的前端资源引用关系:
client/
├── images/
│ └── schedule.png
├── index.html
├── scripts/
│ └── main.js
└── styles/
└── main.css资源依赖关系如下:
index.html 引用了 main.css 和 main.js。main.css 和 index.html 可能引用了 images/ 目录下的图片。为了确保构建过程的正确性,我们必须遵循以下顺序:
我们将逐步实现每个构建环节,并最终将它们串联成一条完整的流水线。
我们约定将构建产物输出到 dist 目录,并保持与 client 目录相同的结构。每次构建前,需要清空旧的产物。
利用 npm 的 pre 钩子,我们可以轻松实现这一步。在 package.json 中添加 prebuild 脚本:
"scripts": {
"prebuild": "rm -rf dist && mkdir -p dist/{images,styles,scripts}"
}为了保持 package.json 的整洁,我们使用 scripty 将复杂的构建命令拆分到独立的文件中。
首先,创建用于存放构建脚本的目录:
mkdir -p scripts/build
touch scripts/build.sh scripts/build/{images,styles,scripts,hash}.sh
chmod -R a+x scripts注意:必须为脚本文件添加可执行权限,否则 scripty 将无法执行。
我们使用 imagemin-cli 来压缩图片。
首先,安装依赖:
npm install imagemin-cli --save-dev然后,在 scripts/build/images.sh 中添加:
imagemin client/images/* --out-dir=dist/images最后,在 package.json 中配置 build:images 命令:
"scripts": {
"build:images": "scripty"
}我们使用 lessc 编译 Less 文件,并用 cssmin 压缩 CSS。
安装依赖:
npm install less cssmin --save-dev在 scripts/build/styles.sh 中添加,利用管道(|)和重定向(>)实现流式处理:
for file in client/styles/*.css
do
lessc $file | cssmin > dist/styles/$(basename $file)
done在 package.json 中配置 build:styles 命令:
"scripts": {
"build:styles": "scripty"
}对于 ES6+ 代码,我们使用 uglify-es 进行压缩。
安装依赖:
npm install uglify-es --save-dev在 scripts/build/scripts.sh 中添加:
for file in client/scripts/*.js
do
./node_modules/uglify-es/bin/uglifyjs $file --mangle > dist/scripts/$(basename $file)
done提示:uglify-es 已停止维护,现代项目建议使用 terser。
提示:uglify-es 提供了丰富的命令行选项,如 sourcemap 生成和代码混淆,详情请查阅其官方文档。
在 package.json 中配置 build:scripts 命令:
"scripts": {
"build:scripts": "scripty"
}为静态资源添加版本号是确保缓存更新的关键。我们使用 hashmark 生成哈希版本号,并用 replaceinfiles 更新文件引用。
安装依赖:
npm install hashmark replaceinfiles --save-dev在 scripts/build/hash.sh 中添加:
# 1. 为图片资源添加版本号,并更新 CSS 中的引用
hashmark -c dist -r -l 8 '**/*.{png,jpg}' '{dir}/{name}.{hash}{ext}' | replaceinfiles -S -s 'dist/**/*.css' -d '{dir}/{base}'
# 2. 为 CSS 和 JS 添加版本号,并更新 HTML 中的引用
hashmark -c dist -r -l 8 '**/*.{css,js}' '{dir}/{name}.{hash}{ext}' | replaceinfiles -S -s 'client/index.html' -d 'dist/index.html'在 package.json 中配置 build:hash 命令:
"scripts": {
"build:hash": "scripty"
}现在,我们将所有步骤串联起来,形成一个完整的构建命令。
在 package.json 中添加 build 脚本:
"scripts": {
"prebuild": "rm -rf dist && mkdir -p dist/{images,styles,scripts}",
"build": "scripty",
"build:images": "scripty",
"build:styles": "scripty",
"build:scripts": "scripty",
"build:hash": "scripty"
}在 scripts/build.sh 中按顺序执行所有构建步骤:
for step in 'images' 'styles' 'scripts' 'hash'
do
npm run build:$step
done现在,运行 npm run build 即可触发完整的构建流水线。
构建完成后,dist 目录将包含优化后的生产代码。
你可以通过以下方式验证构建结果:
dist 目录:确认所有静态资源都已添加哈希版本号。dist/index.html:确认资源引用已更新为带版本号的路径。http-server dist,并在浏览器中打开 http://127.0.0.1:8080,检查页面是否正常渲染。scripty 报错:请确保所有 scripts/build/ 下的脚本文件都具有可执行权限 (chmod a+x)。uglify-es 无法识别 ES6 语法:确保你调用的是 node_modules/uglify-es/bin/uglifyjs,而不是全局安装的 uglifyjs。通过本章的学习,你已经掌握了如何使用 npm script 和命令行工具搭建一个完整、自动化的前端构建流水线。这不仅加深了你对构建过程的理解,也为你将来定制更复杂的构建流程奠定了基础。
你认为这个构建流水线还有哪些可以改进的地方?欢迎留言分享你的想法。
本节用到的代码见 GitHub。建议边看边动手练习,注意切换到正确的分支
12-use-npm-script-as-build-pipeline。