- Notifications
You must be signed in to change notification settings - Fork128
webpack dev server
Thewebpack-dev-server is a little Node.jsExpress server, which uses thewebpack-dev-middleware to serve awebpack bundle. It also has a little runtime which is connected to the server viaSock.js.
The server emits information about the compilation state to the client, which reacts to those events. You can choose between different modes, depending on your needs.
Let's say you have the following config file (webpack.config.js
):
varpath=require("path");module.exports={entry:{app:["./app/main.js"]},output:{path:path.resolve(__dirname,"build"),publicPath:"/assets/",filename:"bundle.js"}};
You have anapp
folder with your initial entry point thatwebpack will bundle into abundle.js
file in thebuild
folder.
NOTE: The webpack dev server is a separate NPM package. You can install it with:npm install webpack-dev-server
.
Thewebpack-dev-server will serve the files in the current directory, unless you configure a specific content base.
$ webpack-dev-server --content-base build/
Using this configuration,webpack-dev-server will serve the static files in yourbuild
folder. It'll watch your source files, and recompile the bundle whenever they are changed.
This modifiedbundle is served from memory at the relative path specified inpublicPath
(seeAPI). It will not be written to your configuredoutput
directory. Where abundle already exists at the same URL path, thebundle in memory takes precedence (by default).
Using the configuration above, thebundle is available atlocalhost:8080/assets/bundle.js
.
To load your bundled files, you will need to create anindex.html
file in thebuild
folder from which static files are served (--content-base
option). Here's an example:
<!DOCTYPE html><htmllang="en"><head><metacharset="UTF-8"><title>Document</title></head><body><scriptsrc="assets/bundle.js"></script></body></html>
By default, go tolocalhost:8080/
to launch your app. In this example's configuration (withpublicPath
), go tolocalhost:8080/assets/
.
Thewebpack-dev-server supports multiple modes to automatically refresh the page:
- Iframe mode (page is embedded in an
iframe
and reloaded on change) - Inline mode (a small webpack-dev-server client entry is added to the bundle which refreshes the page on change)
Each mode also supportsHot Module Replacement. In Hot Module Replacement, the bundle is notified that a change happened. Rather than a full page reload, a Hot Module Replacement runtime could then load the updated modules and inject them into a running app.
No additional configuration is needed to use the iframe mode. Just navigate the browser tohttp://«host»:«port»/webpack-dev-server/«path»
.
With the above configuration:http://localhost:8080/webpack-dev-server/index.html
.
- No configuration change needed.
- Nice information bar on top of your app.
- URL changes in the app arenot reflected in the browser's URL bar.
To use the inline mode, either
- specify
--inline
on the command line. - specify
devServer: { inline: true }
in yourwebpack.config.js
This adds the webpack-dev-server client entry point to the webpack configuration. There is no change in the URL required. Just navigate tohttp://«host»:«port»/«path»
.
With the above configuration:http://localhost:8080/index.html
.
- Config option or command line flag needed.
- Status information in the console and (briefly) in the browser's console log.
- URL changes in the app are reflected in the browser's URL bar.
There is noinline: true
flag in the webpack-dev-server configuration, because the webpack-dev-server module has no access to the webpack configuration. Instead, the user must add the webpack-dev-server client entry point to the webpack configuration.
To do this, simply add the following to all entry points:webpack-dev-server/client?http://«path»:«port»/
With the above configuration:
varconfig=require("./webpack.config.js");config.entry.app.unshift("webpack-dev-server/client?http://localhost:8080/");varcompiler=webpack(config);varserver=newWebpackDevServer(compiler,{...});server.listen(8080);
There is also the option to add a reference to the webpack-dev-server client script to the HTML page:
<scriptsrc="http://localhost:8080/webpack-dev-server.js"></script>
To enable Hot Module Replacement with the webpack-dev-server specify--hot
on the command line. This adds theHotModuleReplacementPlugin
to the webpack configuration.
The easiest way to use Hot Module Replacement with the webpack-dev-server is to use the inline mode.
Nothing more is needed.--inline --hot
does all the relevant work automatically. The CLI of the webpack-dev-server automatically adds the specialwebpack/hot/dev-server
entry point to your configuration.
Just navigate tohttp://«host»:«port»/«path»
and let the magic happen.
You should see the following messages in the browser log:
[HMR] Waiting for update signal from WDS...[WDS] Hot Module Replacement enabled.
Messages prefixed with[HMR]
originate from thewebpack/hot/dev-server
module. Messages prefixed with[WDS]
originate from the webpack-dev-server client.
It's important to specify a correctoutput.publicPath
otherwise the hot update chunks cannot be loaded.
Similar to the inline mode the user must make changes to the webpack configuration.
Three changes are needed:
- add an entry point to the webpack configuration:
webpack/hot/dev-server
. - add the
new webpack.HotModuleReplacementPlugin()
to the webpack configuration. - add
hot: true
to the webpack-dev-server configuration to enable HMR on the server.
With the above configuration:
varconfig=require("./webpack.config.js");config.entry.app.unshift("webpack-dev-server/client?http://localhost:8080/","webpack/hot/dev-server");varcompiler=webpack(config);varserver=newwebpackDevServer(compiler,{hot:true...});server.listen(8080);
Note that many editors support "safe write" feature and have it enabled by default, which makes dev server unable to watch files correctly. "Safe write" means changes are not written directly to original file but to temporary one instead, which is renamed and replaces original file when save operation is completed successfully. This behaviour causes file watcher to lose the track because the original file is removed. In order to prevent this issue, you have to disable "safe write" feature in your editor.
- VIM - set
:set backupcopy=yes
(see documentation) - IntelliJ -Settings ▶︎ System Settings ▶︎ Synchronization ▶︎ disable
safe write
(may differ in various IntelliJ IDEs, but you can still use the search feature)
The Webpack dev server makes use ofhttp-proxy-middleware to optionally proxy requests to a separate, possibly external, backend server. A sample configuration is below.
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}]
See thehttp-proxy-middleware Options documentation for available configuration.
Proxying some URLs can be useful for a variety of configurations. One example is to serve JavaScript files and other static assets from the local development server but still send API requests to an external backend development server. Another example is splitting requests between two separate backend servers such as an authentication backend and a application backend.
(Added in v1.13.0) The proxy can be optionally bypassed based on the return from a function. The function can inspect the HTTP request, response, and any given proxy options. It must return eitherfalse
or a URL path that will be servedinstead of continuing to proxy the request.
For example, the configuration below will not proxy HTTP requests that originate from a browser. This is similar to thehistoryApiFallback
option: browser requests will receive the HTML file as normal but API requests will be proxied to the backend 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';}}}}
(Added in v1.15.0) The request to the proxy can be optionally rewritten by providing a function. The function can inspect and change the HTTP request.
For example, the configuration below will rewrite the HTTP requests to remove the part/api
at the beginning of the URL.
proxy:{'/api':{target:'https://other-server.example.com',pathRewrite:{'^/api' :''}}}
Note thatpathRewrite
is a feature from http-proxy-middleware, so check outtheir docs for more configuration.
It seems thathttp-proxy-middleware
pre-resolves the local hostnames intolocalhost
, you will need the following config to fix the proxy request:
varserver=newwebpackDevServer(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<entry>
AllwebpackCLI options are valid for thewebpack-dev-server CLI too, but there is no<output>
default argument. For thewebpack-dev-server CLI awebpack.config.js
(or the file passed by the--config
option) is accepted as well.
There are some additional options:
--content-base <file/directory/url/port>
: base path for the content.--quiet
: don't output anything to the console.--no-info
: suppress boring information.--colors
: add some colors to the output.--no-colors
: don't use colors in the output.--compress
: use gzip compression.--host <hostname/ip>
: hostname or IP.0.0.0.0
binds to all hosts.--port <number>
: port.--inline
: embed thewebpack-dev-server runtime into thebundle.--hot
: adds theHotModuleReplacementPlugin
and switch the server tohot mode. Note: make sure you don't addHotModuleReplacementPlugin
twice.--hot --inline
also adds thewebpack/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
: serveswebpack-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. Useerror
,warning
,info
ornone
.
When using the CLI it's possible to have the webpack-dev-server options in the configuration file under the keydevServer
. Options passed via CLI arguments override options in configuration file. For options underdevServer
see next section.
Example
module.exports={// ...devServer:{hot:true}}
varWebpackDevServer=require("webpack-dev-server");varwebpack=require("webpack");varfs=require("fs");varcompiler=webpack({// configuration});varserver=newWebpackDevServer(compiler,{// webpack-dev-server optionscontentBase:"/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 assetsproxy:{"**":"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 serverstaticOptions:{},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 optionsquiet: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();
Seewebpack-dev-middleware for documentation on middleware options.
Notice thatwebpack configuration is not passed toWebpackDevServer
API, thusdevServer
option in webpack configuration is not used in this case. Also, there is noinline mode forWebpackDevServer
API.<script src="http://localhost:8080/webpack-dev-server.js"></script>
should be inserted to HTML page manually.
If you are using the HTML5 history API you probably need to serve yourindex.html
in place of 404 responses, which can be done by settinghistoryApiFallback: true
. However, if you have modifiedoutput.publicPath
in your Webpack configuration, you need to specify the URL to redirect to. This is done using thehistoryApiFallback.index
option:
// output.publicPath: '/foo-app/'historyApiFallback: { index: '/foo-app/'}
Using rewrites, it is also possible to use this feature to serve static pages:
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'},],},
You may want to run a backend server or a mock of it in development. You shouldnot use thewebpack-dev-server as a backend. Its only purpose is to serve static (webpacked) assets.
You can run two servers side-by-side: Thewebpack-dev-server and your backend server.
In this case you need to teach the webpack-generated assets to make requests to thewebpack-dev-server even when running on a HTML-page sent by the backend server. On the other side you need to teach your backend server to generate HTML pages that includescript
tags that point to assets on thewebpack-dev-server. In addition to that you need a connection between thewebpack-dev-server and thewebpack-dev-server runtime to trigger reloads on recompilation.
To teachwebpack to make requests (for chunk loading or HMR) to thewebpack-dev-server you need to providea full URL in theoutput.publicPath
option.
To make a connection betweenwebpack-dev-server and its runtime best, use theinline mode with--inline
. Thewebpack-dev-server CLI automatically includes an entry point which establishes a WebSocket connection. (You can also use theiframe mode if you point--content-base
of thewebpack-dev-server to your backend server.If you need a websocket connection to your backend server, you'll have to use iframe mode.
When you use theinline mode just open the backend server URL in your web browsers. (If you use theiframe mode open the/webpack-dev-server/
prefixed URL of thewebpack-dev-server.)
Summary and example:
- webpack-dev-server on port
8080
. - backend server on port
9090
. - generate HTML pages with
<script src="http://localhost:8080/assets/bundle.js">
. - webpack configuration with
output.publicPath = "http://localhost:8080/assets/"
. - when compiling files for production, use
--output-public-path /assets/
. - inline mode:
--inline
.- open
http://localhost:9090
.
- oriframe mode:
- webpack-dev-server
contentBase = "http://localhost:9090/"
(--content-base
). - open
http://localhost:8080/webpack-dev-server/
.
- webpack-dev-server
Or use the proxy option...
webpack 👍