Skip to content

Commit 5ec768d

Browse files
Finish wiring up very basic Node JS interop
1 parent af2ff28 commit 5ec768d

File tree

8 files changed

+54
-25
lines changed

8 files changed

+54
-25
lines changed

src/React.Core/INodeJsEngine.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ public interface INodeJsEngine
1717
void Execute(string code);
1818
T Evaluate<T>(string code);
1919

20+
void ExecuteFile(IFileSystem fileSystem, string path);
21+
2022
T CallFunctionReturningJson<T>(string function, object[] args);
2123

2224
void ExecuteResource(string resourceName, Assembly assembly);

src/React.Core/IReactSiteConfiguration.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ public interface IReactSiteConfiguration
220220
/// <summary>
221221
///
222222
/// </summary>
223-
Func<INodeJsEngine> NodeJsEngine { get; set; }
223+
Func<INodeJsEngine> CreateNodeJsInstance { get; set; }
224224

225225
/// <summary>
226226
///

src/React.Core/ReactSiteConfiguration.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ public IReactSiteConfiguration SetScriptNonceProvider(Func<string> provider)
363363
/// <summary>
364364
/// The Node engine instance
365365
/// </summary>
366-
public Func<INodeJsEngine> NodeJsEngine { get; set; }
366+
public Func<INodeJsEngine> CreateNodeJsInstance { get; set; }
367367

368368
/// <summary>
369369
/// Sets the Node engine instance
@@ -372,7 +372,7 @@ public IReactSiteConfiguration SetScriptNonceProvider(Func<string> provider)
372372
/// <returns></returns>
373373
public IReactSiteConfiguration SetNodeJsEngine(Func<INodeJsEngine> nodeJsEngine)
374374
{
375-
NodeJsEngine = nodeJsEngine;
375+
CreateNodeJsInstance = nodeJsEngine;
376376
return this;
377377
}
378378
}

src/React.Core/ReactWithNodeEnvironment.cs

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using System.Collections.Generic;
1010
using System.Diagnostics;
1111
using System.IO;
12+
using System.Linq;
1213
using System.Reflection;
1314
using System.Text;
1415
using System.Threading;
@@ -130,7 +131,41 @@ IReactIdGenerator reactIdGenerator
130131
_babelTransformer = new Lazy<IBabel>(() =>
131132
new Babel(this, _cache, _fileSystem, _fileCacheHash, _config)
132133
);
133-
_lazyEngine = new Lazy<INodeJsEngine>(() => _config.NodeJsEngine());
134+
_lazyEngine = new Lazy<INodeJsEngine>(() =>
135+
{
136+
var allFiles = _config.Scripts
137+
.Concat(_config.ScriptsWithoutTransform)
138+
.Select(_fileSystem.MapPath);
139+
140+
var nodeInstance = _config.CreateNodeJsInstance();
141+
142+
LoadUserScripts(nodeInstance);
143+
144+
return nodeInstance;
145+
});
146+
}
147+
148+
149+
/// <summary>
150+
/// Loads any user-provided scripts. Only scripts that don't need JSX transformation can
151+
/// run immediately here. JSX files are loaded in ReactEnvironment.
152+
/// </summary>
153+
/// <param name="engine">Engine to load scripts into</param>
154+
private void LoadUserScripts(INodeJsEngine engine)
155+
{
156+
foreach (var file in _config.ScriptsWithoutTransform)
157+
{
158+
try
159+
{
160+
engine.ExecuteFile(_fileSystem, file);
161+
}
162+
catch (NodeJsException ex)
163+
{
164+
}
165+
catch (IOException ex)
166+
{
167+
}
168+
}
134169
}
135170

