Skip to content

Commit 2241c55

Browse files
Support for array-style webpack configs in aspnet-webpack. Fixesaspnet#291.
1 parent 85eba9c commit 2241c55

File tree

3 files changed

+105
-68
lines changed

3 files changed

+105
-68
lines changed

‎src/Microsoft.AspNetCore.SpaServices/Webpack/WebpackDevMiddleware.cs‎

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,20 @@ public static void UseWebpackDevMiddleware(
5858
vardevServerOptions=new
5959
{
6060
webpackConfigPath=Path.Combine(nodeServicesOptions.ProjectPath,options.ConfigFile??DefaultConfigFile),
61-
suppliedOptions=options
61+
suppliedOptions=options,
62+
understandsMultiplePublicPaths=true
6263
};
6364
vardevServerInfo=
6465
nodeServices.InvokeExportAsync<WebpackDevServerInfo>(nodeScript.FileName,"createWebpackDevServer",
6566
JsonConvert.SerializeObject(devServerOptions)).Result;
6667

68+
// Older versions of aspnet-webpack just returned a single 'publicPath', but now we support multiple
69+
if(devServerInfo.PublicPaths==null)
70+
{
71+
thrownewInvalidOperationException(
72+
"To enable Webpack dev middleware, you must update to a newer version of the aspnet-webpack NPM package.");
73+
}
74+
6775
// Proxy the corresponding requests through ASP.NET and into the Node listener
6876
// Note that this is hardcoded to make requests to "localhost" regardless of the hostname of the
6977
// server as far as the client is concerned. This is because ConditionalProxyMiddlewareOptions is
@@ -73,7 +81,10 @@ public static void UseWebpackDevMiddleware(
7381
// able to make outbound requests to it from here.
7482
varproxyOptions=newConditionalProxyMiddlewareOptions(WebpackDevMiddlewareScheme,
7583
"localhost",devServerInfo.Port.ToString());
76-
appBuilder.UseMiddleware<ConditionalProxyMiddleware>(devServerInfo.PublicPath,proxyOptions);
84+
foreach(varpublicPathindevServerInfo.PublicPaths)
85+
{
86+
appBuilder.UseMiddleware<ConditionalProxyMiddleware>(publicPath,proxyOptions);
87+
}
7788

7889
// While it would be nice to proxy the /__webpack_hmr requests too, these return an EventStream,
7990
// and the Microsoft.AspNetCore.Proxy code doesn't handle that entirely - it throws an exception after
@@ -95,7 +106,7 @@ public static void UseWebpackDevMiddleware(
95106
classWebpackDevServerInfo
96107
{
97108
publicintPort{get;set;}
98-
publicstringPublicPath{get;set;}
109+
publicstring[]PublicPaths{get;set;}
99110
}
100111
}
101112
#pragma warning restore CS0649

‎src/Microsoft.AspNetCore.SpaServices/npm/aspnet-webpack/package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "aspnet-webpack",
3-
"version": "1.0.14",
3+
"version": "1.0.15",
44
"description": "Helpers for using Webpack in ASP.NET Core projects. Works in conjunction with the Microsoft.AspNetCore.SpaServices NuGet package.",
55
"main": "index.js",
66
"scripts":{

‎src/Microsoft.AspNetCore.SpaServices/npm/aspnet-webpack/src/WebpackDevMiddleware.ts‎

Lines changed: 90 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@ import * as url from 'url'
44
import{requireNewCopy}from'./RequireNewCopy';
55

66
exportinterfaceCreateDevServerCallback{
7-
(error: any,result: {Port: number,PublicPath: string}): void;
7+
(error: any,result: {Port: number,PublicPaths: string[]}): void;
88
}
99

1010
// These are the options passed by WebpackDevMiddleware.cs
1111
interfaceCreateDevServerOptions{
12+
understandsMultiplePublicPaths: boolean;// For checking that the NuGet package is recent enough. Can be removed when we no longer need back-compatibility.
1213
webpackConfigPath: string;
1314
suppliedOptions: DevServerOptions;
1415
}
@@ -20,11 +21,83 @@ interface DevServerOptions{
2021
ReactHotModuleReplacement: boolean;
2122
}
2223

24+
functionattachWebpackDevMiddleware(app: any,webpackConfig: webpack.Configuration,enableHotModuleReplacement: boolean,enableReactHotModuleReplacement: boolean){
25+
// Build the final Webpack config based on supplied options
26+
if(enableHotModuleReplacement){
27+
// For this, we only support the key/value config format, not string or string[], since
28+
// those ones don't clearly indicate what the resulting bundle name will be
29+
constentryPoints=webpackConfig.entry;
30+
constisObjectStyleConfig=entryPoints
31+
&&typeofentryPoints==='object'
32+
&&!(entryPointsinstanceofArray);
33+
if(!isObjectStyleConfig){
34+
thrownewError('To use HotModuleReplacement, your webpack config must specify an \'entry\' value as a key-value object (e.g., "entry:{main: \'ClientApp/boot-client.ts\'}")');
35+
}
36+
37+
// Augment all entry points so they support HMR
38+
Object.getOwnPropertyNames(entryPoints).forEach(entryPointName=>{
39+
if(typeofentryPoints[entryPointName]==='string'){
40+
entryPoints[entryPointName]=['webpack-hot-middleware/client',entryPoints[entryPointName]];
41+
}else{
42+
entryPoints[entryPointName].unshift('webpack-hot-middleware/client');
43+
}
44+
});
45+
46+
webpackConfig.plugins=webpackConfig.plugins||[];
47+
webpackConfig.plugins.push(
48+
newwebpack.HotModuleReplacementPlugin()
49+
);
50+
51+
// Set up React HMR support if requested. This requires the 'aspnet-webpack-react' package.
52+
if(enableReactHotModuleReplacement){
53+
letaspNetWebpackReactModule: any;
54+
try{
55+
aspNetWebpackReactModule=require('aspnet-webpack-react');
56+
}catch(ex){
57+
thrownewError('ReactHotModuleReplacement failed because of an error while loading \'aspnet-webpack-react\'. Error was: '+ex.stack);
58+
}
59+
60+
aspNetWebpackReactModule.addReactHotModuleReplacementBabelTransform(webpackConfig);
61+
}
62+
}
63+
64+
// Attach Webpack dev middleware and optional 'hot' middleware
65+
constcompiler=webpack(webpackConfig);
66+
app.use(require('webpack-dev-middleware')(compiler,{
67+
noInfo: true,
68+
publicPath: webpackConfig.output.publicPath
69+
}));
70+
71+
if(enableHotModuleReplacement){
72+
letwebpackHotMiddlewareModule;
73+
try{
74+
webpackHotMiddlewareModule=require('webpack-hot-middleware');
75+
}catch(ex){
76+
thrownewError('HotModuleReplacement failed because of an error while loading \'webpack-hot-middleware\'. Error was: '+ex.stack);
77+
}
78+
app.use(webpackHotMiddlewareModule(compiler));
79+
}
80+
}
81+
2382
exportfunctioncreateWebpackDevServer(callback: CreateDevServerCallback,optionsJson: string){
2483
constoptions: CreateDevServerOptions=JSON.parse(optionsJson);
25-
constwebpackConfig: webpack.Configuration=requireNewCopy(options.webpackConfigPath);
26-
constpublicPath=(webpackConfig.output.publicPath||'').trim();
27-
if(!publicPath){
84+
85+
if(!options.understandsMultiplePublicPaths){
86+
callback('To use Webpack dev server, you must update to a newer version of the Microsoft.AspNetCore.SpaServices package',null);
87+
return;
88+
}
89+
90+
// Read the webpack config's export, and normalize it into the more general 'array of configs' format
91+
letwebpackConfigArray: webpack.Configuration[]=requireNewCopy(options.webpackConfigPath);
92+
if(!(webpackConfigArrayinstanceofArray)){
93+
webpackConfigArray=[webpackConfigArrayaswebpack.Configuration];
94+
}
95+
96+
// Check that at least one of the configurations specifies a publicPath. Those are the only ones we'll
97+
// enable middleware for, and if there aren't any, you must be making a mistake.
98+
constwebpackConfigsWithPublicPath=webpackConfigArray
99+
.filter(webpackConfig=>(webpackConfig.output.publicPath||'').trim()!=='');
100+
if(webpackConfigsWithPublicPath.length===0){
28101
callback('To use the Webpack dev server, you must specify a value for \'publicPath\' on the \'output\' section of your webpack.config.',null);
29102
return;
30103
}
@@ -41,69 +114,22 @@ export function createWebpackDevServer(callback: CreateDevServerCallback, option
41114

42115
constapp=connect();
43116
constlistener=app.listen(suggestedHMRPortOrZero,()=>{
44-
// Build the final Webpack config based on supplied options
45-
if(enableHotModuleReplacement){
46-
// For this, we only support the key/value config format, not string or string[], since
47-
// those ones don't clearly indicate what the resulting bundle name will be
48-
constentryPoints=webpackConfig.entry;
49-
constisObjectStyleConfig=entryPoints
50-
&&typeofentryPoints==='object'
51-
&&!(entryPointsinstanceofArray);
52-
if(!isObjectStyleConfig){
53-
callback('To use HotModuleReplacement, your webpack config must specify an \'entry\' value as a key-value object (e.g., "entry:{main: \'ClientApp/boot-client.ts\'}")',null);
54-
return;
55-
}
56-
57-
// Augment all entry points so they support HMR
58-
Object.getOwnPropertyNames(entryPoints).forEach(entryPointName=>{
59-
if(typeofentryPoints[entryPointName]==='string'){
60-
entryPoints[entryPointName]=['webpack-hot-middleware/client',entryPoints[entryPointName]];
61-
}else{
62-
entryPoints[entryPointName].unshift('webpack-hot-middleware/client');
63-
}
117+
try{
118+
// For each webpack config that specifies a public path, add webpack dev middleware for it
119+
webpackConfigsWithPublicPath.forEach(webpackConfig=>{
120+
attachWebpackDevMiddleware(app,webpackConfig,enableHotModuleReplacement,enableReactHotModuleReplacement);
64121
});
65122

66-
webpackConfig.plugins.push(
67-
newwebpack.HotModuleReplacementPlugin()
68-
);
69-
70-
// Set up React HMR support if requested. This requires the 'aspnet-webpack-react' package.
71-
if(enableReactHotModuleReplacement){
72-
letaspNetWebpackReactModule: any;
73-
try{
74-
aspNetWebpackReactModule=require('aspnet-webpack-react');
75-
}catch(ex){
76-
callback('ReactHotModuleReplacement failed because of an error while loading \'aspnet-webpack-react\'. Error was: '+ex.stack,null);
77-
return;
78-
}
79-
80-
aspNetWebpackReactModule.addReactHotModuleReplacementBabelTransform(webpackConfig);
81-
}
82-
}
83-
84-
// Attach Webpack dev middleware and optional 'hot' middleware
85-
constcompiler=webpack(webpackConfig);
86-
app.use(require('webpack-dev-middleware')(compiler,{
87-
noInfo: true,
88-
publicPath: publicPath
89-
}));
90-
91-
if(enableHotModuleReplacement){
92-
letwebpackHotMiddlewareModule;
93-
try{
94-
webpackHotMiddlewareModule=require('webpack-hot-middleware');
95-
}catch(ex){
96-
callback('HotModuleReplacement failed because of an error while loading \'webpack-hot-middleware\'. Error was: '+ex.stack,null);
97-
return;
98-
}
99-
app.use(webpackHotMiddlewareModule(compiler));
123+
// Tell the ASP.NET app what addresses we're listening on, so that it can proxy requests here
124+
callback(null,{
125+
Port: listener.address().port,
126+
PublicPaths: webpackConfigsWithPublicPath.map(webpackConfig=>
127+
removeTrailingSlash(getPath(webpackConfig.output.publicPath))
128+
)
129+
});
130+
}catch(ex){
131+
callback(ex.stack,null);
100132
}
101-
102-
// Tell the ASP.NET app what addresses we're listening on, so that it can proxy requests here
103-
callback(null,{
104-
Port: listener.address().port,
105-
PublicPath: removeTrailingSlash(getPath(publicPath))
106-
});
107133
});
108134
}
109135

0 commit comments

Comments
(0)