mirror of
https://github.com/aspnet/JavaScriptServices.git
synced 2025-12-23 01:58:29 +00:00
WebpackDevMiddleware should run in a separate Node instance that doesn't restart when files change (otherwise there's no point in running it at all)
This commit is contained in:
@@ -34,7 +34,10 @@ namespace Microsoft.AspNet.AngularServices
|
||||
// in your startup file, but then again it might be confusing that you don't need to.
|
||||
if (this.nodeServices == null) {
|
||||
var appEnv = (IApplicationEnvironment)serviceProvider.GetService(typeof (IApplicationEnvironment));
|
||||
this.nodeServices = fallbackNodeServices = Configuration.CreateNodeServices(NodeHostingModel.Http, appEnv.ApplicationBasePath);
|
||||
this.nodeServices = fallbackNodeServices = Configuration.CreateNodeServices(new NodeServicesOptions {
|
||||
HostingModel = NodeHostingModel.Http,
|
||||
ProjectPath = appEnv.ApplicationBasePath
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,24 +3,40 @@ using Microsoft.Extensions.PlatformAbstractions;
|
||||
|
||||
namespace Microsoft.AspNet.NodeServices {
|
||||
public static class Configuration {
|
||||
public static void AddNodeServices(this IServiceCollection serviceCollection, NodeHostingModel hostingModel = NodeHostingModel.Http) {
|
||||
private static string[] defaultWatchFileExtensions = new[] { ".js", ".jsx", ".ts", ".tsx", ".json", ".html" };
|
||||
|
||||
public static void AddNodeServices(this IServiceCollection serviceCollection, NodeServicesOptions options) {
|
||||
serviceCollection.AddSingleton(typeof(INodeServices), (serviceProvider) => {
|
||||
var appEnv = serviceProvider.GetRequiredService<IApplicationEnvironment>();
|
||||
return CreateNodeServices(hostingModel, appEnv.ApplicationBasePath);
|
||||
if (string.IsNullOrEmpty(options.ProjectPath)) {
|
||||
options.ProjectPath = appEnv.ApplicationBasePath;
|
||||
}
|
||||
return CreateNodeServices(options);
|
||||
});
|
||||
}
|
||||
|
||||
public static INodeServices CreateNodeServices(NodeHostingModel hostingModel, string projectPath)
|
||||
public static INodeServices CreateNodeServices(NodeServicesOptions options)
|
||||
{
|
||||
switch (hostingModel)
|
||||
var watchFileExtensions = options.WatchFileExtensions ?? defaultWatchFileExtensions;
|
||||
switch (options.HostingModel)
|
||||
{
|
||||
case NodeHostingModel.Http:
|
||||
return new HttpNodeInstance(projectPath);
|
||||
return new HttpNodeInstance(options.ProjectPath, /* port */ 0, watchFileExtensions);
|
||||
case NodeHostingModel.InputOutputStream:
|
||||
return new InputOutputStreamNodeInstance(projectPath);
|
||||
return new InputOutputStreamNodeInstance(options.ProjectPath);
|
||||
default:
|
||||
throw new System.ArgumentException("Unknown hosting model: " + hostingModel.ToString());
|
||||
throw new System.ArgumentException("Unknown hosting model: " + options.HostingModel.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class NodeServicesOptions {
|
||||
public NodeHostingModel HostingModel { get; set; }
|
||||
public string ProjectPath { get; set; }
|
||||
public string[] WatchFileExtensions { get; set; }
|
||||
|
||||
public NodeServicesOptions() {
|
||||
this.HostingModel = NodeHostingModel.Http;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,12 @@
|
||||
// but simplifies things for the consumer of this module.
|
||||
var http = require('http');
|
||||
var path = require('path');
|
||||
var requestedPortOrZero = parseInt(process.argv[2]) || 0; // 0 means 'let the OS decide'
|
||||
var parsedArgs = parseArgs(process.argv);
|
||||
var requestedPortOrZero = parsedArgs.port || 0; // 0 means 'let the OS decide'
|
||||
|
||||
autoQuitOnFileChange(process.cwd(), ['.js', '.jsx', '.ts', '.tsx', '.json', '.html']);
|
||||
if (parsedArgs.watch) {
|
||||
autoQuitOnFileChange(process.cwd(), parsedArgs.watch.split(','));
|
||||
}
|
||||
|
||||
var server = http.createServer(function(req, res) {
|
||||
readRequestBodyAsJson(req, function(bodyJson) {
|
||||
@@ -75,3 +78,22 @@ function autoQuitOnFileChange(rootDir, extensions) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function parseArgs(args) {
|
||||
// Very simplistic parsing which is sufficient for the cases needed. We don't want to bring in any external
|
||||
// dependencies (such as an args-parsing library) to this file.
|
||||
var result = {};
|
||||
var currentKey = null;
|
||||
args.forEach(function(arg) {
|
||||
if (arg.indexOf('--') === 0) {
|
||||
var argName = arg.substring(2);
|
||||
result[argName] = undefined;
|
||||
currentKey = argName;
|
||||
} else if (currentKey) {
|
||||
result[currentKey] = arg;
|
||||
currentKey = null;
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -17,11 +17,19 @@ namespace Microsoft.AspNet.NodeServices {
|
||||
|
||||
private int _portNumber;
|
||||
|
||||
public HttpNodeInstance(string projectPath, int port = 0)
|
||||
: base(EmbeddedResourceReader.Read(typeof(HttpNodeInstance), "/Content/Node/entrypoint-http.js"), projectPath, port.ToString())
|
||||
public HttpNodeInstance(string projectPath, int port = 0, string[] watchFileExtensions = null)
|
||||
: base(EmbeddedResourceReader.Read(typeof(HttpNodeInstance), "/Content/Node/entrypoint-http.js"), projectPath, MakeCommandLineOptions(port, watchFileExtensions))
|
||||
{
|
||||
}
|
||||
|
||||
private static string MakeCommandLineOptions(int port, string[] watchFileExtensions) {
|
||||
var result = "--port " + port.ToString();
|
||||
if (watchFileExtensions != null && watchFileExtensions.Length > 0) {
|
||||
result += " --watch " + string.Join(",", watchFileExtensions);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public override async Task<T> Invoke<T>(NodeInvocationInfo invocationInfo) {
|
||||
await this.EnsureReady();
|
||||
|
||||
|
||||
@@ -36,7 +36,10 @@ namespace Microsoft.AspNet.SpaServices.Prerendering
|
||||
// in your startup file, but then again it might be confusing that you don't need to.
|
||||
if (this.nodeServices == null) {
|
||||
var appEnv = (IApplicationEnvironment)serviceProvider.GetService(typeof(IApplicationEnvironment));
|
||||
this.nodeServices = fallbackNodeServices = Configuration.CreateNodeServices(NodeHostingModel.Http, appEnv.ApplicationBasePath);
|
||||
this.nodeServices = fallbackNodeServices = Configuration.CreateNodeServices(new NodeServicesOptions {
|
||||
HostingModel = NodeHostingModel.Http,
|
||||
ProjectPath = appEnv.ApplicationBasePath
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,8 +15,6 @@ namespace Microsoft.AspNet.Builder
|
||||
const string WebpackDevMiddlewareHostname = "localhost";
|
||||
const string WebpackHotMiddlewareEndpoint = "/__webpack_hmr";
|
||||
|
||||
static INodeServices fallbackNodeServices; // Used only if no INodeServices was registered with DI
|
||||
|
||||
public static void UseWebpackDevMiddleware(this IApplicationBuilder appBuilder, WebpackDevMiddlewareOptions options = null) {
|
||||
// Validate options
|
||||
if (options != null) {
|
||||
@@ -24,17 +22,19 @@ namespace Microsoft.AspNet.Builder
|
||||
throw new ArgumentException("To enable ReactHotModuleReplacement, you must also enable HotModuleReplacement.");
|
||||
}
|
||||
}
|
||||
|
||||
// Get the NodeServices instance from DI
|
||||
var nodeServices = (INodeServices)appBuilder.ApplicationServices.GetService(typeof (INodeServices)) ?? fallbackNodeServices;
|
||||
|
||||
// Consider removing the following. Having it means you can get away with not putting app.AddNodeServices()
|
||||
// in your startup file, but then again it might be confusing that you don't need to.
|
||||
// Unlike other consumers of NodeServices, WebpackDevMiddleware dosen't share Node instances, nor does it
|
||||
// use your DI configuration. It's important for WebpackDevMiddleware to have its own private Node instance
|
||||
// because it must *not* restart when files change (if it did, you'd lose all the benefits of Webpack
|
||||
// middleware). And since this is a dev-time-only feature, it doesn't matter if the default transport isn't
|
||||
// as fast as some theoretical future alternative.
|
||||
var appEnv = (IApplicationEnvironment)appBuilder.ApplicationServices.GetService(typeof(IApplicationEnvironment));
|
||||
if (nodeServices == null) {
|
||||
nodeServices = fallbackNodeServices = Configuration.CreateNodeServices(NodeHostingModel.Http, appEnv.ApplicationBasePath);
|
||||
}
|
||||
|
||||
var nodeServices = Configuration.CreateNodeServices(new NodeServicesOptions {
|
||||
HostingModel = NodeHostingModel.Http,
|
||||
ProjectPath = appEnv.ApplicationBasePath,
|
||||
WatchFileExtensions = new string[] {} // Don't watch anything
|
||||
});
|
||||
|
||||
// Get a filename matching the middleware Node script
|
||||
var script = EmbeddedResourceReader.Read(typeof (WebpackDevMiddleware), "/Content/Node/webpack-dev-middleware.js");
|
||||
var nodeScript = new StringAsTempFile(script); // Will be cleaned up on process exit
|
||||
|
||||
Reference in New Issue
Block a user