在現有 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

搞定。

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