打包环节
要实现
假设我们的项目结构是这样的
src
├── images
│ ├── a.png
│ └── b.png
├── index.html
├── scripts
│ └── index.js
└── styles
├── css.css
└── less.css
构建过程要完成
- 压缩图片;
- 编译 less, 压缩 css;
- 编译 es,压缩 js;
- 给图片加版本号,并替换在 html、css、js 中的引用;
- 给 css、js 加版本号,并替换在 html 中的引用;
安装依赖
npm i imagemin-cli less cssmin uglify-es uglify-js hashmark replaceinfiles -D
- imagemin-cli 是 imagemin 的命令行工具,用于图片构建(压缩);
- cssmin 实现代码压缩。如果用的是预编译语言 less 自带命令行工具 lessc,或使用的是 sass 的可使用 node-sass;
- uglify-js 压缩代码,如果用的 ES6,那需要用 uglify-es 来进行压缩;
- hashmark 自动添加版本号;
- replaceinfiles 自动完成引用替换,将版本号的输出注入到文件和文件名中;
编写
1.创建目录与文件(并赋权,不做这步操作会这样,你可以试一下)
为什么要做这一步,是因为命令会比较长,前面章节[npm script 复杂场景的应用][]说过可以把复杂命令抽取到 .sh
文件中(应用 scripty)。
mkdir scripts/build
touch scripts/build.sh
touch scripts/build/{images,styles,scripts,hash}.sh
chmod -R a+x scripts
最终 scripts 目录树如下
scripts
├── build
│ ├── hash.sh
│ ├── images.sh
│ ├── scripts.sh
│ └── styles.sh
└── build.sh
2.图片处理文件(scripts/build/images.sh
)脚本
#!/usr/bin/env bash
imagemin src/images/* --out-dir dist/images
3.样式处理文件(scripts/build/styles.sh
)脚本
#!/usr/bin/env bash
for file in src/styles/*.css
do
lessc $file | cssmin > dist/styles/$(basename $file)
done
4.js 处理文件(scripts/build/scripts.sh
)脚本
#!/usr/bin/env bash
for file in src/scripts/*.js
do
./node_modules/uglify-es/bin/gulify $file --mangle > dist/scripts/$(basename $file)
done
4.资源版本号和引用替换(scripts/build/hash.sh
)脚本
#!/usr/bin/env bash
# 给图片资源加上版本号,并且替换引用
hashmark -c dist -r -l 8 '**/*.{png,jpg}' '{dir}/{name}.{hash}{ext}' | replaceinfiles -S -s 'src/**/*.{css,html}' -d '{dir}/{base}'
# 给 js、css 资源加上版本号,并且替换引用
hashmark -c dist -r -l 8 '**/*.{css,js}' '{dir}/{name}.{hash}{ext}' | replaceinfiles -S -s 'src/**/*.html' -d 'dist/{base}'
5.文件 package.json
文件
{
...,
"scripts": {
"src:server": "http-server src/",
"dist:server": "http-server dist -p $npm_package_config_urlPort",
"dist:open": "open http://localhost:$npm_package_config_urlPort",
"prebuild": "rm -rf dist && mkdir -p dist/{images,styles,scripts}",
"build": "scripty",
"build:images": "scripty",
"build:styles": "scripty",
"build:scripts": "scripty",
"build:hash": "scripty",
"postbuild": "npm-run-all --parallel dist:server dist:open"
},
"config": {
"urlPort": 6011
},
...
}
剖析
prebuild
每次构建前,清空之前的构建目录(这里应用了 npm 的钩子机制);build:*
使用 scripty 将脚本抽取到单独文件(目录 scripts 和 srcipts/build 下)中,文件内容是对图片、less、css、js和html的处理工作,注意给.sh
添加权限chmod -R a+x scripts
;- 抽取的文件中应用到了
|
(管道操作符) 和>
(输出重定向),这些都是 shell 语法; hash.sh
是给资源加版本号,我们知道线上静态资源通常是放到 CDN(内容分发网络) 上的,或者是设置了长时间缓存,后期有版本迭代,这个时候资源更新了但是版本号没有更新,浏览器读取不到最新内容,这显然不是我们想要的。如果手动去加版本号,一是繁琐,二是 low(都不好意思自己是做前端的),三是不符合 DRY 原则,四是容易出错。所以,这个过程要做到自动化,通常就是将更新的文件名上做哈希,然后以这个哈希做为版本号,即版本号添加到文件名上,以实现引用的资源都是带版本号的,进而浏览器能读取到最新内容;postbuild
启动静态资源服务和打开浏览器;
执行
npm run build
1.构建过程
2.文件 dist/index.html
3.文件 dist/css/css.css
本章内容代码 npm-script,自己体验一下吧,玩的愉快