react熱替換([HMR])

晴天_雨天發表於2017-06-03

react 熱替換 ([HMR])

熱替換好多地方可以用到,目前比較流行的用法是搭配React和webpack實現在不重新整理頁面的情況下對模組的增刪改。在給專案新增熱替換功能的時候,可以說是踩了各種坑,webpack官方給的配置也有小問題還不得不FQ去解決(百度出來的一個能打的也沒有)。
官方的方案在這兒: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 吧。


相關文章