react 熱替換 ([HMR])
熱替換好多地方可以用到,目前比較流行的用法是搭配React和webpack實現在不刷新頁面的情況下對模塊的增刪改。在給項目添加熱替換功能的時候,可以說是踩了各種坑,webpack官方給的配置也有小問題還不得不翻牆去解決(百度出來的一個能打的也沒有)。
官方的方案在這兒:https://webpack.js.org/guides/hmr-react/
我先把自己配置成功的貼出來,再說一下如果完全照搬官方配置,會產生的問題:
(只保留熱替換相關配置和最基礎配置,且只考慮開發不考慮生產,且假設你已安裝必要的包)
module.exports = {
entry: [
'react-hot-loader/patch', // 1
// 開啟 React 代碼的模塊熱替換(HMR)
'./src',
],
output: {
filename: 'js/bundle.js',
path: path.resolve(__dirname, 'public'),
publicPath:'http://localhost:7000/', // 2
},
module: {
rules: [
{ test: /\.(js|jsx)$/, use: 'babel-loader', exclude: /node_modules/ },
{ test: /\.css$/,
use:['style-loader', 'css-loader', 'postcss-loader'], // 3
exclude: /node_modules/ },
],
},
resolve: {
extensions: ['.js', '.jsx'],
},
devServer: {
port: 7000,
hot: true, // 4
// 開啟服務器的模塊熱替換(HMR)
headers: {
'Access-Control-Allow-Origin': '*', // 5
},
},
plugins: [
new webpack.HotModuleReplacementPlugin(), // 6
// 開啟全局的模塊熱替換(HMR)
new webpack.NamedModulesPlugin(), // +
// 當模塊熱替換(HMR)時在瀏覽器控制台輸出對用戶更友好的模塊名字信息
],
}
react 和babel 部分的配置與官方相同即可。
參考官方配置你遇到第一個問題:
[HMR] Update failed: SyntaxError: Unexpected token < in JSON at position 0
at Object.parse (<anonymous>)
at XMLHttpRequest.request.onreadystatechange
這個問題很頭疼,因為你去搜索完全找不到有用的東西,而且你看不出來錯在哪了,當時的心情真是。。。
最后在 react-hot-loader 的 github 庫的 Issues 里翻到了有人和我一樣的問題,大快人心。
原來是 output 的 publicPath 出了問題用 '/' 是不行滴,要把啟動webpack服務的地址填上:'http://localhost:7000/'。其實也不能怪官方文檔,人家是假設你應用程序和包都托管給 webpack 服務,但是我的只把包托給了 webpack 服務,應用程序是另外啟動的 node 服務。好吧這是個比較小眾的問題,你要是正好有這個問題,還搜到了這篇文章,那是好福氣了。
另外一個
XMLHttpRequest cannot load http://localhost:7000/4221731a75de7a449377.hot-update.json. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8000' is therefore not allowed access. The response had HTTP status code 404
這個問題只在 webpack 服務發生變動時候有,並不影響HMR使用,所以不管它也可以。
devServer里添加
headers: {
'Access-Control-Allow-Origin': '*', // 5
},
即可,也是因為應用程序沒有托管給 webpack 導致。
如果你的應用程序和包都是托管給 webpack 服務,那就沒有這兩個問題了。
(話說應用程序一般都是另啟服務的吧。。。)
再說一個問題,除了上面兩個,是不是這么多配置都是必須的。不配置會導致什么錯誤。
首先,
entry里的
'react-hot-loader/patch', // 1
devServer里的
hot: true, // 4
plugins里的
new webpack.HotModuleReplacementPlugin(), // 6
從字面上看就是必須的,不用想,否則不會熱。
new webpack.NamedModulesPlugin(), // +只是讓控制台輸出的更友好,推薦但非必需
這個比較容易忽略:
{ test: /\.css$/,
use:['style-loader', 'css-loader', 'postcss-loader'], // 3
exclude: /node_modules/ },
style-loader 是必須的,否則樣式的刷新就不熱了。
很多人用 ExtractTextWebpackPlugin 把 css 文件單獨弄出來就不用 style-loader了,不過推薦部署應用之前弄一份就行,開發用不着 ExtractTextWebpackPlugin 。
不用 style-loader 修改樣式表就不會無刷新更新頁面了。不過這一點容易想到。
還有一點就是 babel 配置文件里禁用 modules 很重要,否則導致各種問題,根本別想愉快的開發。這個對應用程序本身使用 import 沒有影響,畢竟 webpack2 啥標准都支持,其他地方就用 require 吧。
