本文將會介紹如何使用gulp4來搭建項目腳手架,如果您還在使用gulp3或更老的版本,您也以通過本文的一些思想將之前的項目進行完善,更新。如果gulp不是你們團隊的重點,也可以移步我的另一篇文章:
用 webpack 4.0 擼單頁/多頁腳手架 (jquery, react, vue, typescript)
前言
由于本文重點是介紹gulp4.0搭建腳手架的思路,相關插件的用法以及項目結構的設計,由于gulp的基本用法很簡單,如果不熟悉可以移步官網自行研究學習。該腳手架的設計思路和功能如下:
同時為了提高開發環境的效率,這里我們參考webpack的配置,區分開發環境和生產環境,在接下來將會具體介紹。
腳手架用到的第三方插件介紹
- gulp-jshint ——js語法檢測
- gulp-util ——終端控制臺打印自定義錯誤信息
- http-proxy-middleware ——設置代理,配合gulp-connect使用
- gulp-less ——將less編譯成css
- gulp-file-include ——用于文件模塊化導入,如用include的方式導入公共部分
- gulp-connect ——用于啟動本地服務器
- gulp-clean ——清理目錄
- gulp-uglify --壓縮js
- gulp-minify-css ——壓縮css
- gulp-autoprefixer ——自動添加瀏覽器前綴
- imagemin-pngquant ——png圖片壓縮
- gulp-imagemin ——圖壓縮
- gulp-cache ——設置gulp打包的緩存,一般用于img
- gulp-md5-plus ——將文件名進行md5處理便于打包更新
當然gulp還有很多常用的插件可以更好的為我們的項目服務,大家也可以整合自己的插件讓項目更加完善。
項目目錄設計
1.src目錄,即我們開發項目時的源目錄,具體結構如下:
我們定義views是我們視圖層,即頁面文件的目錄,js目錄為業務邏輯的腳本文件,lib存放第三方框架,include目錄為公共部分的存放目錄,我們可以用gulp-file-include來導入到html中,images和css大家都比較清楚,分別時存放image和css文件的目錄。
2. dist目錄,即輸出的目錄,具體結構如下:
可以看到我們會看到src打包后的目錄對應static目錄,為什么我們會加一層static呢?我的設計是如果項目使用node等服務層框架,我們可以用gulp一并打包放入dist下,這樣dist就是一個完整的包括前后端服務的項目目錄了,當然大家也可以直接將src打包后的文件和文件夾直接放到dist下,根具業務需求靈活設計吧。
在這里我要說一點,由于筆者親測gulp-md5-plus有時候打包不穩定,可能不會給html自動添加對應的md5后綴,所以筆者在這塊做了特殊的處理,如果大家在工作中有更好的方案,可以及時和筆者溝通交流。
3. gulpfile文件配置
由于我們要區分開發環境和生產環境,所以這里我們使用兩個不同的配置文件,根據NODE_ENV來區分用哪個文件。
我們將配置文件統一放到build目錄下,config為公共配置文件,gulp.dev.js和gulp.prod.js分別為開發和生產環境配置文件。我們整體的目錄結構如下:
腳手架完整源碼(部分插件和配置會給出詳細注釋)
config.jsmodule.exports = {
dist:
'./dist/static',
}
復制代碼gulp.dev.jsconst gulp =
require(
'gulp');
const Jshint =
require(
"gulp-jshint");
const Gutil =
require(
'gulp-util');
const Proxy =
require(
'http-proxy-middleware');
const Less =
require(
'gulp-less');
const FileInclude =
require(
'gulp-file-include');
const Connect =
require(
'gulp-connect');
const Clean =
require(
'gulp-clean');
const config =
require(
'./config');
const { dist } = config;
async function html() {
return gulp.src(
'src/views/*.html').pipe(FileInclude({ prefix:
'##',
basepath:
'@file'})).on(
'error',
function(err) {
console.error(
'Task:copy-html,', err.message);
this.end();}).pipe(gulp.dest(dist)) .pipe(Connect.reload())
}
async function css() {
return await gulp.src(
'src/css/*.less').pipe(Less()) .pipe(gulp.dest(dist +
'/css')) .pipe(Connect.reload());
}
async function js() {
return await gulp.src(
'src/js/**').pipe(Jshint()).on(
'error',
function(err) {Gutil.log(Gutil.colors.red(
'[Error]'), err.toString());}).pipe(gulp.dest(dist +
'/js')) .pipe(Connect.reload());
}
async function image() {
return await gulp.src(
'src/images/*').pipe(gulp.dest(dist +
'/images'));
}
async function clean() {
return await gulp.src(dist, {
allowEmpty:
true}).pipe(Clean());
}
async function server() {Connect.server({
root:dist, livereload:
true, port:
9909, middleware:
function(connect, opt) {
return [
Proxy(
'/api', {
target:
'http://localhost:8080',
changeOrigin:
true}),
Proxy(
'/otherServer', {
target:
'http://IP:Port',
changeOrigin:
true})]}})
}
module.exports = {html,css,js,image,clean,server
}
復制代碼gulp.prod.jsconst gulp =
require(
'gulp');
const Uglify =
require(
'gulp-uglify');
const Minifycss =
require(
'gulp-minify-css');
const Less =
require(
'gulp-less');
const Autoprefixer =
require(
'gulp-autoprefixer');
const MinifyHtml =
require(
"gulp-minify-html");
const FileInclude =
require(
'gulp-file-include');
const Imagemin =
require(
'gulp-imagemin');
const Pngquant =
require(
'imagemin-pngquant');
const Cache =
require(
'gulp-cache');
const Clean =
require(
'gulp-clean');
const md5 =
require(
"gulp-md5-plus");
const config =
require(
'./config');
const { dist } = config;
async function html() {
return gulp.src(
'src/views/*.html').pipe(FileInclude({ prefix:
'##',
basepath:
'@file'})).on(
'error',
function(err) {
console.error(
'Task:copy-html,', err.message);
this.end();}).pipe(gulp.dest(dist))
}
async function css() {
return await gulp.src(
'src/css/**').pipe(Less()) .pipe(Autoprefixer({
cascade:
true, remove:
true })).pipe(Minifycss({ advanced:
true,compatibility:
'',keepBreaks:
false,keepSpecialComments:
'*'})).pipe(gulp.dest(dist +
'/css')).pipe(md5(
10, dist +
'/*.html', {
mappingFile:
'manifest.json',
connector:
'.' })).pipe(gulp.dest(dist +
'/css'))
}
async function js() {
return await gulp.src(
'src/js/**').pipe(Uglify()) .pipe(gulp.dest(dist +
'/js')).pipe(md5(
10, dist +
'/*.html', {
mappingFile:
'manifest.json',
connector:
'.'})).pipe(gulp.dest(dist +
'/js'))
}
async function image() {
return await gulp.src(
'src/images/*').pipe(Cache(Imagemin({
optimizationLevel:
5, progressive:
true, interlaced:
true, multipass:
true, svgoPlugins: [{
removeViewBox:
false}],use: [Pngquant()] }))).pipe(gulp.dest(dist +
'/images'));
}
async function clean() {
return await gulp.src(dist, {
allowEmpty:
true}).pipe(Clean());
}
module.exports = {html,css,js,image,clean
}
復制代碼gulpfile.jsconst gulp =
require(
'gulp');
let buildConfig;
if(process.env.NODE_ENV ===
'dev') {buildConfig =
require(
'./build/gulp.dev');gulp.task(
'server', buildConfig.server); }
else {buildConfig =
require(
'./build/gulp.prod');gulp.task(
'clean', buildConfig.clean);
}gulp.task(
'html', buildConfig.html);
gulp.task(
'js', buildConfig.js);
gulp.task(
'css', buildConfig.css);
gulp.task(
'images', buildConfig.image);
gulp.task(
'sources', gulp.series(
'html', gulp.parallel(
'js',
'css',
'images')));
gulp.task(
'watch',
async () => {gulp.watch(
'src/views/*', gulp.series(
'html')); gulp.watch(
'src/js/**', gulp.series(
'js')); gulp.watch(
'src/css/*', gulp.series(
'css')); gulp.watch(
'src/images/*', gulp.series(
'images'));
});
if(process.env.NODE_ENV ===
'dev') {gulp.task(
'dev', gulp.series(
'sources',
'server',
'watch'));
}
else {gulp.task(
'build', gulp.series(
'sources'));
}
復制代碼package.json{
"dependencies": {
"@babel/core":
"^7.4.5",
"babel-preset-es2015":
"^6.24.1",
"gulp":
"^4.0.2",
"gulp-autoprefixer":
"^6.1.0",
"gulp-babel":
"^8.0.0",
"gulp-cache":
"^1.1.2",
"gulp-clean":
"^0.4.0",
"gulp-connect":
"^5.7.0",
"gulp-file-include":
"^2.0.1",
"gulp-imagemin":
"^6.0.0",
"gulp-jshint":
"^2.1.0",
"gulp-less":
"^4.0.1",
"gulp-md5-plus":
"^1.0.3",
"gulp-minify-css":
"^1.2.4",
"gulp-minify-html":
"^1.0.6",
"gulp-rename":
"^1.4.0",
"gulp-uglify":
"^3.0.2",
"gulp-util":
"^3.0.8",
"http-proxy-middleware":
"^0.19.1",
"http-server":
"^0.11.1",
"imagemin-pngquant":
"^8.0.0",
"jshint":
"^2.10.2",
"jsonfile":
"^5.0.0",
"webpack":
"^4.35.2"},
"scripts": {
"start":
"NODE_ENV=dev gulp dev",
"build":
"NODE_ENV=prod gulp clean && gulp build",
"serve":
"http-server dist/static -p 3000"},
"devDependencies": {}
}
復制代碼要想獲取項目完整源碼和demo,請移步gulp4_multi_pages。
最后
該腳手架任然有需要完善的地方,比如如何兼容uglify和babel,md5需要使用兩次的情況,如果更好的解決方案,歡迎隨時交流。在腳手架選型上,也不一定非要用gulp,webpack,一般的經驗是傳統型的靜態網站適合用gulp,由于不需要編譯es6,所以有更小的體積,當然也可以用webpack,本文主要是給大家提供一使用gulp4搭建個腳手架的思路,希望能有所收獲。
更多推薦
- 如何用不到200行代碼寫一款屬于自己的js類庫)
- 讓你瞬間提高工作效率的常用js函數匯總(持續更新)
- 一張圖教你快速玩轉vue-cli3
- 3分鐘教你用原生js實現具有進度監聽的文件上傳預覽組件
- 3分鐘教你用原生js實現具有進度監聽的文件上傳預覽組件
- 使用Angular8和百度地圖api開發《旅游清單》
- js基本搜索算法實現與170萬條數據下的性能測試
- 《前端算法系列》如何讓前端代碼速度提高60倍
- 《前端算法系列》數組去重
- vue高級進階系列——用typescript玩轉vue和vuex
- 前端三年,談談最值得讀的5本書籍
歡迎關注下方公眾號,獲取更多前端知識精粹和學習社群:
在公眾號點擊進群,可以加入vue學習小組,一起學習前端技術;
回復學習路徑,將獲取筆者多年從業經驗的前端學習路徑的思維導圖
轉載于:https://juejin.im/post/5d2180e5e51d4577614761b7
總結
以上是生活随笔為你收集整理的9012教你如何使用gulp4开发项目脚手架的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。