diff --git a/src/Microsoft.AspNetCore.SpaServices/README.md b/src/Microsoft.AspNetCore.SpaServices/README.md index 43ffca2..c91b6be 100644 --- a/src/Microsoft.AspNetCore.SpaServices/README.md +++ b/src/Microsoft.AspNetCore.SpaServices/README.md @@ -633,6 +633,21 @@ Webpack has built-in HMR support for various types of module, such as styles and This is [documented in detail on the Webpack site](https://webpack.github.io/docs/hot-module-replacement.html). Or to get a working HMR-enabled ASP.NET Core site with Angular 2, React, React+Redux, or Knockout, you can use the [aspnetcore-spa generator](http://blog.stevensanderson.com/2016/05/02/angular2-react-knockout-apps-on-aspnet-core/). +#### Passing options to the Webpack Hot Middleware client + +You can configure the [Webpack Hot Middleware client](https://github.com/glenjamin/webpack-hot-middleware#client) +by modifying your `UseWebpackDevMiddleware` call to include `HotModuleReplacementClientOptions`: + +```csharp +app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions { + HotModuleReplacement = true, + HotModuleReplacementClientOptions = new Dictionary { + { "reload", "true" }, + }, +}); +``` + +**Note**: The `path` option will be ignored, because it is controlled by the `HotModuleReplacementEndpoint` setting. ## Routing helper: MapSpaFallbackRoute diff --git a/src/Microsoft.AspNetCore.SpaServices/Webpack/WebpackDevMiddlewareOptions.cs b/src/Microsoft.AspNetCore.SpaServices/Webpack/WebpackDevMiddlewareOptions.cs index f94a8d2..fa45321 100644 --- a/src/Microsoft.AspNetCore.SpaServices/Webpack/WebpackDevMiddlewareOptions.cs +++ b/src/Microsoft.AspNetCore.SpaServices/Webpack/WebpackDevMiddlewareOptions.cs @@ -30,6 +30,11 @@ namespace Microsoft.AspNetCore.SpaServices.Webpack /// public bool ReactHotModuleReplacement { get; set; } + /// + /// Specifies additional options to be passed to the Webpack Hot Middleware client + /// + public IDictionary HotModuleReplacementClientOptions { get; set; } + /// /// Specifies the Webpack configuration file to be used. If not set, defaults to 'webpack.config.js'. /// diff --git a/src/Microsoft.AspNetCore.SpaServices/npm/aspnet-webpack/src/WebpackDevMiddleware.ts b/src/Microsoft.AspNetCore.SpaServices/npm/aspnet-webpack/src/WebpackDevMiddleware.ts index b07dbd1..26bf6b2 100644 --- a/src/Microsoft.AspNetCore.SpaServices/npm/aspnet-webpack/src/WebpackDevMiddleware.ts +++ b/src/Microsoft.AspNetCore.SpaServices/npm/aspnet-webpack/src/WebpackDevMiddleware.ts @@ -3,6 +3,7 @@ import * as webpack from 'webpack'; import * as url from 'url'; import * as fs from 'fs'; import * as path from 'path'; +import * as querystring from 'querystring'; import { requireNewCopy } from './RequireNewCopy'; export type CreateDevServerResult = { @@ -26,6 +27,7 @@ interface CreateDevServerOptions { interface DevServerOptions { HotModuleReplacement: boolean; HotModuleReplacementServerPort: number; + HotModuleReplacementClientOptions: Object; ReactHotModuleReplacement: boolean; } @@ -37,7 +39,7 @@ interface WebpackConfigFunc { } type WebpackConfigFileExport = WebpackConfigOrArray | WebpackConfigFunc; -function attachWebpackDevMiddleware(app: any, webpackConfig: webpack.Configuration, enableHotModuleReplacement: boolean, enableReactHotModuleReplacement: boolean, hmrClientEndpoint: string, hmrServerEndpoint: string) { +function attachWebpackDevMiddleware(app: any, webpackConfig: webpack.Configuration, enableHotModuleReplacement: boolean, enableReactHotModuleReplacement: boolean, hmrClientOptions: HotModuleReplacementClientOptions, hmrClientEndpoint: string, hmrServerEndpoint: string) { // Build the final Webpack config based on supplied options if (enableHotModuleReplacement) { // For this, we only support the key/value config format, not string or string[], since @@ -53,7 +55,8 @@ function attachWebpackDevMiddleware(app: any, webpackConfig: webpack.Configurati // Augment all entry points so they support HMR (unless they already do) Object.getOwnPropertyNames(entryPoints).forEach(entryPointName => { const webpackHotMiddlewareEntryPoint = 'webpack-hot-middleware/client'; - const webpackHotMiddlewareOptions = `?path=` + encodeURIComponent(hmrClientEndpoint); + hmrClientOptions.path = hmrClientEndpoint; + const webpackHotMiddlewareOptions = '?' + querystring.stringify(hmrClientOptions); if (typeof entryPoints[entryPointName] === 'string') { entryPoints[entryPointName] = [webpackHotMiddlewareEntryPoint + webpackHotMiddlewareOptions, entryPoints[entryPointName]]; } else if (firstIndexOfStringStartingWith(entryPoints[entryPointName], webpackHotMiddlewareEntryPoint) < 0) { @@ -225,6 +228,7 @@ export function createWebpackDevServer(callback: CreateDevServerCallback, option const enableHotModuleReplacement = options.suppliedOptions.HotModuleReplacement; const enableReactHotModuleReplacement = options.suppliedOptions.ReactHotModuleReplacement; + const hmrClientOptions = options.suppliedOptions.HotModuleReplacementClientOptions || {}; if (enableReactHotModuleReplacement && !enableHotModuleReplacement) { callback('To use ReactHotModuleReplacement, you must also enable the HotModuleReplacement option.', null); return; @@ -263,7 +267,7 @@ export function createWebpackDevServer(callback: CreateDevServerCallback, option || `http://localhost:${listener.address().port}/__webpack_hmr`; // Fall back on absolute URL to bypass proxying const hmrServerEndpoint = options.hotModuleReplacementEndpointUrl || '/__webpack_hmr'; // URL is relative to webpack dev server root - attachWebpackDevMiddleware(app, webpackConfig, enableHotModuleReplacement, enableReactHotModuleReplacement, hmrClientEndpoint, hmrServerEndpoint); + attachWebpackDevMiddleware(app, webpackConfig, enableHotModuleReplacement, enableReactHotModuleReplacement, hmrClientOptions, hmrClientEndpoint, hmrServerEndpoint); } });