iT邦幫忙

2017 iT 邦幫忙鐵人賽
DAY 11
0
Modern Web

寫React的那些事系列 第 11

React Day11 - Webpack(4) Hot Module Replacement (HMR)

今天要聊到webpack另一個很實用的功能,當專案開發越來越龐大後,你會發現webpack build讓人真的多出很多發呆的時間,FB可以刷一陣子,所以可以hot reload變成一件很重要的事情,讓開發的流程可以更順暢,只要有程式碼變動,存檔的時候自動更新改動的部分。

Hot reload就是指說只更新有改動部分,不刷新整個頁面,也就是webpack指的HMR。

官網有一篇HMR詳細的文章,這邊就TL;DR。

webpack-dev-server


它是一個用node.js express實作的開發環境伺服器,如果我們在開發時改動檔案,它會透過webpack-dev-middleware進行webpack compile,當compile完成後通知瀏覽器重新整理。它和CLI執行webpack不同的是,它不是實際build出來檔案,它會把bundle的結果先存在記憶體。

webpack-dev-middleware


如同上面所說webpack-dev-server只是一個開發用的伺服器,webpack負責compile/bundle,而webpack-dev-middleware就是在中間負責溝通的中間件。Webpack就是使用這個webpack-dev-middleware來做hot reload。

可以參考Webpack Hot Middleware上面的說明:

Webpack hot reloading using only webpack-dev-middleware. This allows you to add hot reloading into an existing server without webpack-dev-server.

webpack-hot-middleware


它是給webpack-dev-middleware使用的hot reload,簡單說我們可以使用webpack-dev-middleware加上webpack-hot-middleware實現hot reload的功能(不用使用webpack-dev-server)。

使用方式


上面提到分成兩種使用方式,webpack-dev-server 或是 webpack-dev-middleware+webpack-hot-middleware,可以擇一就好,下面會提到兩種不同的使用方法。可以先參考
Webpack HMR Tutorial說明,或是stack overflow這篇,來區表兩則差別,選擇你想要的。目前在專案上我是採用webpack-dev-middleware+webpack-hot-middleware,第二種方式。

webpack-dev-server使用方式


(1) 首先要npm install

npm install webpack-dev-server --save-dev

(2) 建立開發用的webpack.config.js檔 (或另取檔名webpack.config.dev.js)

module.exports = {
    entry: [
      'webpack/hot/dev-server',
      './main.js'
    ],
    output: {
        path: '/',
        filename: 'bundle.js'
    },
    module: {
        loaders: [
          // 任何你需要的loaders
        ]
    }
};

(3) 設定根目錄的html

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8" />
</head>
<body>
  <!--最重要是加上這一行-->
  <script src="http://localhost:8080/webpack-dev-server.js"></script>
  <script src="bundle.js"></script>
</body>
</html>

(4) 在CLI上輸入指令

// webpack-dev-server 會建立localhost:8080的伺服器
// --devtool eval 建立原程式碼位置,當有錯誤可以找到原檔案與行數
// --progress 會顯示打包進度
// --colors 會幫 webpack 顯示的訊息加入顏色
// --hot 會把HotModuleReplacementPlugin到設定中
webpack-dev-server --devtool eval --progress --colors --hot

設定以上四個步驟,就可以在 http://localhost:8080/ 看到網站的樣子,可以改局部程式碼看看就會有變化。

這邊是使用webpack-dev-server inline mode的方式,還有用require('webpack-dev-server')的方式啟用,這邊就不做介紹,因為真的說太多太複雜了XD。可以參考官網 Webpack dev server了解更多。

webpack-dev-middleware + webpack-hot-middleware 使用方式


(1) 首先要npm install

npm install webpack-dev-middleware webpack-hot-middleware --save-dev

(2) 建立開發用的webpack.config.js檔 (或另取檔名webpack.config.dev.js)

var webpack = require('webpack');

module.exports = {
    entry: {
        main: [
          'main.js',
          // reload=true,只說當有不能hot reload的情況,就整頁refresh
          'webpack-hot-middleware/client?reload=true'
        ]
    },
    output: {
        filename: 'bundle.js',
        // compile後結果會存在記憶體中,直接設成根目錄
        path: '/',
        // 有require的靜態資源(例如:CSS),設完整路徑
        publicPath: 'http://localhost:8080/'
    },
    module: {
        loaders: [
          // 任何你需要的loaders
        ]
    },
    plugins: [
        // 提供hot reload功能
        new webpack.HotModuleReplacementPlugin(),
        // 當程式碼有錯誤時,不更新畫面,如果錯誤被修正才會hot reload
        // 這個可以選擇使用。
        new webpack.NoErrorsPlugin()
    ]
};

(3) 建立一個node.js Express程式

var express = require('express');
var webpack = require('webpack');
var webpackDevMiddleware = require('webpack-dev-middleware');
var webpackHotMiddleware = require('webpack-hot-middleware');
var webpackConfig = require('./webpack.config');

var app = express();
var port = 8080;
var compiler = webpack(webpackConfig);

app.use(webpackDevMiddleware(compiler, {
  publicPath: webpackConfig.output.publicPath,
    noInfo: true,
    stats: {
        colors: true
    }
}));
app.use(webpackHotMiddleware(compiler));
app.get('/', function(req, res) {
    var body = '<!doctype html>' +
        '<html lang="en">'+
        '<head><meta charset="utf-8"></head>' +
        '<body>' +
        '<script src="bundle.js"></script>' +
        '</body>'+
        '</html>';

    res.writeHead(200, {"Content-Type": "text/html"});
    res.write(body);
    res.end();
});

app.listen(port, function(error) {
    if (error) {
        console.error(error);
    } else {
        console.info('==> ?  Listening on port %s. Open up http://localhost:%s/ in your browser.', port, port);
    }
});

(4) 在entry point加上HMR JavaScript API

這裏就是要在main.js最後面加上這一段,讓webpack知道這個檔案和他引用的檔案都可以被replace。這部分還有一些進階用法,因為沒有特別研究XD,所以就先放這段即可。

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

最後在CLI執行

node server.js

因為node.js不是很專業,這邊就不多解釋,一樣就可以在 http://localhost:8080/ 看到hot reload功能網站的樣子。

參考


使用 Webpack 建立 React 專案開發環境
Webpack hmr tutorial
手把手深入理解 webpack dev middleware 原理與相關 plugins


上一篇
React Day10 - Webpack(3) Plugins推推
下一篇
React Day12 - Babel介紹
系列文
寫React的那些事31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言