Skip to content
This repository was archived by the owner on Apr 8, 2020. It is now read-only.

Commit 0981599

Browse files
Add ability to configure environment variables for Node instances, plus auto-populate NODE_ENV based on IHostingEnvironment when possible. Fixes #230
1 parent 56cb898 commit 0981599

File tree

7 files changed

+62
-24
lines changed

7 files changed

+62
-24
lines changed

src/Microsoft.AspNetCore.NodeServices/Configuration/Configuration.cs

+6-3
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,15 @@ public static void AddNodeServices(this IServiceCollection serviceCollection, No
2020
{
2121
// Since this instance is being created through DI, we can access the IHostingEnvironment
2222
// to populate options.ProjectPath if it wasn't explicitly specified.
23+
var hostEnv = serviceProvider.GetRequiredService<IHostingEnvironment>();
2324
if (string.IsNullOrEmpty(options.ProjectPath))
2425
{
25-
var hostEnv = serviceProvider.GetRequiredService<IHostingEnvironment>();
2626
options.ProjectPath = hostEnv.ContentRootPath;
2727
}
2828

29+
// Similarly, we can determine the 'is development' value from the hosting environment
30+
options.AddDefaultEnvironmentVariables(hostEnv.IsDevelopment());
31+
2932
// Likewise, if no logger was specified explicitly, we should use the one from DI.
3033
// If it doesn't provide one, CreateNodeInstance will set up a default.
3134
if (options.NodeInstanceOutputLogger == null)
@@ -69,11 +72,11 @@ private static INodeInstance CreateNodeInstance(NodeServicesOptions options)
6972
{
7073
case NodeHostingModel.Http:
7174
return new HttpNodeInstance(options.ProjectPath, options.WatchFileExtensions, logger,
72-
options.LaunchWithDebugging, options.DebuggingPort, /* port */ 0);
75+
options.EnvironmentVariables, options.LaunchWithDebugging, options.DebuggingPort, /* port */ 0);
7376
case NodeHostingModel.Socket:
7477
var pipeName = "pni-" + Guid.NewGuid().ToString("D"); // Arbitrary non-clashing string
7578
return new SocketNodeInstance(options.ProjectPath, options.WatchFileExtensions, pipeName, logger,
76-
options.LaunchWithDebugging, options.DebuggingPort);
79+
options.EnvironmentVariables, options.LaunchWithDebugging, options.DebuggingPort);
7780
default:
7881
throw new ArgumentException("Unknown hosting model: " + options.HostingModel);
7982
}

src/Microsoft.AspNetCore.NodeServices/Configuration/NodeServicesOptions.cs

+18
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Generic;
23
using Microsoft.AspNetCore.NodeServices.HostingModels;
34
using Microsoft.Extensions.Logging;
45

@@ -22,6 +23,23 @@ public NodeServicesOptions()
2223
public string[] WatchFileExtensions { get; set; }
2324
public ILogger NodeInstanceOutputLogger { get; set; }
2425
public bool LaunchWithDebugging { get; set; }
26+
public IDictionary<string, string> EnvironmentVariables { get; set; }
2527
public int? DebuggingPort { get; set; }
28+
29+
public NodeServicesOptions AddDefaultEnvironmentVariables(bool isDevelopmentMode)
30+
{
31+
if (EnvironmentVariables == null)
32+
{
33+
EnvironmentVariables = new Dictionary<string, string>();
34+
}
35+
36+
if (!EnvironmentVariables.ContainsKey("NODE_ENV"))
37+
{
38+
// These strings are a de-facto standard in Node
39+
EnvironmentVariables["NODE_ENV"] = isDevelopmentMode ? "development" : "production";
40+
}
41+
42+
return this;
43+
}
2644
}
2745
}

src/Microsoft.AspNetCore.NodeServices/HostingModels/HttpNodeInstance.cs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.IO;
34
using System.Net.Http;
45
using System.Text;
@@ -34,7 +35,7 @@ internal class HttpNodeInstance : OutOfProcessNodeInstance
3435
private int _portNumber;
3536

3637
public HttpNodeInstance(string projectPath, string[] watchFileExtensions, ILogger nodeInstanceOutputLogger,
37-
bool launchWithDebugging, int? debuggingPort, int port = 0)
38+
IDictionary<string, string> environmentVars, bool launchWithDebugging, int? debuggingPort, int port = 0)
3839
: base(
3940
EmbeddedResourceReader.Read(
4041
typeof(HttpNodeInstance),
@@ -43,6 +44,7 @@ public HttpNodeInstance(string projectPath, string[] watchFileExtensions, ILogge
4344
watchFileExtensions,
4445
MakeCommandLineOptions(port),
4546
nodeInstanceOutputLogger,
47+
environmentVars,
4648
launchWithDebugging,
4749
debuggingPort)
4850
{

src/Microsoft.AspNetCore.NodeServices/HostingModels/OutOfProcessNodeInstance.cs

+27-7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.Diagnostics;
34
using System.IO;
45
using System.Linq;
@@ -46,6 +47,7 @@ public OutOfProcessNodeInstance(
4647
string[] watchFileExtensions,
4748
string commandLineArguments,
4849
ILogger nodeOutputLogger,
50+
IDictionary<string, string> environmentVars,
4951
bool launchWithDebugging,
5052
int? debuggingPort)
5153
{
@@ -58,7 +60,7 @@ public OutOfProcessNodeInstance(
5860
_entryPointScript = new StringAsTempFile(entryPointScript);
5961

6062
var startInfo = PrepareNodeProcessStartInfo(_entryPointScript.FileName, projectPath, commandLineArguments,
61-
launchWithDebugging, debuggingPort);
63+
environmentVars, launchWithDebugging, debuggingPort);
6264
_nodeProcess = LaunchNodeProcess(startInfo);
6365
_watchFileExtensions = watchFileExtensions;
6466
_fileSystemWatcher = BeginFileWatcher(projectPath);
@@ -99,7 +101,7 @@ public void Dispose()
99101
// This method is virtual, as it provides a way to override the NODE_PATH or the path to node.exe
100102
protected virtual ProcessStartInfo PrepareNodeProcessStartInfo(
101103
string entryPointFilename, string projectPath, string commandLineArguments,
102-
bool launchWithDebugging, int? debuggingPort)
104+
IDictionary<string, string> environmentVars, bool launchWithDebugging, int? debuggingPort)
103105
{
104106
string debuggingArgs;
105107
if (launchWithDebugging)
@@ -122,6 +124,19 @@ protected virtual ProcessStartInfo PrepareNodeProcessStartInfo(
122124
WorkingDirectory = projectPath
123125
};
124126

127+
// Append environment vars
128+
if (environmentVars != null)
129+
{
130+
foreach (var envVarKey in environmentVars.Keys)
131+
{
132+
var envVarValue = environmentVars[envVarKey];
133+
if (envVarValue != null)
134+
{
135+
SetEnvironmentVariable(startInfo, envVarKey, envVarValue);
136+
}
137+
}
138+
}
139+
125140
// Append projectPath to NODE_PATH so it can locate node_modules
126141
var existingNodePath = Environment.GetEnvironmentVariable("NODE_PATH") ?? string.Empty;
127142
if (existingNodePath != string.Empty)
@@ -130,11 +145,7 @@ protected virtual ProcessStartInfo PrepareNodeProcessStartInfo(
130145
}
131146

132147
var nodePathValue = existingNodePath + Path.Combine(projectPath, "node_modules");
133-
#if NET451
134-
startInfo.EnvironmentVariables["NODE_PATH"] = nodePathValue;
135-
#else
136-
startInfo.Environment["NODE_PATH"] = nodePathValue;
137-
#endif
148+
SetEnvironmentVariable(startInfo, "NODE_PATH", nodePathValue);
138149

139150
return startInfo;
140151
}
@@ -179,6 +190,15 @@ private void EnsureFileSystemWatcherIsDisposed()
179190
}
180191
}
181192

193+
private static void SetEnvironmentVariable(ProcessStartInfo startInfo, string name, string value)
194+
{
195+
#if NET451
196+
startInfo.EnvironmentVariables[name] = value;
197+
#else
198+
startInfo.Environment[name] = value;
199+
#endif
200+
}
201+
182202
private static Process LaunchNodeProcess(ProcessStartInfo startInfo)
183203
{
184204
var process = Process.Start(startInfo);

src/Microsoft.AspNetCore.NodeServices/HostingModels/SocketNodeInstance.cs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.IO;
34
using System.Text;
45
using System.Threading;
@@ -38,7 +39,8 @@ internal class SocketNodeInstance : OutOfProcessNodeInstance
3839
private VirtualConnectionClient _virtualConnectionClient;
3940

4041
public SocketNodeInstance(string projectPath, string[] watchFileExtensions, string socketAddress,
41-
ILogger nodeInstanceOutputLogger, bool launchWithDebugging, int? debuggingPort)
42+
ILogger nodeInstanceOutputLogger, IDictionary<string, string> environmentVars,
43+
bool launchWithDebugging, int? debuggingPort)
4244
: base(
4345
EmbeddedResourceReader.Read(
4446
typeof(SocketNodeInstance),
@@ -47,6 +49,7 @@ public SocketNodeInstance(string projectPath, string[] watchFileExtensions, stri
4749
watchFileExtensions,
4850
MakeNewCommandLineOptions(socketAddress),
4951
nodeInstanceOutputLogger,
52+
environmentVars,
5053
launchWithDebugging,
5154
debuggingPort)
5255
{

src/Microsoft.AspNetCore.SpaServices/Prerendering/PrerenderTagHelper.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public PrerenderTagHelper(IServiceProvider serviceProvider)
3636
_nodeServices = _fallbackNodeServices = Configuration.CreateNodeServices(new NodeServicesOptions
3737
{
3838
ProjectPath = _applicationBasePath
39-
});
39+
}.AddDefaultEnvironmentVariables(hostEnv.IsDevelopment()));
4040
}
4141
}
4242

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

