建議在github閱讀
webpack-dev-server會使用當前的路徑作為請求的資源路徑,但是你可以通過指定content base來修改這個默認行為:
$ webpack-dev-server --content-base build/這樣webpack-dev-server就會使用build目錄下的文件來處理網絡請求。他會監聽資源文件,當他們改變的時候會自動編譯。這些改變的bundle將會從內存中直接拿出來進而處理網絡請求(所謂的改變的bundle指的就是,相對你在publicPath中指定的路徑的資源),而不會被寫出到我們的output路徑下面。如果一個已經存在的bundle具有相同的URL,那么我們也會使用內存中的資源來替換
他!比如我們有一個如下的配置:
那么我們要訪問編譯后的資源可以通過localhost:8080/assets/bundle.js來訪問。如果我們在build目錄下有一個文件,那么我們可以使用下面的方式來訪問js資源:
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Document</title></head><body> <script src="assets/bundle.js"></script></body></html>此時你會看到控制臺輸出如下內容:
主要關注下面兩句輸出:
Webpack result is served from /assets/
Content is served from /users/…./build(因為我們設置了contentBase)
注意:我們此時通過http://localhost:8080/index.html來訪問build下的index.html;同時,我們的會發現在build目錄下并沒有生成我們的bundle.js文件本身
。也就是說,此時我們的靜態文件全部從build目錄來獲取,我們生成的靜態文件bundle.js也在build目錄之下,不過要訪問它必須要加上publicPath路徑才可以!
我們的頁面被嵌套在一個iframe中,當資源改變的時候會重新加載。只需要在路徑中加入webpack-dev-server就可以了,不需要其他的任何處理:
http://localhost:8080/webpack-dev-server/index.html從而在頁面中就會產生如下的一個iframe標簽并注入CSS/js/DOM:
這個iframe頁面會請求 live.bundle.js ,其中里面會新建一個 Iframe ,你的應用就被注入到了這個 Iframe 當中。同時 live.bundle.js 中含有 socket.io 的 client 代碼,這樣它就能和 webpack-dev-server 建立的 http server 進行 websocket 通訊了,并根據返回的信息完成相應的動作。(總之,因為我們的http://localhost:8080/webpack-dev-server/index.html訪問的時候加載了live.bundle.js,其具有websocket的client代碼,所以當websocket-dev-server服務端代碼發生變化的時候會通知到這個頁面,這個頁面只是需要重新刷新iframe中的頁面就可以了
)
該模式有如下作用:
No configuration change needed.(不需要修改配置文件)
Nice information bar on top of your app.(在app上面有information bar)
URL changes in the app are not reflected in the browser’s URL bar.(在app里面的URL改變不會反應到瀏覽器的地址欄中)
一個小的webpack-dev-server的客戶端入口被添加到文件中,用于自動刷新頁面。其中在cli中輸入的是:
webpack-dev-server --inline --content-base ./build此時在頁面中輸出的內容中看不到插入任何的js代碼:
但是在控制臺中可以清楚的知道頁面的重新編譯等信息:
該模式有如下作用:
Config option or command line flag needed.(webpack配置或者命令行配置)
Status information in the console and (briefly) in the browser’s console log.(狀態信息在瀏覽器的console.log中)
URL changes in the app are reflected in the browser’s URL bar(URL的改變會反應到瀏覽器的地址欄中).
每一個模式都是支持Hot Module Replacement的,在HMR模式下,每一個文件都會被通知內容已經改變而不是重新加載整個頁面。因此,在HMR執行的時候可以加載更新的模塊,從而把他們注冊到運行的應用里面。
在webpack-dev-server配置中沒有inline:true去開啟inline模式,因為webpack-dev-server模塊無法訪問webpack的配置
。因此,用戶必須添加webpack-dev-server的客戶端入口文件到webpack的配置中,具體方式如下:
方式1:To do this, simply add the following to all entry points: webpack-dev-server/client?http://?path?:?port?/,也就是在entry中添加一個內容:
entry: { app: [ 'webpack-dev-server/client?http://localhost:8080/', "./app/main.js" ] }方式2:通過下面的代碼來完成:
var config = require("./webpack.config.js");config.entry.app.unshift("webpack-dev-server/client?http://localhost:8080/");var compiler = webpack(config);var server = new WebpackDevServer(compiler, {...});server.listen(8080);或者也可以在HTML中加入下面的文件來完成:
<script src="http://localhost:8080/webpack-dev-server.js"></script>為我們的webpack-dev-server開啟HMR模式只需要在命令行中添加–hot,他會將HotModuleReplacementPlugin這個插件添加到webpack的配置中去,所以開啟HotModuleReplacementPlugin最簡單的方式就是使用inline模式。
你只需要在命令行中添加–inline –hot就可以自動實現。這時候webpack-dev-server就會自動添加webpack/hot/dev-server入口文件到你的配置中去,這時候你只是需要訪問下面的路徑就可以了http://?host?:?port?/?path?。在控制臺中你可以看到如下的內容:
其中以[HMR]開頭的部分來自于webpack/hot/dev-server模塊,而以[WDS]開頭的部分來自于webpack-dev-server的客戶端
。下面的部分來自于webpack-dev-server/client/index.js內容,其中的log都是以[WDS]開頭的:
而在我們的webpack/hot/dev-server中的log都是以[HMR]開頭的(他是來自于webpack本身的一個plugin):
if(!updatedModules) { console.warn("[HMR] Cannot find update. Need to do a full reload!"); console.warn("[HMR] (PRobably because of restarting the webpack-dev-server)"); window.location.reload(); return; }注意:我們必須指定正確的output.publicPath,否則熱更新的chunks不會被加載!
此時需要修改三處配置文件:
第一:添加一個webpack的入口點,也就是webpack/hot/dev-server
第二:添加一個new webpack.HotModuleReplacementPlugin()到webpack的配置中
第三:添加hot:true到webpack-dev-server配置中,從而在服務端啟動HMR(可以在cli中使用webpack-dev-server –hot)
if(options.inline) { var devClient = [require.resolve("../client/") + "?" + protocol + "://" + (options.public || (options.host + ":" + options.port))]; //將webpack-dev-server的客戶端入口添加到的bundle中,從而達到自動刷新 if(options.hot) devClient.push("webpack/hot/dev-server"); //這里是webpack-dev-server中對hot配置的處理 [].concat(wpOpt).forEach(function(wpOpt) { if(typeof wpOpt.entry === "object" && !Array.isArray(wpOpt.entry)) { Object.keys(wpOpt.entry).forEach(function(key) { wpOpt.entry[key] = devClient.concat(wpOpt.entry[key]); }); } else { wpOpt.entry = devClient.concat(wpOpt.entry); } });}滿足上面三個條件的nodejs使用方式如下:
var config = require("./webpack.config.js");config.entry.app.unshift("webpack-dev-server/client?http://localhost:8080/", "webpack/hot/dev-server");//條件一(添加了webpack-dev-server的客戶端和HMR的服務端)var compiler = webpack(config);var server = new webpackDevServer(compiler, { hot: true //條件二(--hot配置,webpack-dev-server會自動添加HotModuleReplacementPlugin),條件三 ...});server.listen(8080);webpack-dev-server使用http-proxy-middleware去把請求代理到一個外部的服務器,配置的樣例如下:
proxy: { '/api': { target: 'https://other-server.example.com', secure: false }}// In webpack.config.js{ devServer: { proxy: { '/api': { target: 'https://other-server.example.com', secure: false } } }}// Multiple entryproxy: [ { context: ['/api-v1/**', '/api-v2/**'], target: 'https://other-server.example.com', secure: false }]這種代理在很多情況下是很重要的,比如你可以把一些靜態文件通過本地的服務器加載,而一些API請求全部通過一個遠程的服務器來完成。還有一個情景就是在兩個獨立的服務器之間進行請求分割,如一個服務器負責授權而另外一個服務應用本身。
通過一個函數的返回值可以視情況的繞開一個代理。這個函數可以查看http請求和響應以及一些代理的選項。它必須返回要么是false要么是一個URL的path,這個path將會用于處理請求而不是使用原來代理的方式完成。下面的例子的配置將會忽略來自于瀏覽器的HTTP請求,他和historyApiFallback配置類似。瀏覽器請求可以像往常一樣接收到HTML文件,但是API請求將會被代理到另外的服務器:
proxy: { '/some/path': { target: 'https://other-server.example.com', secure: false, bypass: function(req, res, proxyOptions) { if (req.headers.accept.indexOf('html') !== -1) { console.log('Skipping proxy for browser request.'); return '/index.html'; } } }}對于代理的請求可以通過提供一個函數來重寫,這個函數可以查看或者改變http請求。下面的例子就會重寫HTTP請求,其主要作用就是移除URL前面的/api部分。
proxy: { '/api': { target: 'https://other-server.example.com', pathRewrite: {'^/api' : ''} }}其中pathRewrite配置來自于http-proxy-middleware。
http-proxy-middleware會預解析本地hostname成為localhost,你可以使用下面的配置來修改這種默認行為:
var server = new webpackDevServer(compiler, { quiet: false, stats: { colors: true }, proxy: { "/api": { "target": { "host": "action-js.dev", "protocol": 'http:', "port": 80 }, ignorePath: true, changeOrigin: true, secure: false } }});server.listen(8080);webpack-dev-server命令行的使用如下:
$ webpack-dev-server <entry>所有的webpack cli配置在webpack-dev-server cli中都是存在的有效的,除了output的默認參數。 –content-base
var wpOpt = require("webpack/bin/convert-argv")(optimist, argv, { outputFilename: "/bundle.js"});if(options.inline) { var devClient = [require.resolve("../client/") + "?" + protocol + "://" + (options.public || (options.host + ":" + options.port))]; if(options.hot) devClient.push("webpack/hot/dev-server"); //添加webpack/hot/dev-server入口 [].concat(wpOpt).forEach(function(wpOpt) { if(typeof wpOpt.entry === "object" && !Array.isArray(wpOpt.entry)) { Object.keys(wpOpt.entry).forEach(function(key) { wpOpt.entry[key] = devClient.concat(wpOpt.entry[key]); }); } else { wpOpt.entry = devClient.concat(wpOpt.entry); } });}–hot: adds the HotModuleReplacementPlugin and switch the server to hot mode. Note: make sure you don’t add HotModuleReplacementPlugin twice.
–hot –inline also adds the webpack/hot/dev-server entry.
–public: overrides the host and port used in –inline mode for the client (useful for a VM or Docker).
–lazy: no watching, compiles on request (cannot be combined with –hot).
–https: serves webpack-dev-server over HTTPS Protocol. Includes a self-signed certificate that is used when serving the requests.
–cert, –cacert, –key: Paths the certificate files.
–open: opens the url in default browser (for webpack-dev-server versions > 2.0).
–history-api-fallback: enables support for history API fallback.
–client-log-level: controls the console log messages shown in the browser. Use error, warning, info or none.
當使用cli的時候,可以把webpack-dev-server的配置放在一個單獨的文件中,其中key是devServer。在cli中傳入的參數將會覆蓋我們的配置文件的內容。如下例:
module.exports = { // ... devServer: { hot: true }}var WebpackDevServer = require("webpack-dev-server");var webpack = require("webpack");var fs = require("fs");var compiler = webpack({ // configuration});var server = new WebpackDevServer(compiler, { // webpack-dev-server options contentBase: "/path/to/directory", // Can also be an array, or: contentBase: "http://localhost/", hot: true, // Enable special support for Hot Module Replacement // Page is no longer updated, but a "webpackHotUpdate" message is sent to the content // Use "webpack/hot/dev-server" as additional module in your entry point // Note: this does _not_ add the `HotModuleReplacementPlugin` like the CLI option does. historyApiFallback: false, // Set this as true if you want to access dev server from arbitrary url. // This is handy if you are using a html5 router. compress: true, // Set this if you want to enable gzip compression for assets proxy: { "**": "http://localhost:9090" }, // Set this if you want webpack-dev-server to delegate a single path to an arbitrary server. // Use "**" to proxy all paths to the specified server. // This is useful if you want to get rid of 'http://localhost:8080/' in script[src], // and has many other use cases (see https://github.com/webpack/webpack-dev-server/pull/127 ). setup: function(app) { // Here you can access the Express app object and add your own custom middleware to it. // For example, to define custom handlers for some paths: // app.get('/some/path', function(req, res) { // res.json({ custom: 'response' }); // }); }, // pass [static options](http://expressjs.com/en/4x/api.html#express.static) to inner express server staticOptions: { }, clientLogLevel: "info", // Control the console log messages shown in the browser when using inline mode. Can be `error`, `warning`, `info` or `none`. // webpack-dev-middleware options quiet: false, noInfo: false, lazy: true, filename: "bundle.js", watchOptions: { aggregateTimeout: 300, poll: 1000 }, // It's a required option. publicPath: "/assets/", headers: { "X-Custom-Header": "yes" }, stats: { colors: true }, https: { cert: fs.readFileSync("path-to-cert-file.pem"), key: fs.readFileSync("path-to-key-file.pem"), cacert: fs.readFileSync("path-to-cacert-file.pem") }});server.listen(8080, "localhost", function() {});// server.close();其中的配置可以查看webpack-dev-server。注意:我們的webpack配置沒有傳入到我們的WebpackDevServer中,因此,webpack中的devServer配置并非用于這個場景。而且,在webpackDevServer中是沒有inline模式的,因此如下的js必須手動插入到頁面中:
<script src="http://localhost:8080/webpack-dev-server.js"><//script>當你使用HTML5的history API的時候,當404出現的時候你可能希望使用index.html來作為請求的資源,這時候你可以使用這個配置historyApiFallback:true。然而,如果你修改了output.publicPath,你就需要指定重定向的URL,你可以使用historyApiFallback.index選項。
// output.publicPath: '/foo-app/'historyApiFallback: { index: '/foo-app/'}使用rewrite選項你可以重新設置靜態資源
historyApiFallback: { rewrites: [ // shows views/landing.html as the landing page { from: /^//$/, to: '/views/landing.html' }, // shows views/subpage.html for all routes starting with /subpage { from: /^//subpage/, to: '/views/subpage.html' }, // shows views/404.html on all other pages { from: /./, to: '/views/404.html' }, ],},你可能想要在生產環境中運行一個后置服務器,而我們的webpack-dev-server是不應該作為一個后置服務器的,他的主要工作就是處理靜態文件的請求。
你可以運行兩個服務器:webpack-dev-server和后置服務器
這時候,一方面
:你需要讓webpack產生的資源去請求我們的webpack-dev-server,即使是后置服務器中的HTML請求。另一方面
:你需要讓你的后置服務器產生HTML頁面,而這個頁面包括script標簽,其指向我們的webpack-dev-server中的資源;除了這兩點,你需要把webpack-dev-server和webpack-dev-server runtime連接起來以便當重新編譯后可以觸發加載。
讓webpack請求我們的webpack-dev-server,你需要在output.publicPath選項中提供一個完整的URL;為了讓webpack-dev-server和他的runtime鏈接起來,我們可以開啟–inline模式。webpack-dev-server cli會自動添加一個入口點,其可以建立Websocket連接(你也可以使用iframe模式,如果你為webpack-dev-server指定了–content-base,這個contentBase指向后置服務器。如果你需要為你的后置服務器添加一個websocket連接,那么你就需要使用iframe模式)。
當你使用的是inline模式的時候,你只需要在web瀏覽器中打開你的后置服務器的URL即可(iframe模式的時候,你需要為URL添加/webpack-dev-server/前綴)。下面是一個例子:
webpack-dev-server on port 8080.
backend server on port 9090.
generate HTML pages with
新聞熱點
疑難解答