Web前端熱更新

熱更新是什麼?

簡單來講,熱更新通常是指手機裏的app有小規模更新,以直接打補丁的形式更新。
相對應的,另外一種更新方式就是下載新的安裝包,從新安裝。
因此熱更新在手遊裏頭是比較常見的,畢竟遊戲應用個個都幾百兆起步。css

那Web前端有熱更新?

按上面那個說法,Web應該是不存在熱更新的。
由於網頁的架構是B/S,即 瀏覽器+服務器 , 它不像手機app同樣是 C/S 客戶端+服務器
因此在網頁這一塊是沒法推送補丁讓瀏覽器去更新的。html

那爲何我搜前端熱更新有好多文章在講?

網上大多數前端熱更新講的都是熱加載 hot-loader 或者是模塊熱更替 HMR前端

熱加載是什麼?

  • 問題背景
    前端頁面是由 HTML+CSS+JavaScript 組成的,咱們前端開發頁面調試的時候,
    通常是這樣:編輯器修改保存 --> 切換瀏覽器刷新
    ps:因此前端汪F5鍵是用得最多的。
  • 怎麼解決
    能不能我這邊修改完,瀏覽器就自動從新加載那些修改過的文件?
    想要解決這個問題,那麼咱們就要去檢測代碼文件是否修改了,而後通知瀏覽器去從新加載。
    那咱們就須要一個瀏覽器與服務器之間的通訊機制。
    在早期,瀏覽器與服務器間的通訊機制就只有http協議,可http協議是無狀態協議,這就很尷尬了,並且服務器沒法主動給瀏覽器發消息,那就能瀏覽器不斷跟服務器請求。
  • 還好在HTML5裏頭添加了websocket
    websocket 是一種容許瀏覽器與服務器間創建tcp長連接的通訊機制
    tcp協議:雙向通訊,有狀態
    這樣的話,咱們就能夠經過服務器檢測文件修改,有修改了,咱們就通知瀏覽器,沒有咱們就不通知。

盜圖
盜圖

因此大概流程就以下:vue

  • 服務器檢測代碼是否修改了
  • 修改了通知瀏覽器
  • 瀏覽器根據修改的文件狀況選擇局部刷新或全局刷新

具體實例

試一下

  • package.json 配置文件
    "scripts": {
      "test": "echo \"Error: no test specified\" && exit 1",
      "start": "webpack",
      "server": "webpack-dev-server --open",
      "server-hot": "webpack-dev-server --hot"
    },複製代碼
  • webpack.config.js 配置文件
    //  本地開發服務器
      devServer: {
          //  本地服務器加載資源所在路徑
          contentBase: "./public",
          //  true 表示全部跳轉都是index.html
          historyApiFallback: true,
          //  當源文件修改時,自動刷新頁面
          inline: true,
          //  端口號,若不設置,默認爲8080
          port: 3000,
      },複製代碼
    因此咱們在webpack-demo目錄下,運行npm run server就等於運行了webpack-dev-server --open
    這樣咱們就啓用了webpack-dev-server可是咱們配置項沒有配置啓用HMR
    因此當你修改了文件時,它只是從新打包了,並通知瀏覽器重載一遍頁面。

運行webpack-dev-server
運行webpack-dev-server

$ npm run server是我執行的命令,根據package.json 配置文件這個命令等同於webpack-dev-server --open
下面那些輸出語句,一些是webpack-dev-server啓用狀態,還有webpack的打包文件的打包過程node

瀏覽器的頁面效果是這樣的
瀏覽器的頁面效果是這樣的

爲何輸出的是這個?

  • webpack.config.js 配置文件
    module.exports = {
      //  入口文件
      entry: __dirname + "/app/main.js",
      //  輸入文件
      output: {
          //  輸出路徑
          path: __dirname + "/public",
          //  輸出文件名
          filename: "bundle.js"
      },複製代碼
  • /app/main.js文件
    //  ES6導入模塊的語法,因此入口文件跟下面兩個文件有關聯
    import hello from "./hello";
    import "./main.css";
    //  簡單的DOM操做
    document.querySelector("#root").appendChild(hello());複製代碼
  • /app/hello.js文件
    import style from "./style.css";
    //  下面這個是CommonJS的文件導入,由於node.js自己是支持CommonJS的
    let test = require("./test.json");
    //  這個是CommonJS的模塊導出
    module.exports = function () {
    let hello = document.createElement('div');
    hello.textContent = test.hhh;
    //  這裏的hello這個元素的class的取值是來自上面導入"./style.css"文件,這涉及到CSS模塊
    hello.className = style.hello;
    return hello;
    };複製代碼
  • /app/main.css文件
    body{
      color: blue;
      font-size: 64px;
    }複製代碼
  • /app/style.css文件
    .hello{
      color: red;
    }複製代碼
  • /app/test.json文件
    {
      "hhh":"this a message from .json"
    }複製代碼
  • 哦,還有index.html文件webpack

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta http-equiv="X-UA-Compatible" content="ie=edge">
      <title>webpack demo</title>
    </head>
    <body>
    
      <div id="root">
      </div>
      <script src="bundle.js"></script>
    </body>
    </html>複製代碼

實際頁面index.html代碼
實際頁面index.html代碼

這樣應該很清晰了吧
首先入口文件main.js引入了hello.jsmain.css
而後hello.js又引入了style.csstest.json
因此上面這些與入口文件有直接聯繫或間接聯繫的文件都會經過webpack去打包,輸出爲一個bundle.js
index.html是引用了bundle.js文件的,因此就出現了這個效果。git

你好像沒講到webpack-dev-server的做用哦

  • 咱們上面運行的是沒有啓用HMR,因此這時候咱們修改main.css文件
    body{
      color: blue;
      /* font-size: 64px; */ 
    }
    你會看到終端webpack在從新打包,打包完後瀏覽器自動刷新了頁面,而後字體變成默認大小複製代碼
  • 若是啓用了HMR呢?
    這時候咱們要用到的命令是$ npm run server-hot
    一樣修改main.css文件,咱們會發現字體大小變了,但是瀏覽器並無刷新,並且發現改一次就多一個js文件,頁面只是局部刷新

多了的js文件其實就是一些樣式的更替
多了的js文件其實就是一些樣式的更替

  • 那是否是用了HMR就能夠實現任何修改都是局部刷新呢?
    不是的。
    若是隻是修改了CSS樣式,那能夠經過JS以打補丁的形式去進行替換樣式。並且也不是說改樣式就都能實現局部刷新,若是你改的是style.css這個文件,它的結果是會從新加載頁面,爲何呢?由於style.css這裏頭用到了CSS模塊的東西,因此沒辦法說直接打個補丁就能搞定。

結論

熱加載這個東西,首要就是靠服務器與瀏覽器之間的通訊,有了通訊才能通知瀏覽器何時去刷新,而刷新又分全局和局部,這個要看服務端改了哪些代碼文件,而這些文件若是能夠局部刷新就局部刷新,不行的話就只能從新加載頁面了。github

參考資料

前端開發熱更新原理解讀web

相關文章
相關標籤/搜索