+3-11
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,8 @@ public static void UseWebpackDevMiddleware(
3535
"To enable ReactHotModuleReplacement, you must also enable HotModuleReplacement.");
3636
}
3737

38-
string projectPath;
39-
if (options.ProjectPath == null)
40-
{
41-
var hostEnv = (IHostingEnvironment)appBuilder.ApplicationServices.GetService(typeof(IHostingEnvironment));
42-
projectPath = hostEnv.ContentRootPath;
43-
}
44-
else
45-
{
46-
projectPath = options.ProjectPath;
47-
}
38+
var hostEnv = (IHostingEnvironment)appBuilder.ApplicationServices.GetService(typeof(IHostingEnvironment));
39+
var projectPath = options.ProjectPath ?? hostEnv.ContentRootPath;
4840

4941
// Unlike other consumers of NodeServices, WebpackDevMiddleware dosen't share Node instances, nor does it
5042
// use your DI configuration. It's important for WebpackDevMiddleware to have its own private Node instance
@@ -55,7 +47,7 @@ public static void UseWebpackDevMiddleware(
5547
{
5648
ProjectPath = projectPath,
5749
WatchFileExtensions = new string[] { } // Don't watch anything
58-
});
50+
}.AddDefaultEnvironmentVariables(hostEnv.IsDevelopment()));
5951

6052
// Get a filename matching the middleware Node script
6153
var script = EmbeddedResourceReader.Read(typeof(WebpackDevMiddleware),

0 commit comments

Comments
 (0)