构建流水线
在现代前端开发中,构建是项目交付前不可或缺的一环。它涵盖了从源代码到生产环境代码的转换过程,主要包括:
- 源代码预编译:处理 Sass、Less、TypeScript 等需要转换的语言。
- 代码优化:合并与压缩 JavaScript 和 CSS 文件,减少网络请求。
- 资源处理:优化图片、生成雪碧图,提升加载性能。
- 版本管理:为静态资源添加哈希版本号,解决浏览器缓存问题。
- CDN 部署:将静态资源上传到内容分发网络,加速全球访问。
虽然许多项目的构建流程已经预先配置好,但理解其背后的原理和考量,对于提升开发效率和解决复杂问题至关重要。
本章将引导你使用 npm script 和命令行工具,从零开始为一个典型的前端项目搭建构建流水线,让你深入理解每个环节的实现细节。
准备工作
在开始之前,请确保你已具备以下基础:
- 熟悉基本的命令行操作。
- 了解 npm script 的基本用法。
- 项目中已安装 Node.js 和 npm。
项目设置
我们从一个简单的项目结构开始,它代表了典型的前端资源引用关系:
client/
├── images/
│ └── schedule.png
├── index.html
├── scripts/
│ └── main.js
└── styles/
└── main.css资源依赖关系如下:
index.html引用了main.css和main.js。main.css和index.html可能引用了images/目录下的图片。
为了确保构建过程的正确性,我们必须遵循以下顺序:
- 图片优化:压缩图片以减少文件大小。
- 样式处理:编译 Less/Sass 并压缩 CSS。
- 脚本处理:编译和压缩 JavaScript。
- 资源版本化:
- 为图片添加版本号,并更新 CSS/JS 中的引用。
- 为 CSS/JS 添加版本号,并更新 HTML 中的引用。
构建流水线详解
我们将逐步实现每个构建环节,并最终将它们串联成一条完整的流水线。
1. 初始化构建环境
我们约定将构建产物输出到 dist 目录,并保持与 client 目录相同的结构。每次构建前,需要清空旧的产物。
利用 npm 的 pre 钩子,我们可以轻松实现这一步。在 package.json 中添加 prebuild 脚本:
"scripts": {
"prebuild": "rm -rf dist && mkdir -p dist/{images,styles,scripts}"
}2. 组织构建脚本
为了保持 package.json 的整洁,我们使用 scripty 将复杂的构建命令拆分到独立的文件中。
首先,创建用于存放构建脚本的目录:
mkdir -p scripts/build
touch scripts/build.sh scripts/build/{images,styles,scripts,hash}.sh
chmod -R a+x scripts注意:必须为脚本文件添加可执行权限,否则 scripty 将无法执行。
3. 图片优化
我们使用 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"
}4. 样式处理
我们使用 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"
}5. 脚本处理
对于 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 提供了丰富的命令行选项,如 sourcemap 生成和代码混淆,详情请查阅其官方文档。
在 package.json 中配置 build:scripts 命令:
"scripts": {
"build:scripts": "scripty"
}6. 资源版本化与引用替换
为静态资源添加版本号是确保缓存更新的关键。我们使用 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"
}7. 整合构建流水线
现在,我们将所有步骤串联起来,形成一个完整的构建命令。
在 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' 'scripts' 'styles' '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。