在现有 server 中集成 webpack + react 热加载

前因

当前应用中有个模块实验着采用 react 来做,想看看这东西能否解决之前的一些痛点。此模块采用 webpack 打包,于是顺便加上了热加载功能。

由于 HTML 页面是现有系统生成的,所以需要在开发环境下集成热加载功能有些要点需要注意,仔细翻了官方文档之后搞定。

下面把一些要点记录下来。

更新说明

一开始采用的是 react-hot-loader,不过在配合 antd 的时候老是报错:

Uncaught TypeError: Cannot read property '__reactAutoBindMap' of null

后来按照 Antd issue 的提示,换成了 react-transform 后问题解决。

环境说明

  • 现有系统服务器端口为 8080
  • webpack 热加载服务端口为 3000
  • 测试模块名为:testModule
  • webpack 配置已经实现,但没有热加载相关配置(这些配置转移到了启动脚本中了,参见下面源码)

实现方式

webpack 热加载支持两种方式

一种是直接命令行来搞:

webpack-dev-server ...

不过这种方式比较死板,不推荐。

还是采用专门写个 js 来定义,然后采用 npm scripts 命令来执行:

npm run start:testModule

准备工作

此处假定已经配置好 webpack 打包环境,下面需要安装热加载相关组件:

npm install --save-dev webpack-dev-server

(此条已作废)npm install --save-dev react-hot-loader

npm install --save-dev babel-preset-react-hmre

babel 相关配置

"env": {
      "development": {
        "presets": [
          "react-hmre"
        ]
      }
    }

热加载服务启动脚本:testModuleServer.js

/*eslint-disable no-console */

var WebpackDevServer = require('webpack-dev-server');
var webpack          = require('webpack');

// 引入现有 webpack 设置
var config = require('../webpack.config.js');

// webpack 热加载服务的端口号
var port   = 3000;

// 在 webpack config 中将需要的模块的 entry 中增加下面两条设置
// 采用的 only-dev-server 而不是 dev-server 是为了在语法出错的时候不会重载浏览器页面
config.entry.testModule.unshift(
    `webpack-dev-server/client?http://0.0.0.0:${port}`, 
    'webpack/hot/only-dev-server' 
);

// 我的 babel loader 位于第一个位置,所以这儿直接采用 [0] 来重新设置此 loader
// 加上了 react-hot 来处理 babel 编译后的源码
// 由于改用  react-transform,所以下面设置也作废
// config.module.loaders[0].loader = 'react-hot!babel';

// publicPath 必须设置,这是在现有 HTML 页面中嵌入 script的 路径
// 如果不设置,热加载生成的一些内部脚本将会无处依存
config.output.publicPath = `http://localhost:${port}/assets/`;

// 在 webpack 配置中增加热加载插件
// 这个必须有,否则即使下面的 hot: true 设置了也没用
// 但是也要注意一下源配置文件中是否已经设置过了,不要重复设置
// 我的建议是原配置中不要牵扯任何跟热加载有关的东西,保持纯净
config.plugins.push(new webpack.HotModuleReplacementPlugin());

var compiler = webpack(config);

// 下面是具体的服务设置
var server   = new WebpackDevServer(compiler, {
    // 这个显然必须有
    // 需要注意的是这儿的这个属性和命令行中的同名属性有所区别
    // 这儿设置了并不会自动增加 HotModuleReplacementPlugin
    // 所以上面才需要设置一个
    hot: true,
    
    // 注意:这个属性也必须设置,且与上面的 publicPath 中的相应位置一致
    // 否则也不起作用
    publicPath: "/assets/",

    stats: { colors: true }
    //historyApiFallback: true
});
server.listen(port);

至此 webpack 部分设置完毕。

react 相关设置(已作废)

由于换用了 react-transform,所以 react 相关设置已作废

:bangbang: 如果你的 react 是直接采用 webpack 打包的话,下面设置可以忽略。

不过我为了节省编译时间,是把 react 和 react-dom 直接在 HTML 中引入的,所以这儿还需要做一些额外设置。

在模块入口文件(一般为 index.js 吧)中一般有:

ReactDOM.render(
	<Provider store={store}>
		<App />
	</Provider>,
	document.getElementById('root')
);

将此部分代码赋值给一个变量,然后增加热加载相关代码(参考):

var rootInstance = ReactDOM.render(
	<Provider store={store}>
		<App />
	</Provider>,
	document.getElementById('root')
);

if (process.env.NODE_ENV !== 'production') {
	if (module.hot) {
		require('react-hot-loader/Injection').RootInstanceProvider.injectProvider({
			getRootInstances: function () {
				// Help React Hot Loader figure out the root component instances on the page:
				return [rootInstance];
			}
		});
	}
}

npm 命令

在 package.json 的 scripts 部分增加一行:

"start:testModule": "NODE_ENV=development node ./server/testModuleServer.js"

最后执行:

npm run start:testModule

搞定。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章