1.創建項目骨架
新建三個文件夾,分別命名為 app,server,tasks。其中 app 里面放置我們寫的 js 代碼和視圖(HTML)代碼,error.ejs 指向出錯界面,index.ejs 是默認頁面。server 放置服務端代碼。tasks 中放置構建工具的任務,util 下的 args.js 是處理命令行參數的一個文件。
2. 使用express腳手架創建服務端代碼
進入 server 文件夾,一句命令 express -e .
,-e 代表使用 ejs 模板引擎。ejs 是嵌入式 JavaScript 模板,文件以 .ejs 結尾。
輸入這句命令后(首先要 npm install express)會提示 npm install 安裝所需的依賴,安裝完成后,server 文件夾下目錄結構增加了這么多:
3.在 tasks 文件夾下創建構建工具
util/args.js
/**
* 對命令行參數進行解析
*/
// node.js 命令行框架
import yargs from 'yargs';
const args = yargs
.option('production', {
// 生產環境,默認關閉
boolean: true,
default: false,
describe: 'min all scripts'
})
.option('watch', {
// 監聽開發環境中的文件,自動更新
boolean: true,
default: false,
describe: 'min all files'
})
.option('verbose', {
// 輸出命令行執行日志
boolean: true,
default: false,
describe: 'log'
})
.option('sourcemaps', {
// 壓縮
describe: 'force the creation of sourcemaps'
})
.option('port', {
// 服務器端口
string: true,
default: 8080,
describe: 'server port'
})
.argv;
export default args;
創建 scripts.js、pages.js、css.js、server.js
/**
* gulp 自動化配置
* 處理 js 代碼
*/
import gulp from 'gulp';
// gulp 判斷語句
import gulpif from 'gulp-if';
// 字符串拼接
import concat from 'gulp-concat';
// 構建
import webpack from 'webpack';
// 基于流的構建
import gulpWebpack from 'webpack-stream';
// 處理文件信息流
import plumber from 'gulp-plumber';
// 文件命名
import named from 'vinyl-named';
// 文件重命名
import rename from 'gulp-rename';
// 瀏覽器熱更新
import livereload from 'gulp-livereload';
// css、js壓縮
import uglify from 'gulp-uglify';
// 命令行輸出
import { log, colors } from 'gulp-util';
// 對命令行參數進行解析
import args from './util/args';
// 使用 gulp 創建一個任務
gulp.task('scripts', () => {
return gulp.src('app/js/*.js')
// 錯誤日志檢查處理
.pipe(plumber({
errorHandle: function() {
}
}))
// 文件命名
.pipe(named())
// 遇到 js 文件時,用 babel 處理
// npm install babel-loader babel-core babel-preset-env --save-dev
.pipe(gulpWebpack({
module: {
loaders: [{
test: /\.js$/,
loader: 'babel'
}]
}
}), null, (err, stats) => {
log(`Finished '${colors.cyan('scripts')}'`, stats.toString({
chunks: false
}));
})
// 文件存放路徑
.pipe(gulp.dest('server/public/js'))
// 備份并重命名
.pipe(rename({
basename: 'cp',
extname: '.min.js'
}))
// 壓縮
.pipe(uglify({
compress: {
properties: false
},
output: {
'quote_keys': true
}
}))
// 文件存放路徑
.pipe(gulp.dest('server/public/js'))
// 熱更新,若命令行中有 watch 這個參數才執行
.pipe(gulpif(args.watch, livereload()));
});
/**
* gulp 自動化配置
* 處理模板 views 信息
*/
import gulp from 'gulp';
// gulp 判斷語句
import gulpif from 'gulp-if';
// 瀏覽器熱更新
import livereload from 'gulp-livereload';
// 對命令行參數進行解析
import args from './util/args';
// 使用 gulp 創建一個任務
gulp.task('pages', () => {
return gulp.src('app/**/*.ejs')
// 文件存放路徑
.pipe(gulp.dest('server'))
// 熱更新,若命令行中有 watch 這個參數才執行
.pipe(gulpif(args.watch, livereload()));
});
/**
* gulp 自動化配置
* 處理 css 文件
*/
import gulp from 'gulp';
// gulp 判斷語句
import gulpif from 'gulp-if';
// 瀏覽器熱更新
import livereload from 'gulp-livereload';
// 對命令行參數進行解析
import args from './util/args';
// 使用 gulp 創建一個任務
gulp.task('styles', () => {
return gulp.src('app/**/*.css')
// 文件存放路徑
.pipe(gulp.dest('server/public'))
// 熱更新,若命令行中有 watch 這個參數才執行
.pipe(gulpif(args.watch, livereload()));
});
/**
* gulp 自動化配置
* 處理服務器的腳本
*/
import gulp from 'gulp';
// gulp 判斷語句
import gulpif from 'gulp-if';
// 啟動服務器
import liveserver from 'gulp-live-server';
// 對命令行參數進行解析
import args from './util/args';
// 使用 gulp 創建一個任務
gulp.task('serve', (cb) => {
// 若命令行不處于監聽狀態,返回
// if (!args.watch) {
// return cb();
// }
// 創建一個服務器并啟動
var server = liveserver.new(['--harmony', 'server/bin/www']);
server.start();
// 熱更新
gulp.watch(['server/public/**/*.js', 'server/public/**/*.css', 'server/views/*.ejs'], (file) => {
server.notify.apply(server, [file]);
});
// 需要重啟服務器才能更新
gulp.watch(['server/routes/**/*.js', 'server/app.js'], () => {
server.start.bind(server)();
});
});
要熱更新 (控制臺輸入 gulp --watch
實時監控文件變化),還必須在服務器代碼上加 app.use(require('connect-livereload')))
這句代碼。位置在
server/app.js:
app.use()使用的中間件的順序不能隨意放,劃線部分的代碼必須放在那,即在監聽根目錄下的文件變化。
創建 browser.js
/**
* gulp 自動化配置
* 瀏覽器熱更新監聽
* 當 app/js 變化時,啟動 task/scripts.js
* 當 app/css 變化時,啟動 task/styles.js
* 當 app/views 變化時,啟動 task/pages.js
*/
import gulp from 'gulp';
// gulp 判斷語句
import gulpif from 'gulp-if';
// 瀏覽器熱更新
import livereload from 'gulp-livereload';
// 命令行輸出
import util from 'gulp-util';
// 對命令行參數進行解析
import args from './util/args';
// 使用 gulp 創建一個任務
gulp.task('browser', (cb) => {
if (!args.watch) {
return cb();
}
// 熱更新
gulp.watch(['app/**/*.js'], ['scripts']);
gulp.watch(['app/**/*.css'], ['styles']);
gulp.watch(['app/**/*.ejs'], ['pages']);
});
clean.js
/**
* gulp 自動化配置
* 清空指定文件夾里的文件
*/
import gulp from 'gulp';
// 刪除命令
import del from 'del';
// 對命令行參數進行解析
import args from './util/args';
// 使用 gulp 創建一個任務
gulp.task('clean', () => {
return del(['server/public', 'server/views']);
});
創建 build.js,按順序依次執行各任務
/**
* gulp 自動化配置
* 設置 gulp task 的順序
*/
import gulp from 'gulp';
// 刪除命令
import gulpSequence from 'gulp-sequence';
// 設置 gulp task 的順序
// 使用 gulp 創建一個任務
gulp.task('build', gulpSequence('clean', 'styles', 'pages', 'scripts', ['browser', 'serve']));
default.js
/**
* gulp 自動化配置
* 默認文件
* 執行:gulp
*/
import gulp from 'gulp';
// 使用 gulp 創建一個任務
gulp.task('default', ['build']);
4. 放在項目最外面的 gulpfile.babel.js
gulpfile.babel.js(名字固定,且不為 gulpfile.js,,因為要使用 babel 轉 ES6 語法.)
import requireDir from 'require-dir';
requireDir('./tasks');
最好的寫法是將 tasks 下的文件全寫在 gulpfile.babel.js 里,減少 js 文件有利于提升頁面渲染速度,上面的分解步驟只是為了看的更容易。
5. 必不可少的 .babelrc 文件
{
// ES6 轉 ES5
"presets": ["es2015"]
}
6. app/views/index.ejs 里編輯文件
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
test
</body>
</html>
在控制臺輸入 gulp --watch
打包文件,啟動服務器,并實時監聽,服務啟動后,在瀏覽器地址欄輸入 http://localhost:3000
可以看到test
字樣,修改 index.ejs 里面的內容,不用刷新瀏覽器,gulp 會自動刪除之前的打包后的文件重新編譯生成新的文件并自動刷新瀏覽器。