Skip to content

Commit c4211bc

Browse files
authored
Merge pull request #74 from mozilla-spidermonkey/module-dynamic-import
Example of how to do dynamic import
2 parents e8f9bfd + 0c279a9 commit c4211bc

1 file changed

Lines changed: 66 additions & 4 deletions

File tree

examples/modules.cpp

Lines changed: 66 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
#include <string>
33

44
#include <jsapi.h>
5+
#include <jsfriendapi.h>
56

67
#include <js/CompilationAndEvaluation.h>
8+
#include <js/Initialization.h>
79
#include <js/Modules.h>
810
#include <js/SourceText.h>
911

@@ -76,6 +78,13 @@ static JSObject* ExampleResolveHook(JSContext* cx,
7678
}
7779
}
7880

81+
if (filename == u"b") {
82+
mod = CompileExampleModule(cx, "b", "export const C2 = 2;");
83+
if (!mod) {
84+
return nullptr;
85+
}
86+
}
87+
7988
// Register result in table.
8089
if (mod) {
8190
moduleRegistry.emplace(filename, JS::PersistentRootedObject(cx, mod));
@@ -86,7 +95,43 @@ static JSObject* ExampleResolveHook(JSContext* cx,
8695
return nullptr;
8796
}
8897

98+
// Callback for embedding to implement an asynchronous dynamic import. This must
99+
// do the same thing as the module resolve hook, but also link and evaluate the
100+
// module, and it must always call JS::FinishDynamicModuleImport when done.
101+
static bool ExampleDynamicImportHook(JSContext* cx,
102+
JS::Handle<JS::Value> referencingPrivate,
103+
JS::Handle<JSObject*> moduleRequest,
104+
JS::Handle<JSObject*> promise) {
105+
JS::Rooted<JSObject*> mod{
106+
cx, ExampleResolveHook(cx, referencingPrivate, moduleRequest)};
107+
if (!mod || !JS::ModuleLink(cx, mod)) {
108+
return JS::FinishDynamicModuleImport(cx, nullptr, referencingPrivate,
109+
moduleRequest, promise);
110+
}
111+
112+
JS::Rooted<JS::Value> rval{cx};
113+
if (!JS::ModuleEvaluate(cx, mod, &rval)) {
114+
return JS::FinishDynamicModuleImport(cx, nullptr, referencingPrivate,
115+
moduleRequest, promise);
116+
}
117+
if (rval.isObject()) {
118+
JS::Rooted<JSObject*> evaluationPromise{cx, &rval.toObject()};
119+
return JS::FinishDynamicModuleImport(
120+
cx, evaluationPromise, referencingPrivate, moduleRequest, promise);
121+
}
122+
return JS::FinishDynamicModuleImport(cx, nullptr, referencingPrivate,
123+
moduleRequest, promise);
124+
}
125+
89126
static bool ModuleExample(JSContext* cx) {
127+
// In order to use dynamic imports, we need a job queue. We can use the
128+
// default SpiderMonkey job queue for this example, but a more sophisticated
129+
// embedding would use a custom job queue to schedule its own tasks.
130+
if (!js::UseInternalJobQueues(cx)) return false;
131+
132+
// We must instantiate self-hosting *after* setting up job queue.
133+
if (!JS::InitSelfHostedCode(cx)) return false;
134+
90135
JS::RootedObject global(cx, boilerplate::CreateGlobal(cx));
91136
if (!global) {
92137
return false;
@@ -95,11 +140,17 @@ static bool ModuleExample(JSContext* cx) {
95140
JSAutoRealm ar(cx, global);
96141

97142
// Register a hook in order to provide modules
98-
JS::SetModuleResolveHook(JS_GetRuntime(cx), ExampleResolveHook);
143+
JSRuntime* rt = JS_GetRuntime(cx);
144+
JS::SetModuleResolveHook(rt, ExampleResolveHook);
145+
JS::SetModuleDynamicImportHook(rt, ExampleDynamicImportHook);
99146

100147
// Compile the top module.
101-
JS::RootedObject mod(
102-
cx, CompileExampleModule(cx, "top", "import {C1} from 'a';"));
148+
static const char top_module_source[] = R"js(
149+
import {C1} from 'a';
150+
const {C2} = await import('b');
151+
)js";
152+
JS::Rooted<JSObject*> mod{cx,
153+
CompileExampleModule(cx, "top", top_module_source)};
103154
if (!mod) {
104155
boilerplate::ReportAndClearException(cx);
105156
return false;
@@ -120,11 +171,22 @@ static bool ModuleExample(JSContext* cx) {
120171
return false;
121172
}
122173

174+
js::RunJobs(cx);
175+
if (rval.isObject()) {
176+
JS::Rooted<JSObject*> evaluationPromise{cx, &rval.toObject()};
177+
if (!JS::ThrowOnModuleEvaluationFailure(
178+
cx, evaluationPromise,
179+
JS::ModuleErrorBehaviour::ThrowModuleErrorsSync)) {
180+
boilerplate::ReportAndClearException(cx);
181+
return false;
182+
}
183+
}
184+
123185
return true;
124186
}
125187

126188
int main(int argc, const char* argv[]) {
127-
if (!boilerplate::RunExample(ModuleExample)) {
189+
if (!boilerplate::RunExample(ModuleExample, /* initSelfHosting = */ false)) {
128190
return 1;
129191
}
130192
return 0;

0 commit comments

Comments
 (0)