[turbopack] Remove WebAssembly helpers from the default runtime (#94373)

This PR builds on https://github.com/vercel/next.js/pull/94372. It does
a similar thing but for the WebAssembly-related helpers. Collectively,
these cut the run time by about 2KB (5%).

The WebAssembly-related module is inserted within
`turbopack-wasm/src/loader.rs`. Similar design questions to #94372
exist. `RUNTIME_ROOT` is added to `contextPrototype` and the JS-code
lives in the `turbopack-wasm` package.
This commit is contained in:
Sam Poder
2026-06-08 13:31:58 -07:00
committed by GitHub
parent 0a074bda44
commit 83eea78b32
35 changed files with 235 additions and 500 deletions
@@ -67,19 +67,6 @@ interface RuntimeBackend {
* Returns the same Promise for the same chunk URL.
*/
loadChunkCached: (sourceType: SourceType, chunkUrl: ChunkUrl) => Promise<void>
loadWebAssembly: (
sourceType: SourceType,
sourceData: SourceData,
wasmChunkPath: ChunkPath,
edgeModule: () => WebAssembly.Module,
importsObj: WebAssembly.Imports
) => Promise<Exports>
loadWebAssemblyModule: (
sourceType: SourceType,
sourceData: SourceData,
wasmChunkPath: ChunkPath,
edgeModule: () => WebAssembly.Module
) => Promise<WebAssembly.Module>
}
interface DevRuntimeBackend {
@@ -413,33 +400,3 @@ function isJs(chunkUrlOrPath: ChunkUrl | ChunkPath): boolean {
function isCss(chunkUrl: ChunkUrl): boolean {
return endsWithExtension(chunkUrl, '.css')
}
function loadWebAssembly(
this: TurbopackBaseContext<Module>,
chunkPath: ChunkPath,
edgeModule: () => WebAssembly.Module,
importsObj: WebAssembly.Imports
): Promise<Exports> {
return BACKEND.loadWebAssembly(
SourceType.Parent,
this.m.id,
chunkPath,
edgeModule,
importsObj
)
}
contextPrototype.w = loadWebAssembly
function loadWebAssemblyModule(
this: TurbopackBaseContext<Module>,
chunkPath: ChunkPath,
edgeModule: () => WebAssembly.Module
): Promise<WebAssembly.Module> {
return BACKEND.loadWebAssemblyModule(
SourceType.Parent,
this.m.id,
chunkPath,
edgeModule
)
}
contextPrototype.u = loadWebAssemblyModule
@@ -74,34 +74,6 @@ const chunkResolvers: Map<ChunkUrl, ChunkResolver> = new Map()
loadChunkCached(sourceType: SourceType, chunkUrl: ChunkUrl) {
return doLoadChunk(sourceType, chunkUrl)
},
async loadWebAssembly(
_sourceType: SourceType,
_sourceData: SourceData,
wasmChunkPath: ChunkPath,
_edgeModule: () => WebAssembly.Module,
importsObj: WebAssembly.Imports
): Promise<Exports> {
const req = fetchWebAssembly(wasmChunkPath)
const { instance } = await WebAssembly.instantiateStreaming(
req,
importsObj
)
return instance.exports
},
async loadWebAssemblyModule(
_sourceType: SourceType,
_sourceData: SourceData,
wasmChunkPath: ChunkPath,
_edgeModule: () => WebAssembly.Module
): Promise<WebAssembly.Module> {
const req = fetchWebAssembly(wasmChunkPath)
return await WebAssembly.compileStreaming(req)
},
}
function getOrCreateResolver(chunkUrl: ChunkUrl): ChunkResolver {
@@ -229,8 +201,4 @@ const chunkResolvers: Map<ChunkUrl, ChunkResolver> = new Map()
resolver.loadingStarted = true
return resolver.promise
}
function fetchWebAssembly(wasmChunkPath: ChunkPath) {
return fetch(getChunkRelativeUrl(wasmChunkPath))
}
})()
@@ -56,27 +56,6 @@ let BACKEND: RuntimeBackend
loadChunkCached(_sourceType: SourceType, _chunkUrl: ChunkUrl) {
throw new Error('chunk loading is not supported')
},
async loadWebAssembly(
_sourceType: SourceType,
_sourceData: SourceData,
chunkPath: ChunkPath,
edgeModule: () => WebAssembly.Module,
imports: WebAssembly.Imports
): Promise<Exports> {
const module = await loadEdgeWasm(chunkPath, edgeModule)
return await WebAssembly.instantiate(module, imports)
},
async loadWebAssemblyModule(
_sourceType: SourceType,
_sourceData: SourceData,
chunkPath: ChunkPath,
edgeModule: () => WebAssembly.Module
): Promise<WebAssembly.Module> {
return loadEdgeWasm(chunkPath, edgeModule)
},
}
const registeredChunks: Set<ChunkPath> = new Set()
@@ -149,22 +128,4 @@ let BACKEND: RuntimeBackend
getOrInstantiateRuntimeModule(chunkPath, moduleId)
}
}
async function loadEdgeWasm(
chunkPath: ChunkPath,
edgeModule: () => WebAssembly.Module
): Promise<WebAssembly.Module> {
let module
try {
module = edgeModule()
} catch (_e) {}
if (!module) {
throw new Error(
`dynamically loading WebAssembly is not supported in this runtime as global was not injected for chunk '${chunkPath}'`
)
}
return module
}
})()
@@ -3,7 +3,6 @@
/// <reference path="../../shared/runtime/runtime-utils.ts" />
/// <reference path="../../shared-node/base-externals-utils.ts" />
/// <reference path="../../shared-node/node-externals-utils.ts" />
/// <reference path="../../shared-node/node-wasm-utils.ts" />
/// <reference path="./nodejs-globals.d.ts" />
/**
@@ -143,26 +142,9 @@ function loadChunkAsyncByUrl<TModule extends Module>(
}
contextPrototype.L = loadChunkAsyncByUrl
function loadWebAssembly(
chunkPath: ChunkPath,
_edgeModule: () => WebAssembly.Module,
imports: WebAssembly.Imports
) {
const resolved = path.resolve(RUNTIME_ROOT, chunkPath)
return instantiateWebAssemblyFromPath(resolved, imports)
}
contextPrototype.w = loadWebAssembly
function loadWebAssemblyModule(
chunkPath: ChunkPath,
_edgeModule: () => WebAssembly.Module
) {
const resolved = path.resolve(RUNTIME_ROOT, chunkPath)
return compileWebAssemblyFromPath(resolved)
}
contextPrototype.u = loadWebAssemblyModule
// Shared runtime primitive: the root that on-disk chunk paths are resolved
// against. Used by the bundled wasm helper (exposed as `__turbopack_runtime_root__`).
contextPrototype.w = RUNTIME_ROOT
const regexJsUrl = /\.js(?:\?[^#]*)?(?:#.*)?$/
/**
@@ -1,39 +0,0 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
/// <reference path="../shared/runtime/runtime-utils.ts" />
function readWebAssemblyAsResponse(path: string) {
const { createReadStream } = require('fs') as typeof import('fs')
const { Readable } = require('stream') as typeof import('stream')
const stream = createReadStream(path)
// @ts-ignore unfortunately there's a slight type mismatch with the stream.
return new Response(Readable.toWeb(stream), {
headers: {
'content-type': 'application/wasm',
},
})
}
async function compileWebAssemblyFromPath(
path: string
): Promise<WebAssembly.Module> {
const response = readWebAssemblyAsResponse(path)
return await WebAssembly.compileStreaming(response)
}
async function instantiateWebAssemblyFromPath(
path: string,
importsObj: WebAssembly.Imports
): Promise<Exports> {
const response = readWebAssemblyAsResponse(path)
const { instance } = await WebAssembly.instantiateStreaming(
response,
importsObj
)
return instance.exports
}
@@ -76,15 +76,6 @@ type DynamicExport = (
type LoadChunk = (chunkPath: ChunkPath) => Promise<any> | undefined
type LoadChunkByUrl = (chunkUrl: ChunkUrl) => Promise<any> | undefined
type LoadWebAssembly = (
wasmChunkPath: ChunkPath,
edgeModule: () => WebAssembly.Module,
imports: WebAssembly.Imports
) => Exports
type LoadWebAssemblyModule = (
wasmChunkPath: ChunkPath,
edgeModule: () => WebAssembly.Module
) => WebAssembly.Module
type ModuleCache<M> = Record<ModuleId, M>
// TODO properly type values here
@@ -155,8 +146,7 @@ interface TurbopackBaseContext<M> {
l: LoadChunk
L: LoadChunkByUrl
h: GetChunkRelativeURL
w: LoadWebAssembly
u: LoadWebAssemblyModule
w: string
P: ResolveAbsolutePath
F: ResolveFileUrl
U: RelativeURL
@@ -205,17 +205,6 @@ pub async fn get_browser_runtime_code(
.await?,
);
}
if *environment.supports_wasm().await? {
code.push_code(
&*embed_static_code(
asset_context,
rcstr!("shared-node/node-wasm-utils.ts"),
generate_source_map,
)
.await?,
);
}
for backend_code in runtime_backend_code {
code.push_code(
&*embed_static_code(asset_context, backend_code.into(), generate_source_map).await?,
@@ -33,12 +33,6 @@ pub async fn get_nodejs_runtime_code(
rcstr!("shared-node/node-externals-utils.ts"),
generate_source_map,
);
let shared_node_wasm_utils_code = embed_static_code(
asset_context,
rcstr!("shared-node/node-wasm-utils.ts"),
generate_source_map,
);
// Runtime base is shared between production and development
let runtime_base_code = embed_static_code(
asset_context,
@@ -61,7 +55,6 @@ pub async fn get_nodejs_runtime_code(
}
code.push_code(&*shared_base_external_utils_code.await?);
code.push_code(&*shared_node_external_utils_code.await?);
code.push_code(&*shared_node_wasm_utils_code.await?);
code.push_code(&*runtime_base_code.await?);
match runtime_type {
@@ -90,16 +90,15 @@ pub const TURBOPACK_EXTERNAL_IMPORT: &TurbopackRuntimeFunctionShortcut = make_sh
pub const TURBOPACK_REFRESH: &TurbopackRuntimeFunctionShortcut = make_shortcut!("k");
pub const TURBOPACK_REQUIRE_STUB: &TurbopackRuntimeFunctionShortcut = make_shortcut!("z");
pub const TURBOPACK_REQUIRE_REAL: &TurbopackRuntimeFunctionShortcut = make_shortcut!("t");
pub const TURBOPACK_WASM: &TurbopackRuntimeFunctionShortcut = make_shortcut!("w");
pub const TURBOPACK_WASM_MODULE: &TurbopackRuntimeFunctionShortcut = make_shortcut!("u");
pub const TURBOPACK_GLOBAL: &TurbopackRuntimeFunctionShortcut = make_shortcut!("g");
pub const TURBOPACK_CHUNK_RELATIVE_URL: &TurbopackRuntimeFunctionShortcut = make_shortcut!("h");
pub const TURBOPACK_RUNTIME_ROOT: &TurbopackRuntimeFunctionShortcut = make_shortcut!("w");
pub const TURBOPACK_CHUNK_BASE_PATH: &TurbopackRuntimeFunctionShortcut = make_shortcut!("b");
pub const TURBOPACK_ASSET_SUFFIX: &TurbopackRuntimeFunctionShortcut = make_shortcut!("X");
/// Adding an entry to this list will automatically ensure that `__turbopack_XXX__` can be called
/// from user code (by inserting a replacement into free_var_references)
pub const TURBOPACK_RUNTIME_FUNCTION_SHORTCUTS: [(&str, &TurbopackRuntimeFunctionShortcut); 26] = [
pub const TURBOPACK_RUNTIME_FUNCTION_SHORTCUTS: [(&str, &TurbopackRuntimeFunctionShortcut); 25] = [
("__turbopack_require__", TURBOPACK_REQUIRE),
("__turbopack_module_context__", TURBOPACK_MODULE_CONTEXT),
("__turbopack_import__", TURBOPACK_IMPORT),
@@ -130,12 +129,11 @@ pub const TURBOPACK_RUNTIME_FUNCTION_SHORTCUTS: [(&str, &TurbopackRuntimeFunctio
"__turbopack_clear_chunk_cache__",
TURBOPACK_CLEAR_CHUNK_CACHE,
),
("__turbopack_wasm__", TURBOPACK_WASM),
("__turbopack_wasm_module__", TURBOPACK_WASM_MODULE),
(
"__turbopack_chunk_relative_url__",
TURBOPACK_CHUNK_RELATIVE_URL,
),
("__turbopack_chunk_base_path__", TURBOPACK_CHUNK_BASE_PATH),
("__turbopack_chunk_asset_suffix__", TURBOPACK_ASSET_SUFFIX),
("__turbopack_runtime_root__", TURBOPACK_RUNTIME_ROOT),
];
@@ -17,7 +17,7 @@ use turbopack_core::{
output::{OutputAsset, OutputAssets, OutputAssetsWithReferenced},
reference::{ModuleReference, ModuleReferences, SingleChunkableModuleReference},
reference_type::{EcmaScriptModulesReferenceSubType, ReferenceType},
resolve::{ExportUsage, ModulePart, ModuleResolveResult},
resolve::{ExportUsage, ModuleResolveResult},
};
use super::worker_type::WorkerType;
@@ -149,9 +149,7 @@ impl WorkerLoaderModule {
.asset_context
.process(
Vc::upcast(FileSource::new(embed_fs().root().await?.join(&helper)?)),
ReferenceType::EcmaScriptModules(EcmaScriptModulesReferenceSubType::ImportPart(
ModulePart::Export(rcstr!("default")),
)),
ReferenceType::EcmaScriptModules(EcmaScriptModulesReferenceSubType::Import),
)
.module())
}
@@ -1,4 +1,4 @@
;!function(){try { var e="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof global?global:"undefined"!=typeof window?window:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&((e._debugIds|| (e._debugIds={}))[n]="10b725f6-0979-dcb8-6d04-f7f42400db60")}catch(e){}}();
;!function(){try { var e="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof global?global:"undefined"!=typeof window?window:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&((e._debugIds|| (e._debugIds={}))[n]="66516bcd-473e-2cdd-712a-f3f1d535fbca")}catch(e){}}();
(globalThis["TURBOPACK"] || (globalThis["TURBOPACK"] = [])).push([
"output/1i9t_crates_turbopack-tests_tests_snapshot_debug-ids_browser_input_index_19boa0e.js",
{"otherChunks":["output/1do3_crates_turbopack-tests_tests_snapshot_debug-ids_browser_input_index_03ibyvs.js"],"runtimeModuleIds":["[project]/turbopack/crates/turbopack-tests/tests/snapshot/debug-ids/browser/input/index.js [test] (ecmascript)"]}
@@ -827,14 +827,6 @@ function isJs(chunkUrlOrPath) {
function isCss(chunkUrl) {
return endsWithExtension(chunkUrl, '.css');
}
function loadWebAssembly(chunkPath, edgeModule, importsObj) {
return BACKEND.loadWebAssembly(SourceType.Parent, this.m.id, chunkPath, edgeModule, importsObj);
}
contextPrototype.w = loadWebAssembly;
function loadWebAssemblyModule(chunkPath, edgeModule) {
return BACKEND.loadWebAssemblyModule(SourceType.Parent, this.m.id, chunkPath, edgeModule);
}
contextPrototype.u = loadWebAssemblyModule;
/// <reference path="./runtime-utils.ts" />
/// <reference path="./runtime-types.d.ts" />
/// <reference path="./dev-extensions.ts" />
@@ -1992,15 +1984,6 @@ let BACKEND;
* has been loaded.
*/ loadChunkCached (sourceType, chunkUrl) {
return doLoadChunk(sourceType, chunkUrl);
},
async loadWebAssembly (_sourceType, _sourceData, wasmChunkPath, _edgeModule, importsObj) {
const req = fetchWebAssembly(wasmChunkPath);
const { instance } = await WebAssembly.instantiateStreaming(req, importsObj);
return instance.exports;
},
async loadWebAssemblyModule (_sourceType, _sourceData, wasmChunkPath, _edgeModule) {
const req = fetchWebAssembly(wasmChunkPath);
return await WebAssembly.compileStreaming(req);
}
};
function getOrCreateResolver(chunkUrl) {
@@ -2113,9 +2096,6 @@ let BACKEND;
resolver.loadingStarted = true;
return resolver.promise;
}
function fetchWebAssembly(wasmChunkPath) {
return fetch(getChunkRelativeUrl(wasmChunkPath));
}
})();
/**
* This file contains the runtime code specific to the Turbopack development
@@ -2233,5 +2213,5 @@ chunkListsToRegister.forEach(registerChunkList);
})();
//# debugId=10b725f6-0979-dcb8-6d04-f7f42400db60
//# debugId=66516bcd-473e-2cdd-712a-f3f1d535fbca
//# sourceMappingURL=1do3_crates_turbopack-tests_tests_snapshot_debug-ids_browser_input_index_19boa0e.js.map
@@ -659,31 +659,9 @@ Context.prototype.P = resolveAbsolutePath;
return require('url').pathToFileURL(resolveAbsolutePath(modulePath)).href;
}
Context.prototype.F = resolveFileUrl;
/* eslint-disable @typescript-eslint/no-unused-vars */ /// <reference path="../shared/runtime/runtime-utils.ts" />
function readWebAssemblyAsResponse(path) {
const { createReadStream } = require('fs');
const { Readable } = require('stream');
const stream = createReadStream(path);
// @ts-ignore unfortunately there's a slight type mismatch with the stream.
return new Response(Readable.toWeb(stream), {
headers: {
'content-type': 'application/wasm'
}
});
}
async function compileWebAssemblyFromPath(path) {
const response = readWebAssemblyAsResponse(path);
return await WebAssembly.compileStreaming(response);
}
async function instantiateWebAssemblyFromPath(path, importsObj) {
const response = readWebAssemblyAsResponse(path);
const { instance } = await WebAssembly.instantiateStreaming(response, importsObj);
return instance.exports;
}
/* eslint-disable @typescript-eslint/no-unused-vars */ /// <reference path="../../shared/runtime/runtime-utils.ts" />
/// <reference path="../../shared-node/base-externals-utils.ts" />
/// <reference path="../../shared-node/node-externals-utils.ts" />
/// <reference path="../../shared-node/node-wasm-utils.ts" />
/// <reference path="./nodejs-globals.d.ts" />
/**
* Base Node.js runtime shared between production and development.
@@ -787,16 +765,9 @@ function loadChunkAsyncByUrl(chunkUrl) {
return loadChunkAsync.call(this, path1);
}
contextPrototype.L = loadChunkAsyncByUrl;
function loadWebAssembly(chunkPath, _edgeModule, imports) {
const resolved = path.resolve(RUNTIME_ROOT, chunkPath);
return instantiateWebAssemblyFromPath(resolved, imports);
}
contextPrototype.w = loadWebAssembly;
function loadWebAssemblyModule(chunkPath, _edgeModule) {
const resolved = path.resolve(RUNTIME_ROOT, chunkPath);
return compileWebAssemblyFromPath(resolved);
}
contextPrototype.u = loadWebAssemblyModule;
// Shared runtime primitive: the root that on-disk chunk paths are resolved
// against. Used by the bundled wasm helper (exposed as `__turbopack_runtime_root__`).
contextPrototype.w = RUNTIME_ROOT;
const regexJsUrl = /\.js(?:\?[^#]*)?(?:#.*)?$/;
/**
* Checks if a given path/URL ends with .js, optionally followed by ?query or #fragment.
File diff suppressed because one or more lines are too long
@@ -527,31 +527,9 @@ Context.prototype.P = resolveAbsolutePath;
return require('url').pathToFileURL(resolveAbsolutePath(modulePath)).href;
}
Context.prototype.F = resolveFileUrl;
/* eslint-disable @typescript-eslint/no-unused-vars */ /// <reference path="../shared/runtime/runtime-utils.ts" />
function readWebAssemblyAsResponse(path) {
const { createReadStream } = require('fs');
const { Readable } = require('stream');
const stream = createReadStream(path);
// @ts-ignore unfortunately there's a slight type mismatch with the stream.
return new Response(Readable.toWeb(stream), {
headers: {
'content-type': 'application/wasm'
}
});
}
async function compileWebAssemblyFromPath(path) {
const response = readWebAssemblyAsResponse(path);
return await WebAssembly.compileStreaming(response);
}
async function instantiateWebAssemblyFromPath(path, importsObj) {
const response = readWebAssemblyAsResponse(path);
const { instance } = await WebAssembly.instantiateStreaming(response, importsObj);
return instance.exports;
}
/* eslint-disable @typescript-eslint/no-unused-vars */ /// <reference path="../../shared/runtime/runtime-utils.ts" />
/// <reference path="../../shared-node/base-externals-utils.ts" />
/// <reference path="../../shared-node/node-externals-utils.ts" />
/// <reference path="../../shared-node/node-wasm-utils.ts" />
/// <reference path="./nodejs-globals.d.ts" />
/**
* Base Node.js runtime shared between production and development.
@@ -655,16 +633,9 @@ function loadChunkAsyncByUrl(chunkUrl) {
return loadChunkAsync.call(this, path1);
}
contextPrototype.L = loadChunkAsyncByUrl;
function loadWebAssembly(chunkPath, _edgeModule, imports) {
const resolved = path.resolve(RUNTIME_ROOT, chunkPath);
return instantiateWebAssemblyFromPath(resolved, imports);
}
contextPrototype.w = loadWebAssembly;
function loadWebAssemblyModule(chunkPath, _edgeModule) {
const resolved = path.resolve(RUNTIME_ROOT, chunkPath);
return compileWebAssemblyFromPath(resolved);
}
contextPrototype.u = loadWebAssemblyModule;
// Shared runtime primitive: the root that on-disk chunk paths are resolved
// against. Used by the bundled wasm helper (exposed as `__turbopack_runtime_root__`).
contextPrototype.w = RUNTIME_ROOT;
const regexJsUrl = /\.js(?:\?[^#]*)?(?:#.*)?$/;
/**
* Checks if a given path/URL ends with .js, optionally followed by ?query or #fragment.
@@ -826,14 +826,6 @@ function isJs(chunkUrlOrPath) {
function isCss(chunkUrl) {
return endsWithExtension(chunkUrl, '.css');
}
function loadWebAssembly(chunkPath, edgeModule, importsObj) {
return BACKEND.loadWebAssembly(SourceType.Parent, this.m.id, chunkPath, edgeModule, importsObj);
}
contextPrototype.w = loadWebAssembly;
function loadWebAssemblyModule(chunkPath, edgeModule) {
return BACKEND.loadWebAssemblyModule(SourceType.Parent, this.m.id, chunkPath, edgeModule);
}
contextPrototype.u = loadWebAssemblyModule;
/// <reference path="./runtime-utils.ts" />
/// <reference path="./runtime-types.d.ts" />
/// <reference path="./dev-extensions.ts" />
@@ -1991,15 +1983,6 @@ let BACKEND;
* has been loaded.
*/ loadChunkCached (sourceType, chunkUrl) {
return doLoadChunk(sourceType, chunkUrl);
},
async loadWebAssembly (_sourceType, _sourceData, wasmChunkPath, _edgeModule, importsObj) {
const req = fetchWebAssembly(wasmChunkPath);
const { instance } = await WebAssembly.instantiateStreaming(req, importsObj);
return instance.exports;
},
async loadWebAssemblyModule (_sourceType, _sourceData, wasmChunkPath, _edgeModule) {
const req = fetchWebAssembly(wasmChunkPath);
return await WebAssembly.compileStreaming(req);
}
};
function getOrCreateResolver(chunkUrl) {
@@ -2112,9 +2095,6 @@ let BACKEND;
resolver.loadingStarted = true;
return resolver.promise;
}
function fetchWebAssembly(wasmChunkPath) {
return fetch(getChunkRelativeUrl(wasmChunkPath));
}
})();
/**
* This file contains the runtime code specific to the Turbopack development
@@ -1176,14 +1176,6 @@ function isJs(chunkUrlOrPath) {
function isCss(chunkUrl) {
return endsWithExtension(chunkUrl, '.css');
}
function loadWebAssembly(chunkPath, edgeModule, importsObj) {
return BACKEND.loadWebAssembly(SourceType.Parent, this.m.id, chunkPath, edgeModule, importsObj);
}
contextPrototype.w = loadWebAssembly;
function loadWebAssemblyModule(chunkPath, edgeModule) {
return BACKEND.loadWebAssemblyModule(SourceType.Parent, this.m.id, chunkPath, edgeModule);
}
contextPrototype.u = loadWebAssemblyModule;
/// <reference path="./runtime-base.ts" />
/// <reference path="./dummy.ts" />
var moduleCache = {};
@@ -1485,47 +1477,6 @@ var BACKEND;
* has been loaded.
*/ loadChunkCached: function loadChunkCached(sourceType, chunkUrl) {
return doLoadChunk(sourceType, chunkUrl);
},
loadWebAssembly: function loadWebAssembly(_sourceType, _sourceData, wasmChunkPath, _edgeModule, importsObj) {
return _async_to_generator(function() {
var req, instance;
return _ts_generator(this, function(_state) {
switch(_state.label){
case 0:
req = fetchWebAssembly(wasmChunkPath);
return [
4,
WebAssembly.instantiateStreaming(req, importsObj)
];
case 1:
instance = _state.sent().instance;
return [
2,
instance.exports
];
}
});
})();
},
loadWebAssemblyModule: function loadWebAssemblyModule(_sourceType, _sourceData, wasmChunkPath, _edgeModule) {
return _async_to_generator(function() {
var req;
return _ts_generator(this, function(_state) {
switch(_state.label){
case 0:
req = fetchWebAssembly(wasmChunkPath);
return [
4,
WebAssembly.compileStreaming(req)
];
case 1:
return [
2,
_state.sent()
];
}
});
})();
}
};
function getOrCreateResolver(chunkUrl) {
@@ -1655,9 +1606,6 @@ var BACKEND;
resolver.loadingStarted = true;
return resolver.promise;
}
function fetchWebAssembly(wasmChunkPath) {
return fetch(getChunkRelativeUrl(wasmChunkPath));
}
})();
var chunksToRegister = globalThis["TURBOPACK"];
globalThis["TURBOPACK"] = { push: registerChunk };
@@ -826,14 +826,6 @@ function isJs(chunkUrlOrPath) {
function isCss(chunkUrl) {
return endsWithExtension(chunkUrl, '.css');
}
function loadWebAssembly(chunkPath, edgeModule, importsObj) {
return BACKEND.loadWebAssembly(SourceType.Parent, this.m.id, chunkPath, edgeModule, importsObj);
}
contextPrototype.w = loadWebAssembly;
function loadWebAssemblyModule(chunkPath, edgeModule) {
return BACKEND.loadWebAssemblyModule(SourceType.Parent, this.m.id, chunkPath, edgeModule);
}
contextPrototype.u = loadWebAssemblyModule;
/// <reference path="./runtime-utils.ts" />
/// <reference path="./runtime-types.d.ts" />
/// <reference path="./dev-extensions.ts" />
@@ -1991,15 +1983,6 @@ let BACKEND;
* has been loaded.
*/ loadChunkCached (sourceType, chunkUrl) {
return doLoadChunk(sourceType, chunkUrl);
},
async loadWebAssembly (_sourceType, _sourceData, wasmChunkPath, _edgeModule, importsObj) {
const req = fetchWebAssembly(wasmChunkPath);
const { instance } = await WebAssembly.instantiateStreaming(req, importsObj);
return instance.exports;
},
async loadWebAssemblyModule (_sourceType, _sourceData, wasmChunkPath, _edgeModule) {
const req = fetchWebAssembly(wasmChunkPath);
return await WebAssembly.compileStreaming(req);
}
};
function getOrCreateResolver(chunkUrl) {
@@ -2112,9 +2095,6 @@ let BACKEND;
resolver.loadingStarted = true;
return resolver.promise;
}
function fetchWebAssembly(wasmChunkPath) {
return fetch(getChunkRelativeUrl(wasmChunkPath));
}
})();
/**
* This file contains the runtime code specific to the Turbopack development
@@ -826,14 +826,6 @@ function isJs(chunkUrlOrPath) {
function isCss(chunkUrl) {
return endsWithExtension(chunkUrl, '.css');
}
function loadWebAssembly(chunkPath, edgeModule, importsObj) {
return BACKEND.loadWebAssembly(SourceType.Parent, this.m.id, chunkPath, edgeModule, importsObj);
}
contextPrototype.w = loadWebAssembly;
function loadWebAssemblyModule(chunkPath, edgeModule) {
return BACKEND.loadWebAssemblyModule(SourceType.Parent, this.m.id, chunkPath, edgeModule);
}
contextPrototype.u = loadWebAssemblyModule;
/// <reference path="./runtime-utils.ts" />
/// <reference path="./runtime-types.d.ts" />
/// <reference path="./dev-extensions.ts" />
@@ -1991,15 +1983,6 @@ let BACKEND;
* has been loaded.
*/ loadChunkCached (sourceType, chunkUrl) {
return doLoadChunk(sourceType, chunkUrl);
},
async loadWebAssembly (_sourceType, _sourceData, wasmChunkPath, _edgeModule, importsObj) {
const req = fetchWebAssembly(wasmChunkPath);
const { instance } = await WebAssembly.instantiateStreaming(req, importsObj);
return instance.exports;
},
async loadWebAssemblyModule (_sourceType, _sourceData, wasmChunkPath, _edgeModule) {
const req = fetchWebAssembly(wasmChunkPath);
return await WebAssembly.compileStreaming(req);
}
};
function getOrCreateResolver(chunkUrl) {
@@ -2112,9 +2095,6 @@ let BACKEND;
resolver.loadingStarted = true;
return resolver.promise;
}
function fetchWebAssembly(wasmChunkPath) {
return fetch(getChunkRelativeUrl(wasmChunkPath));
}
})();
/**
* This file contains the runtime code specific to the Turbopack development
@@ -826,14 +826,6 @@ function isJs(chunkUrlOrPath) {
function isCss(chunkUrl) {
return endsWithExtension(chunkUrl, '.css');
}
function loadWebAssembly(chunkPath, edgeModule, importsObj) {
return BACKEND.loadWebAssembly(SourceType.Parent, this.m.id, chunkPath, edgeModule, importsObj);
}
contextPrototype.w = loadWebAssembly;
function loadWebAssemblyModule(chunkPath, edgeModule) {
return BACKEND.loadWebAssemblyModule(SourceType.Parent, this.m.id, chunkPath, edgeModule);
}
contextPrototype.u = loadWebAssemblyModule;
/// <reference path="./runtime-utils.ts" />
/// <reference path="./runtime-types.d.ts" />
/// <reference path="./dev-extensions.ts" />
@@ -1991,15 +1983,6 @@ let BACKEND;
* has been loaded.
*/ loadChunkCached (sourceType, chunkUrl) {
return doLoadChunk(sourceType, chunkUrl);
},
async loadWebAssembly (_sourceType, _sourceData, wasmChunkPath, _edgeModule, importsObj) {
const req = fetchWebAssembly(wasmChunkPath);
const { instance } = await WebAssembly.instantiateStreaming(req, importsObj);
return instance.exports;
},
async loadWebAssemblyModule (_sourceType, _sourceData, wasmChunkPath, _edgeModule) {
const req = fetchWebAssembly(wasmChunkPath);
return await WebAssembly.compileStreaming(req);
}
};
function getOrCreateResolver(chunkUrl) {
@@ -2112,9 +2095,6 @@ let BACKEND;
resolver.loadingStarted = true;
return resolver.promise;
}
function fetchWebAssembly(wasmChunkPath) {
return fetch(getChunkRelativeUrl(wasmChunkPath));
}
})();
/**
* This file contains the runtime code specific to the Turbopack development
@@ -826,14 +826,6 @@ function isJs(chunkUrlOrPath) {
function isCss(chunkUrl) {
return endsWithExtension(chunkUrl, '.css');
}
function loadWebAssembly(chunkPath, edgeModule, importsObj) {
return BACKEND.loadWebAssembly(SourceType.Parent, this.m.id, chunkPath, edgeModule, importsObj);
}
contextPrototype.w = loadWebAssembly;
function loadWebAssemblyModule(chunkPath, edgeModule) {
return BACKEND.loadWebAssemblyModule(SourceType.Parent, this.m.id, chunkPath, edgeModule);
}
contextPrototype.u = loadWebAssemblyModule;
/// <reference path="./runtime-utils.ts" />
/// <reference path="./runtime-types.d.ts" />
/// <reference path="./dev-extensions.ts" />
@@ -1991,15 +1983,6 @@ let BACKEND;
* has been loaded.
*/ loadChunkCached (sourceType, chunkUrl) {
return doLoadChunk(sourceType, chunkUrl);
},
async loadWebAssembly (_sourceType, _sourceData, wasmChunkPath, _edgeModule, importsObj) {
const req = fetchWebAssembly(wasmChunkPath);
const { instance } = await WebAssembly.instantiateStreaming(req, importsObj);
return instance.exports;
},
async loadWebAssemblyModule (_sourceType, _sourceData, wasmChunkPath, _edgeModule) {
const req = fetchWebAssembly(wasmChunkPath);
return await WebAssembly.compileStreaming(req);
}
};
function getOrCreateResolver(chunkUrl) {
@@ -2112,9 +2095,6 @@ let BACKEND;
resolver.loadingStarted = true;
return resolver.promise;
}
function fetchWebAssembly(wasmChunkPath) {
return fetch(getChunkRelativeUrl(wasmChunkPath));
}
})();
/**
* This file contains the runtime code specific to the Turbopack development
@@ -0,0 +1,23 @@
// Bundled WebAssembly helper for the browser (DOM) runtime. Loaded on demand by
// the generated wasm loader instead of living in the default runtime.
//
// The wasm file is fetched relative to the chunk base path via the shared
// `__turbopack_chunk_relative_url__` runtime primitive. `edgeModule` is unused in
// the DOM runtime (the wasm is fetched, not provided as a global).
declare const __turbopack_chunk_relative_url__: (chunkPath: string) => string
export async function instantiate(
chunkPath: string,
imports: WebAssembly.Imports
): Promise<WebAssembly.Exports> {
const req = fetch(__turbopack_chunk_relative_url__(chunkPath))
const { instance } = await WebAssembly.instantiateStreaming(req, imports)
return instance.exports
}
export async function compileModule(
chunkPath: string
): Promise<WebAssembly.Module> {
const req = fetch(__turbopack_chunk_relative_url__(chunkPath))
return await WebAssembly.compileStreaming(req)
}
@@ -0,0 +1,42 @@
// Bundled WebAssembly helper for the edge runtime. Loaded on demand by the
// generated wasm loader instead of living in the default runtime.
//
// In edge runtimes wasm can't be fetched dynamically; it's provided ahead of
// time via the `edgeModule` thunk that the loader passes in. This helper is fully
// self-contained — it needs nothing from the runtime.
function loadEdgeWasm(
chunkPath: string,
edgeModule: () => WebAssembly.Module
): WebAssembly.Module {
let module
try {
module = edgeModule()
} catch (_e) {}
if (!module) {
throw new Error(
`dynamically loading WebAssembly is not supported in this runtime as global was not injected for chunk '${chunkPath}'`
)
}
return module
}
export async function instantiate(
chunkPath: string,
imports: WebAssembly.Imports,
edgeModule: () => WebAssembly.Module
): Promise<Exports> {
const module = loadEdgeWasm(chunkPath, edgeModule)
// inconsistent with the `node` and `dom` runtimes
// we return the wrong object here. we return `instance`
// here but the other runtimes return `instance.exports`
return await WebAssembly.instantiate(module, imports)
}
export async function compileModule(
chunkPath: string,
edgeModule: () => WebAssembly.Module
): Promise<WebAssembly.Module> {
return loadEdgeWasm(chunkPath, edgeModule)
}
@@ -0,0 +1,42 @@
// Bundled WebAssembly helper for Node.js runtimes. Loaded on demand by the
// generated wasm loader instead of living in the default runtime.
//
// The wasm file is read from disk relative to the shared `__turbopack_runtime_root__`
// runtime primitive. `fs`/`stream`/`path` are required lazily so they're only
// pulled in when wasm is actually used.
declare const __turbopack_runtime_root__: string
function readWebAssemblyAsResponse(filePath: string): Response {
const { createReadStream } = require('fs') as typeof import('fs')
const { Readable } = require('stream') as typeof import('stream')
const stream = createReadStream(resolvePath(filePath))
// @ts-ignore unfortunately there's a slight type mismatch with the stream.
return new Response(Readable.toWeb(stream), {
headers: {
'content-type': 'application/wasm',
},
})
}
function resolvePath(chunkPath: string): string {
const { resolve } = require('path') as typeof import('path')
return resolve(__turbopack_runtime_root__, chunkPath)
}
export async function instantiate(
chunkPath: string,
imports: WebAssembly.Imports
): Promise<WebAssembly.Exports> {
const response = readWebAssemblyAsResponse(chunkPath)
const { instance } = await WebAssembly.instantiateStreaming(response, imports)
return instance.exports
}
export async function compileModule(
chunkPath: string
): Promise<WebAssembly.Module> {
const response = readWebAssemblyAsResponse(chunkPath)
return await WebAssembly.compileStreaming(response)
}
@@ -0,0 +1,7 @@
use turbo_tasks::Vc;
use turbo_tasks_fs::{FileSystem, embed_directory};
#[turbo_tasks::function]
pub(crate) fn embed_fs() -> Vc<Box<dyn FileSystem>> {
embed_directory!("turbopack-wasm", "$CARGO_MANIFEST_DIR/js/src")
}
@@ -16,6 +16,7 @@ use turbo_tasks_hash::HashAlgorithm;
use turbopack_core::asset::{Asset, no_hash_salt};
pub(crate) mod analysis;
pub(crate) mod embed;
pub(crate) mod loader;
pub mod module_asset;
pub(crate) mod output_asset;
+24 -4
View File
@@ -15,6 +15,7 @@ use crate::{analysis::analyze, source::WebAssemblySource, wasm_edge_var_name};
#[turbo_tasks::function]
pub(crate) async fn instantiating_loader_source(
source: Vc<WebAssemblySource>,
is_edge: bool,
) -> Result<Vc<Box<dyn Source>>> {
let analysis = analyze(source).await?;
@@ -37,19 +38,28 @@ pub(crate) async fn instantiating_loader_source(
}
writeln!(imports_obj, "}}")?;
writeln!(code, "import {{ instantiate }} from \"WASM_HELPER\";")?;
writeln!(code, "import wasmPath from \"WASM_PATH\";")?;
writeln!(code)?;
// Omitted entirely when `is_edge` is false. As the node and browser
// implementations do not use this parameter.
let edge_arg = if is_edge {
format!(", () => {}", wasm_edge_var_name(Vc::upcast(source)).await?)
} else {
String::new()
};
writedoc!(
code,
r#"
const {{ {exports} }} = await __turbopack_wasm__(wasmPath, () => {edgeVariable}, {imports});
const {{ {exports} }} = await instantiate(wasmPath, {imports}{edge_arg});
export {{ {exports} }};
"#,
edgeVariable = wasm_edge_var_name(Vc::upcast(source)).await?,
imports = imports_obj,
edge_arg = edge_arg,
exports = analysis.exports.join(", "),
)?;
@@ -66,16 +76,26 @@ pub(crate) async fn instantiating_loader_source(
#[turbo_tasks::function]
pub(crate) async fn compiling_loader_source(
source: Vc<WebAssemblySource>,
is_edge: bool,
) -> Result<Vc<Box<dyn Source>>> {
// Omitted entirely when `is_edge` is false. As the node and browser
// implementations do not use this parameter.
let edge_arg = if is_edge {
format!(", () => {}", wasm_edge_var_name(Vc::upcast(source)).await?)
} else {
String::new()
};
let code: RcStr = formatdoc! {
r#"
import {{ compileModule }} from "WASM_HELPER";
import wasmPath from "WASM_PATH";
const mod = await __turbopack_wasm_module__(wasmPath, () => {edgeVariable});
const mod = await compileModule(wasmPath{edge_arg});
export default mod;
"#,
edgeVariable = wasm_edge_var_name(Vc::upcast(source)).await?
edge_arg = edge_arg,
}
.into();
@@ -1,10 +1,12 @@
use anyhow::{Result, bail};
use turbo_rcstr::rcstr;
use turbo_tasks::{ResolvedVc, Vc, fxindexmap};
use turbo_tasks_fs::FileSystemPath;
use turbo_tasks_fs::{FileSystem, FileSystemPath};
use turbopack_core::{
chunk::{AsyncModuleInfo, ChunkableModule, ChunkingContext},
context::AssetContext,
environment::ChunkLoading,
file_source::FileSource,
ident::AssetIdent,
module::{Module, ModuleSideEffects},
module_graph::ModuleGraph,
@@ -23,6 +25,7 @@ use turbopack_ecmascript::{
};
use crate::{
embed,
loader::{compiling_loader_source, instantiating_loader_source},
output_asset::WebAssemblyAsset,
raw::RawWebAssemblyModuleAsset,
@@ -63,16 +66,48 @@ impl WebAssemblyModuleAsset {
async fn loader_as_module(&self) -> Result<Vc<Box<dyn Module>>> {
let query = &self.source.ident().await?.query;
let chunk_loading = self
.asset_context
.compile_time_info()
.environment()
.chunk_loading()
.await?;
let is_edge = matches!(*chunk_loading, ChunkLoading::Edge);
let loader_source = if query == "?module" {
compiling_loader_source(*self.source)
compiling_loader_source(*self.source, is_edge)
} else {
instantiating_loader_source(*self.source)
instantiating_loader_source(*self.source, is_edge)
};
let helper_path = match *chunk_loading {
ChunkLoading::Edge => rcstr!("edge/loadWasm.ts"),
ChunkLoading::NodeJs => rcstr!("node/loadWasm.ts"),
ChunkLoading::Dom => rcstr!("browser/loadWasm.ts"),
};
let helper = self
.asset_context
.process(
Vc::upcast(FileSource::new(
embed::embed_fs().root().await?.join(&helper_path)?,
)),
/*
TODO (@sampoder): ideally, we would have some sort of hint
here that suggests whether we are using `compileModule()` or
`instantiate()` to avoid loading the other unused function.
*/
ReferenceType::Runtime,
)
.module()
.to_resolved()
.await?;
let module = self.asset_context.process(
loader_source,
ReferenceType::Internal(ResolvedVc::cell(fxindexmap! {
rcstr!("WASM_PATH") => ResolvedVc::upcast(RawWebAssemblyModuleAsset::new(*self.source, *self.asset_context).to_resolved().await?),
rcstr!("WASM_HELPER") => helper,
})),
).module();