上一篇的gulp配置很簡單,主要就是為了demo的查看和調試,這一篇則會相對詳細一些,包括壓縮合併打時間戳等。 在互聯網環境比較好的城市,需要多人協作的,大一點的項目應該都用上了模塊化(這裡主要指commonjs和ES6模塊系統,不是再早的require.js和sea.js)。代碼也會更註重如何分離 ...
上一篇的gulp配置很簡單,主要就是為了demo的查看和調試,這一篇則會相對詳細一些,包括壓縮合併打時間戳等。
在互聯網環境比較好的城市,需要多人協作的,大一點的項目應該都用上了模塊化(這裡主要指commonjs和ES6模塊系統,不是再早的require.js和sea.js)。代碼也會更註重如何分離和註入,而不再是單純的合併。
但是在很多小公司,開發模式或技術都還是比較傳統的,或者一些小項目也完全不需要用上那些比較前沿的技術。
所以這篇配置就主要為了這樣的中小項目。
1.所需工具和版本
包管理工具:yarn v0.24.5
自動化構建工具:gulp v4.0
2.工具安裝
yarn add global gulpjs/gulp#4.0
3.開發環境配置
var gulp = require('gulp'), pug = require('gulp-pug'), less = require('gulp-less'), //當發生異常時提示錯誤 確保本地安裝gulp-notify和gulp-plumber notify = require('gulp-notify'), plumber = require('gulp-plumber'), sourcemaps = require('gulp-sourcemaps'), browserSync = require('browser-sync').create() reload = browserSync.reload; var LessAutoprefix = require('less-plugin-autoprefix'), autoprefix = new LessAutoprefix({ browsers: ['last 2 versions'] }); // 文件路徑 var paths = { pug: { src: 'src/pug/pages/*.pug', dest: 'dev/html/', watch: 'src/pug/**/*.pug' }, less: { src: 'src/less/**/*.less', dest: 'dev/css/', watch: 'src/less/**/*.less' }, js: { src: 'src/js/**/*.js', dest: 'dev/js/', watch: 'src/js/**/*.js' }, img: { src: 'src/img/**/*', dest: 'dev/img/', watch: 'src/img/**/*' } } // 啟動 browserSync 服務,自己啟動server,並且為瀏覽器實時刷新提供服務 gulp.task('browserSync', function() { return browserSync.init({ server: { baseDir: './' }, files: './dev/**/*' }); }) // 將pug文件轉換為html gulp.task('pug', function buildHTML() { return gulp.src(paths.pug.src) .pipe(plumber({errorHandler: notify.onError('Error: <%= error.message %>')})) .pipe(pug()) .pipe(gulp.dest(paths.pug.dest)); }); // 編譯less文件 gulp.task('less', function() { return gulp.src(paths.less.src) .pipe(plumber({errorHandler: notify.onError('Error: <%= error.message %>')})) .pipe(sourcemaps.init()) .pipe(less({ plugins: [autoprefix] })) .pipe(sourcemaps.write()) .pipe(gulp.dest(paths.less.dest)); }) // 複製js文件 gulp.task('js', function() { return gulp.src(paths.js.src) .pipe(gulp.dest(paths.js.dest)); }) // 複製img文件 gulp.task('img', function() { return gulp.src(paths.img.src) .pipe(gulp.dest(paths.img.dest)); }) // 監聽文件變化 gulp.task('watch', function() { gulp.watch(paths.pug.watch, gulp.parallel('pug')) gulp.watch(paths.less.watch, gulp.parallel('less')) gulp.watch(paths.js.watch, gulp.parallel('js')) gulp.watch(paths.img.watch, gulp.parallel('img')) }) // 預設任務,在命令行輸入`gulp`來啟動任務 gulp.task('default', gulp.parallel('watch', 'browserSync', 'pug', 'less', 'js'))
gulp-pug這個插件是用來編譯pug模板的,也就是以前的jade模板,pug模板是一個很強大的前後端通用的模板引擎,而且學習也很簡單,具體用法可以看我另外一篇關於pug的教程文章——基於express+mongodb+pug的博客系統——pug篇。
大家知道gulp在監聽任務的過程中,如果某個環節出了錯誤,gulp就會被中斷,然後得重新啟動gulp任務才行,這是一件很麻煩的事。這裡可以通過gulp-notify和gulp-plumber兩個插件來避免gulp任務中斷。
4.生產環境配置
var gulp = require('gulp'), del = require('del'), pug = require('gulp-pug'), less = require('gulp-less'), cleanCSS = require('gulp-clean-css'), base64 = require('gulp-tobase64'), // img64 = require('gulp-imgbase64'), imagemin = require('gulp-imagemin'), babel = require('gulp-babel'), uglify = require('gulp-uglify'), rev = require('gulp-rev'), // 添加時間戳 revCollector = require('gulp-rev-collector'); var LessAutoprefix = require('less-plugin-autoprefix'), autoprefix = new LessAutoprefix({ browsers: ['last 2 versions'] }); // 文件路徑 var paths = { pug: { src: 'src/pug/pages/*.pug', dest: 'dist/html/' }, less: { src: 'src/less/main.less', dest: 'dist/css/' }, js: { src: ['src/js/**/*.js', '!src/js/lib/*.js'], dest: 'dist/js/' }, img: { src: 'src/img/**/*', dest: 'dist/img/' } }; // 將pug文件轉換為html gulp.task('pug', function() { return gulp.src(paths.pug.src) .pipe(pug()) .pipe(gulp.dest(paths.pug.dest)); }); // 編譯less文件 gulp.task('less', function() { return gulp.src(paths.less.src) .pipe(less({ plugins: [autoprefix] })) .pipe(base64({ maxsize: 8 })) .pipe(cleanCSS({ compatibility: 'ie8' // 相容性首碼保留 })) .pipe(rev()) .pipe(gulp.dest(paths.less.dest)) .pipe(rev.manifest()) .pipe(gulp.dest('rev/css')) }); // 壓縮圖片 gulp.task('img', function() { return gulp.src(paths.img.src) .pipe(imagemin({ optimizationLevel: 3, progressive: true, interlaced: true })) .pipe(gulp.dest(paths.img.dest)); }); // 編譯JS文件 gulp.task('js', function() { return gulp.src(paths.js.src) .pipe(babel({ presets: ['es2015'] })) .pipe(uglify()) .pipe(rev()) .pipe(gulp.dest(paths.js.dest)) .pipe(rev.manifest()) .pipe(gulp.dest('rev/js')); }); // 引用的外部 JS 庫,不需要做壓縮和打時間戳等處理 // 所以直接複製就行 gulp.task('copyJs', function() { return gulp.src('src/js/lib/*.js') .pipe(gulp.dest('dist/js/lib/')) }) // 替換加了MD5時間戳的文件 gulp.task('rev', gulp.series(gulp.parallel('img64', 'less', 'js'), function() { return gulp.src(['rev/**/*.json', 'dist/html/*.html']) .pipe(revCollector({ replaceReved: true })) .pipe(gulp.dest(paths.pug.dest)); })); // Clean 任務執行前,先清除之前生成的文件 gulp.task('clean', function() { return del('dist/') }); // 預設任務,在命令行輸入`gulp`來啟動任務 gulp.task('default', gulp.series('clean', gulp.series('img', gulp.parallel('rev', 'copyJs'))))
在生成環境中,代碼需要壓縮合併,另外在每次代碼更新發佈新版本時,為了用戶客戶端能下載更新代碼,所以我們還需要給CSS和JS文件打上時間戳。
gulp-rev這個插件就專門給文件打MD5戳的,打完MD5戳之後,HTML文件里的引用當然也需要更改,如果每個都去手動更改肯定會是一件很麻煩的事,所以我們還需要gulp-rev-collector這個插件來幫我們替換打了MD5戳的文件。
gulp-imgbase64,這個插件可以指定html文件中,哪些img元素轉換為base64,需要更加個性化轉換的可以使用這個插件。
5.項目目錄結構
XXX——
| — dist
| — html
| — css
| — img
| — js
| — lib
| — dev
| — html
| — css
| — img
| — js
| — lib
| — src
| — pug
| — components
| — pages
| — layout.pug
| — less
| — pages
| — main.less
| — reset.less
| — common.less
| — feature.less
| — img
| — js
| — lib
src文件夾里是主要的業務代碼,這裡面是需要長期維護的代碼。
dev文件夾是開發時gulp生成代碼的地方。
dist文件夾是生成時gulp生成代碼的地方。
在這份配置里,我並沒有像其他很多人那樣,把開發時通過gulp生成的代碼也放在src文件夾里,因為那樣會造成很多引用上的麻煩,而且把開發和生產的代碼環境都分開,能很好保持src文件夾里的純凈,不會有任何雜亂代碼。
所以一些沒經過gulp處理的文件,我會直接把它們複製到dev或者dist文件夾里對應的位置。
dist文件夾在每次gulp任務生成代碼前都會被清空,所以我們不用關心dist文件夾里的內容。
而dev文件夾可能會有很多冗餘文件,但我們也不需要擔心它會對我們造成任何影響,文件刪除或覆蓋都不重要,只需要保證src文件夾里的文件正確即可。