項目自動化構(gòu)建思路

image.png
自動化構(gòu)建邏輯
- 若app文件夾(前端靜. 態(tài)頁面)資源發(fā)生改變 ->
- 調(diào)用browser.js腳本 ->
- browser.js運(yùn)行script腳本 ->
- 將新的js文件打包后寫入server目錄public目錄下 ->
- 此行為觸發(fā)server.js監(jiān)聽到服務(wù)端js靜態(tài)資源文件被修改 ->
- 執(zhí)行服務(wù)器重啟重新渲染頁面 ->
- 前臺看到瀏覽器熱更新
構(gòu)建目錄結(jié)構(gòu),安裝服務(wù)端腳手架工具
- 創(chuàng)建項目目錄
app(放置靜態(tài)頁面資源),server(用express腳手架初始化,將來放入熱更新后的靜態(tài)資源),tasks放置所有上述過程的腳本文件 - 初始化服務(wù)端express
npm install -g express-generator//安裝express腳手架
express -e .//使用express腳手架命令,初始化腳手架,-e代表使用ejs模板引擎 - 在根目錄創(chuàng)建 .babelrc文件,此為babel轉(zhuǎn)碼器
- 在根目錄創(chuàng)建
gulpfile.js, 若用es6語法寫gulpfile文件就創(chuàng)建gulpfile.babel.js
gulp工作流代碼構(gòu)建流程
處理命令行參數(shù)
import yargs from 'yargs'; //處理命令行參數(shù)的包
//區(qū)分開發(fā)環(huán)境和線上環(huán)境
const args = yargs
//提取--production參數(shù)
.option('production',{
boolean:true,//選項是布爾類型
default:false,//默認(rèn)是false
describe:'min all scripts' //只是給人看的描述
})
//用來監(jiān)聽文件改變的選項
.option('watch',{
boolean:true,
default:false,
describe:'watch all files'
})
//要不要輸出命令行詳細(xì)監(jiān)視的日志
.option('verbose',{
boolean:true,
default:false,
describe:'log'
})
//強(qiáng)制生成sourcemaps映射
.option('sourcemaps',{
describe:'force the creation of sroucemaps'
})
//端口號
.option('port',{
string:true,
default:8080,
describe:'server port'
})
//表示把輸入的命令以字符串的方式進(jìn)行解析
.argv
export default args;
處理js
import gulp from 'gulp';
import gulpif from 'gulp-if'; //gulp語句中做if判斷
import concat from 'gulp-concat'; //gulp中處理文件拼接
import webpack from 'webpack';
import gulpWebpack from 'webpack-stream'; //支持webpack在gulp stream中的功能
import named from 'vinyl-named'; //保證webpack生成的文件名能夠和原文件對上
import livereload from 'gulp-livereload'; //瀏覽器熱更新
import plumber from 'gulp-plumber'; //處理文件信息流
import rename from 'gulp-rename'; //對文件重命名
import uglify from 'gulp-uglify'; //壓縮js
import {log, colors} from 'gulp-util'; //命令行工具包,log與色彩輸出
import args from './util/args'; //剛自己寫的對命令行參數(shù)進(jìn)行解析的包
// 為了集中處理項目js文件拋出異常引起gulp流出現(xiàn)問題,需用plumber統(tǒng)一處理錯誤
gulp.task('scripts', () => {
return gulp
.src(['app/js/index.js'])
.pipe(plumber({errorHandle: function () {}}))
.pipe(named())
.pipe(gulpWebpack({
module: {
loaders: [
{
test: /\.js$/,
loader: 'babel-loader'
}
]
}
}), null, (err, stats) => {
log(`Finished '${colors.cyan('scripts')}'`, stats.toString({chunks: false}))
})
//gulp處理完的js指定寫入路徑,api:gulp.dest
.pipe(gulp.dest('server/public/js'))
//js文件重命名為cp.min.js,還沒壓縮,只是復(fù)制一份
.pipe(rename({basename: 'cp', extname: '.min.js'}))
// 壓縮
.pipe(uglify({
compress: {
properties: false
},
output: {
'quote_keys': true
}
}))
// 把壓縮后的文件放入服務(wù)器目錄
.pipe(gulp.dest('server/public/js'))
// 使用gulpif監(jiān)視命令行傳入的參數(shù),若有--watch,則執(zhí)行熱更新
.pipe(gulpif(args.watch, livereload()))
})
處理后臺頁面模板
import gulp from 'gulp';
import gulpif from 'gulp-if';
import livereload from 'gulp-livereload';
import args from './util/args';
gulp.task('pages',()=>{
return gulp.src('app/**/*.ejs')
.pipe(gulp.dest('server')) //文件被寫入的路徑是以所給的相對路徑根據(jù)所給的目標(biāo)目錄計算而來。類似的,相對路徑也可以根據(jù)所給的 base 來計算。這里實際寫到的路徑是server下的/**/*.ejs,即server/views/*.ejs
.pipe(gulpif(args.watch,livereload()))
})
處理css
import gulp from 'gulp';
import gulpif from 'gulp-if';
import livereload from 'gulp-livereload';
import args from './util/args';
gulp.task('css',()=>{
return gulp.src('app/**/*.css')
.pipe(gulp.dest('server/public'))
//文件被寫入的路徑是以所給的相對路徑根據(jù)所給的目標(biāo)目錄計算而來。類似的,相對路徑也可以根據(jù)所給的 base 來計算。這里實際寫到的路徑是server下的/**/*.css,即server/public/css/*.css
.pipe(gulpif(args.watch,livereload()))
})
處理服務(wù)端熱重啟
import gulp from 'gulp';
import gulpif from 'gulp-if';
import liveserver from 'gulp-live-server'; //啟動gulp服務(wù)器的包
import args from './util/args';
gulp.task('serve',(cb)=>{
//如果沒在監(jiān)聽,直接運(yùn)行回調(diào)函數(shù)
if(!args.watch) return cb();
//啟動express腳手架默認(rèn)的服務(wù)器腳本
const server = liveserver.new(['--harmony','server/bin/www']);
server.start();
//監(jiān)聽server目錄下的js文件和ejs模板文件,通知服務(wù)器哪些文件改變了
gulp.watch(['server/public/**/*.js','server/views/**/*.ejs'],function(file){
server.notify.apply(server,[file]);
})
//監(jiān)視服務(wù)器路由及入口文件的改變,進(jìn)行服務(wù)器重啟
gulp.watch(['server/routes/**/*.js','server/app.js'],function(){
server.start.bind(server)()
});
})
處理瀏覽器熱更新
import gulp from 'gulp';
import gulpif from 'gulp-if';
import gutil from 'gulp-util';
import args from './util/args';
gulp.task('browser',(cb)=>{
if(!args.watch) return cb();//若沒監(jiān)聽,則直接執(zhí)行回調(diào)
gulp.watch('app/**/*.js',['scripts']);//若js文件發(fā)生改變,則調(diào)用剛才創(chuàng)建的scripts腳本
gulp.watch('app/**/*.ejs',['pages']); //同上
gulp.watch('app/**/*.css',['css']); //同上
});
處理服務(wù)器清除舊文件
每次服務(wù)器監(jiān)聽到靜態(tài)資源文件的改變, 會觸發(fā)重啟, 用新的靜態(tài)資源去render頁面,此時需要刪除舊的靜態(tài)資源文件
import gulp from 'gulp';
import del from 'del';
import args from './util/args';
//清除服務(wù)端的靜態(tài)資源文件和模板文件
gulp.task('clean',()=>{
return del(['server/public','server/views'])
})
build.js處理所有g(shù)ulp文件運(yùn)行關(guān)聯(lián)順序
import gulp from 'gulp';
import gulpSequence from 'gulp-sequence'; //處理文件關(guān)聯(lián)關(guān)系和先后順序
//先clean,再css,再pages,再編譯js,最后一個數(shù)組說明數(shù)組里的任務(wù)都放在前面四個任務(wù)執(zhí)行過一次之后再執(zhí)行,且serve端更新一定 在 browser靜態(tài)資源改變之后
gulp.task('build',gulpSequence('clean','css','pages','scripts',['browser','serve']));
default.js gulp工作流默認(rèn)入口
gulp在無命令行參數(shù)時會優(yōu)先運(yùn)行defalut.js
import gulp from 'gulp';
gulp.task('default',['build']);
gulp程序入口
import requireDir from 'require-dir';//需要運(yùn)行某一文件夾的gulp任務(wù)
requireDir('./tasks'); //放入tasks目錄
編輯.babelrc
{
"presets":["es2015"],
"plugins":["transform-decorators-legacy"]
}
給express腳手架添加熱更新中間件
//在處理路由前,express優(yōu)先處理靜態(tài)資源,若在這個static方法定義的目錄中沒有找到req.url對應(yīng)的靜態(tài)資源,則調(diào)用Next()方法傳入下一個中間件,最終會傳遞到路由中間件上
app.use(express.static(path.join(__dirname, 'public')));
//一定要再靜態(tài)資源設(shè)置之后使用熱更新中間件,此插件的安裝要再最外層項目目錄下的依賴安裝,而不是server目錄的依賴
app.use(require('connect-livereload')());
gulp程序啟動
gulp --watch
在app/public/js下寫一個簡單的js,再在app/public/css下寫一個chotee.css,例如
class Chotee{
constructor(){
this.name = 'chotee 啊,成功!'
}
}
const ct1 = new Chotee
document.body.innerHTML = ct1.name;
body {
background-color: pink;
}
在app/views/目錄下的index.ejs模板中引入
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<link rel="stylesheet" href="/css/chotee.css">
</head>
<body>
hello chotee
<script src="/js/index.js" charset="utf-8"></script>
</body>
</html>
打開瀏覽器訪問localhost:3000端口(express腳手架默認(rèn)端口), 看到

image.png
成功! 此時再去修改js文件,模板文件,熱更新文件,成功,成功,成功!
整個項目github地址: https://github.com/choteewang/gulp-es6-work-flow