9012教你如何使用gulp4開發項目腳手架

本文將會介紹如何使用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分別為開發和生產環境配置文件。我們整體的目錄結構如下:

腳手架完整源碼(部分插件和配置會給出詳細注釋)

  1. config.js
module.exports = {dist: './dist/static',  // 配置構建目錄
}
復制代碼
  1. gulp.dev.js
const gulp = require('gulp');
// js
const Jshint = require("gulp-jshint");          //js檢查
const Gutil = require('gulp-util');
const Proxy = require('http-proxy-middleware');
// const Webpack = require('webpack');
// const WebpackConfig = require('./webpack.config.js');// css
const Less = require('gulp-less');              // 編譯less// html
const FileInclude = require('gulp-file-include'); // 文件模塊化// server
const Connect = require('gulp-connect');        //引入gulp-connect模塊 const Clean = require('gulp-clean');            // 清理目錄// 配置文件
const config = require('./config');
const { dist } = config;// html
async function html() {return gulp.src('src/views/*.html').pipe(FileInclude({ // HTML模板替換,具體用法見下文prefix: '##',basepath: '@file'})).on('error', function(err) {console.error('Task:copy-html,', err.message);this.end();}).pipe(gulp.dest(dist)) // 拷貝 .pipe(Connect.reload())
}// css
async function css() {return await gulp.src('src/css/*.less').pipe(Less())       //編譯less.pipe(gulp.dest(dist + '/css')) //當前對應css文件.pipe(Connect.reload());//更新
}// js
// const compilerJS = Webpack(WebpackConfig);async function js() {return await gulp.src('src/js/**').pipe(Jshint())//檢查代碼// .pipe(Babel({//     presets: ['es2015']// })).on('error', function(err) {Gutil.log(Gutil.colors.red('[Error]'), err.toString());}).pipe(gulp.dest(dist + '/js')) // 拷貝.pipe(Connect.reload()); //更新// 使用es6+可以單獨配置// compilerJS.run(function(err, stats) {//     if(err) throw new Gutil.PluginError("webpack:js", err);//     Gutil.log("[webpack]", stats.toString({//         colors: true//     }));//     cb()// });
}// image
async function image() {return await gulp.src('src/images/*').pipe(gulp.dest(dist + '/images'));
}// clean dir
async function clean() {// 不設置allowEmpty: true會報File not found with singular globreturn await gulp.src(dist, {allowEmpty: true}).pipe(Clean());
}// 服務器函數
async function server() {Connect.server({root:dist, //根目錄// ip:'192.168.11.62',//默認localhost:8080livereload: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
}
復制代碼
  1. gulp.prod.js
const gulp = require('gulp');
// const Rename = require('gulp-rename');          // 重命名
// js
const Uglify = require('gulp-uglify');          // 壓縮js
// const Babel = require('gulp-babel');
// css
const Minifycss = require('gulp-minify-css');   // 壓縮css
const Less = require('gulp-less');              // 編譯less
const Autoprefixer = require('gulp-autoprefixer');  // 瀏覽器前綴
// html
const MinifyHtml = require("gulp-minify-html"); //壓縮html
const FileInclude = require('gulp-file-include'); // 文件模塊化
// image
const Imagemin = require('gulp-imagemin');
const Pngquant = require('imagemin-pngquant');  //png圖片壓縮插件
const Cache = require('gulp-cache'); const Clean = require('gulp-clean');            // 清理目錄// md5 發版本的時候為了避免瀏覽器讀取了舊的緩存文件,需要為其添加md5戳
const md5 = require("gulp-md5-plus");const config = require('./config');
const { dist } = config;
// html
async function html() {return gulp.src('src/views/*.html').pipe(FileInclude({ // HTML模板替換,具體用法見下文prefix: '##',basepath: '@file'}))// .pipe(MinifyHtml()).on('error', function(err) {console.error('Task:copy-html,', err.message);this.end();}).pipe(gulp.dest(dist)) // 拷貝 
}// css
async function css() {return await gulp.src('src/css/**').pipe(Less())       //編譯less.pipe(Autoprefixer({cascade: true, //是否美化屬性值 默認:true 像這樣://-webkit-transform: rotate(45deg);//        transform: rotate(45deg);remove: true //是否去掉不必要的前綴 默認:true})).pipe(Minifycss({   // 壓縮css//類型:Boolean 默認:true [是否開啟高級優化(合并選擇器等)]advanced: true,//保留ie7及以下兼容寫法 類型:String 默認:''or'*' [啟用兼容模式; 'ie7':IE7兼容模式,'ie8':IE8兼容模式,'*':IE9+兼容模式]compatibility: '',//類型:Boolean 默認:false [是否保留換行]keepBreaks: false,//保留所有特殊前綴 當你用autoprefixer生成的瀏覽器前綴,如果不加這個參數,有可能將會刪除你的部分前綴        keepSpecialComments: '*'})).pipe(gulp.dest(dist + '/css')).pipe(md5(10, dist + '/*.html', {mappingFile: 'manifest.json',connector: '.' // 文件名和hash的連接符})).pipe(gulp.dest(dist + '/css')) //當前對應css文件
}// js
async function js() {return await gulp.src('src/js/**')// .pipe(Babel({//     presets: ['es2015']// })).pipe(Uglify()) // 壓縮js.pipe(gulp.dest(dist + '/js')).pipe(md5(10, dist + '/*.html', {mappingFile: 'manifest.json',connector: '.'})).pipe(gulp.dest(dist + '/js')) // 拷貝
}// image
async function image() {return await gulp.src('src/images/*').pipe(Cache(Imagemin({optimizationLevel: 5, //類型:Number  默認:3  取值范圍:0-7(優化等級)progressive: true, //類型:Boolean 默認:false 無損壓縮jpg圖片interlaced: true, //類型:Boolean 默認:false 隔行掃描gif進行渲染multipass: true, //類型:Boolean 默認:false 多次優化svg直到完全優化svgoPlugins: [{removeViewBox: false}],//不要移除svg的viewbox屬性use: [Pngquant()] //使用pngquant深度壓縮png圖片的imagemin插件}))).pipe(gulp.dest(dist + '/images'));
}// clean dir
async function clean() {// 不設置allowEmpty: true會報File not found with singular globreturn await gulp.src(dist, {allowEmpty: true}).pipe(Clean());
}module.exports = {html,css,js,image,clean
}
復制代碼
  1. gulpfile.js
const 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('md5', gulp.series(buildConfig.md5Css, buildConfig.md5Js));gulp.task('clean', buildConfig.clean);    // 清理目錄   
}gulp.task('html', buildConfig.html);      // 打包html
gulp.task('js', buildConfig.js);          // 打包js
gulp.task('css', buildConfig.css);        // 打包css
gulp.task('images', buildConfig.image);   // 打包image
gulp.task('sources', gulp.series('html', gulp.parallel('js', 'css', 'images')));// 監聽文件變化
gulp.task('watch', async () => {gulp.watch('src/views/*', gulp.series('html')); // 監聽HTML變化gulp.watch('src/js/**', gulp.series('js')); // 監聽js變化gulp.watch('src/css/*', gulp.series('css')); // 監聽css變化gulp.watch('src/images/*', gulp.series('images')); // 監聽image變化
});// build
if(process.env.NODE_ENV === 'dev') {gulp.task('dev', gulp.series('sources', 'server', 'watch'));
} else {gulp.task('build', gulp.series('sources'));
}復制代碼
  1. 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

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/247614.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/247614.shtml
英文地址,請注明出處:http://en.pswp.cn/news/247614.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

nodejs模塊

nodejs模塊遵循commonJS規范,但并不是完全實現規范,主要使用require引入模塊、使用exports導出模塊。 導出屬性或方法 使用exports mouduleA.js: var say function(world){console.info("say: "world); }var sing function(wo…

Array.prototype.slice.call(arguments)

Array.prototype.slice.call(arguments)能將具有length屬性的對象轉成數組,除了IE下的節點集合(因為ie下的dom對象是以com對象的形式實現的,js對象與com對象不能進行轉換)如:1 var a{length:2,0:first,1:second}; 2 Ar…

動態內存分配導致內存泄漏之處

摘要:舉了幾個動態內存分配過程中,發生內存泄漏的例子 1. 分配了內存,卻沒有及時刪除,導致泄漏 1: void doSomething() 2: { 3: int *pnValue new int; 4: } 2. 為指針變量分配了一個內存,然后又讓指針變量指向其他的值,導致…

nodejs常用模塊-url

URL nodejs中針對url的常用方法。 node下打印url,結果: 引入url模塊 var url require(url) 1、parse方法 將url解析成對象,parse方法原型: url.parse(urlStr[, parseQueryString][, slashesDenoteHost]) 可傳遞三個參數…

常用的javascript設計模式

請堅持 什么是設計模式 百度百科: 設計模式(Design pattern)是一套被反復使用、多數人知曉的、經過分類編目的、代碼設計經驗的總結。 使用設計模式是為了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。 毫無疑問,設計模式…

express項目創建

1、安裝項目生成器 cnpm i express-generator -g express4.0以后,express與express-generator包分離,全局使用express命令生成項目骨架時應該安裝express-generator包。 2、生成項目骨架 express server 默認使用的是jade模板,使用ejs模…

設置Jexus開機啟動

把jexus做成系統服務,就像windows服務一樣,可以設置開機啟動就可以了。 第一、進入目錄 /lib/systemd/system/ 第二、新建文件 vi jexus.service 文件內容 [Unit] Descriptionjexus Afternetwork.target[Service] Typeforking ExecStart/usr/jexus/jw…

iOS警告-This block declaration is not a prototype

關于警告 我們定義一個不帶參數的block,通常是如下的方式 1typedefvoid (^UpdateSwichBtnBlock)();在xcode9中會提示一個警告 12This block declaration is not a prototypeInsert ‘void解決方式可以是如下的幾種 1typedefvoid (^UpdateSwichBtnBlock)(void);但是這樣,很多第三…

mac環境mongodb安裝與配置

一、安裝 MAC環境安裝mongodb有兩種方式,一種方式是通過下載安裝包,另一種方式是通過homebrew。 1、安裝包方式 從mongodb官網可以下載MAC安裝包:https://www.mongodb.com/download-center#community 或者使用curl下載 # 進入 /usr/loca…

用兩個棧來實現一個隊列,完成隊列的Push和Pop操作。 隊列中的元素為int類型...

以下為借鑒 var stack1 [], stack2[]; function push(node){stack1.push(node);}function pop(){if(stack2.length){return stack2.pop();}else{if(stack1.length){var len stack1.length;for(var i0;i<len;i){stack2.push(stack1.pop());}return stack2.pop()}else{retur…

使用CocoaPods導入百度地圖SDK所遇到的坑

執行pod install遇到的問題:解決方安:百度了下,發現pod install命令被墻了,換成pod install --verbose --no-repo-update

NSTimer不準確與GCDTimer詳解

NSTimer不準&#xff0c;scheduleTimer放在runloop里面&#xff0c;受runloop模式影響會不準// [NSTimer scheduledTimerWithTimeInterval:<#(NSTimeInterval)#> target:<#(nonnull id)#> selector:<#(nonnull SEL)#> userInfo:<#(nullable id)#> r…

flex的12個屬性

容器&#xff08;父元素&#xff09;的屬性&#xff1a; flex-direction屬性決定主軸的方向 flex-wrap 屬性決定項目在一行排不下的情況下是否換行 flex-flow flex-flow屬性是flex-direction屬性和flex-wrap屬性的簡寫形式&#xff0c;默認值為row nowrap。 jstify-content …

vue圖片懶加載插件vue-lazyload

插件地址&#xff1a;https://github.com/hilongjw/vue-lazyload demo&#xff1a;http://hilongjw.github.io/vue-lazyload/ 1、安裝 cnpm i vue-lazyload -S 2、使用 main.js import VueLazyLoad from vue-lazyloadVue.use(VueLazyLoad, {error:/static/error.png,loadin…

IT需求過程管理

IT部門就是為其他業務、內勤部門提供信息化手段的&#xff0c;所以在實施信息化系統的時候首先要做的就是需求調研&#xff0c;但是針對于絕大多數業務部門的人員而言&#xff0c;信息系統是很不熟悉的&#xff0c;我們會經常聽到這樣的回復“這個應該很快就可以實現吧”、“當…

maskView與CAGradientLayer詳解

#maskView基本原理 - png圖片透明像素的原理 - maskView可類比于多張png圖片的疊加遮罩&#xff0c;原理類似 - maskView是iOS8以上才有的&#xff0c;如果要考慮兼容低版本&#xff0c;用maskLayer替代 //使用maskView的情況 property (nonatomic, strong)UIImageView *addIma…

nodejs的啟動方式

1、原始node命令 直接命令行中使用node命令 node xxx.js 或者安裝nodemon&#xff0c;使用nodemon啟動方便在開發階段熱部署代碼改動 npm i nodemon -G nodemon xxx.js 2、webstorm方式 webstorm中&#xff0c;需要執行的文件的上&#xff0c;右鍵->run&#xff0c;右…

win7rc 序列號- 10/21之前

安裝介紹&#xff1a;http://www.microsoft.com/china/windows/windows-7/download.aspx 注冊獲得序列號&#xff1a;http://technet.microsoft.com/zh-cn/evalcenter/dd353205.aspx?ITPIDmscomsc在 2009 年 10 月 21 日之前&#xff0c;您仍可以通過注冊來獲取產品密鑰或查找…

maskView與CAGradientLayer那回事兒

maskView基本原理 png圖片透明像素的原理maskView可類比于多張png圖片的疊加遮罩&#xff0c;原理類似maskView是iOS8以上才有的&#xff0c;如果要考慮兼容低版本&#xff0c;用maskLayer替代 //使用maskView的情況 property (nonatomic, strong)UIImageView *addImageView;…

mongoose操作mongodb

http://mongoosejs.com/docs/api.html#index-js mongoose是nodejs環境下操作mongodb的模塊封裝&#xff0c;使用mongoose之后&#xff0c;實際上只需要在mongodb中創建好數據庫與用戶&#xff0c;集合的定義、創建、操作等直接使用mongoose即可。 一、連接二、重要概念三、基本…