|
7 | 7 | using Microsoft.AspNetCore.Hosting; |
8 | 8 | using Microsoft.Extensions.PlatformAbstractions; |
9 | 9 | using Newtonsoft.Json; |
| 10 | +using System.Threading; |
10 | 11 |
|
11 | 12 | // Putting in this namespace so it's always available whenever MapRoute is |
12 | 13 |
|
13 | 14 | namespace Microsoft.AspNetCore.Builder |
14 | 15 | { |
15 | 16 | public static class WebpackDevMiddleware |
16 | 17 | { |
17 | | - private const string WebpackDevMiddlewareScheme = "http"; |
18 | | - private const string WebpackHotMiddlewareEndpoint = "/__webpack_hmr"; |
19 | 18 | private const string DefaultConfigFile = "webpack.config.js"; |
20 | 19 |
|
21 | 20 | public static void UseWebpackDevMiddleware( |
@@ -62,30 +61,27 @@ public static void UseWebpackDevMiddleware( |
62 | 61 | JsonConvert.SerializeObject(devServerOptions)).Result; |
63 | 62 |
|
64 | 63 | // Proxy the corresponding requests through ASP.NET and into the Node listener |
| 64 | + // Anything under /<publicpath> (e.g., /dist) is proxied as a normal HTTP request with a typical timeout (100s is the default from HttpClient), |
| 65 | + // plus /__webpack_hmr is proxied with infinite timeout, because it's an EventSource (long-lived request). |
| 66 | + appBuilder.UseProxyToLocalWebpackDevMiddleware(devServerInfo.PublicPath, devServerInfo.Port, TimeSpan.FromSeconds(100)); |
| 67 | + appBuilder.UseProxyToLocalWebpackDevMiddleware("/__webpack_hmr", devServerInfo.Port, Timeout.InfiniteTimeSpan); |
| 68 | + } |
| 69 | + |
| 70 | + private static void UseProxyToLocalWebpackDevMiddleware(this IApplicationBuilder appBuilder, string publicPath, int proxyToPort, TimeSpan requestTimeout) |
| 71 | + { |
65 | 72 | // Note that this is hardcoded to make requests to "localhost" regardless of the hostname of the |
66 | 73 | // server as far as the client is concerned. This is because ConditionalProxyMiddlewareOptions is |
67 | 74 | // the one making the internal HTTP requests, and it's going to be to some port on this machine |
68 | 75 | // because aspnet-webpack hosts the dev server there. We can't use the hostname that the client |
69 | 76 | // sees, because that could be anything (e.g., some upstream load balancer) and we might not be |
70 | 77 | // able to make outbound requests to it from here. |
71 | | - var proxyOptions = new ConditionalProxyMiddlewareOptions(WebpackDevMiddlewareScheme, |
72 | | - "localhost", devServerInfo.Port.ToString()); |
73 | | - appBuilder.UseMiddleware<ConditionalProxyMiddleware>(devServerInfo.PublicPath, proxyOptions); |
74 | | - |
75 | | - // While it would be nice to proxy the /__webpack_hmr requests too, these return an EventStream, |
76 | | - // and the Microsoft.AspNetCore.Proxy code doesn't handle that entirely - it throws an exception after |
77 | | - // a while. So, just serve a 302 for those. But note that we must use the hostname that the client |
78 | | - // sees, not "localhost", so that it works even when you're not running on localhost (e.g., Docker). |
79 | | - appBuilder.Map(WebpackHotMiddlewareEndpoint, builder => |
80 | | - { |
81 | | - builder.Use(next => ctx => |
82 | | - { |
83 | | - var hostname = ctx.Request.Host.Host; |
84 | | - ctx.Response.Redirect( |
85 | | - $"{WebpackDevMiddlewareScheme}://{hostname}:{devServerInfo.Port.ToString()}{WebpackHotMiddlewareEndpoint}"); |
86 | | - return Task.FromResult(0); |
87 | | - }); |
88 | | - }); |
| 78 | + // Also note that the webpack HMR service always uses HTTP, even if your app server uses HTTPS, |
| 79 | + // because the HMR service has no need for HTTPS (the client doesn't see it directly - all traffic |
| 80 | + // to it is proxied), and the HMR service couldn't use HTTPS anyway (in general it wouldn't have |
| 81 | + // the necessary certificate). |
| 82 | + var proxyOptions = new ConditionalProxyMiddlewareOptions( |
| 83 | + "http", "localhost", proxyToPort.ToString(), requestTimeout); |
| 84 | + appBuilder.UseMiddleware<ConditionalProxyMiddleware>(publicPath, proxyOptions); |
89 | 85 | } |
90 | 86 |
|
91 | 87 | #pragma warning disable CS0649 |
|
0 commit comments