- koa 2*
- react 16*
- babel 7*
- webpack 4*
- webpack-dev-middleware
- webpack-hot-middleware
- ...
-
生成koa目录
npm install -g koa2-generator koa2 koa-hot-demo
-
使用webpack热部署中间件
这个过程中本来想找一些koa相关的webpack热部署中间件,后来发现这些中间件并不怎么好使,于是就使用比较成熟的webpack-dev-middleware和webpack-hot-middleware这两个中间件,但是他们是属于Express的中间件,所以需要做一下适配:
/middleware/webpackMiddleware.js
const webpackDevMiddleware = require('webpack-dev-middleware'); const webpackHotMiddleware = require('webpack-hot-middleware'); const PassThrough = require('stream').PassThrough; const webpack = require('webpack'); /** * 添加hot必要的entry */ function addEntry(webpackDevConfig){ let publicPath = webpackDevConfig.output.publicPath || "/"; let abPublicPath = 'http://localhost:' + (process.env.PORT || 3000 ) + publicPath; let hotMiddlewareScript = 'webpack-hot-middleware/client?' + abPublicPath; let hotDevServer = 'webpack/hot/dev-server'; if (typeof webpackDevConfig.entry === 'string') { webpackDevConfig.entry = [hotMiddlewareScript, hotDevServer, webpackDevConfig.entry]; } else if (typeof webpackDevConfig.entry === 'object') { for (var k in webpackDevConfig.entry) { var main = webpackDevConfig.entry[k]; webpackDevConfig.entry[k] = [hotMiddlewareScript, hotDevServer].concat(main) } } } /** * 转换为dev的middleware * @param {*} compiler * @param {*} opts */ const devMiddleware = (compiler, opts) => { const middleware = webpackDevMiddleware(compiler, opts) return async (ctx, next) => { await middleware(ctx.req, { end: (content) => { ctx.body = content }, setHeader: (name, value) => { ctx.set(name, value) } }, next) } } /** * 转换为hot的middleware * @param {*} compiler * @param {*} opts */ const hotMiddleware = (compiler, opts) => { const middleware = webpackHotMiddleware(compiler, opts); return async (ctx, next) => { let stream = new PassThrough() ctx.body = stream await middleware(ctx.req, { write: stream.write.bind(stream), writeHead: (status, headers) => { ctx.status = status ctx.set(headers) } }, next) } } module.exports = function (app,webpackDevConfig,devOpt,hotOpt){ addEntry(webpackDevConfig); var compiler = webpack(webpackDevConfig); var devOpt = Object.assign({},devOpt.publicPath,{ publicPath : (webpackDevConfig.output.publicPath || "/") }); app.use(devMiddleware(compiler, devOpt)); app.use(hotMiddleware(compiler,hotOpt)); }
app.js
//...其他代码 if (process.env.NODE_ENV === "development") { //开发环境 let webpackDevConfig = require('./webpack.config.dev.js'); let webpackMiddleware = require('./middleware/webpackMiddleware.js'); webpackMiddleware(app,webpackDevConfig,{ serverSideRender: true, noInfo: true, hot: true, stats: { colors: true } }); } else { //生产环境 app.use(require('koa-static')(__dirname + '/public')) } //...其他代码
-
webpack.config.dev.js中引入插件
plugins: [ webpack.optimize.OccurrenceOrderPlugin(), new webpack.HotModuleReplacementPlugin() ]
-
代码支持热替换
src/index.js
//...其他代码 //开启热替换 if (module.hot) { module.hot.accept(); }
-
遇到一个坑
上述代码整完以后已经可以热替换了,但是这里有一个问题如果使用了nodemon来加载node代码,那么每次node代码修改以后都会重新加载,那么webpack热替换模块会失去连接。
这里需要做2个处理:
-
让nodemon忽略前端相关的代码变动
nodemon.json
{ "verbose": true, "restartable": "rs", "ignore": [ "*.test.js", "/src/", "/public/", ".git", ".svn", "node_modules/**/node_modules"] }
-
如过node代码改动后,则重新刷新页面
我们最常用的reload模块是提供给Express使用的,并不适合koa,我试了好几种模块,最后发现比较好使的是koa-reload.
/bin/www
//...其他代码 var reload = require('koa-reload'); var reloadObj = reload(server); app.use(reloadObj.Reloadrouter.routes(), reloadObj.Reloadrouter.allowedMethods()); //...其他代码
src/index.html
<script src="/reload/reload.js"></script>
-
通过上面5个步骤已经大功告成了,感兴趣的可以克隆(或者下载)这个代码,以便自己运行一下。
最后的效果图: