diff --git a/src/Microsoft.AspNetCore.NodeServices/Configuration/Configuration.cs b/src/Microsoft.AspNetCore.NodeServices/Configuration/Configuration.cs index 6ecd43f..bd76dc8 100644 --- a/src/Microsoft.AspNetCore.NodeServices/Configuration/Configuration.cs +++ b/src/Microsoft.AspNetCore.NodeServices/Configuration/Configuration.cs @@ -20,12 +20,15 @@ namespace Microsoft.AspNetCore.NodeServices { // Since this instance is being created through DI, we can access the IHostingEnvironment // to populate options.ProjectPath if it wasn't explicitly specified. + var hostEnv = serviceProvider.GetRequiredService(); if (string.IsNullOrEmpty(options.ProjectPath)) { - var hostEnv = serviceProvider.GetRequiredService(); options.ProjectPath = hostEnv.ContentRootPath; } + // Similarly, we can determine the 'is development' value from the hosting environment + options.AddDefaultEnvironmentVariables(hostEnv.IsDevelopment()); + // Likewise, if no logger was specified explicitly, we should use the one from DI. // If it doesn't provide one, CreateNodeInstance will set up a default. if (options.NodeInstanceOutputLogger == null) @@ -69,11 +72,11 @@ namespace Microsoft.AspNetCore.NodeServices { case NodeHostingModel.Http: return new HttpNodeInstance(options.ProjectPath, options.WatchFileExtensions, logger, - options.LaunchWithDebugging, options.DebuggingPort, /* port */ 0); + options.EnvironmentVariables, options.LaunchWithDebugging, options.DebuggingPort, /* port */ 0); case NodeHostingModel.Socket: var pipeName = "pni-" + Guid.NewGuid().ToString("D"); // Arbitrary non-clashing string return new SocketNodeInstance(options.ProjectPath, options.WatchFileExtensions, pipeName, logger, - options.LaunchWithDebugging, options.DebuggingPort); + options.EnvironmentVariables, options.LaunchWithDebugging, options.DebuggingPort); default: throw new ArgumentException("Unknown hosting model: " + options.HostingModel); } diff --git a/src/Microsoft.AspNetCore.NodeServices/Configuration/NodeServicesOptions.cs b/src/Microsoft.AspNetCore.NodeServices/Configuration/NodeServicesOptions.cs index 5e6f518..4ff981e 100644 --- a/src/Microsoft.AspNetCore.NodeServices/Configuration/NodeServicesOptions.cs +++ b/src/Microsoft.AspNetCore.NodeServices/Configuration/NodeServicesOptions.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using Microsoft.AspNetCore.NodeServices.HostingModels; using Microsoft.Extensions.Logging; @@ -22,6 +23,23 @@ namespace Microsoft.AspNetCore.NodeServices public string[] WatchFileExtensions { get; set; } public ILogger NodeInstanceOutputLogger { get; set; } public bool LaunchWithDebugging { get; set; } + public IDictionary EnvironmentVariables { get; set; } public int? DebuggingPort { get; set; } + + public NodeServicesOptions AddDefaultEnvironmentVariables(bool isDevelopmentMode) + { + if (EnvironmentVariables == null) + { + EnvironmentVariables = new Dictionary(); + } + + if (!EnvironmentVariables.ContainsKey("NODE_ENV")) + { + // These strings are a de-facto standard in Node + EnvironmentVariables["NODE_ENV"] = isDevelopmentMode ? "development" : "production"; + } + + return this; + } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.NodeServices/HostingModels/HttpNodeInstance.cs b/src/Microsoft.AspNetCore.NodeServices/HostingModels/HttpNodeInstance.cs index 0e828ea..9400d6e 100644 --- a/src/Microsoft.AspNetCore.NodeServices/HostingModels/HttpNodeInstance.cs +++ b/src/Microsoft.AspNetCore.NodeServices/HostingModels/HttpNodeInstance.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.IO; using System.Net.Http; using System.Text; @@ -34,7 +35,7 @@ namespace Microsoft.AspNetCore.NodeServices.HostingModels private int _portNumber; public HttpNodeInstance(string projectPath, string[] watchFileExtensions, ILogger nodeInstanceOutputLogger, - bool launchWithDebugging, int? debuggingPort, int port = 0) + IDictionary environmentVars, bool launchWithDebugging, int? debuggingPort, int port = 0) : base( EmbeddedResourceReader.Read( typeof(HttpNodeInstance), @@ -43,6 +44,7 @@ namespace Microsoft.AspNetCore.NodeServices.HostingModels watchFileExtensions, MakeCommandLineOptions(port), nodeInstanceOutputLogger, + environmentVars, launchWithDebugging, debuggingPort) { diff --git a/src/Microsoft.AspNetCore.NodeServices/HostingModels/OutOfProcessNodeInstance.cs b/src/Microsoft.AspNetCore.NodeServices/HostingModels/OutOfProcessNodeInstance.cs index 3c9cfd5..d9ede58 100644 --- a/src/Microsoft.AspNetCore.NodeServices/HostingModels/OutOfProcessNodeInstance.cs +++ b/src/Microsoft.AspNetCore.NodeServices/HostingModels/OutOfProcessNodeInstance.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; @@ -46,6 +47,7 @@ If you haven't yet installed node-inspector, you can do so as follows: string[] watchFileExtensions, string commandLineArguments, ILogger nodeOutputLogger, + IDictionary environmentVars, bool launchWithDebugging, int? debuggingPort) { @@ -58,7 +60,7 @@ If you haven't yet installed node-inspector, you can do so as follows: _entryPointScript = new StringAsTempFile(entryPointScript); var startInfo = PrepareNodeProcessStartInfo(_entryPointScript.FileName, projectPath, commandLineArguments, - launchWithDebugging, debuggingPort); + environmentVars, launchWithDebugging, debuggingPort); _nodeProcess = LaunchNodeProcess(startInfo); _watchFileExtensions = watchFileExtensions; _fileSystemWatcher = BeginFileWatcher(projectPath); @@ -99,7 +101,7 @@ If you haven't yet installed node-inspector, you can do so as follows: // This method is virtual, as it provides a way to override the NODE_PATH or the path to node.exe protected virtual ProcessStartInfo PrepareNodeProcessStartInfo( string entryPointFilename, string projectPath, string commandLineArguments, - bool launchWithDebugging, int? debuggingPort) + IDictionary environmentVars, bool launchWithDebugging, int? debuggingPort) { string debuggingArgs; if (launchWithDebugging) @@ -122,6 +124,19 @@ If you haven't yet installed node-inspector, you can do so as follows: WorkingDirectory = projectPath }; + // Append environment vars + if (environmentVars != null) + { + foreach (var envVarKey in environmentVars.Keys) + { + var envVarValue = environmentVars[envVarKey]; + if (envVarValue != null) + { + SetEnvironmentVariable(startInfo, envVarKey, envVarValue); + } + } + } + // Append projectPath to NODE_PATH so it can locate node_modules var existingNodePath = Environment.GetEnvironmentVariable("NODE_PATH") ?? string.Empty; if (existingNodePath != string.Empty) @@ -130,11 +145,7 @@ If you haven't yet installed node-inspector, you can do so as follows: } var nodePathValue = existingNodePath + Path.Combine(projectPath, "node_modules"); -#if NET451 - startInfo.EnvironmentVariables["NODE_PATH"] = nodePathValue; -#else - startInfo.Environment["NODE_PATH"] = nodePathValue; -#endif + SetEnvironmentVariable(startInfo, "NODE_PATH", nodePathValue); return startInfo; } @@ -179,6 +190,15 @@ If you haven't yet installed node-inspector, you can do so as follows: } } + private static void SetEnvironmentVariable(ProcessStartInfo startInfo, string name, string value) + { +#if NET451 + startInfo.EnvironmentVariables[name] = value; +#else + startInfo.Environment[name] = value; +#endif + } + private static Process LaunchNodeProcess(ProcessStartInfo startInfo) { var process = Process.Start(startInfo); diff --git a/src/Microsoft.AspNetCore.NodeServices/HostingModels/SocketNodeInstance.cs b/src/Microsoft.AspNetCore.NodeServices/HostingModels/SocketNodeInstance.cs index 5f3a6ec..46115f6 100644 --- a/src/Microsoft.AspNetCore.NodeServices/HostingModels/SocketNodeInstance.cs +++ b/src/Microsoft.AspNetCore.NodeServices/HostingModels/SocketNodeInstance.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.IO; using System.Text; using System.Threading; @@ -38,7 +39,8 @@ namespace Microsoft.AspNetCore.NodeServices.HostingModels private VirtualConnectionClient _virtualConnectionClient; public SocketNodeInstance(string projectPath, string[] watchFileExtensions, string socketAddress, - ILogger nodeInstanceOutputLogger, bool launchWithDebugging, int? debuggingPort) + ILogger nodeInstanceOutputLogger, IDictionary environmentVars, + bool launchWithDebugging, int? debuggingPort) : base( EmbeddedResourceReader.Read( typeof(SocketNodeInstance), @@ -47,6 +49,7 @@ namespace Microsoft.AspNetCore.NodeServices.HostingModels watchFileExtensions, MakeNewCommandLineOptions(socketAddress), nodeInstanceOutputLogger, + environmentVars, launchWithDebugging, debuggingPort) { diff --git a/src/Microsoft.AspNetCore.SpaServices/Prerendering/PrerenderTagHelper.cs b/src/Microsoft.AspNetCore.SpaServices/Prerendering/PrerenderTagHelper.cs index e773bbb..1baaa60 100644 --- a/src/Microsoft.AspNetCore.SpaServices/Prerendering/PrerenderTagHelper.cs +++ b/src/Microsoft.AspNetCore.SpaServices/Prerendering/PrerenderTagHelper.cs @@ -36,7 +36,7 @@ namespace Microsoft.AspNetCore.SpaServices.Prerendering _nodeServices = _fallbackNodeServices = Configuration.CreateNodeServices(new NodeServicesOptions { ProjectPath = _applicationBasePath - }); + }.AddDefaultEnvironmentVariables(hostEnv.IsDevelopment())); } } diff --git a/src/Microsoft.AspNetCore.SpaServices/Webpack/WebpackDevMiddleware.cs b/src/Microsoft.AspNetCore.SpaServices/Webpack/WebpackDevMiddleware.cs index 89d6950..5a8c06f 100644 --- a/src/Microsoft.AspNetCore.SpaServices/Webpack/WebpackDevMiddleware.cs +++ b/src/Microsoft.AspNetCore.SpaServices/Webpack/WebpackDevMiddleware.cs @@ -35,16 +35,8 @@ namespace Microsoft.AspNetCore.Builder "To enable ReactHotModuleReplacement, you must also enable HotModuleReplacement."); } - string projectPath; - if (options.ProjectPath == null) - { - var hostEnv = (IHostingEnvironment)appBuilder.ApplicationServices.GetService(typeof(IHostingEnvironment)); - projectPath = hostEnv.ContentRootPath; - } - else - { - projectPath = options.ProjectPath; - } + var hostEnv = (IHostingEnvironment)appBuilder.ApplicationServices.GetService(typeof(IHostingEnvironment)); + var projectPath = options.ProjectPath ?? hostEnv.ContentRootPath; // 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 @@ -55,7 +47,7 @@ namespace Microsoft.AspNetCore.Builder { ProjectPath = projectPath, WatchFileExtensions = new string[] { } // Don't watch anything - }); + }.AddDefaultEnvironmentVariables(hostEnv.IsDevelopment())); // Get a filename matching the middleware Node script var script = EmbeddedResourceReader.Read(typeof(WebpackDevMiddleware),