Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Core concepts of webpack-dev-server and thermal loading

2025-02-25 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article mainly explains "the core concept of webpack-dev-server and thermal loading". The content of the explanation is simple and clear, and it is easy to learn and understand. Please follow the editor's train of thought to study and learn "the core concept of webpack-dev-server and thermal loading".

ContentBase vs publicPath vs output.path of Webpack, the core concept of webpack-dev-server

Webpack-dev-server uses the current path as the requested resource path (the so-called

Current path

This is the path to run the webpack-dev-server command. If webpack-dev-server is wrapped, such as wcf, then the current path refers to the path where the wcf command is run (usually the root path of the project), but the reader can modify this default behavior by specifying content-base:

Webpack-dev-server-content-base build/

In this way, webpack-dev-server will use the resources in the build directory to handle requests for static resources, such as css/ images. Generally speaking, content-base should not be confused with publicPath and output.path. Where content-base indicates what the path to the static resource is, such as the following example:

Js content is to be inserted here

After being the template of html-webpack-plugin, what exactly is the index.css path above? Relative to who? It has been emphasized above: if you do not specify content-base in the case of the current path is relative to the current path, the so-called current path is running webpack-dev-server directory, so if you run this command in the project root path, then it is necessary to ensure that the index.css resource exists under the project root path, otherwise there will be html-webpack-plugin 404 error reports. Of course, to solve this problem, you can change content-base to the same directory as html-webpack-plugin 's html template.

The content-base mentioned above is only related to requests for static resources, so let's make a distinction between publicPath and output.path.

First of all: if you set output.path to build (build here has nothing to do with content-base 's build, please don't get confused), know that webpack-dev-server doesn't actually write these packaged bundle to this directory, but exists in memory, but we can assume (note here is hypothetical) that it is written to this directory.

Then: when requested, the path of these packaged bundle is relative to the configured publicPath, and the publicPath is equivalent to the virtual path, which is mapped to the specified output.path. If the specified publicPath is "/ assets/" and output.path is "build", then the virtual path "/ assets/" corresponds to "build" (the former and the latter point to the same location), and if there is a "index.css" under build, then access through the virtual path is / assets/index.css.

Finally: if a specific bundle already exists in a memory path (the file is written in memory) and there are new resources in compiled memory, then we will also use the new resources in memory to process the request instead of using the old bundle! For example, there is a configuration as follows:

Module.exports = {entry: {app: [". / app/main.js"]}, output: {path: path.resolve (_ _ dirname, "build"), publicPath: "/ assets/", / / at this time, the / assets/ path corresponds to the build directory, which is a mapped relationship filename: "bundle.js"}.

So we want to access the compiled resources can be accessed through localhost:8080/assets/bundle.js. If you have a html file in the build directory, you can access js resources in the following ways:

Document

You will see the console output as follows:

Enter image description here

Mainly focus on the following two sentences of output:

Webpack result is served from / assets/

Content is served from / users/... . / build

The reason for this output is that contentBase is set to build, because the command you run is webpack-dev-server-- content-base build/. So, in general: if there is no reference to external relative resources in the html template, we do not need to specify content-base, but if there is a reference to external relative resource css/ image, you can set the default static resource loading path by specifying content-base, unless all static resources are in the current directory.

Webpack-dev-server hot loading (HMR)

To turn on HMR mode for webpack-dev-server, you only need to add-- hot to the command line, and it will add the plug-in HotModuleReplacementPlugin to the configuration of webpack, so the easiest way to turn on HotModuleReplacementPlugin is to use inline mode. In inline mode, you can do this automatically by adding-- inline-- hot to the command line.

At this point, webpack-dev-server will automatically add the webpack/hot/dev-server entry file to the configuration, just need to access the following path to http:// «host »: «port »/ «path ». You can see the following in the console

The part that starts with [HMR] comes from the webpack/hot/dev-server module, while the part that starts with [WDS] comes from the client side of webpack-dev-server. The following section comes from webpack-dev-server/client/index.js content, where log starts with [WDS]:

Function reloadApp () {if (hot) {log ("info", "[WDS] App hot update..."); window.postMessage ("webpackHotUpdate" + currentHash, "*");} else {log ("info", "[WDS] App updated. Reloading..."); _ window.location.reload ();}}

Log in webpack/hot/dev-server starts with [HMR] (it comes from a plugin of Webpack itself):

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;}

So how do you use HMR functionality in nodejs? At this point, three configuration files need to be modified:

1. Add an entry point for Webpack, namely webpack/hot/dev-server

two。 Add a new webpack.HotModuleReplacementPlugin () to the configuration of webpack

3. Add hot:true to the webpack-dev-server configuration to start HMR on the server side (you can use webpack-dev-server-- hot in cli)

For example, the following code shows how webpack-dev-server handles the entry file in order to implement HMR:

If (options.inline) {var devClient = [require.resolve (".. / client/") + "?" + protocol + ": / /" + (options.public | (options.host + ":" + options.port))]; / / add the client entry of webpack-dev-server to the bundle to achieve automatic refresh of if (options.hot) devClient.push ("webpack/hot/dev-server") / / here is the handling of hot configuration in webpack-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);}});}

