Gavin Zhou
Back to Writing

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服务器。

目录结构

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

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是热加载必需的

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

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:用于实现无刷新更新

// 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启动文件

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' } ] }

Comments