(一)首先实现编译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构建生产环境的文件