Skip to content

Commit bd8f5cf

Browse files
Taritsyndustinsoftware
authored andcommitted
Ensure availability of the script pre-compilation (#648)
1 parent ce370c6 commit bd8f5cf

File tree

3 files changed

+135
-56
lines changed

3 files changed

+135
-56
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright (c) Facebook, Inc. and its affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
using System;
9+
using System.Runtime.Serialization;
10+
11+
namespace React.Exceptions
12+
{
13+
/// <summary>
14+
/// Thrown when the script pre-compilation is not available.
15+
/// </summary>
16+
#if !NETSTANDARD1_6
17+
[Serializable]
18+
#endif
19+
public class ReactScriptPrecompilationNotAvailableException : ReactException
20+
{
21+
/// <summary>
22+
/// Initializes a new instance of the <see cref="ReactScriptPrecompilationNotAvailableException"/> class.
23+
/// </summary>
24+
/// <param name="message">The message that describes the error.</param>
25+
public ReactScriptPrecompilationNotAvailableException(string message) : base(message) { }
26+
27+
#if !NETSTANDARD1_6
28+
/// <summary>
29+
/// Used by deserialization
30+
/// </summary>
31+
protected ReactScriptPrecompilationNotAvailableException(SerializationInfo info, StreamingContext context)
32+
: base(info, context) { }
33+
#endif
34+
}
35+
}

src/React.Core/JavaScriptEnginePrecompilationUtils.cs

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using System;
2-
using System.Diagnostics;
32
using System.Reflection;
43
using JavaScriptEngineSwitcher.Core;
4+
using React.Exceptions;
55

66
namespace React
77
{
@@ -36,10 +36,7 @@ public static class JavaScriptEnginePrecompilationUtils
3636
public static bool TryExecuteFileWithPrecompilation(this IJsEngine engine, ICache cache,
3737
IFileSystem fileSystem, string path, Func<string, string> scriptLoader = null)
3838
{
39-
if (!CheckPrecompilationAvailability(engine, cache))
40-
{
41-
return false;
42-
}
39+
EnsurePrecompilationAvailability(engine, cache);
4340

4441
var cacheKey = string.Format(PRECOMPILED_JS_FILE_CACHE_KEY, path);
4542
var precompiledScript = cache.Get<IPrecompiledScript>(cacheKey);
@@ -73,10 +70,7 @@ public static bool TryExecuteFileWithPrecompilation(this IJsEngine engine, ICach
7370
public static bool TryExecuteResourceWithPrecompilation(this IJsEngine engine, ICache cache,
7471
string resourceName, Assembly assembly)
7572
{
76-
if (!CheckPrecompilationAvailability(engine, cache))
77-
{
78-
return false;
79-
}
73+
EnsurePrecompilationAvailability(engine, cache);
8074

8175
var cacheKey = string.Format(PRECOMPILED_JS_RESOURCE_CACHE_KEY, resourceName);
8276
var precompiledScript = cache.Get<IPrecompiledScript>(cacheKey);
@@ -97,27 +91,27 @@ public static bool TryExecuteResourceWithPrecompilation(this IJsEngine engine, I
9791
}
9892

9993
/// <summary>
100-
/// Checks a availability of the script pre-compilation
94+
/// Ensures that the script pre-compilation is available.
10195
/// </summary>
10296
/// <param name="engine">Instance of the JavaScript engine</param>
10397
/// <param name="cache">Cache used for storing the pre-compiled scripts</param>
104-
/// <returns>true if the script pre-compilation is available; otherwise, false.</returns>
105-
private static bool CheckPrecompilationAvailability(IJsEngine engine, ICache cache)
98+
private static void EnsurePrecompilationAvailability(IJsEngine engine, ICache cache)
10699
{
107100
if (!engine.SupportsScriptPrecompilation)
108101
{
109-
Trace.WriteLine(string.Format("The {0} version {1} does not support the script pre-compilation.",
110-
engine.Name, engine.Version));
111-
return false;
102+
throw new ReactScriptPrecompilationNotAvailableException(string.Format(
103+
"The {0} version {1} does not support the script pre-compilation.",
104+
engine.Name,
105+
engine.Version
106+
));
112107
}
113108

114109
if (cache is NullCache)
115110
{
116-
Trace.WriteLine("Usage of script pre-compilation without caching does not make sense.");
117-
return false;
111+
throw new ReactScriptPrecompilationNotAvailableException(string.Format(
112+
"Usage of the script pre-compilation without caching does not make sense."
113+
));
118114
}
119-
120-
return true;
121115
}
122116
}
123117
}

tests/React.Tests/Core/JavaScriptEngineFactoryTest.cs

Lines changed: 87 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -136,31 +136,6 @@ public void ShouldLoadResourcesWithoutPrecompilation()
136136
jsEngine.Verify(x => x.ExecuteResource("React.Core.Resources.react.generated.min.js", reactCoreAssembly));
137137
}
138138

139-
[Fact]
140-
public void ShouldLoadResourcesWithPrecompilationAndWithoutCache()
141-
{
142-
var reactCoreAssembly = typeof(JavaScriptEngineFactory).GetTypeInfo().Assembly;
143-
144-
var jsEngine = new Mock<IJsEngine>();
145-
jsEngine.Setup(x => x.SupportsScriptPrecompilation).Returns(true);
146-
jsEngine.Setup(x => x.Evaluate<int>("1 + 1")).Returns(2);
147-
148-
var config = new Mock<IReactSiteConfiguration>();
149-
config.Setup(x => x.AllowJavaScriptPrecompilation).Returns(true);
150-
config.Setup(x => x.LoadReact).Returns(true);
151-
152-
var cache = new NullCache();
153-
154-
var fileSystem = new Mock<IFileSystem>();
155-
156-
var factory = CreateFactory(config.Object, cache, fileSystem.Object, () => jsEngine.Object);
157-
158-
factory.GetEngineForCurrentThread();
159-
160-
jsEngine.Verify(x => x.ExecuteResource("React.Core.Resources.shims.js", reactCoreAssembly));
161-
jsEngine.Verify(x => x.ExecuteResource("React.Core.Resources.react.generated.min.js", reactCoreAssembly));
162-
}
163-
164139
[Fact]
165140
public void ShouldLoadResourcesWithPrecompilationAndEmptyCache()
166141
{
@@ -227,49 +202,74 @@ public void ShouldLoadResourcesWithPrecompilationAndNotEmptyCache()
227202
}
228203

229204
[Fact]
230-
public void ShouldLoadFilesThatDoNotRequireTransformWithoutPrecompilation()
205+
public void ShouldThrowIfEngineNotSupportPrecompilationOfResources()
231206
{
207+
var reactCoreAssembly = typeof(JavaScriptEngineFactory).GetTypeInfo().Assembly;
208+
232209
var jsEngine = new Mock<IJsEngine>();
233-
jsEngine.Setup(x => x.SupportsScriptPrecompilation).Returns(true);
210+
jsEngine.Setup(x => x.Name).Returns("FooJsEngine");
211+
jsEngine.Setup(x => x.Version).Returns("1.2.3");
212+
jsEngine.Setup(x => x.SupportsScriptPrecompilation).Returns(false);
234213
jsEngine.Setup(x => x.Evaluate<int>("1 + 1")).Returns(2);
235214

236215
var config = new Mock<IReactSiteConfiguration>();
237-
config.Setup(x => x.ScriptsWithoutTransform).Returns(new List<string> { "First.js", "Second.js" });
238-
config.Setup(x => x.AllowJavaScriptPrecompilation).Returns(false);
216+
config.Setup(x => x.AllowJavaScriptPrecompilation).Returns(true);
239217
config.Setup(x => x.LoadReact).Returns(true);
240218

241219
var cache = new Mock<ICache>();
242220

243221
var fileSystem = new Mock<IFileSystem>();
244-
fileSystem.Setup(x => x.ReadAsString(It.IsAny<string>())).Returns<string>(path => "CONTENTS_" + path);
245222

246223
var factory = CreateFactory(config, cache, fileSystem, () => jsEngine.Object);
247224

248-
factory.GetEngineForCurrentThread();
249-
250-
jsEngine.Verify(x => x.Execute("CONTENTS_First.js", "First.js"));
251-
jsEngine.Verify(x => x.Execute("CONTENTS_Second.js", "Second.js"));
225+
var ex = Assert.Throws<ReactScriptPrecompilationNotAvailableException>(
226+
() => factory.GetEngineForCurrentThread());
227+
Assert.Equal("The FooJsEngine version 1.2.3 does not support the script pre-compilation.", ex.Message);
252228
}
253229

254230
[Fact]
255-
public void ShouldLoadFilesThatDoNotRequireTransformWithPrecompilationAndWithoutCache()
231+
public void ShouldThrowIfPrecompilationOfResourcesIsPerformedWithoutCache()
256232
{
233+
var reactCoreAssembly = typeof(JavaScriptEngineFactory).GetTypeInfo().Assembly;
234+
257235
var jsEngine = new Mock<IJsEngine>();
258236
jsEngine.Setup(x => x.SupportsScriptPrecompilation).Returns(true);
259237
jsEngine.Setup(x => x.Evaluate<int>("1 + 1")).Returns(2);
260238

261239
var config = new Mock<IReactSiteConfiguration>();
262-
config.Setup(x => x.ScriptsWithoutTransform).Returns(new List<string> { "First.js", "Second.js" });
263240
config.Setup(x => x.AllowJavaScriptPrecompilation).Returns(true);
264241
config.Setup(x => x.LoadReact).Returns(true);
265242

266243
var cache = new NullCache();
267244

268245
var fileSystem = new Mock<IFileSystem>();
269-
fileSystem.Setup(x => x.ReadAsString(It.IsAny<string>())).Returns<string>(path => "CONTENTS_" + path);
270246

271247
var factory = CreateFactory(config.Object, cache, fileSystem.Object, () => jsEngine.Object);
272248

249+
var ex = Assert.Throws<ReactScriptPrecompilationNotAvailableException>(
250+
() => factory.GetEngineForCurrentThread());
251+
Assert.Equal("Usage of the script pre-compilation without caching does not make sense.", ex.Message);
252+
}
253+
254+
[Fact]
255+
public void ShouldLoadFilesThatDoNotRequireTransformWithoutPrecompilation()
256+
{
257+
var jsEngine = new Mock<IJsEngine>();
258+
jsEngine.Setup(x => x.SupportsScriptPrecompilation).Returns(true);
259+
jsEngine.Setup(x => x.Evaluate<int>("1 + 1")).Returns(2);
260+
261+
var config = new Mock<IReactSiteConfiguration>();
262+
config.Setup(x => x.ScriptsWithoutTransform).Returns(new List<string> { "First.js", "Second.js" });
263+
config.Setup(x => x.AllowJavaScriptPrecompilation).Returns(false);
264+
config.Setup(x => x.LoadReact).Returns(true);
265+
266+
var cache = new Mock<ICache>();
267+
268+
var fileSystem = new Mock<IFileSystem>();
269+
fileSystem.Setup(x => x.ReadAsString(It.IsAny<string>())).Returns<string>(path => "CONTENTS_" + path);
270+
271+
var factory = CreateFactory(config, cache, fileSystem, () => jsEngine.Object);
272+
273273
factory.GetEngineForCurrentThread();
274274

275275
jsEngine.Verify(x => x.Execute("CONTENTS_First.js", "First.js"));
@@ -340,6 +340,56 @@ public void ShouldLoadFilesThatDoNotRequireTransformWithPrecompilationAndNotEmpt
340340
jsEngine.Verify(x => x.Execute(secondPrecompiledScript));
341341
}
342342

343+
[Fact]
344+
public void ShouldThrowIfEngineNotSupportPrecompilationOfFilesThatDoNotRequireTransform()
345+
{
346+
var jsEngine = new Mock<IJsEngine>();
347+
jsEngine.Setup(x => x.Name).Returns("FooJsEngine");
348+
jsEngine.Setup(x => x.Version).Returns("1.2.3");
349+
jsEngine.Setup(x => x.SupportsScriptPrecompilation).Returns(false);
350+
jsEngine.Setup(x => x.Evaluate<int>("1 + 1")).Returns(2);
351+
352+
var config = new Mock<IReactSiteConfiguration>();
353+
config.Setup(x => x.ScriptsWithoutTransform).Returns(new List<string> { "First.js", "Second.js" });
354+
config.Setup(x => x.AllowJavaScriptPrecompilation).Returns(true);
355+
config.Setup(x => x.LoadReact).Returns(true);
356+
357+
var cache = new Mock<ICache>();
358+
359+
var fileSystem = new Mock<IFileSystem>();
360+
fileSystem.Setup(x => x.ReadAsString(It.IsAny<string>())).Returns<string>(path => "CONTENTS_" + path);
361+
362+
var factory = CreateFactory(config, cache, fileSystem, () => jsEngine.Object);
363+
364+
var ex = Assert.Throws<ReactScriptPrecompilationNotAvailableException>(
365+
() => factory.GetEngineForCurrentThread());
366+
Assert.Equal("The FooJsEngine version 1.2.3 does not support the script pre-compilation.", ex.Message);
367+
}
368+
369+
[Fact]
370+
public void ShouldThrowIfPrecompilationOfFilesThatDoNotRequireTransformIsPerformedWithoutCache()
371+
{
372+
var jsEngine = new Mock<IJsEngine>();
373+
jsEngine.Setup(x => x.SupportsScriptPrecompilation).Returns(true);
374+
jsEngine.Setup(x => x.Evaluate<int>("1 + 1")).Returns(2);
375+
376+
var config = new Mock<IReactSiteConfiguration>();
377+
config.Setup(x => x.ScriptsWithoutTransform).Returns(new List<string> { "First.js", "Second.js" });
378+
config.Setup(x => x.AllowJavaScriptPrecompilation).Returns(true);
379+
config.Setup(x => x.LoadReact).Returns(true);
380+
381+
var cache = new NullCache();
382+
383+
var fileSystem = new Mock<IFileSystem>();
384+
fileSystem.Setup(x => x.ReadAsString(It.IsAny<string>())).Returns<string>(path => "CONTENTS_" + path);
385+
386+
var factory = CreateFactory(config.Object, cache, fileSystem.Object, () => jsEngine.Object);
387+
388+
var ex = Assert.Throws<ReactScriptPrecompilationNotAvailableException>(
389+
() => factory.GetEngineForCurrentThread());
390+
Assert.Equal("Usage of the script pre-compilation without caching does not make sense.", ex.Message);
391+
}
392+
343393
[Fact]
344394
public void ShouldHandleLoadingExternalReactVersion()
345395
{

0 commit comments

Comments
 (0)