Gulp(1): 打包压缩小程序 小程序瘦身
在当今前端技术愈加成熟的环境下,小程序的压缩瘦身,相对变得容易多了。
webpack 中一切皆模块,基于其丰富的自由配置,会从入口处对所有依赖进行整合并重新分配,本是一个极大的优势,但在小程序中却也是一个弊端。
相比较而言,gulp 任务规划,功能明确,运行可控,对于小程序这样的对文件索引更严格的模式下,更显得得心应手。
1. 安装 gulp
选择一个目录,安装 gulp
npm i -D gulp
创建配置文件 gulpfile.js,输入:
function defaultTask(cb) {
// task
console.log('hello gulp')
cb();
}
exports.default = defaultTask
在 package.json 中添加脚本命令 "dev": "gulp"
, 然后命令行执行 npm run dev
,就会执行默认任务,并打印 ' hello gulp '。
创建文件夹 demo,并在其中创建 test.js、common.css 等测试文件,填充基本内容。为后续操作做准备。
2. 基本配置
可以说,gulp是面向任务的工具,所有功能都由一个个任务组合而成,每个任务都是一个函数。
处理小程序中的文件,最主要的api 是 src()
读取文件流、 dest()
输出文件流、 pipe()
处理数据流。
如下,先安装 gulp-babel
、 gulp-uglify
两个插件用于转义es6 并压缩js。
npm i -D gulp-babel @babel/core @babel/preset-env gulp-uglify
gulpfile.js 中改为:
const { src, dest } = require('gulp');
const babel = require('gulp-babel');
const uglify = require('gulp-uglify');
exports.default = function() {
return src('demo/*.js')
.pipe(babel())
.pipe(uglify())
.pipe(dest('dist/'));
}
src()
和dest()
都是接受 glob 参数,传入地址目录,此处不再展开。
值得注意的是,gulp 不支持同步任务,意味着,所有的任务必须使用 callback 或 async函数,或返回 stream、promise、event emitter、child process、observable。若在使用中出现 "Did you forget to signal async completion?" 警告,表示未使用前面提到的返回方式。
执行 npm run dev
即可看到,同级目录内出现 dist 文件夹,内部包含前面提到的测试文件的压缩版js。
随后引入 gulp-clean-css
用于压缩 wxss 文件,gulp-htmlmin
用于压缩 wxml,同时需要 gulp-if
、lazypipe
进行条件编译,对js、wxss、wxml 文件进行分别处理。
npm i -D gulp-clean-css gulp-htmlmin gulp-if lazypipe
gulp-if 第一个参数为判断条件,第二参数为判断为 true 时,执行的任务,第三参数为判断为 false 时,执行的任务,可不传。
对js的处理需要两步操作,首先进行 babel转换,然后 uglify压缩,在这里就需要用 lazypipe 把这两个操作转化为操作链。
注意,lazypipe 实例在调用 pipe() 时,pipe 中函数的参数,需紧跟 pipe 中函数的后面:
lazypipe().pipe(fn[, arg1[, arg2[, ...]]])
并且, pipe 中函数与参数,需分开传入 !! 例如:
lazypipe()
.pipe( babel, {
presets: ["@babel/env"],
})
Vinyl 是描述文件的元数据对象,同样存在于文件流中,可以使用 Vinyl api 获取文件流的文件类型,如:file.extname = '.js';
const { src, dest} = require('gulp');
const gulpif = require('gulp-if');
const lazypipe = require('lazypipe');
const babel = require('gulp-babel');
const uglify = require('gulp-uglify');
const cleanCss = require('gulp-clean-css');
const htmlmin = require('gulp-htmlmin');
const isJS = (file) => file.extname === '.js';
const isCSS = (file) => file.extname === '.wxss' || file.extname === '.css';
const isWXML = (file) => file.extname === '.wxml';
const jsChannel = lazypipe()
.pipe( babel, { presets: ['@babel/env'] } )
.pipe( uglify, {
// 压缩配置
compress: {
drop_console: true,
},
// 输出配置
output: {
comments: false, // 移除注释
},
toplevel: false, // 混淆最高作用域中的变量和函数名
})
async function fileHandle() {
src('demo/**/*', {
allowEmpty: true
})
// 分别处理 js、wxss
.pipe(gulpif( isJS, jsChannel()))
.pipe(gulpif( isCSS, cleanCss()))
// 取消对 wxml 的处理,<input></input>等与 html 中存在冲突
// .pipe(gulpif( isWXML, htmlmin({
// caseSensitive: true, // 大小写敏感
// removeComments: true, // 删除HTML注释
// keepClosingSlash: true, // 单标签上保留斜线
// })))
.pipe(dest('dist/'))
}
exports.default = fileHandle
引入 del 库,
npm i -D del
。
在编译前,清空输出目录,这里涉及到顺序执行,所以还需使用 gulp.series
组合任务。
const { series} = require('gulp');
const del = require('del');
// 清理
async function clean(){
await del(output);
}
exports.clean = clean
exports.default = series( clean, fileHandle)
另外,把输入输出目录 提取出来,统一配置
最后,gulpfile.js 源码如下:
const { src, dest, series} = require('gulp');
const gulpif = require('gulp-if');
const lazypipe = require('lazypipe');
const babel = require('gulp-babel');
const uglify = require('gulp-uglify');
const del = require('del');
const cleanCss = require('gulp-clean-css');
const htmlmin = require('gulp-htmlmin');
// const entry = '../wx' // 小程序地址
const entry = './demo' // 示例地址
const output = './dist' // 输出目录
const isJS = (file) => file.extname === '.js';
const isCSS = (file) => file.extname === '.wxss' || file.extname === '.css';
const isWXML = (file) => file.extname === '.wxml';
const jsChannel = lazypipe()
.pipe( babel, { presets: ['@babel/env'] } )
.pipe( uglify, )
// 清理
async function clean(){
await del(output);
}
async function fileHandle() {
src([
`${entry}/**/*`,
`!${entry}/**/.*`,
`!${entry}/node_modules/*`,
`!${entry}/**/*.md`,
], {
allowEmpty: true
})
// 分别处理 js、wxss、wxml
.pipe(gulpif( isJS, jsChannel()))
.pipe(gulpif( isCSS, cleanCss()))
// 取消对 wxml 的处理,<input></input>等与 html 中存在冲突
// .pipe(gulpif( isWXML, htmlmin({
// caseSensitive: true, // 大小写敏感
// removeComments: true, // 删除HTML注释
// keepClosingSlash: true, // 单标签上保留斜线
// })))
.pipe(dest(output))
}
exports.clean = clean
exports.default = series( clean, fileHandle)
package.json
{
"devDependencies": {
"@babel/core": "^7.11.1",
"@babel/preset-env": "^7.11.0",
"del": "^5.1.0",
"gulp": "^4.0.2",
"gulp-babel": "^8.0.0",
"gulp-clean-css": "^4.3.0",
"gulp-htmlmin": "^5.0.1",
"gulp-if": "^3.0.0",
"gulp-uglify": "^3.0.2",
"lazypipe": "^1.0.2"
},
"scripts": {
"dev": "gulp",
"clean": "gulp clean"
}
}
- 源码可查看:git 地址