Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

esm: add package type wasm #31388

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/internal/modules/cjs/loader.js
Expand Up @@ -1225,7 +1225,7 @@ Module._extensions['.js'] = function(module, filename) {
if (filename.endsWith('.js')) {
const pkg = readPackageScope(filename);
// Function require shouldn't be used in ES modules.
if (pkg && pkg.data && pkg.data.type === 'module') {
if (pkg && pkg.data && pkg.data.type !== 'commonjs') {
const parentPath = module.parent && module.parent.filename;
const packageJsonPath = path.resolve(pkg.path, 'package.json');
throw new ERR_REQUIRE_ESM(filename, parentPath, packageJsonPath);
Expand Down
41 changes: 32 additions & 9 deletions lib/internal/modules/esm/get_format.js
Expand Up @@ -14,29 +14,52 @@ const { ERR_UNKNOWN_FILE_EXTENSION } = require('internal/errors').codes;

// const TYPE_NONE = 0;
// const TYPE_COMMONJS = 1;
const TYPE_MODULE = 2;
// const TYPE_MODULE = 2;
// const TYPE_WASM = 3;

const extensionFormatMap = {
const wasmFormatMap = {
'__proto__': null,
'.cjs': 'commonjs',
'.mjs': 'module',
};

const moduleFormatMap = {
'__proto__': null,
'': 'module',
'.cjs': 'commonjs',
'.js': 'module',
'.mjs': 'module'
};

const legacyExtensionFormatMap = {
'__proto__': null,
'': 'commonjs',
'.cjs': 'commonjs',
'.js': 'commonjs',
'.json': 'commonjs',
'.mjs': 'module',
'.node': 'commonjs'
};

if (experimentalWasmModules)
extensionFormatMap['.wasm'] = legacyExtensionFormatMap['.wasm'] = 'wasm';
const formatMaps = [
legacyExtensionFormatMap,
legacyExtensionFormatMap,
moduleFormatMap,
experimentalWasmModules ? wasmFormatMap : legacyExtensionFormatMap
];

if (experimentalWasmModules) {
wasmFormatMap[''] =
wasmFormatMap['.wasm'] =
moduleFormatMap['.wasm'] =
legacyExtensionFormatMap['.wasm'] = 'wasm';
}

if (experimentalJsonModules)
extensionFormatMap['.json'] = legacyExtensionFormatMap['.json'] = 'json';
if (experimentalJsonModules) {
wasmFormatMap['.json'] =
moduleFormatMap['.json'] =
legacyExtensionFormatMap['.json'] = 'json';
}

function defaultGetFormat(url, context, defaultGetFormat) {
if (NativeModule.canBeRequiredByUsers(url)) {
Expand All @@ -56,10 +79,10 @@ function defaultGetFormat(url, context, defaultGetFormat) {
const ext = extname(parsed.pathname);
let format;
if (ext === '.js' || ext === '') {
format = getPackageType(parsed.href) === TYPE_MODULE ?
'module' : 'commonjs';
const type = getPackageType(parsed.href);
format = formatMaps[type][ext];
} else {
format = extensionFormatMap[ext];
format = moduleFormatMap[ext];
}
if (!format) {
if (experimentalSpeciferResolution === 'node') {
Expand Down
3 changes: 2 additions & 1 deletion lib/internal/modules/run_main.js
Expand Up @@ -34,7 +34,8 @@ function shouldUseESMLoader(mainPath) {
if (!mainPath || mainPath.endsWith('.cjs'))
return false;
const pkg = readPackageScope(mainPath);
return pkg && pkg.data.type === 'module';
return pkg && typeof pkg.data.type === 'string' &&
pkg.data.type !== 'commonjs';
}

function runMainESM(mainPath) {
Expand Down
3 changes: 2 additions & 1 deletion src/env.h
Expand Up @@ -94,7 +94,7 @@ struct PackageConfig {
enum class IsValid { Yes, No };
enum class HasMain { Yes, No };
enum class HasName { Yes, No };
enum PackageType : uint32_t { None = 0, CommonJS, Module };
enum PackageType : uint32_t { None = 0, CommonJS, Module, WASM };

const Exists exists;
const IsValid is_valid;
Expand Down Expand Up @@ -377,6 +377,7 @@ constexpr size_t kFsStatsBufferLength =
V(value_string, "value") \
V(verify_error_string, "verifyError") \
V(version_string, "version") \
V(wasm_string, "wasm") \
V(weight_string, "weight") \
V(windows_hide_string, "windowsHide") \
V(windows_verbatim_arguments_string, "windowsVerbatimArguments") \
Expand Down
2 changes: 2 additions & 0 deletions src/module_wrap.cc
Expand Up @@ -649,6 +649,8 @@ Maybe<const PackageConfig*> GetPackageConfig(Environment* env,
pkg_type = PackageType::Module;
} else if (type_v->StrictEquals(env->commonjs_string())) {
pkg_type = PackageType::CommonJS;
} else if (type_v->StrictEquals(env->wasm_string())) {
pkg_type = PackageType::WASM;
}
// ignore unknown types for forwards compatibility
}
Expand Down
62 changes: 42 additions & 20 deletions test/es-module/test-esm-wasm.mjs
@@ -1,5 +1,5 @@
// Flags: --experimental-wasm-modules
import '../common/index.mjs';
import { mustCall } from '../common/index.mjs';
import { path } from '../common/fixtures.mjs';
import { add, addImported } from '../fixtures/es-modules/simple.wasm';
import { state } from '../fixtures/es-modules/wasm-dep.mjs';
Expand All @@ -16,22 +16,44 @@ strictEqual(state, 'WASM JS Function Executed');

strictEqual(addImported(1), 43);

// Test warning message
const child = spawn(process.execPath, [
'--experimental-wasm-modules',
path('/es-modules/wasm-modules.mjs')
]);

let stderr = '';
child.stderr.setEncoding('utf8');
child.stderr.on('data', (data) => {
stderr += data;
});
child.on('close', (code, signal) => {
strictEqual(code, 0);
strictEqual(signal, null);
ok(stderr.toString().includes(
'ExperimentalWarning: Importing Web Assembly modules is ' +
'an experimental feature. This feature could change at any time'
));
});
{
// Test warning message
const child = spawn(process.execPath, [
'--experimental-wasm-modules',
path('/es-modules/wasm-modules.mjs')
]);

let stderr = '';
child.stderr.setEncoding('utf8');
child.stderr.on('data', (data) => {
stderr += data;
});
child.on('close', (code, signal) => {
strictEqual(code, 0);
strictEqual(signal, null);
ok(stderr.toString().includes(
'ExperimentalWarning: Importing Web Assembly modules is ' +
'an experimental feature. This feature could change at any time'
));
});
}

{
const entry = path('/es-modules/package-type-wasm/noext-wasm');

// Run a module that does not have extension.
// This is to ensure that "type": "module" applies to extensionless files.

const child = spawn(process.execPath, ['--experimental-wasm-modules', entry]);

let stdout = '';
child.stdout.setEncoding('utf8');
child.stdout.on('data', (data) => {
stdout += data;
});
child.on('close', mustCall((code, signal) => {
strictEqual(code, 0);
strictEqual(signal, null);
strictEqual(stdout, '');
}));
}