136171
/// <summary>
@@ -168,7 +203,7 @@ public virtual string Version
168203
/// </summary>
169204
protected virtual void EnsureUserScriptsLoaded()
170205
{
171-
// Scripts already loaded into this environment, don't load them again
206+
// Scripts already loaded into this environment, don't load them agai n
172207
if (Engine.HasVariable(USER_SCRIPTS_LOADED_KEY) || _config == null)
173208
{
174209
return;
@@ -303,13 +338,6 @@ public virtual string GetInitJavaScript(bool clientOnly = false)
303338
/// <returns>JavaScript for all components</returns>
304339
public virtual void GetInitJavaScript(TextWriter writer, bool clientOnly = false)
305340
{
306-
// Propagate any server-side console.log calls to corresponding client-side calls.
307-
if (!clientOnly && _components.Count != 0)
308-
{
309-
var consoleCalls = Execute<string>("console.getCalls()");
310-
writer.Write(consoleCalls);
311-
}
312-
313341
foreach (var component in _components)
314342
{
315343
if (!component.ServerOnly)

src/React.NodeServices/NodeJsEngine.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.Reflection;
44
using Jering.Javascript.NodeJS;
5+
using Newtonsoft.Json;
56
using React;
67

78
namespace React.NodeServices
@@ -11,13 +12,14 @@ public class NodeJsEngine : INodeJsEngine, IDisposable
1112
private Dictionary<string, bool> _dict = new Dictionary<string, bool>();
1213
private object _lock = new object();
1314
private readonly INodeJSService _nodeJSService;
15+
private static readonly JsonSerializerSettings _settings = new JsonSerializerSettings { StringEscapeHandling = StringEscapeHandling.EscapeNonAscii };
1416

1517
private NodeJsEngine(INodeJSService nodeJSService)
1618
{
1719
_nodeJSService = nodeJSService;
1820
}
1921

20-
private string WrapAsModule(string code) => $"function wrappedCode() {{ {{{code}}} }} module.exports = function(callback, message) {{ callback(null, wrappedCode()); }}";
22+
private string WrapAsModule(string code) => $"let wrappedCode = () => eval({JsonConvert.SerializeObject(code, _settings)}); module.exports = function(callback, message) {{ callback(null, wrappedCode()); }}";
2123

2224
public static INodeJsEngine CreateEngine(INodeJSService nodeJSService) => new NodeJsEngine(nodeJSService);
2325
public string Name => throw new NotImplementedException();
@@ -49,6 +51,12 @@ public void Execute(string code)
4951
_nodeJSService.InvokeFromStringAsync(WrapAsModule(code)).ConfigureAwait(false).GetAwaiter().GetResult();
5052
}
5153

54+
public void ExecuteFile(IFileSystem fileSystem, string path)
55+
{
56+
var contents = fileSystem.ReadAsString(path);
57+
Execute(contents);
58+
}
59+
5260
public void ExecuteResource(string resourceName, Assembly assembly)
5361
{
5462
throw new NotImplementedException();

src/React.Sample.Webpack.CoreMvc/Startup.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ public void ConfigureServices(IServiceCollection services)
3131
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
3232

3333
services.AddNodeJS();
34+
services.Configure<NodeJSProcessOptions>(options => options.NodeAndV8Options = "--inspect");
3435

3536
// Build the intermediate service provider then return it
3637
services.BuildServiceProvider();

src/React.Sample.Webpack.CoreMvc/Views/Home/Index.cshtml

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,8 @@
55

66
@{
77
Layout = "_Layout";
8-
var emotionFunctions = new EmotionFunctions();
9-
var styledComponentsFunctions = new StyledComponentsFunctions();
10-
var reactJssFunctions = new ReactJssFunctions();
11-
var helmetFunctions = new ReactHelmetFunctions();
12-
13-
var chainedFunctions = new ChainedRenderFunctions(emotionFunctions, styledComponentsFunctions, reactJssFunctions, helmetFunctions);
14-
}
15-
@Html.ReactRouter("RootComponent", new { initialComments = Model.Comments, page = Model.Page }, renderFunctions: chainedFunctions)
16-
@{
17-
ViewBag.ServerStyles = styledComponentsFunctions.RenderedStyles + reactJssFunctions.RenderedStyles;
18-
ViewBag.HelmetTitle = helmetFunctions.RenderedHelmet?.GetValueOrDefault("title");
198
}
9+
@Html.React("RootComponent", new { initialComments = Model.Comments, page = Model.Page, context = new { } })
2010
<script src="/dist/runtime.js"></script>
2111
<script src="/dist/vendor.js"></script>
2212
<script src="/dist/components.js"></script>

src/React.Sample.Webpack.CoreMvc/webpack.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ module.exports = {
66
},
77
output: {
88
filename: '[name].js',
9-
globalObject: 'this',
9+
globalObject: 'global',
1010
path: path.resolve(__dirname, 'wwwroot/dist'),
1111
publicPath: 'dist/'
1212
},

0 commit comments

Comments
 (0)