前因
當前應用中有個模塊實驗着採用 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
搞定。