前言
如今我們開發web網頁的方式主要有幾種,使用
vue-cli、create-react-app、webpack、不借助建構工具
等實作單頁或多頁網站。“工欲善其事,必先利其器”,前三種方式無疑能滿足我們開發網頁的絕大部分需求,但在某些情況下,比如前後端不分離(jsp、php、tpl等嵌套後端語言的方式),以及單純地開發一些靜态頁(活動頁、幫助手冊等),使用gulp搭建一個輕量級的前端開發環境是一個選擇。
gulp相對上手簡單,有經驗的前端也都比較熟悉,這裡不打算一步步地介紹gulp開發環境的搭建,而是分享一下實際使用gulp的代碼及思路。
實作哪些功能
使用gulp的目的是實作自動化建構,提升開發效率、代碼品質,是以有以下一些目标。
- 壓縮html、css、js、圖檔
- 編譯ES6、less/scss
- 補全css字首
- px轉rem
- 靜态資源緩存控制
- 靜态伺服器
- 代碼檢查
實際上gulp能做到的還有更多,不過出于開發靜态頁的目的,這裡隻羅列了一些常用功能。
代碼
基本目錄如下
gulpfile.js主要代碼
靜态伺服器
gulp.task('server', done => {
connect.server({
root: 'dist',//根目錄
livereload: true,//自動更新
port: 9090//端口
})
done();
});
壓縮html
gulp.task('html', function () {
return gulp.src('src/*.html')
.pipe(htmlmin({ collapseWhitespace: true }))
.pipe(gulp.dest('dist'))
.pipe(connect.reload())
})
編譯并壓縮css
gulp.task('css', done => {
var processors = [px2rem({ remUnit: 100 })];
gulp.src('src/less/**/*.less') //擷取所有less檔案路徑
.pipe(less()) //執行less
.pipe(autoprefixer({//補全字首
overrideBrowserslist: [
"Android 4.1",
"iOS 7.1",
"Chrome > 31",
"ff > 31",
"ie >= 8"
]
}))
.pipe(postcss(processors))//px轉rem tips: 如果某個px不轉換,可使用大寫代替,類似1PX
.pipe(minifyCss())
.pipe(gulp.dest('dist/css'))
.pipe(connect.reload())
done();
});
編譯并壓縮js
gulp.task('js', function () {
return gulp.src('src/js/**/*.js')
//.pipe(jshint())//檢查代碼
.pipe(babel({//編譯ES6
presets: ['@babel/env']
}))
.pipe(uglify())//壓縮js
.pipe(gulp.dest('dist/js'))
.pipe(connect.reload())
})
壓縮圖檔
gulp.task('images', function () {
return gulp.src('src/images/**/*.+(png|jpg|jpeg|gif|svg)')
.pipe(imagemin())
.pipe(gulp.dest('dist/images'))
});
監控檔案變化
gulp.task('watcher', done => { //監聽變化
gulp.watch('src/*.html', gulp.series('html'));
gulp.watch('src/less/**/*.less', gulp.series('css'));
gulp.watch('src/js/**/*.js', gulp.series('js'));
gulp.watch('src/images/**/*', gulp.series('images'));
done();
})
生成帶hash值的檔案名及路徑
這裡還使用了
gulp-rev-delete-original
删除舊檔案。
gulp.task("hash", done => {
gulp
.src("dist/**")
.pipe(
RevAll.revision({
dontRenameFile: [/\.html$/]
})
)
.pipe(revdel({
exclude: function (file) {
if (/\.html$/.test(file.name)) {
return true; //if you want to exclude the file from being deleted
}
}
}))
.pipe(gulp.dest("dist"))
done();
});
gulp指令
打開本地伺服器,以及打封包件。
// 初始化
gulp.task('init', gulp.series('clean', gulp.parallel('html', 'css', 'js', 'images')));
// 開發
gulp.task('default', gulp.series('init', 'server', 'watcher'));
// 打包
gulp.task('build', gulp.series('hash'));
可以看出上面的代碼比較簡單,因為初衷是做一些簡單的靜态頁,是以并沒有做得比較複雜,監控檔案變化編譯至dist目錄,再由gulp-rev-all生成hash檔案名。
前後端不分離的情況
這裡需要區分前後端不分離的情況,由于公司的技術不更新,或者需要維護老項目,就要應付前後端不分離的場景。比如頁面是jsp、php檔案,這時靜态頁跟實際頁面并沒有直接對應關系,每次gulp打包後,gulp-rev-all會重新生成帶hash的檔案和路徑,并且不支援
test.css?v=123
這種方式,這樣全部手動複制到項目目錄并不實際,隻能放棄gulp-rev-all(
build
),并且移除代碼壓縮。
值得一提的是,前後端不分離可以用後端語言進行資源的緩存控制,例如使用php讀取檔案的修改日期來做版本号。
function autoVersion($file) {
if( file_exists($_SERVER['DOCUMENT_ROOT'].$file) ) {
$ver = filemtime($_SERVER['DOCUMENT_ROOT'] . $file);
} else {
$ver = 1;
}
return $file .'?v=' .$ver;
}
此外,應對前後端不分離應該還有一種解決方案,借助建構工具直接生成後端所需的模闆檔案(如index.tpl),這裡暫不讨論。
最後
這些是根據工作經驗總結出來的,雖然當下使用或基于webpack開發單頁是主流,但在某些覆寫不到的場景下進行一些梳理還是有必要的。
源碼位址:gulp-util,另外附上一個webpack多頁腳手架webpack-multiple-entry,這是作者fork别人的項目來修改的,比較簡單實用,感興趣的小夥伴可以參考下。