(一)首先實現編譯react文件,編譯並分離scss文件,靜態文件的形式訪問index.htmljavascript
1. 各類路徑信息存儲在config.js文件中css
2. gulp文件:引入config.js, 引入webpack.config.js, 引入gulp-webpack包html
gulp default執行:java
gulp.task('webpack', function() { gulp.src('') .pipe(webpack(webpackConfig())) .pipe(gulp.dest(config.jsDistDir)); }); gulp.task('default', ['webpack']);
3. webpack.config.jsnode
module.exports = function() { return { watch: true, entry: { 'index/index.page': './src/js/src/page/index/index.page.jsx', 'detail/index.page': './src/js/src/page/detail/index.page.jsx' //打包入口文件。entry對象key實際上是目標路徑的一部分。key也能夠是絕對路徑。 }, output: { path: config.jsDistDir, //目標文件地址 filename: "[name].js" //name是entry對象的key }, externals: { react: 'React', reactDOM: 'ReactDOM', 'react-dom': 'ReactDOM' //不被打包的文件。目前react的引用方式是index.html中經過script標籤引入。經實踐,去掉externals對webpack打包沒影響。 }, module: { loaders: [{ test: /\.jsx?$/, exclude: /node_modules/, loaders: ['babel?presets[]=react'] //loaders,編譯react文件 }, { test: /\.scss$/, loader: ExtractTextPlugin.extract('style-loader', 'css!sass') }] }, resolve: { alias: getAlias(), extensions: ["", ".min.js", ".js", ".jsx"] }, plugins: [ new ExtractTextPlugin('[name].css', { allChunks: true }) ], devtool: 'source-map' } }
4.能夠在jsx文件中直接require.scss文件: sass-loader編譯scss文件, css-loader讓css文件能夠做爲模塊引入,extractTextPlugin將css抽取問一個獨立文件,能夠在head中經過link方式引入react
5. resolve中的alias能夠爲模塊取別名。一些自定義的模塊能夠不經過文件路徑而經過別名的方式來引用。getAlias是自定義函數,實現了filename-filePath的mapwebpack
(二)加入expressweb
1. 設置serve任務express
gulp.task('serve', function() { var app = express(); app.use(appConfig.jsPath, headerStatic(path.join(appConfig.webapp, appConfig.jsPath), {})); //js路徑映射 app.use(appConfig.cssPath, headerStatic(path.join(appConfig.webapp, appConfig.cssPath), {}));//css路徑映射 app.use("", headerStatic(appConfig.webapp, {}));//html, 放在webapp目錄下 gulp.run('webpack');//打包 app.listen(8082, function(err) { //監聽請求 if (err) { return console.log(err); } console.log('listening on %d', 8082); }); });
2. headerStatic函數返回一個函數,這個函數根據請求req返回靜態文件。json
function headerStatic(staticPath, headers) { return function(req, res, next) { var reqPath = req.path === '/' ? 'index' : req.path; var f = path.join(staticPath, reqPath); //設置不一樣的contentType if (fs.existsSync(f)) { if (/\.html$/.test(reqPath)) { res.set('Content-Type', 'text/html'); res.send(fs.readFileSync(f, 'utf-8')); } else { if (/\.js$/.test(reqPath)) { res.set('Content-Type', 'text/javascript'); res.send(fs.readFileSync(f, 'UTF-8')); } else if (/\.css$/.test(reqPath)) { res.set('Content-Type', 'text/css'); res.send(fs.readFileSync(f, 'UTF-8')); } else { res.send(fs.readFileSync(f)); } } } else { next(); } } }
(三)build
1. 在這個demo中build的過程很簡單,包括:clean, webpack, uglifyjs, minifyCss, revision-css, revision-js, revreplace-html。
2. 這幾個步驟分別以下實現:
clean: 清空上次打包生成的文件
gulp.task('clean', function() { return gulp.src([tmp1, tmp2, appConfig.build], {read: false}).pipe(clean()); //tmp1, tmp2是生成目標文件的中間目錄,appConfig.build是存放最終打包好的文件的位置。每一個項目是否須要中間目錄及中間目錄的路徑是自定義的 });
webpack: 編譯js文件。在咱們的demo中,打包後的文件在目錄/.tmp/step1/js/dist下
uglifyjs: 壓縮js文件。壓縮後的文件仍在tmp1下
gulp.task('uglifyjs', function() { return gulp.src(path.join(tmp1, '**/*.js')) .pipe(gulpif(uglifyJs, uglify().on('error', util.log))) //gulpif: 第一個參數是函數。若是返回true, 執行後面的語句 .pipe(gulp.dest(tmp1)); });
minifyCss: 壓縮css文件
壓縮後的css文件也在tmp1下。
gulp.task('minifyCss', function() { return gulp.src(path.join(tmp1, '**/*.css')) .pipe(minifyCss()) .pipe(gulp.dest(tmp1)); });
revision-css, revision-js: 爲js和css文件追加hash後綴標識版本
gulp.task('revision-css', function() { return gulp.src(path.join(tmp1, '**/*.css')) .pipe(rev()) .pipe(gulp.dest(tmp2)) //加過版本號的css文件拷貝到tmp2目錄下 .pipe(rev.manifest('style-rev-manifest.json')) //生成原有文件名與revision後的文件名的map .pipe(gulp.dest(tmp2)); }); gulp.task('revision-js', function() { return gulp.src(path.join(tmp1, '**/*.js')) .pipe(rev()) .pipe(gulp.dest(tmp2)) .pipe(rev.manifest('js-rev-manifest.json')) .pipe(gulp.dest(tmp2)); });
revreplace-html: 把html文件中對js和css文件的引用替換爲最新版本。輸出目標爲tmp2
gulp.task('revreplace-html', function() { var manifest = gulp.src([ path.join(tmp2, '/style-rev-manifest.json'), path.join(tmp2, '/js-rev-manifest.json') ]); return gulp.src(path.join(appConfig.webapp, '**/*.html')) .pipe(revReplace({ manifest: manifest, replaceInExtensions: ['.html'] })) .pipe(gulp.dest(tmp2)); });
(四)livereload: 文件更新後自動刷新頁面
function watchFiles(ext) { gulp.watch(path.join(config.webappDir, '**/*.' + ext), function(event) { tinylr.changed(event.path); }); } //gulp task serve中
app.use(body()).use(tinylr.middleware({ //tinylr = require('tiny-lr'); app: app })); watchFiles('js'); watchFiles('html');
以上,這個簡單的demo能夠經過gulp serve啓動本地調試環境,經過gulp build構建生產環境的文件