Skip to content
This repository has been archived by the owner on Apr 16, 2020. It is now read-only.

esm: experimental wasm modules #46

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion lib/internal/modules/esm/default_resolve.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const preserveSymlinks = getOptionValue('--preserve-symlinks');
const preserveSymlinksMain = getOptionValue('--preserve-symlinks-main');
const experimentalJsonModules = getOptionValue('--experimental-json-modules');
const typeFlag = getOptionValue('--input-type');

const experimentalWasmModules = getOptionValue('--experimental-wasm-modules');
const { resolve: moduleWrapResolve,
getPackageType } = internalBinding('module_wrap');
const { pathToFileURL, fileURLToPath } = require('internal/url');
Expand Down Expand Up @@ -44,6 +44,16 @@ const legacyExtensionFormatMap = {
'.node': 'commonjs'
};

if (experimentalWasmModules) {
// This is a total hack
Object.assign(extensionFormatMap, {
guybedford marked this conversation as resolved.
Show resolved Hide resolved
'.wasm': 'wasm'
});
Object.assign(legacyExtensionFormatMap, {
'.wasm': 'wasm'
});
}

if (experimentalJsonModules) {
// This is a total hack
Object.assign(extensionFormatMap, {
Expand Down
41 changes: 39 additions & 2 deletions lib/internal/modules/esm/translators.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
'use strict';

/* global WebAssembly */

const {
JSON,
Object,
SafeMap,
StringPrototype,
JSON
StringPrototype
} = primordials;

const { NativeModule } = require('internal/bootstrap/loaders');
Expand Down Expand Up @@ -141,3 +144,37 @@ translators.set('json', async function jsonStrategy(url) {
reflect.exports.default.set(module.exports);
});
});

// Strategy for loading a wasm module
translators.set('wasm', async function(url) {
const pathname = fileURLToPath(url);
const buffer = await readFileAsync(pathname);
debug(`Translating WASMModule ${url}`);
try {
const compiled = await WebAssembly.compile(buffer);
// Note: This approach executes dependencies early, and will
// deadlock in cycles, both of which will be resolved when
// top-level await support lands.
guybedford marked this conversation as resolved.
Show resolved Hide resolved
const loader = await esmLoader.loaderPromise;
const imports = Object.create(null);
await Promise.all(
WebAssembly.Module.imports(compiled).map(async (impt) => {
imports[impt.module] = await loader.import(impt.module, url);
})
guybedford marked this conversation as resolved.
Show resolved Hide resolved
);
const exportNames = WebAssembly.Module.exports(compiled)
.map((i) => i.name);
return createDynamicModule(exportNames, url, (reflect) => {
// Creating a wasm instance with the JS api will automatically
// run the wasm start function, so this must be done inside the
// dynamic module callback.
const { exports } = new WebAssembly.Instance(compiled, imports);
exportNames.forEach((name) => {
reflect.exports[name].set(exports[name]);
});
});
} catch (err) {
err.message = pathname + ': ' + err.message;
throw err;
}
});
4 changes: 4 additions & 0 deletions src/node_options.cc
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,10 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
"experimental ES Module support and caching modules",
&EnvironmentOptions::experimental_modules,
kAllowedInEnvironment);
AddOption("--experimental-wasm-modules",
"experimental ES Module support for webassembly modules",
&EnvironmentOptions::experimental_wasm_modules,
kAllowedInEnvironment);
AddOption("--experimental-policy",
"use the specified file as a "
"security policy",
Expand Down
1 change: 1 addition & 0 deletions src/node_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ class EnvironmentOptions : public Options {
bool experimental_json_modules = false;
bool experimental_modules = false;
std::string es_module_specifier_resolution;
bool experimental_wasm_modules = false;
std::string module_type;
std::string experimental_policy;
bool experimental_repl_await = false;
Expand Down
9 changes: 9 additions & 0 deletions test/es-module/test-esm-wasm.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Flags: --experimental-modules --experimental-wasm-modules
/* eslint-disable node-core/required-modules */
import { add, addImported } from '../fixtures/es-modules/simple.wasm';
import { strictEqual } from 'assert';

strictEqual(add(10, 20), 30);

strictEqual(addImported(0), 42);
strictEqual(addImported(1), 43);
Binary file added test/fixtures/es-modules/simple.wasm
Binary file not shown.
3 changes: 3 additions & 0 deletions test/fixtures/es-modules/wasm-dep.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function jsFn () {
return 42;
}