使用webpack實現react的熱更新

  • 2019 年 10 月 10 日
  • 筆記

單獨把熱更新拿出來,是因為它的配置稍微比較繁瑣。網上也各說風雲,這裡就上個demo,說下個人的實現吧

前言

項目結構大致如下:

app 中自然就是源代碼,app/index.js是最外層的js文件。因為涉及到是熱更新,所以當然是在我們的 webpack.dev.js 文件下操作。

webpack的常規配置這裡不再贅述。項目的打包主要通過 server.js 文件

webpack-dev-middleware

webpack dev server 是一個開發服務器,內建 webpack 使用的 live reloading 功能。

這裡的使用其實就是當做一個Express中間件來使用的,用於服務webpack的包。

安裝webpack-dev-middleware

npm i webpack-dev-middleware --save-dev

配置webpack-dev-middleware

這裡我直接粘貼了 server.js 的代碼

const Webpack = require('webpack');  const WebpackDevMiddleware = require('webpack-dev-middleware');  const config = require('./webpack.dev');const app = new (require('express'))();  const port = 3000;const compiler = Webpack(config);  app.use(WebpackDevMiddleware(compiler, {     publicPath: config.output.publicPath,     stats: {colors: true},     lazy: false,     watchOptions: {         aggregateTimeout: 300,         poll: true     },  }));app.get('/', function (req, res) {     res.sendFile(__dirname + '/build/index.html');  });app.listen(port);

通過運行server.js即可進行打包,因為webpack提供了express的middleware,讓我們可以處理靜態資源文件而不需要使用express.static。而打成這像功能,就是我們配置的webpack-dev-middleware。

簡單說下上面devMiddle的配置:

  • publicPath:這裡我導入的是webpack中的輸出publicPath,注意:這是一個必填項。其實就是告訴index.html頁面相對於瀏覽器地址怎麼拿到他要拿到的js。
  • stats:非必填項,這裡的color,就是指console統計日誌帶顏色輸出。
  • lazy:指示是否懶人加載模式。true表示不監控源碼修改狀態,收到請求才執行webpack的build。false表示監控源碼狀態,配套使用的watchOptions可以設置與之相關的參數。

小結

到這一步,我們不需要再運行webpack命令去打包文件了,我們可以直接

node server.js

然後修改我們的源碼文件你可以在控制台中發現,他會自動打包。

打開瀏覽器,127.0.0.1:3000 可以看到我們的的項目,修改後刷新就可以看到修改後的效果。

當然,我們任務還沒結束。目前只是實現了不需要手動打包了,但是還是要手動刷新哇!

熱更新

熱更新,就是讓我們更改完源碼後,不需要再瀏覽器上手動刷新即可看到效果。解放我們的雙手有木有

安裝插件

npm i --save-dev webpack-hot-middleware

修改配置文件

這裡我們需要修改三個地方的配置文件:webpack.dev.js server.js index.js

server.js 添加一個中間件

const WebpackHotMiddleware = require('webpack-hot-middleware');  ...  app.use(WebpackHotMiddleware(compiler));

webpack.dev.js

入口文件部分修改如下:

entry: {         index: [             'react-hot-loader/patch',             'webpack-hot-middleware/client',             'babel-polyfill',             pathLib.resolve(ENTRY_PATH, 'index.js')         ],         vendor: ['react', 'react-dom', 'react-router-dom']     },

插件部分添加上 HotModuleReplacementPlugin

new webpack.HotModuleReplacementPlugin()

一切都給你打包好了,得告訴前端來接收下: index.js 部分:

if(module.hot){     module.hot.accept();  }

小結

這個時候當我們再次運行

node server.js

的時候,啟動瀏覽器,可以看到當我們修改源碼文件後,瀏覽器會自動的刷新的。

問題

代碼如上。當我點擊button,state也會隨之增加。但是這個時候如果我修改了某一個文件內容,可以看到我瀏覽器的確刷新了。但是!state卻重置到了1,這並不是我們想要的。

熱更新保留組件狀態

之前的我們只需要安裝 babel-preset-react-hmre ,然後配置 .babelrc 文件就可以完美解決了。但是目前這個插件已經放棄維護了。推出了 react-hot-loader 插件。目前還都是在測試版。但是可以使用。

這裡我們使用的版本時 3.0.0-beta.6

安裝插件

npm i --save-dev react-hot-reload

修改配置文件

.bebelrc

{   "presets": ["es2015","react","stage-0","env"],   "plugins": ["react-hot-loader/babel"],   "env": {     "production":{       "preset":["react-optimize"]     }   }  }

在plugins中添加 react-hot-loader/babel

webpack.dev.js entry 部分修改:

entry: {         index: [             'react-hot-loader/patch',             'webpack-hot-middleware/client',             'babel-polyfill',             pathLib.resolve(ENTRY_PATH, 'index.js')         ],         vendor: ['react', 'react-dom', 'react-router-dom']     },

修改index.js文件

import {AppContainer} from 'react-hot-loader'  ...  render(     <AppContainer >         <IndexApp/>     </AppContainer>     ,     mountNode  );

注意 3.0.0-beta.6 通過component屬性傳組件也是可以的。

完結

至此,我們就已經實現了,修改源碼後 ,瀏覽器自動刷新的效果了,並且還保留了刷新前的state狀態。

說明

這是我寫一個博客系統的demo(項目還在進行中)配置中的一部分。

項目地址: https://github.com/Nealyang/React-Express-Blog-Demo

喜歡的朋友可以關注公眾號,交流更多前端知識總結demo實戰,讓你我共贏!