webpack打包react项目添砖加瓦

时间:2022-12-19 15:21:40

(一)首先实现编译react文件,编译并分离scss文件,静态文件的形式访问index.html

1. 各种路径信息存储在config.js文件中

2. gulp文件:引入config.js, 引入webpack.config.js, 引入gulp-webpack包

gulp default执行:

gulp.task('webpack', function() {
gulp.src('')
.pipe(webpack(webpackConfig()))
.pipe(gulp.dest(config.jsDistDir));
});

gulp.task('default', ['webpack']);

3. webpack.config.js

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方式引入

5. resolve中的alias可以为模块取别名。一些自定义的模块可以不通过文件路径而通过别名的方式来引用。getAlias是自定义函数,实现了filename-filePath的map

(二)加入express

1. 设置serve任务

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返回静态文件。

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构建生产环境的文件