Skip to content

Commit 6106c30

Browse files
Fixed Twitter badge, updated Jekyll dependencies, and added module interop blog entry.
1 parent 5f54c40 commit 6106c30

File tree

3 files changed

+134
-4
lines changed

3 files changed

+134
-4
lines changed

ReadMe.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[![Banner](https://github.com/microsoft/ClearScript/blob/master/docs/ClearScript7-ReadMe.png)](https://microsoft.github.io/ClearScript/)
22

3-
[![Follow](https://img.shields.io/twitter/follow/ClearScriptLib?style=social&label=Follow)](https://twitter.com/ClearScriptLib)
3+
[![Twitter Follow](https://img.shields.io/badge/Follow-%40ClearScriptLib-white?logo=twitter&style=social)](https://twitter.com/ClearScriptLib)
44

55
# Description
66
ClearScript is a library that makes it easy to add scripting to your .NET applications. It currently supports JavaScript (via [V8](https://developers.google.com/v8/) and [JScript](https://docs.microsoft.com/en-us/previous-versions//hbxc2t98(v=vs.85))) and [VBScript](https://docs.microsoft.com/en-us/previous-versions//t0aew7h6(v=vs.85)).

docs/Gemfile.lock

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
GEM
22
remote: https://rubygems.org/
33
specs:
4-
activesupport (6.0.6)
4+
activesupport (6.0.6.1)
55
concurrent-ruby (~> 1.0, >= 1.0.2)
66
i18n (>= 0.7, < 2)
77
minitest (~> 5.1)
@@ -15,7 +15,7 @@ GEM
1515
coffee-script-source (1.11.1)
1616
colorator (1.1.0)
1717
commonmarker (0.23.7)
18-
concurrent-ruby (1.1.10)
18+
concurrent-ruby (1.2.0)
1919
dnsruby (1.61.9)
2020
simpleidn (~> 0.1)
2121
em-websocket (0.5.3)
@@ -25,7 +25,7 @@ GEM
2525
ffi (>= 1.15.0)
2626
eventmachine (1.2.7)
2727
execjs (2.8.1)
28-
faraday (2.7.2)
28+
faraday (2.7.4)
2929
faraday-net_http (>= 2.0, < 3.1)
3030
ruby2_keywords (>= 0.0.4)
3131
faraday-net_http (3.0.2)
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
---
2+
title: Module Interoperability in ClearScript 7.3.7
3+
---
4+
Standard (ES6) modules can now import CommonJS modules.
5+
6+
# Introduction
7+
8+
[JavaScript modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) offer a way to split complex scripts into independent functional units with well-defined interfaces. The [`import`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import) and [`export`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export) declarations, as well as the [`import`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import) operator, were introduced in ECMAScript 2015 (ES6) as a standard way for modules to share code and data.
9+
10+
This facility supersedes earlier module specifications such as [CommonJS](https://commonjs.org/). However, the latter remains in heavy use, and many popular libraries aren't available in any other form.
11+
12+
ClearScript 7.3.7 allows JavaScript modules to import resources from CommonJS libraries. In this post we'll walk through an example.
13+
14+
# Basic Setup
15+
16+
For this example, let's allow scripts to load documents and use the console:
17+
18+
{% highlight C# %}
19+
20+
engine.DocumentSettings.AccessFlags = DocumentAccessFlags.EnableFileLoading;
21+
engine.AddHostType(typeof(Console));
22+
23+
{% endhighlight %}
24+
25+
26+
# Document Categories
27+
28+
ClearScript uses [_document categories_](https://microsoft.github.io/ClearScript/Reference/html/T_Microsoft_ClearScript_DocumentCategory.htm) to distinguish between the following document types:
29+
- JavaScript
30+
module – [`ModuleCategory.Standard`](https://microsoft.github.io/ClearScript/Reference/html/P_Microsoft_ClearScript_JavaScript_ModuleCategory_Standard.htm)
31+
- CommonJS module – [`ModuleCategory.CommonJS`](https://microsoft.github.io/ClearScript/Reference/html/P_Microsoft_ClearScript_JavaScript_ModuleCategory_CommonJS.htm)
32+
- Normal script – [`DocumentCategory.Script`](https://microsoft.github.io/ClearScript/Reference/html/P_Microsoft_ClearScript_DocumentCategory_Script.htm)
33+
34+
However, it has no way to _detect_ the category of a document. Instead, the host must specify the category when it initiates script execution:
35+
36+
{% highlight C# %}
37+
38+
engine.Execute(new DocumentInfo { Category = ModuleCategory.Standard }, @"
39+
import { Rectangle } from 'Geometry';
40+
Console.WriteLine('The area is {0}.', new Rectangle(3, 4).Area);
41+
");
42+
43+
{% endhighlight %}
44+
45+
If the host doesn't provide a category, ClearScript assumes `DocumentCategory.Script`.
46+
47+
On the other hand, if a module is loaded on behalf of another module, it _inherits_ its category from the requesting module. In our example, **Geometry** inherits `ModuleCategory.Standard`.
48+
49+
# Overriding the Category
50+
51+
Now let's suppose that **Geometry** is actually a CommonJS module and looks something like this:
52+
53+
{% highlight JavaScript %}
54+
55+
// Geometry.js
56+
exports.Rectangle = class {
57+
constructor(width, height) {
58+
this.width = width;
59+
this.height = height;
60+
}
61+
get Area() {
62+
return this.width * this.height;
63+
}
64+
}
65+
66+
{% endhighlight %}
67+
68+
Normally, the sample code above would result in a [`SyntaxError`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SyntaxError) with a message such as "The requested module 'Geometry' does not provide an export named 'Rectangle'".
69+
70+
To allow our example to work, we must _override_ **Geometry**'s document category. To do that, we can use a [document load callback](https://microsoft.github.io/ClearScript/Reference/html/P_Microsoft_ClearScript_DocumentSettings_LoadCallback.htm):
71+
72+
{% highlight C# %}
73+
74+
engine.DocumentSettings.LoadCallback = (ref DocumentInfo info) => {
75+
if (Path.GetFileNameWithoutExtension(info.Uri.AbsolutePath) == "Geometry") {
76+
info.Category = ModuleCategory.CommonJS;
77+
}
78+
};
79+
80+
{% endhighlight %}
81+
82+
Note that we're using a simple file name comparison to assign the document category. A real-world host might use a more generic algorithm, basing the assignment on the document's location, its file name extension, an external manifest, or even the document's contents.
83+
84+
# A Final Hurdle
85+
86+
In ClearScript 7.3.7, `V8ScriptEngine` is capable of importing CommonJS resources via the standard `import` declaration and operator. However, by default, the document loader throws an exception if a newly loaded document is of an unexpected category.
87+
88+
In other words, simply overriding the category would make our example fail even earlier – at the document loading stage. ClearScript 7.3.7 retains that behavior for compatibility and safety reasons. In many cases, blocking unexpected document categories is the prudent option.
89+
90+
In _this_ case, however, we can use a new flag to relax that requirement:
91+
92+
{% highlight C# %}
93+
94+
engine.DocumentSettings.AccessFlags |= DocumentAccessFlags.AllowCategoryMismatch;
95+
96+
{% endhighlight %}
97+
98+
With this flag in place, the document loader allows **Geometry** to pass on to the script engine, which now supports the CommonJS module category and safely imports the requested resources.
99+
100+
# Putting It All Together
101+
102+
Here's the complete, working sample code:
103+
104+
{% highlight C# %}
105+
106+
engine.DocumentSettings.AccessFlags = DocumentAccessFlags.EnableFileLoading | DocumentAccessFlags.AllowCategoryMismatch;
107+
engine.DocumentSettings.LoadCallback = (ref DocumentInfo info) => {
108+
if (Path.GetFileNameWithoutExtension(info.Uri.AbsolutePath) == "Geometry") {
109+
info.Category = ModuleCategory.CommonJS;
110+
}
111+
};
112+
engine.AddHostType(typeof(Console));
113+
engine.Execute(new DocumentInfo { Category = ModuleCategory.Standard }, @"
114+
import { Rectangle } from 'Geometry';
115+
Console.WriteLine('The area is {0}.', new Rectangle(3, 4).Area);
116+
");
117+
118+
{% endhighlight %}
119+
120+
Module interoperability allows newer scripts to use the standard JavaScript module facility while consuming existing CommonJS libraries.
121+
122+
# How About Reverse Interoperability?
123+
124+
Unfortunately, importing standard modules from CommonJS modules is _not_ possible. The problem has to do with synchronous vs. asynchronous execution modes.
125+
126+
Specifically, standard modules can be [asynchronous](https://github.com/tc39/proposal-top-level-await), so they can invoke both synchronous and asynchronous code at the top level. Even if a module doesn't use [`await`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await), its top-level code can be effectively asynchronous if it imports any asynchronous modules.
127+
128+
The top-level code of a CommonJS module is executed as a normal (synchronous) function, so it cannot interoperate with asynchronous code.
129+
130+
Good luck!

0 commit comments

Comments
 (0)