From e71fa62d152d02ddc9d1479a5c854d177b0dc261 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 25 Feb 2026 13:01:11 +0100 Subject: [PATCH 1/7] lazy and satelite assemblies --- .../Common/JavaScript/cross-module/index.ts | 2 + .../libs/Common/JavaScript/host/assets.ts | 18 ++++- .../libs/Common/JavaScript/loader/assets.ts | 75 ++++++++++++++++++- .../libs/Common/JavaScript/loader/config.ts | 3 + .../libs/Common/JavaScript/loader/index.ts | 6 +- .../libs/Common/JavaScript/loader/run.ts | 7 +- .../libs/Common/JavaScript/types/exchange.ts | 7 +- .../interop/lazy.ts | 8 +- 8 files changed, 111 insertions(+), 15 deletions(-) diff --git a/src/native/libs/Common/JavaScript/cross-module/index.ts b/src/native/libs/Common/JavaScript/cross-module/index.ts index 1e0165ee80ba03..82eff36e6979f6 100644 --- a/src/native/libs/Common/JavaScript/cross-module/index.ts +++ b/src/native/libs/Common/JavaScript/cross-module/index.ts @@ -137,6 +137,8 @@ export function dotnetUpdateInternalsSubscriber() { abortStartup: table[15], quitNow: table[16], normalizeException: table[17], + fetchSatelliteAssemblies: table[18], + fetchLazyAssembly: table[19], }; Object.assign(dotnetLoaderExports, loaderExportsLocal); Object.assign(logger, loggerLocal); diff --git a/src/native/libs/Common/JavaScript/host/assets.ts b/src/native/libs/Common/JavaScript/host/assets.ts index 80582aac2b240f..a9bae30ad08d37 100644 --- a/src/native/libs/Common/JavaScript/host/assets.ts +++ b/src/native/libs/Common/JavaScript/host/assets.ts @@ -9,9 +9,14 @@ import { browserVirtualAppBase, sizeOfPtr } from "../per-module"; const hasInstantiateStreaming = typeof WebAssembly !== "undefined" && typeof WebAssembly.instantiateStreaming === "function"; const loadedAssemblies: Map = new Map(); -// eslint-disable-next-line @typescript-eslint/no-unused-vars export function registerPdbBytes(bytes: Uint8Array, virtualPath: string) { - // WASM-TODO: https://github.com/dotnet/runtime/issues/122921 + const lastSlash = virtualPath.lastIndexOf("/"); + const parentDirectory = lastSlash > 0 ? virtualPath.substring(0, lastSlash) : "/"; + const fileName = lastSlash > 0 ? virtualPath.substring(lastSlash + 1) : virtualPath; + + _ems_.dotnetLogger.debug(`Registering PDB '${fileName}' in directory '${parentDirectory}'`); + _ems_.FS.createPath("/", parentDirectory, true, true); + _ems_.FS.createDataFile(parentDirectory, fileName, bytes, true /* canRead */, true /* canWrite */, true /* canOwn */); } export function registerDllBytes(bytes: Uint8Array, virtualPath: string) { @@ -25,7 +30,10 @@ export function registerDllBytes(bytes: Uint8Array, virtualPath: string) { const ptr = _ems_.HEAPU32[ptrPtr as any >>> 2]; _ems_.HEAPU8.set(bytes, ptr >>> 0); - const name = virtualPath.substring(virtualPath.lastIndexOf("/") + 1); + const name = virtualPath.startsWith(browserVirtualAppBase) + ? virtualPath.substring(browserVirtualAppBase.length) + : virtualPath.substring(virtualPath.lastIndexOf("/") + 1); + _ems_.dotnetLogger.debug(`Registered assembly '${virtualPath}' (name: '${name}') at ${ptr.toString(16)} length ${bytes.length}`); loadedAssemblies.set(virtualPath, { ptr, length: bytes.length }); loadedAssemblies.set(name, { ptr, length: bytes.length }); @@ -69,7 +77,9 @@ export async function instantiateWebcilModule(webcilPromise: Promise, const getWebcilPayload = instance.exports.getWebcilPayload as (ptr: number, size: number) => void; getWebcilPayload(payloadPtr, payloadSize); - const name = virtualPath.substring(virtualPath.lastIndexOf("/") + 1); + const name = virtualPath.startsWith(browserVirtualAppBase) + ? virtualPath.substring(browserVirtualAppBase.length) + : virtualPath.substring(virtualPath.lastIndexOf("/") + 1); _ems_.dotnetLogger.debug(`Registered Webcil assembly '${virtualPath}' (name: '${name}') at ${payloadPtr.toString(16)} length ${payloadSize}`); loadedAssemblies.set(virtualPath, { ptr: payloadPtr, length: payloadSize }); loadedAssemblies.set(name, { ptr: payloadPtr, length: payloadSize }); diff --git a/src/native/libs/Common/JavaScript/loader/assets.ts b/src/native/libs/Common/JavaScript/loader/assets.ts index 75c00401533c04..735ee6dc6c4e60 100644 --- a/src/native/libs/Common/JavaScript/loader/assets.ts +++ b/src/native/libs/Common/JavaScript/loader/assets.ts @@ -92,12 +92,17 @@ export async function fetchDll(asset: AssemblyAsset): Promise { totalAssetsToDownload++; const assetInternal = asset as AssetEntryInternal; dotnetAssert.check(assetInternal.virtualPath, "Assembly asset must have virtualPath"); + if (assetInternal.culture) { + assetInternal.name = `${assetInternal.culture}/${assetInternal.name}`; + } if (assetInternal.name && !asset.resolvedUrl) { asset.resolvedUrl = locateFile(assetInternal.name); } assetInternal.virtualPath = assetInternal.virtualPath.startsWith("/") ? assetInternal.virtualPath - : browserVirtualAppBase + assetInternal.virtualPath; + : assetInternal.culture + ? `${browserVirtualAppBase}${assetInternal.culture}/${assetInternal.virtualPath}` + : browserVirtualAppBase + assetInternal.virtualPath; if (assetInternal.virtualPath.endsWith(".wasm")) { assetInternal.behavior = "webcil10"; const webcilPromise = loadResource(assetInternal); @@ -110,10 +115,9 @@ export async function fetchDll(asset: AssemblyAsset): Promise { assetInternal.behavior = "assembly"; const bytes = await fetchBytes(assetInternal); onDownloadedAsset(); - await nativeModulePromiseController.promise; if (bytes) { - dotnetBrowserHostExports.registerDllBytes(bytes, assetInternal.virtualPath); + dotnetBrowserHostExports.registerDllBytes(bytes, asset.virtualPath!); } } } @@ -154,6 +158,71 @@ export async function fetchVfs(asset: AssemblyAsset): Promise { } } +export async function fetchSatelliteAssemblies(culturesToLoad: string[]): Promise { + const satelliteResources = loaderConfig.resources?.satelliteResources; + if (!satelliteResources) { + return; + } + + const promises: Promise[] = []; + for (const culture of culturesToLoad) { + if (!Object.prototype.hasOwnProperty.call(satelliteResources, culture)) { + continue; + } + for (const asset of satelliteResources[culture]) { + const assetInternal = asset as AssetEntryInternal; + assetInternal.culture = culture; + promises.push(fetchDll(asset)); + } + } + await Promise.all(promises); +} + +export async function fetchLazyAssembly(assemblyNameToLoad: string): Promise { + const lazyAssemblies = loaderConfig.resources?.lazyAssembly; + if (!lazyAssemblies) { + throw new Error("No assemblies have been marked as lazy-loadable. Use the 'BlazorWebAssemblyLazyLoad' item group in your project file to enable lazy loading an assembly."); + } + + let assemblyNameWithoutExtension = assemblyNameToLoad; + if (assemblyNameToLoad.endsWith(".dll")) + assemblyNameWithoutExtension = assemblyNameToLoad.substring(0, assemblyNameToLoad.length - 4); + else if (assemblyNameToLoad.endsWith(".wasm")) + assemblyNameWithoutExtension = assemblyNameToLoad.substring(0, assemblyNameToLoad.length - 5); + + const assemblyNameToLoadDll = assemblyNameWithoutExtension + ".dll"; + const assemblyNameToLoadWasm = assemblyNameWithoutExtension + ".wasm"; + + let dllAsset: AssemblyAsset | null = null; + for (const asset of lazyAssemblies) { + if (asset.virtualPath === assemblyNameToLoadDll || asset.virtualPath === assemblyNameToLoadWasm) { + dllAsset = asset; + break; + } + } + + if (!dllAsset) { + throw new Error(`${assemblyNameToLoad} must be marked with 'BlazorWebAssemblyLazyLoad' item group in your project file to allow lazy-loading.`); + } + + await fetchDll(dllAsset); + + if (loaderConfig.debugLevel != 0) { + const pdbNameToLoad = assemblyNameWithoutExtension + ".pdb"; + const pdbAssets = loaderConfig.resources?.pdb; + if (pdbAssets) { + for (const pdbAsset of pdbAssets) { + if (pdbAsset.virtualPath === pdbNameToLoad) { + await fetchPdb(pdbAsset); + break; + } + } + } + } + + return true; +} + export async function fetchNativeSymbols(asset: SymbolsAsset): Promise { totalAssetsToDownload++; const assetInternal = asset as AssetEntryInternal; diff --git a/src/native/libs/Common/JavaScript/loader/config.ts b/src/native/libs/Common/JavaScript/loader/config.ts index 7a3766278cd368..2425857f12032b 100644 --- a/src/native/libs/Common/JavaScript/loader/config.ts +++ b/src/native/libs/Common/JavaScript/loader/config.ts @@ -68,6 +68,9 @@ function mergeResources(target: Assets, source: Assets): Assets { for (const key in source.satelliteResources) { source.satelliteResources![key] = [...target.satelliteResources![key] || [], ...source.satelliteResources![key] || []]; } + for (const key in target.satelliteResources) { + source.satelliteResources![key] = [...target.satelliteResources![key] || [], ...source.satelliteResources![key] || []]; + } return Object.assign(target, source); } diff --git a/src/native/libs/Common/JavaScript/loader/index.ts b/src/native/libs/Common/JavaScript/loader/index.ts index 457f1a1c8825c9..6230e80c594152 100644 --- a/src/native/libs/Common/JavaScript/loader/index.ts +++ b/src/native/libs/Common/JavaScript/loader/index.ts @@ -21,7 +21,7 @@ import { check, error, info, warn, debug, fastCheck, normalizeException } from " import { dotnetAssert, dotnetLoaderExports, dotnetLogger, dotnetUpdateInternals, dotnetUpdateInternalsSubscriber } from "./cross-module"; import { rejectRunMainPromise, resolveRunMainPromise, getRunMainPromise, abortStartup } from "./run"; import { createPromiseCompletionSource, getPromiseCompletionSource, isControllablePromise } from "./promise-completion-source"; -import { instantiateMainWasm } from "./assets"; +import { fetchLazyAssembly, fetchSatelliteAssemblies, instantiateMainWasm } from "./assets"; export function dotnetInitializeModule(): RuntimeAPI { @@ -67,6 +67,8 @@ export function dotnetInitializeModule(): RuntimeAPI { abortStartup, quitNow, normalizeException, + fetchSatelliteAssemblies, + fetchLazyAssembly, }; Object.assign(dotnetLoaderExports, loaderFunctions); const logger: LoggerType = { @@ -114,6 +116,8 @@ export function dotnetInitializeModule(): RuntimeAPI { dotnetLoaderExports.abortStartup, dotnetLoaderExports.quitNow, dotnetLoaderExports.normalizeException, + dotnetLoaderExports.fetchSatelliteAssemblies, + dotnetLoaderExports.fetchLazyAssembly, ]; } diff --git a/src/native/libs/Common/JavaScript/loader/run.ts b/src/native/libs/Common/JavaScript/loader/run.ts index 60162d31a56143..b507f4a5cca672 100644 --- a/src/native/libs/Common/JavaScript/loader/run.ts +++ b/src/native/libs/Common/JavaScript/loader/run.ts @@ -8,14 +8,13 @@ import { exit, runtimeState } from "./exit"; import { createPromiseCompletionSource } from "./promise-completion-source"; import { getIcuResourceName } from "./icu"; import { loaderConfig, validateLoaderConfig } from "./config"; -import { fetchDll, fetchIcu, fetchNativeSymbols, fetchPdb, fetchVfs, fetchWasm, loadDotnetModule, loadJSModule, nativeModulePromiseController, verifyAllAssetsDownloaded } from "./assets"; +import { fetchDll, fetchIcu, fetchNativeSymbols, fetchPdb, fetchSatelliteAssemblies, fetchVfs, fetchWasm, loadDotnetModule, loadJSModule, nativeModulePromiseController, verifyAllAssetsDownloaded } from "./assets"; import { initPolyfills } from "./polyfills"; import { validateWasmFeatures } from "./bootstrap"; const runMainPromiseController = createPromiseCompletionSource(); // WASM-TODO: downloadOnly - blazor render mode auto pre-download. Really no start. -// WASM-TODO: loadAllSatelliteResources // WASM-TODO: debugLevel // WASM-TODO: load symbolication json https://github.com/dotnet/runtime/issues/122647 @@ -56,6 +55,9 @@ export async function createRuntime(downloadOnly: boolean): Promise { const coreVfsPromise = Promise.all((loaderConfig.resources.coreVfs || []).map(fetchVfs)); const assembliesPromise = Promise.all(loaderConfig.resources.assembly.map(fetchDll)); + const satelliteResourcesPromise = loaderConfig.loadAllSatelliteResources && loaderConfig.resources.satelliteResources + ? fetchSatelliteAssemblies(Object.keys(loaderConfig.resources.satelliteResources)) + : Promise.resolve(); const vfsPromise = Promise.all((loaderConfig.resources.vfs || []).map(fetchVfs)); const icuResourceName = getIcuResourceName(); @@ -87,6 +89,7 @@ export async function createRuntime(downloadOnly: boolean): Promise { } await assembliesPromise; + await satelliteResourcesPromise; await corePDBsPromise; await pdbsPromise; await runtimeModuleReady; diff --git a/src/native/libs/Common/JavaScript/types/exchange.ts b/src/native/libs/Common/JavaScript/types/exchange.ts index b2562f17f1ff79..d58b6507008e23 100644 --- a/src/native/libs/Common/JavaScript/types/exchange.ts +++ b/src/native/libs/Common/JavaScript/types/exchange.ts @@ -8,6 +8,7 @@ import type { addOnExitListener, isExited, isRuntimeRunning, quitNow } from "../ import type { initializeCoreCLR } from "../host/host"; import type { instantiateWasm, installVfsFile, registerDllBytes, loadIcuData, registerPdbBytes, instantiateWebcilModule } from "../host/assets"; import type { createPromiseCompletionSource, getPromiseCompletionSource, isControllablePromise } from "../loader/promise-completion-source"; +import type { fetchSatelliteAssemblies, fetchLazyAssembly } from "../loader/assets"; import type { isSharedArrayBuffer, zeroRegion } from "../../../System.Native.Browser/utils/memory"; import type { stringToUTF16, stringToUTF16Ptr, stringToUTF8, stringToUTF8Ptr, utf16ToString } from "../../../System.Native.Browser/utils/strings"; @@ -71,7 +72,9 @@ export type LoaderExports = { addOnExitListener: typeof addOnExitListener, abortStartup: typeof abortStartup, quitNow: typeof quitNow, - normalizeException: typeof normalizeException + normalizeException: typeof normalizeException, + fetchSatelliteAssemblies: typeof fetchSatelliteAssemblies, + fetchLazyAssembly: typeof fetchLazyAssembly, } export type LoaderExportsTable = [ @@ -93,6 +96,8 @@ export type LoaderExportsTable = [ typeof abortStartup, typeof quitNow, typeof normalizeException, + typeof fetchSatelliteAssemblies, + typeof fetchLazyAssembly, ] export type BrowserHostExports = { diff --git a/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/lazy.ts b/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/lazy.ts index dd233fbccca2c8..8deb7efacb9d80 100644 --- a/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/lazy.ts +++ b/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/lazy.ts @@ -1,12 +1,12 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -// eslint-disable-next-line @typescript-eslint/no-unused-vars +import { dotnetLoaderExports } from "./cross-module"; + export async function loadSatelliteAssemblies(culturesToLoad: string[]): Promise { - throw new Error("TODO: loadSatelliteAssemblies is not implemented yet"); + await dotnetLoaderExports.fetchSatelliteAssemblies(culturesToLoad); } -// eslint-disable-next-line @typescript-eslint/no-unused-vars export async function loadLazyAssembly(assemblyNameToLoad: string): Promise { - throw new Error("TODO: loadLazyAssembly is not implemented yet"); + return dotnetLoaderExports.fetchLazyAssembly(assemblyNameToLoad); } From 116d37423436c2b57de228242e8a6a16c4504f1e Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 25 Feb 2026 13:03:56 +0100 Subject: [PATCH 2/7] cleanup --- src/native/libs/Common/JavaScript/loader/run.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/native/libs/Common/JavaScript/loader/run.ts b/src/native/libs/Common/JavaScript/loader/run.ts index b507f4a5cca672..ee2d9b2d1cba0f 100644 --- a/src/native/libs/Common/JavaScript/loader/run.ts +++ b/src/native/libs/Common/JavaScript/loader/run.ts @@ -16,7 +16,6 @@ const runMainPromiseController = createPromiseCompletionSource(); // WASM-TODO: downloadOnly - blazor render mode auto pre-download. Really no start. // WASM-TODO: debugLevel -// WASM-TODO: load symbolication json https://github.com/dotnet/runtime/issues/122647 // many things happen in parallel here, but order matters for performance! // ideally we want to utilize network and CPU at the same time From 92f78c7c36e139b1785f7e4b04e8cc059c0fe828 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 25 Feb 2026 14:31:11 +0100 Subject: [PATCH 3/7] feedback --- src/native/libs/Common/JavaScript/host/assets.ts | 9 +++++++-- src/native/libs/Common/JavaScript/loader/assets.ts | 2 +- src/native/libs/Common/JavaScript/loader/config.ts | 4 +++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/native/libs/Common/JavaScript/host/assets.ts b/src/native/libs/Common/JavaScript/host/assets.ts index a9bae30ad08d37..290866254575d9 100644 --- a/src/native/libs/Common/JavaScript/host/assets.ts +++ b/src/native/libs/Common/JavaScript/host/assets.ts @@ -11,8 +11,13 @@ const loadedAssemblies: Map = new Map() export function registerPdbBytes(bytes: Uint8Array, virtualPath: string) { const lastSlash = virtualPath.lastIndexOf("/"); - const parentDirectory = lastSlash > 0 ? virtualPath.substring(0, lastSlash) : "/"; - const fileName = lastSlash > 0 ? virtualPath.substring(lastSlash + 1) : virtualPath; + const parentDirectory = lastSlash > 0 + ? virtualPath.substring(0, lastSlash) + : browserVirtualAppBase; + let fileName = lastSlash > 0 ? virtualPath.substring(lastSlash + 1) : virtualPath; + if (fileName.startsWith("/")) { + fileName = fileName.substring(1); + } _ems_.dotnetLogger.debug(`Registering PDB '${fileName}' in directory '${parentDirectory}'`); _ems_.FS.createPath("/", parentDirectory, true, true); diff --git a/src/native/libs/Common/JavaScript/loader/assets.ts b/src/native/libs/Common/JavaScript/loader/assets.ts index 735ee6dc6c4e60..b928c21a631ea3 100644 --- a/src/native/libs/Common/JavaScript/loader/assets.ts +++ b/src/native/libs/Common/JavaScript/loader/assets.ts @@ -117,7 +117,7 @@ export async function fetchDll(asset: AssemblyAsset): Promise { onDownloadedAsset(); await nativeModulePromiseController.promise; if (bytes) { - dotnetBrowserHostExports.registerDllBytes(bytes, asset.virtualPath!); + dotnetBrowserHostExports.registerDllBytes(bytes, assetInternal.virtualPath); } } } diff --git a/src/native/libs/Common/JavaScript/loader/config.ts b/src/native/libs/Common/JavaScript/loader/config.ts index 2425857f12032b..5684ac77844fee 100644 --- a/src/native/libs/Common/JavaScript/loader/config.ts +++ b/src/native/libs/Common/JavaScript/loader/config.ts @@ -69,7 +69,9 @@ function mergeResources(target: Assets, source: Assets): Assets { source.satelliteResources![key] = [...target.satelliteResources![key] || [], ...source.satelliteResources![key] || []]; } for (const key in target.satelliteResources) { - source.satelliteResources![key] = [...target.satelliteResources![key] || [], ...source.satelliteResources![key] || []]; + if (!Object.prototype.hasOwnProperty.call(source.satelliteResources, key)) { + source.satelliteResources![key] = target.satelliteResources![key] || []; + } } return Object.assign(target, source); } From 8cfa998ad3f3b51d258f343f84b1aa7f7209e52e Mon Sep 17 00:00:00 2001 From: Pavel Savara Date: Wed, 25 Feb 2026 15:50:32 +0100 Subject: [PATCH 4/7] Update src/native/libs/Common/JavaScript/loader/assets.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/native/libs/Common/JavaScript/loader/assets.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/native/libs/Common/JavaScript/loader/assets.ts b/src/native/libs/Common/JavaScript/loader/assets.ts index b928c21a631ea3..a46183eade7b2b 100644 --- a/src/native/libs/Common/JavaScript/loader/assets.ts +++ b/src/native/libs/Common/JavaScript/loader/assets.ts @@ -92,11 +92,11 @@ export async function fetchDll(asset: AssemblyAsset): Promise { totalAssetsToDownload++; const assetInternal = asset as AssetEntryInternal; dotnetAssert.check(assetInternal.virtualPath, "Assembly asset must have virtualPath"); - if (assetInternal.culture) { - assetInternal.name = `${assetInternal.culture}/${assetInternal.name}`; - } - if (assetInternal.name && !asset.resolvedUrl) { - asset.resolvedUrl = locateFile(assetInternal.name); + const assetNameForUrl = assetInternal.culture + ? `${assetInternal.culture}/${assetInternal.name}` + : assetInternal.name; + if (assetNameForUrl && !asset.resolvedUrl) { + asset.resolvedUrl = locateFile(assetNameForUrl); } assetInternal.virtualPath = assetInternal.virtualPath.startsWith("/") ? assetInternal.virtualPath From ef58abfde4b047060ef0a3271d652d32bf00620a Mon Sep 17 00:00:00 2001 From: Pavel Savara Date: Wed, 25 Feb 2026 15:51:48 +0100 Subject: [PATCH 5/7] Update src/native/libs/Common/JavaScript/loader/assets.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/native/libs/Common/JavaScript/loader/assets.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/native/libs/Common/JavaScript/loader/assets.ts b/src/native/libs/Common/JavaScript/loader/assets.ts index a46183eade7b2b..8bf77fbe79753f 100644 --- a/src/native/libs/Common/JavaScript/loader/assets.ts +++ b/src/native/libs/Common/JavaScript/loader/assets.ts @@ -210,14 +210,26 @@ export async function fetchLazyAssembly(assemblyNameToLoad: string): Promise Date: Wed, 25 Feb 2026 16:00:32 +0100 Subject: [PATCH 6/7] Update src/native/libs/Common/JavaScript/loader/assets.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/native/libs/Common/JavaScript/loader/assets.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/native/libs/Common/JavaScript/loader/assets.ts b/src/native/libs/Common/JavaScript/loader/assets.ts index 8bf77fbe79753f..9489382fb54d68 100644 --- a/src/native/libs/Common/JavaScript/loader/assets.ts +++ b/src/native/libs/Common/JavaScript/loader/assets.ts @@ -207,7 +207,7 @@ export async function fetchLazyAssembly(assemblyNameToLoad: string): Promise Date: Wed, 25 Feb 2026 16:08:28 +0100 Subject: [PATCH 7/7] feedback --- src/native/libs/Common/JavaScript/host/assets.ts | 5 ++++- src/native/libs/Common/JavaScript/loader/assets.ts | 10 ++++++++-- src/native/libs/Common/JavaScript/types/internal.ts | 1 + 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/native/libs/Common/JavaScript/host/assets.ts b/src/native/libs/Common/JavaScript/host/assets.ts index 290866254575d9..0811c32ae68e01 100644 --- a/src/native/libs/Common/JavaScript/host/assets.ts +++ b/src/native/libs/Common/JavaScript/host/assets.ts @@ -11,13 +11,16 @@ const loadedAssemblies: Map = new Map() export function registerPdbBytes(bytes: Uint8Array, virtualPath: string) { const lastSlash = virtualPath.lastIndexOf("/"); - const parentDirectory = lastSlash > 0 + let parentDirectory = lastSlash > 0 ? virtualPath.substring(0, lastSlash) : browserVirtualAppBase; let fileName = lastSlash > 0 ? virtualPath.substring(lastSlash + 1) : virtualPath; if (fileName.startsWith("/")) { fileName = fileName.substring(1); } + if (!parentDirectory.startsWith("/")) { + parentDirectory = browserVirtualAppBase + parentDirectory; + } _ems_.dotnetLogger.debug(`Registering PDB '${fileName}' in directory '${parentDirectory}'`); _ems_.FS.createPath("/", parentDirectory, true, true); diff --git a/src/native/libs/Common/JavaScript/loader/assets.ts b/src/native/libs/Common/JavaScript/loader/assets.ts index 9489382fb54d68..8ec3a80e7a6708 100644 --- a/src/native/libs/Common/JavaScript/loader/assets.ts +++ b/src/native/libs/Common/JavaScript/loader/assets.ts @@ -15,6 +15,7 @@ let currentParallelDownloads = 0; let downloadedAssetsCount = 0; let totalAssetsToDownload = 0; let loadBootResourceCallback: LoadBootResourceCallback | undefined = undefined; +const loadedLazyAssemblies = new Set(); export function setLoadBootResourceCallback(callback: LoadBootResourceCallback | undefined): void { loadBootResourceCallback = callback; @@ -205,12 +206,17 @@ export async function fetchLazyAssembly(assemblyNameToLoad: string): Promise