## 第二步 構建系統
如果你經常參與web社區,那么你應該聽說過[Browserify](http://browserify.org/)和[Webpack](http://webpack.github.io/)工具。如果不使用它們,你將面臨手動的在HTML輸入很多`<script>`標簽,并且需要將JS代碼放到合適的地方。

并且,我們還不能直接在瀏覽器使用ES6,在將代碼提供給用戶之前,我們需要用Babel將它們轉換為ES5代碼。
我們將使用Gulp和Browserify而不用Webpack。我并不認為它們兩個誰優誰劣,但我想說Gulp+Browserify比等價的Webpack文件要直觀多了,我還沒有在任何React boilerplate項目中看到一個易于理解的*webpack.config.js*文件。
創建文件*gulpfile.js*并粘貼下面的代碼:
~~~
var gulp = require('gulp');
var gutil = require('gulp-util');
var gulpif = require('gulp-if');
var streamify = require('gulp-streamify');
var autoprefixer = require('gulp-autoprefixer');
var cssmin = require('gulp-cssmin');
var less = require('gulp-less');
var concat = require('gulp-concat');
var plumber = require('gulp-plumber');
var source = require('vinyl-source-stream');
var babelify = require('babelify');
var browserify = require('browserify');
var watchify = require('watchify');
var uglify = require('gulp-uglify');
var production = process.env.NODE_ENV === 'production';
var dependencies = [
'alt',
'react',
'react-router',
'underscore'
];
/*
|--------------------------------------------------------------------------
| Combine all JS libraries into a single file for fewer HTTP requests.
|--------------------------------------------------------------------------
*/
gulp.task('vendor', function() {
return gulp.src([
'bower_components/jquery/dist/jquery.js',
'bower_components/bootstrap/dist/js/bootstrap.js',
'bower_components/magnific-popup/dist/jquery.magnific-popup.js',
'bower_components/toastr/toastr.js'
]).pipe(concat('vendor.js'))
.pipe(gulpif(production, uglify({ mangle: false })))
.pipe(gulp.dest('public/js'));
});
/*
|--------------------------------------------------------------------------
| Compile third-party dependencies separately for faster performance.
|--------------------------------------------------------------------------
*/
gulp.task('browserify-vendor', function() {
return browserify()
.require(dependencies)
.bundle()
.pipe(source('vendor.bundle.js'))
.pipe(gulpif(production, streamify(uglify({ mangle: false }))))
.pipe(gulp.dest('public/js'));
});
/*
|--------------------------------------------------------------------------
| Compile only project files, excluding all third-party dependencies.
|--------------------------------------------------------------------------
*/
gulp.task('browserify', ['browserify-vendor'], function() {
return browserify('app/main.js')
.external(dependencies)
.transform(babelify)
.bundle()
.pipe(source('bundle.js'))
.pipe(gulpif(production, streamify(uglify({ mangle: false }))))
.pipe(gulp.dest('public/js'));
});
/*
|--------------------------------------------------------------------------
| Same as browserify task, but will also watch for changes and re-compile.
|--------------------------------------------------------------------------
*/
gulp.task('browserify-watch', ['browserify-vendor'], function() {
var bundler = watchify(browserify('app/main.js', watchify.args));
bundler.external(dependencies);
bundler.transform(babelify);
bundler.on('update', rebundle);
return rebundle();
function rebundle() {
var start = Date.now();
return bundler.bundle()
.on('error', function(err) {
gutil.log(gutil.colors.red(err.toString()));
})
.on('end', function() {
gutil.log(gutil.colors.green('Finished rebundling in', (Date.now() - start) + 'ms.'));
})
.pipe(source('bundle.js'))
.pipe(gulp.dest('public/js/'));
}
});
/*
|--------------------------------------------------------------------------
| Compile LESS stylesheets.
|--------------------------------------------------------------------------
*/
gulp.task('styles', function() {
return gulp.src('app/stylesheets/main.less')
.pipe(plumber())
.pipe(less())
.pipe(autoprefixer())
.pipe(gulpif(production, cssmin()))
.pipe(gulp.dest('public/css'));
});
gulp.task('watch', function() {
gulp.watch('app/stylesheets/**/*.less', ['styles']);
});
gulp.task('default', ['styles', 'vendor', 'browserify-watch', 'watch']);
gulp.task('build', ['styles', 'vendor', 'browserify']);
~~~
> 如果你從未使用過Gulp,這里有一個很棒的教程《[An Introduction to Gulp.js](http://www.sitepoint.com/introduction-gulp-js/)》
下面簡單介紹一下每個Gulp任務是干嘛的。
| Gulp Task | Description |
| --- | --- |
| `vendor` | 將所有第三方JS文件合并到一個文件 |
| `browserify-vendor` | 因為性能原因,我們將NPM模塊和前端模塊分開編譯和打包,因此每次重新編譯將會快個幾百毫秒 |
| `browserify` | 僅將app文件編譯并打包,不包括其它模塊和庫 |
| `browserify-watch` | 包括上面的功能,并且監聽文件改變,然后重新編譯打包app文件 |
| `watch` | 當文件改變時重新編譯LESS文件 |
| `default` | 運行上面所有任務并開始監聽文件改變 |
| `build` | 運行上面所有任務然后退出 |
下面,我們將注意力轉移到項目結構上,我們將創建*gulpfile.js*需要的文件和文件夾。
- 前言
- 概述
- 第一步:新建Express項目
- 第二步:構建系統
- 第三步:項目結構
- 第四步: ES6速成教程
- 第五步: React速成教程
- 第六步:Flux架構速成教程
- 第七步:React路由(客戶端)
- 第八步:React路由(服務端)
- 第九步:Footer和Navbar組件
- 第十步:Socke.IO – 實時用戶數
- 第十一步:添加Character的組件
- 第十二步:數據庫模式
- 第十三步:Express API 路由(1/2)
- 第十五步:Home組件
- 第十四步:Express API 路由(2/2)
- 第十六步:角色(資料)組件
- 第十七步:Top 100 組件
- 第十八步:Stats組件
- 第十九步:部署
- 第二十步: 附加資源
- 總結