webpack 之 webpack-dev-server自動刷新

watch

  首先介紹watch選項,參考這裏。可實現相關源文件改變後自動更新bundle.js文件的功能。在配置文件中添加 watch:true 或執行 webpack -w,便可開啓watch功能;css

  測試發現,與(一個或多個)bundle.js有關的全部js、css等模塊發生變化,就會自動執行打包,更新硬盤上的bundle.js文件html

webpack-dev-server

  webpack-dev-server默認開啓以上的監視功能。但二者監視效果存在差別:node

  1. webpack-dev-server自帶的監視自動打包功能,新打包的文件存在於內存中,對硬盤上的bundle.js無影響。新文件的內存路徑與配置文件中的publicPath相關,如http://localhost:8080/{publicPath}/bundle.js
  2. 手動執行webpack -w來啓動的watch效果,會修改硬盤上的bundle.js文件

  假如在配置文件中配置了publicPath(沒有配置的話默認是是  /):webpack

    output: {
        path: __dirname + "/dist",
        filename: "bundle.js",
        publicPath: "/p/"
    },

  則webpack-dev-server 的監視功能只會更新內存中的文件,如 以上就是http://localhost:8080/p/bundle.js(該頁面不會自動刷新)。但這個 http://localhost:8080/webpack-dev-server/p/bundle.js 這個路徑下的文件也會更新,並且會自動刷新。git

  到這裏能夠理解爲:github

  1. 打包後文件的內存路徑 = devServer.contentBase + output.publicPath + output.filename,只能經過瀏覽器來訪問這個路由來訪問內存中的bundle
  2. 使用webpack打包更新的文件硬盤路徑 = output.path + output.filename
  3. 在路由前加上/webpack-dev-server/,只要源文件發生變化,這個地址下的頁面都會自動刷新。以上面的/webpack-dev-server/p/bundle.js爲例,自動刷新後頁面的內容爲/p/bundle.js。(這裏實際就是後面會說到的iframe模式)

  對於publicPath,有兩個用處:web

  1. 像以上的被webpack-dev-server做爲在內存中的輸出目錄。
  2. 被其餘的loader插件所讀取,修改url地址等。

自動刷新

  根據文檔的提示。自動刷新有兩種方式:瀏覽器

iframe模式dom

  使用這個模式不須要任何的配置,但須要改變頁面的訪問路徑,好比要訪問根目錄下的首頁,源連接是 http://localhost:8080/index.html 須要換成http://localhost:8080/webpack-dev-server/index.html 。訪問這個鏈接時,查看頁面的dom結構,發現頁面是嵌入到一個iframe中顯示的:webpack-dev-server

修改相關聯模塊文件時,這個頁面會自動刷新。

inline模式

  這個模式中有兩種使用方式,分別是node和html方式。inline模式下訪問頁面不須要像iframe模式那樣須要改變訪問的路徑,inline模式下只須要訪問源路徑便可

html方式:在須要自動刷新的頁面中添加以下腳本便可,不須要像文檔所說那樣須要添加 --inline參數 或者 配置添加 devServer: { inline: true }

<script src="http://localhost:8080/webpack-dev-server.js"></script>

  理解就是當webpack-dev-server自帶的watch檢測到變化時,會經過以上的這個js來使瀏覽器自動刷新

node方式:

  對於這裏的理解實際就是,不直接運行webpack-dev-server指令了,而是經過node來啓動webpack-dev-server。node代碼以下:

var config = require("./webpack.config.js");
var webpack = require("webpack");
var WebpackDevServer = require("Webpack-dev-server");
config.entry.unshift("webpack-dev-server/client?http://localhost:8080/");
var compiler = webpack(config);
var server = new WebpackDevServer(compiler, {});
server.listen(8080);

  光光運行這段代碼是沒辦法使瀏覽器自動刷新的,由於這效果僅僅是運行了webpack-dev-server而已,還須要配合以上說的html方式來使瀏覽器自動刷新。

總結inline模式

  就是直接或經過node來間接啓動webpack-dev-server來檢測文件變化,自動打包,而後再html中添加一個額外js來使瀏覽器自動刷新。以上代碼中容許webpack的動態配置,即在js中配置運行,而不須要去修改配置文件。

 

回顧一個重點

  webpack-dev-server檢測到變化自動打包後,新打包後的文件實際上存在於內存中,而硬盤上的bundle.js依然是舊的。因此就算瀏覽器自動刷新了,讀取的是硬盤上的文件,頁面刷新後,仍是和刷新前的頁面同樣。

解決辦法有兩個:

  1. 使頁面讀取內存中的文件。將頁面中的bundle.js路徑修改成內存路徑(上文有提到),不推薦這種方式
  2. 更新硬盤上的文件。即開啓webpack-dev-server的同時,開始webpack -w。前者的做用時使瀏覽器自動刷新,後者的做用是更新硬盤上的文件。
  3. 【推薦】。在webpack的output配置中,使文件的輸出路徑與內存路徑一致。如:
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'dist'),
        publicPath:"dist"
    },
    devServer: {
         contentBase: "."
    }
    
    // 或者
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'dist'),
    },
    devServer: {
        contentBase: './dist',
        hot: true
    }

  由於webpack-dev-server對於文件請求會優先到內存中查找,沒有的話再轉到硬盤上。因此這樣瀏覽器訪問/dist/bundle.js時,能訪問到內存中的文件,並且當沒有啓動server時,訪問的恰好就是對應文件在硬盤上的路徑。這樣一來,在開發的時候,修改和讀取的文件都是內存中的文件,能提高開發效率。

  並且更重要的是,不這麼配置的話,hmr會無效的。

相關文章
相關標籤/搜索