compileSources static method
Compile sources (module name → source text) into a bundle.
Compilation runs in a scratch engine so the peak parser cost is not
charged to the engine that later runs the code. When verify is set the
import graph is linked (but not executed) and a missing module fails here
instead of at the first import at runtime.
stripSource drops function source text, which shrinks both the bytecode
and the runtime heap at the cost of Function.prototype.toString.
Implementation
static JsModuleBundle compileSources({
required String entry,
required Map<String, String> sources,
bool stripSource = true,
bool verify = true,
}) {
if (!sources.containsKey(entry)) {
throw ArgumentError.value(
entry,
'entry',
'entry module is not present in sources',
);
}
final modules = <String, Uint8List>{};
final missing = <String>{};
// QuickJS resolves a module's imports while compiling it, so the scratch
// engine has to be able to reach every dependency. Serving them from
// [sources] is also what turns an incomplete graph into an error here
// instead of at the first import at runtime.
final scratch = QuickJsRuntime2(
memoryLimit: 0,
webApis: const JsWebApis.none(),
moduleHandler: (name) {
final source = sources[name];
if (source == null) {
missing.add(name);
throw JSError('module "$name" is not in sources');
}
return source;
},
);
try {
sources.forEach((name, source) {
missing.clear();
try {
modules[name] = scratch.compile(
source,
name,
stripSource: stripSource,
asModule: true,
);
} on JSError catch (error) {
if (missing.isEmpty) rethrow;
throw JSError(
'$name imports ${missing.join(', ')}, which '
'${missing.length == 1 ? 'is' : 'are'} not in sources',
error.stack,
);
}
});
} finally {
scratch.dispose();
}
final bundle = JsModuleBundle(entry: entry, modules: modules);
if (verify) bundle.verify();
return bundle;
}