The use of nodejs that meets the above three conditions is as follows:

Var config = require (". / webpack.config.js"); config.entry.app.unshift ("webpack-dev-server/client? http://localhost:8080/"," webpack/hot/dev-server "); / / condition 1 (client with webpack-dev-server and server with HMR) var compiler = webpack (config) Var server = new webpackDevServer (compiler, {hot: true / / condition 2 (--hot configuration, webpack-dev-server will automatically add HotModuleReplacementPlugin).}); server.listen (8080); webpack-dev-server starts the proxy agent

Webpack-dev-server usage

Http-proxy-middleware

To proxy the request to an external server, the sample configuration is as follows:

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}]

This kind of proxy is important in many cases, such as loading some static files through a local server, while some API requests are all done through a remote server. Another scenario is to split the request between two separate servers, such as one server for authorization and the other for the application itself. Here is an example encountered in daily development:

(1) A request is made through a relative path, such as the address "/ msg/show.htm". However, different domain names will be added in front of the daily and production environment, such as daily you.test.com and production environment you.inc.com.

(2) for example, now you want to start a webpack-dev-server locally, and then access the daily server through webpack-dev-server, and the daily server address is 11.160.119.131, so it will be done through the following configuration:

DevServer: {port: 8000, proxy: {"/ msg/show.htm": {target: "http://11.160.119.131/", secure: false}

At this point, when you request "/ msg/show.htm", the real URL address requested is "http//11.160.119.131/msg/show.htm".

(3) there is a problem in the development environment, that is: if the local devServer startup address is "http://30.11.160.255:8000/" or common" http://0.0.0.0:8000/", then the real server will return a URL to request login, but This problem does not exist when the local devServer is launched on the localhost (one possible reason is that the localhost is planted with the cookie needed by the backend, while other domain names are not planted with cookie, so that the proxy server does not have the corresponding cookie when accessing the daily server, thus requiring permission verification). The way to specify localhost can be through the

Wcf

Because wcf can be accessed by IP or localhost by default. Of course, you can do this by adding the following code:

DevServer: {port: 8000, host:'localhost', proxy: {"/ msg/show.htm": {target: "http://11.160.119.131/", secure: false}

(4) about the principle of webpack-dev-server, readers can check the information such as "why reverse proxy is called reverse proxy". In fact, forward proxy and reverse proxy can be summarized in one sentence: "forward proxy hides the real client, while reverse proxy hides the real server." Webpack-dev-server actually acts as a proxy server, and the communication between servers does not have the same origin strategy that is common in the front end, so when requesting webpack-dev-server, it will request data from the real server and send the data to your browser.

Browser = > localhost:8080 (webpack-dev-server has no agent) = > http://you.test.com browser = > localhost:8080 (webpack-dev-server has agent) = > http://you.test.com

The first case above is that there is no agent. In the localhost:8080 page, there is a homologous policy to access the http://you.test.com through the front-end policy, that is, the second step is to access another address through the front-end policy. But for the second case, the second step is actually done through the agent, that is, the communication between servers, there is no homologous policy problem. However, we visit the proxy server directly, and the proxy server returns a page, and some front-end requests (proxy, rewrite configuration) that meet the specific conditions in the page are all completed by the proxy server, so the homologous problem is solved by the proxy server.

(5) what is described above is that target is IP. If you want to specify target as a domain name, you may need to bind host. For example, the host bound below:

11.160.119.131 youku.min.com

Then the domain name can be used in the following proxy configuration:

DevServer: {port: 8000, proxy: {"/ msg/show.htm": {target: "http://youku.min.com/", secure: false}

This is exactly the same as the effect of binding target to an IP address. To sum up: "target specifies which host the request that satisfies a particular URL should correspond to, that is, the real host address that the proxy server should access."

In fact, proxy can also bypass a proxy as appropriate by configuring the return value of a bypass () function. This function can view HTTP requests and responses as well as options for some agents. It returns either a false or a path of a URL that will be used to process the request rather than using the original agent. The configuration of the following example ignores HTTP requests from the browser, which is similar to the historyApiFallback configuration. The browser request can receive the html file as usual, but the API request will be proxied to another server:

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';}

Requests for agents can also be overridden by providing a function that can view or change HTTP requests. The following example rewrites the HTTP request, and its main purpose is to remove the / api part in front of the URL.

Proxy: {'/ api': {target: 'https://other-server.example.com', pathRewrite: {' ^ / api':'}

Where the pathRewrite configuration comes from http-proxy-middleware. More configurations can be viewed.

Http-proxy-middleware official documentation.

HistoryApiFallback option

When using HTML 5's history API, you may want to use index.html as the requested resource when 404 appears, so you can use this configuration: historyApiFallback:true. However, if you modify the output.publicPath, you need to specify the redirected URL, and you can use the historyApiFallback.index option.

/ / output.publicPath:'/ foo-app/'historyApiFallback: {index:'/ foo-app/'}

Use the rewrite option to reset static resources

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'},],}

Use disableDotRule to satisfy a requirement that if a resource request contains a

. Symbol, which means that it is a request for a particular resource, which satisfies the dotRule. Let's see.

How connect-history-api-fallback is handled internally:

If (parsedUrl.pathname.indexOf ('.')! =-1 & & options.disableDotRule! = = true) {logger ('Not rewriting', req.method, req.url,' because the path includes a dot (.) Character.'); return next ();} rewriteTarget = options.index |'/ index.html'; logger ('Rewriting', req.method, req.url,' to', rewriteTarget); req.url = rewriteTarget; next ();}

In other words, if it is a request for absolute resources, that is, dotRule is satisfied, but disableDotRule (disable dot rule file request) is false, it means that we will handle the resources that meet dotRule by ourselves, so we don't have to direct to index.html! If disableDotRule is true, resources that satisfy dotRule will not be processed, so direct to index.html!

History ({disableDotRule: true}) webpack-dev-server more configuration var server = new WebpackDevServer (compiler, {contentBase: "/ path/to/directory", / / content-base configuration hot: true, / / enable HMR Send "webpackHotUpdate" message from webpack-dev-server to client code historyApiFallback: false, / / single page application 404 turns on index.html compress: true, / / enable gzip compression of resources proxy: {"* *": "http://localhost:9090"}, / / proxy configuration Originating from http-proxy-middleware setup: function (app) {/ / webpack-dev-server itself is Express server can add its own route / / app.get ('/ some/path', function (req, res) {/ / res.json ({custom: 'response'})) / /});}, / / configure the parameter http://expressjs.com/en/4x/api.html#express.static staticOptions for the express.static method of the Express server: {}, / / it is used to control the log level printed in the browser in inline mode, such as `error`, `warning`, `info` or `none`. ClientLogLevel: "info", / / do not print any log quiet: false in the console, / / do not output startup log noInfo: false, / / webpack does not listen for changes in files, and recompile lazy: true, / / file name filename: "bundle.js", / / watch configuration of webpack every time the request comes WatchOptions: {aggregateTimeout: 300, poll: 1000}, / / Virtual path mapping of output.path publicPath: "/ assets/", / / set custom http header headers: {"X-Custom-Header": "yes"}, / / package status information output configuration stats: {colors: true} / / configure https such as certificates required by 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 ()

The other configurations above are easy to understand except filename and lazy, so let's continue to analyze the specific usage scenarios of lazy and filename. We know that during the lazy phase, webpack-dev-server does not call the compiler.watch method, but waits for the request to be compiled. The source code is as follows:

StartWatch: function () {var options = context.options; var compiler = context.compiler; / / start watching if (! options.lazy) {var watching = compiler.watch (options.watchOptions, share.handleCompilerCallback); context.watching = watching / / context.watching gets the returned Watching object} else {/ / if it is lazy, it means that we are not listening to watching, but that context.state = true;} is compiled when the request is made.

Context.state is judged when rebuild is called. After each recompilation, context.state is reset to true in compiler.done!

Rebuild: function rebuild () {/ / if no Stats object has been generated through compiler.done, then set forceRebuild to true / / if there is already a Stats indicating that it has been previously build, then call the run method if (context.state) {context.state = false; / / lazy context.state is true, re-rebuild context.compiler.run (share.handleCompilerCallback);} else {context.forceRebuild = true }}

The following is that when the request comes, we call the above rebuild to continue the recompilation:

HandleRequest: function (filename, processRequest, req) {/ / in lazy mode, rebuild on bundle request if (context.options.lazy & (! context.options.filename | | context.options.filename.test (filename) share.rebuild (); / / if there is hash in filename, the file name is read from memory through fs, and the callback sends the message directly to the client! If (HASH_REGEXP.test (filename)) {try {if (context.fs.statSync (filename). IsFile ()) {processRequest (); return;}} catch (e) {}} share.ready (processRequest, req); / / callback function sends the file result to the client}

ProcessRequest sends the compiled resources directly to the client:

Function processRequest () {try {var stat = context.fs.statSync (filename); / / get the file name if (! stat.isFile ()) {if (stat.isDirectory ()) {filename = pathJoin (filename, context.options.index | | "index.html"); / / File name stat = context.fs.statSync (filename) If (! stat.isFile ()) throw "next";} else {throw "next";} catch (e) {return goNext ();} / / server content / / directly access the file so read, if it is a folder, then access the folder var content = context.fs.readFileSync (filename) Content = shared.handleRangeHeaders (content, req, res); res.setHeader ("Access-Control-Allow-Origin", "*"); / / To support XHR, etc. Res.setHeader ("Content-Type", mime.lookup (filename) + "; charset=UTF-8"); res.setHeader ("Content-Length", content.length) If (context.options.headers) {for (var name in context.options.headers) {res.setHeader (name, context.options.headers [name]);} / / Express automatically sets the statusCode to 200, but not all servers do (Koa). Res.statusCode = res.statusCode | | 200; if (res.send) res.send (content); else res.end (content);}}

So, in lazy mode, if we don't specify the file name filename, that is, the Webpack output file (chunk) that is requested each time, it will be re-rebuild every time! But if a file name is specified, it will only be rebuild if the file name is accessed!

Thank you for your reading, the above is the "core concepts of webpack-dev-server and thermal loading" content, after the study of this article, I believe you have a deeper understanding of the core concepts of webpack-dev-server and thermal loading this problem, the specific use of the situation also needs to be verified in practice. Here is, the editor will push for you more related knowledge points of the article, welcome to follow!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report