在當今前端技術愈加成熟的環境下,小程序的壓縮瘦身,相對變得容易多了。
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[, ...]]])
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 地址