koa2.0+webpack3.x实现React热更新

前言

最近在研究react同构,由于后端打算使用koa2.0,因此在开发环境想搭一套koa服务器代替webpack-dev-server,实现代码实时刷新。中间遇到过很多坑,好在最后还是跑通了这个流程,写下此文帮助后人爬坑- -。

PS:对于koa和webpack还不是很了解的同学,可以点击koa官网 webpack官网

大体流程

此教程仅限适用于开发环境。先介绍三个文件

webpack.config.dev.js webpack配置文件

server.dev.js server入口文件

app.js app启动文件。该文件在开发环境和生产环境都可以使用

通过npm的脚本命令,执行入口文件server.dev.js,该文件会载入webpack配置文件webpack.config.dev.js,再通过app.js启动一个koa服务器。

目录结构

为了简明易懂,只展示该教程中用到的文件,大体结构如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
project/                                 // root directory
├── build/ // webpack config directory
│ └── webpack.config.dev.js // config for webpack when run development bundle
├── client/ // client directory
│ ├── about/ // `about` module
│ ├── common/ // `common` module
│ ├── home/ // `home` module
│ ├── index.js // client entry file
│ └── routes.js // client route config
├── server/ // server directory
│ ├── controllers/ // controllers in server
│ ├── middlewares/ // custom middlewares in server
│ ├── models/ // models in server
│ ├── routes/ // routes in server
│ ├── app.js // create koa instance in server
│ └── server.dev.js // entry file in development mode
└── package.json // npm entry file

webpack配置文件

安装相应的babel插件,可以把es6/es7、jsx语法编译成浏览器可以兼容的代码。

npm install --save-dev babel-loader babel-plugin-transform-runtime babel-preset-es2015 babel-preset-react babel-preset-react-hmre babel-preset-stage-2

其中babel-preset-react-hmre是热加载必需的

这边只留下了一些关键性配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
const webpack = require('webpack');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

const config = {
devtool: 'eval-source-map',
entry: {
index: [
'webpack-hot-middleware/client?path=/__webpack_hmr&timeout=10000', // 这个是必需的
'./client/index.js',
],
vendor: [ // 将公用的框架库打成一个js
'react',
'react-dom',
]
},
output: {
path: path.resolve(__dirname, '../dist/client'),
filename: '[name].js',
chunkFilename: 'chunk.[name].js',
publicPath: '/'
},
module: {
// 加载器配置
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['es2015', 'react', 'stage-2', 'react-hmre'],
plugins: ['transform-runtime'],
cacheDirectory: true
}
},
{
test: /\.json$/,
loader: 'json'
}
]
},

plugins: [
new HtmlWebpackPlugin({
template: './client/index.html',
inject: true, // 如果设置为 true 或者 body,所有的 javascript 资源将被放置到 body 元素的底部,'head' 将放置到 head 元素中。
hash: true, // 将添加一个唯一的 webpack 编译 hash 到所有包含的脚本和 CSS 文件,对于解除 cache 很有用
minify: {
removeComments: true,
collapseWhitespace: false
},
// 允许只添加某些块
chunks: [
'index', 'vendor', 'manifest'
],
filename: 'index.html'
}),
new webpack.optimize.OccurrenceOrderPlugin(), // 根据模块调用次数,给模块分配ids,常被调用的ids分配更短的id,使得ids可预测,降低文件大小
new webpack.HotModuleReplacementPlugin(), // 模块热替换
new webpack.NoEmitOnErrorsPlugin() // 在编译出现错误时,用于跳过输出阶段。这样可以确保输出资源不会包含错误。
]
};

module.exports = config

server入口文件

此处的babel-register是针对node还未支持的es6/es7进行兼容。

koa-webpack-dev-middleware:用于处理静态文件
koa-webpack-hot-middleware:用于实现无刷新更新

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Javascript require hook
require('babel-register')({
presets: ['es2015', 'react', 'stage-2'],
plugins: ['transform-runtime']
})
const app = require('./app.js').default
const webpack = require('webpack')
const devMiddleware = require('koa-webpack-dev-middleware')
const hotMiddleware = require('koa-webpack-hot-middleware')
const config = require('../build/webpack.config.dev')
const compile = webpack(config)
app.use(devMiddleware(compile, {
noInfo: true,
publicPath: config.output.publicPath
}))
app.use(hotMiddleware(compile))
app.listen(3000);

app启动文件

1
2
3
4
5
import Koa from 'koa';
...
const app = new Koa();
...
export default app;

执行

package.json中添加脚本命令

"scripts": { "dev": node ./server/server.dev.js --watch server --watch build" }

最后通过在命令行执行

npm run dev

就大功告成啦!

本文只讲了关于热加载的必要配置,大家可以根据自己的项目进行相应修改即可。

常见问题

__webpack_hmr found 404

出现原因:koa-webpack-hot-middleware或koa-webpack-dev-middleware版本不对

解决方案:

npm install --save-dev [email protected] [email protected]

update check failed: error: manifest request to XXX

出现原因:个人认为是.json文件无法被识别

解决方案:

webpack.config.js中增加

module: { rules: [ { test: /\.json$/, loader: 'json' } ] }