Skip to content

Commit 6df065d

Browse files
authored
[browser] Bundler friendly build output (#116300)
1 parent 7747825 commit 6df065d

35 files changed

+905
-390
lines changed

src/libraries/sendtohelix-browser.targets

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@
138138
<_XUnitTraitArg Condition="'$(TestUsingWorkloads)' == 'true'">-notrait category=no-workload</_XUnitTraitArg>
139139
<_XUnitTraitArg Condition="'$(TestUsingWorkloads)' != 'true'">-trait category=no-workload</_XUnitTraitArg>
140140
<_XUnitTraitArg Condition="'$(WasmFingerprintAssets)' == 'false'">$(_XUnitTraitArg) -trait category=no-fingerprinting</_XUnitTraitArg>
141+
<_XUnitTraitArg Condition="'$(WasmBundlerFriendlyBootConfig)' == 'true'">$(_XUnitTraitArg) -trait category=bundler-friendly</_XUnitTraitArg>
141142
</PropertyGroup>
142143

143144
<PropertyGroup>

src/libraries/sendtohelix-wasm.targets

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
<WorkItemPrefix Condition="'$(TestUsingWorkloads)' != 'true'">NoWorkload-</WorkItemPrefix>
1515
<WorkItemPrefix Condition="'$(WasmEnableWebcil)' == 'false'">NoWebcil-</WorkItemPrefix>
1616
<WorkItemPrefix Condition="'$(WasmFingerprintAssets)' == 'false'">NoFingerprint-</WorkItemPrefix>
17+
<WorkItemPrefix Condition="'$(WasmBundlerFriendlyBootConfig)' == 'true'">JavascriptBundler-</WorkItemPrefix>
1718
<WorkItemPrefix Condition="'$(WasmEnableThreads)' != 'true'">$(WorkItemPrefix)ST-</WorkItemPrefix>
1819
<WorkItemPrefix Condition="'$(WasmEnableThreads)' == 'true'">$(WorkItemPrefix)MT-</WorkItemPrefix>
1920
</PropertyGroup>
@@ -50,15 +51,15 @@
5051

5152
<!-- for testing with workloads, we use separate items -->
5253
<ItemGroup>
53-
<HelixWorkItem Include="@(BuildWasmApps_PerJobList->'$(WorkItemPrefix)%(Identity)')" Condition="'$(TestUsingWorkloads)' == 'true' and '$(WasmFingerprintAssets)' == 'true'">
54+
<HelixWorkItem Include="@(BuildWasmApps_PerJobList->'$(WorkItemPrefix)%(Identity)')" Condition="'$(TestUsingWorkloads)' == 'true' and '$(WasmFingerprintAssets)' == 'true' and '$(WasmBundlerFriendlyBootConfig)' == 'false'">
5455
<PayloadArchive>$(_BuildWasmAppsPayloadArchive)</PayloadArchive>
5556
<PreCommands Condition="'$(OS)' == 'Windows_NT'">set &quot;HELIX_XUNIT_ARGS=-class %(Identity)&quot;</PreCommands>
5657
<PreCommands Condition="'$(OS)' != 'Windows_NT'">export &quot;HELIX_XUNIT_ARGS=-class %(Identity)&quot;</PreCommands>
5758
<Command>$(HelixCommand)</Command>
5859
<Timeout>$(_workItemTimeout)</Timeout>
5960
</HelixWorkItem>
6061

61-
<HelixWorkItem Include="$(WorkItemPrefix)Wasm.Build.Tests" Condition="'$(TestUsingWorkloads)' != 'true' or '$(WasmFingerprintAssets)' != 'true'">
62+
<HelixWorkItem Include="$(WorkItemPrefix)Wasm.Build.Tests" Condition="'$(TestUsingWorkloads)' != 'true' or '$(WasmFingerprintAssets)' != 'true' or '$(WasmBundlerFriendlyBootConfig)' != 'false'">
6263
<PayloadArchive>$(_BuildWasmAppsPayloadArchive)</PayloadArchive>
6364
<Command>$(HelixCommand)</Command>
6465
<Timeout>$(_workItemTimeout)</Timeout>

src/libraries/sendtohelix.proj

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,12 @@
8888
<_TestUsingWorkloadsValues Include="true;false" />
8989
<_TestUsingWebcilValues Include="true;false" Condition="'$(TargetOS)' == 'browser'" />
9090
<_TestUsingFingerprintingValues Include="true;false" Condition="'$(TargetOS)' == 'browser'" />
91+
<_TestUsingJavascriptBundlerValues Include="true;false" Condition="'$(TargetOS)' == 'browser'" />
9192

9293
<!-- now make the cartesian product of true and false values for two categories -->
9394
<_TestUsingCrossProductValuesTemp Include="@(_TestUsingWorkloadsValues)">
9495
<Workloads>%(_TestUsingWorkloadsValues.Identity)</Workloads>
96+
<BundlerFriendly>false</BundlerFriendly>
9597
</_TestUsingCrossProductValuesTemp>
9698
<_TestUsingCrossProductValuesTemp2 Include="@(_TestUsingCrossProductValuesTemp)">
9799
<Webcil>%(_TestUsingWebcilValues.Identity)</Webcil>
@@ -102,9 +104,24 @@
102104

103105
<!-- There no tests without fingerprinting and without workloads -->
104106
<_TestUsingCrossProductValues Remove="@(_TestUsingCrossProductValues)" Condition="'%(_TestUsingCrossProductValues.Workloads)' == 'false' and '%(_TestUsingCrossProductValues.Fingerprinting)' == 'false'" />
107+
108+
<!-- Add combination for JavascriptBundler friendliness -->
109+
<_TestUsingCrossProductValues Include="JavaScriptBundlerFriendly">
110+
<Workloads>true</Workloads>
111+
<Webcil>true</Webcil>
112+
<Fingerprinting>true</Fingerprinting>
113+
<BundlerFriendly>true</BundlerFriendly>
114+
</_TestUsingCrossProductValues>
105115

106116
<_BuildWasmAppsProjectsToBuild Include="$(PerScenarioProjectFile)">
107-
<AdditionalProperties>$(_PropertiesToPass);Scenario=BuildWasmApps;TestArchiveRuntimeFile=$(TestArchiveRuntimeFile);TestUsingWorkloads=%(_TestUsingCrossProductValues.Workloads);WasmEnableWebcil=%(_TestUsingCrossProductValues.Webcil);WasmFingerprintAssets=%(_TestUsingCrossProductValues.Fingerprinting)</AdditionalProperties>
117+
<AdditionalProperties>
118+
$(_PropertiesToPass);Scenario=BuildWasmApps;
119+
TestArchiveRuntimeFile=$(TestArchiveRuntimeFile);
120+
TestUsingWorkloads=%(_TestUsingCrossProductValues.Workloads);
121+
WasmEnableWebcil=%(_TestUsingCrossProductValues.Webcil);
122+
WasmFingerprintAssets=%(_TestUsingCrossProductValues.Fingerprinting);
123+
WasmBundlerFriendlyBootConfig=%(_TestUsingCrossProductValues.BundlerFriendly)
124+
</AdditionalProperties>
108125
<AdditionalProperties Condition="'$(NeedsToBuildWasmAppsOnHelix)' != ''">%(_BuildWasmAppsProjectsToBuild.AdditionalProperties);NeedsToBuildWasmAppsOnHelix=$(NeedsToBuildWasmAppsOnHelix)</AdditionalProperties>
109126
</_BuildWasmAppsProjectsToBuild>
110127
</ItemGroup>

src/libraries/sendtohelixhelp.proj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@
159159
<HelixCommandPrefixEnvVarItem Condition="'$(TestUsingWorkloads)' == 'true'" Include="TEST_USING_WORKLOADS=true" />
160160
<HelixCommandPrefixEnvVarItem Condition="'$(WasmEnableWebcil)' == 'false'" Include="WASM_ENABLE_WEBCIL=false" />
161161
<HelixCommandPrefixEnvVarItem Condition="'$(WasmFingerprintAssets)' == 'false'" Include="WASM_FINGERPRINT_ASSETS=false" />
162+
<HelixCommandPrefixEnvVarItem Condition="'$(WasmBundlerFriendlyBootConfig)' == 'true'" Include="WASM_BUNDLER_FRIENDLY_BOOT_CONFIG=true" />
162163
<HelixCommandPrefixEnvVarItem Condition="'$(WorkloadsTestPreviousVersions)' == 'true'" Include="WORKLOADS_TEST_PREVIOUS_VERSIONS=true" />
163164
</ItemGroup>
164165

@@ -348,7 +349,7 @@
348349
<Target Name="PrintHelixQueues">
349350
<Message Importance="High" Text="Using Queues: $(HelixTargetQueues)" />
350351
<Message Condition="'$(Scenario)' == 'BuildWasmApps'" Importance="High"
351-
Text="Scenario: $(Scenario), TestUsingWorkloads: $(TestUsingWorkloads), WasmEnableWebcil: $(WasmEnableWebcil), WasmFingerprintAssets: $(WasmFingerprintAssets)" />
352+
Text="Scenario: $(Scenario), TestUsingWorkloads: $(TestUsingWorkloads), WasmEnableWebcil: $(WasmEnableWebcil), WasmFingerprintAssets: $(WasmFingerprintAssets), WasmBundlerFriendlyBootConfig: $(WasmBundlerFriendlyBootConfig)" />
352353
</Target>
353354

354355
<Target Name="PrintBuildTargetFramework">

src/mono/browser/runtime/dotnet.d.ts

Lines changed: 74 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -220,10 +220,7 @@ type MonoConfig = {
220220
* Gets the application culture. This is a name specified in the BCP 47 format. See https://tools.ietf.org/html/bcp47
221221
*/
222222
applicationCulture?: string;
223-
/**
224-
* definition of assets to load along with the runtime.
225-
*/
226-
resources?: ResourceGroups;
223+
resources?: Assets;
227224
/**
228225
* appsettings files to load to VFS
229226
*/
@@ -247,36 +244,84 @@ type MonoConfig = {
247244
type ResourceExtensions = {
248245
[extensionName: string]: ResourceList;
249246
};
250-
interface ResourceGroups {
247+
interface Assets {
251248
hash?: string;
252-
fingerprinting?: {
253-
[name: string]: string;
254-
};
255-
coreAssembly?: ResourceList;
256-
assembly?: ResourceList;
257-
lazyAssembly?: ResourceList;
258-
corePdb?: ResourceList;
259-
pdb?: ResourceList;
260-
jsModuleWorker?: ResourceList;
261-
jsModuleDiagnostics?: ResourceList;
262-
jsModuleNative: ResourceList;
263-
jsModuleRuntime: ResourceList;
264-
wasmSymbols?: ResourceList;
265-
wasmNative: ResourceList;
266-
icu?: ResourceList;
249+
coreAssembly?: AssemblyAsset[];
250+
assembly?: AssemblyAsset[];
251+
lazyAssembly?: AssemblyAsset[];
252+
corePdb?: PdbAsset[];
253+
pdb?: PdbAsset[];
254+
jsModuleWorker?: JsAsset[];
255+
jsModuleDiagnostics?: JsAsset[];
256+
jsModuleNative: JsAsset[];
257+
jsModuleRuntime: JsAsset[];
258+
wasmSymbols?: SymbolsAsset[];
259+
wasmNative: WasmAsset[];
260+
icu?: IcuAsset[];
267261
satelliteResources?: {
268-
[cultureName: string]: ResourceList;
262+
[cultureName: string]: AssemblyAsset[];
269263
};
270-
modulesAfterConfigLoaded?: ResourceList;
271-
modulesAfterRuntimeReady?: ResourceList;
264+
modulesAfterConfigLoaded?: JsAsset[];
265+
modulesAfterRuntimeReady?: JsAsset[];
272266
extensions?: ResourceExtensions;
273-
coreVfs?: {
274-
[virtualPath: string]: ResourceList;
275-
};
276-
vfs?: {
277-
[virtualPath: string]: ResourceList;
278-
};
267+
coreVfs?: VfsAsset[];
268+
vfs?: VfsAsset[];
279269
}
270+
type Asset = {
271+
/**
272+
* this should be absolute url to the asset
273+
*/
274+
resolvedUrl?: string;
275+
/**
276+
* If true, the runtime startup would not fail if the asset download was not successful.
277+
*/
278+
isOptional?: boolean;
279+
/**
280+
* If provided, runtime doesn't have to fetch the data.
281+
* Runtime would set the buffer to null after instantiation to free the memory.
282+
*/
283+
buffer?: ArrayBuffer | Promise<ArrayBuffer>;
284+
/**
285+
* It's metadata + fetch-like Promise<Response>
286+
* If provided, the runtime doesn't have to initiate the download. It would just await the response.
287+
*/
288+
pendingDownload?: LoadingResource;
289+
};
290+
type WasmAsset = Asset & {
291+
name: string;
292+
hash?: string | null | "";
293+
};
294+
type AssemblyAsset = Asset & {
295+
virtualPath: string;
296+
name: string;
297+
hash?: string | null | "";
298+
};
299+
type PdbAsset = Asset & {
300+
virtualPath: string;
301+
name: string;
302+
hash?: string | null | "";
303+
};
304+
type JsAsset = Asset & {
305+
/**
306+
* If provided, runtime doesn't have to import it's JavaScript modules.
307+
* This will not work for multi-threaded runtime.
308+
*/
309+
moduleExports?: any | Promise<any>;
310+
name?: string;
311+
};
312+
type SymbolsAsset = Asset & {
313+
name: string;
314+
};
315+
type VfsAsset = Asset & {
316+
virtualPath: string;
317+
name: string;
318+
hash?: string | null | "";
319+
};
320+
type IcuAsset = Asset & {
321+
virtualPath: string;
322+
name: string;
323+
hash?: string | null | "";
324+
};
280325
/**
281326
* A "key" is name of the file, a "value" is optional hash for integrity check.
282327
*/

src/mono/browser/runtime/lazyLoading.ts

Lines changed: 23 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33

44
import { loaderHelpers } from "./globals";
55
import { load_lazy_assembly } from "./managed-exports";
6-
import { AssetEntry } from "./types";
6+
import { type AssemblyAsset, type PdbAsset } from "./types";
7+
import { type AssetEntryInternal } from "./types/internal";
78

89
export async function loadLazyAssembly (assemblyNameToLoad: string): Promise<boolean> {
910
const resources = loaderHelpers.config.resources!;
@@ -20,50 +21,35 @@ export async function loadLazyAssembly (assemblyNameToLoad: string): Promise<boo
2021

2122
const assemblyNameToLoadDll = assemblyNameWithoutExtension + ".dll";
2223
const assemblyNameToLoadWasm = assemblyNameWithoutExtension + ".wasm";
23-
if (loaderHelpers.config.resources!.fingerprinting) {
24-
const map = loaderHelpers.config.resources!.fingerprinting;
25-
for (const fingerprintedName in map) {
26-
const nonFingerprintedName = map[fingerprintedName];
27-
if (nonFingerprintedName == assemblyNameToLoadDll || nonFingerprintedName == assemblyNameToLoadWasm) {
28-
assemblyNameToLoad = fingerprintedName;
29-
break;
30-
}
31-
}
32-
}
3324

34-
if (!lazyAssemblies[assemblyNameToLoad]) {
35-
if (lazyAssemblies[assemblyNameToLoadDll]) {
36-
assemblyNameToLoad = assemblyNameToLoadDll;
37-
} else if (lazyAssemblies[assemblyNameToLoadWasm]) {
38-
assemblyNameToLoad = assemblyNameToLoadWasm;
39-
} else {
40-
throw new Error(`${assemblyNameToLoad} must be marked with 'BlazorWebAssemblyLazyLoad' item group in your project file to allow lazy-loading.`);
25+
let dllAsset: (AssemblyAsset & AssetEntryInternal) | null = null;
26+
for (let i = 0; i < lazyAssemblies.length; i++) {
27+
const asset = lazyAssemblies[i];
28+
if (asset.virtualPath === assemblyNameToLoadDll || asset.virtualPath === assemblyNameToLoadWasm) {
29+
dllAsset = asset as AssemblyAsset & AssetEntryInternal;
30+
dllAsset.behavior = "assembly";
31+
break;
4132
}
4233
}
4334

44-
const dllAsset: AssetEntry = {
45-
name: assemblyNameToLoad,
46-
hash: lazyAssemblies[assemblyNameToLoad],
47-
behavior: "assembly",
48-
};
35+
if (dllAsset == null) {
36+
throw new Error(`${assemblyNameToLoad} must be marked with 'BlazorWebAssemblyLazyLoad' item group in your project file to allow lazy-loading.`);
37+
}
4938

50-
if (loaderHelpers.loadedAssemblies.includes(assemblyNameToLoad)) {
39+
if (loaderHelpers.loadedAssemblies.includes(dllAsset.name)) {
5140
return false;
5241
}
5342

54-
let pdbNameToLoad = assemblyNameWithoutExtension + ".pdb";
43+
const pdbNameToLoad = assemblyNameWithoutExtension + ".pdb";
5544
let shouldLoadPdb = false;
45+
let pdbAsset: (PdbAsset & AssetEntryInternal) | null = null;
5646
if (loaderHelpers.config.debugLevel != 0 && loaderHelpers.isDebuggingSupported()) {
57-
shouldLoadPdb = Object.prototype.hasOwnProperty.call(lazyAssemblies, pdbNameToLoad);
58-
if (loaderHelpers.config.resources!.fingerprinting) {
59-
const map = loaderHelpers.config.resources!.fingerprinting;
60-
for (const fingerprintedName in map) {
61-
const nonFingerprintedName = map[fingerprintedName];
62-
if (nonFingerprintedName == pdbNameToLoad) {
63-
pdbNameToLoad = fingerprintedName;
64-
shouldLoadPdb = true;
65-
break;
66-
}
47+
for (let i = 0; i < lazyAssemblies.length; i++) {
48+
if (lazyAssemblies[i].virtualPath === pdbNameToLoad) {
49+
shouldLoadPdb = true;
50+
pdbAsset = lazyAssemblies[i] as PdbAsset & AssetEntryInternal;
51+
pdbAsset.behavior = "pdb";
52+
break;
6753
}
6854
}
6955
}
@@ -73,12 +59,8 @@ export async function loadLazyAssembly (assemblyNameToLoad: string): Promise<boo
7359
let dll = null;
7460
let pdb = null;
7561
if (shouldLoadPdb) {
76-
const pdbBytesPromise = lazyAssemblies[pdbNameToLoad]
77-
? loaderHelpers.retrieve_asset_download({
78-
name: pdbNameToLoad,
79-
hash: lazyAssemblies[pdbNameToLoad],
80-
behavior: "pdb"
81-
})
62+
const pdbBytesPromise = pdbAsset != null
63+
? loaderHelpers.retrieve_asset_download(pdbAsset)
8264
: Promise.resolve(null);
8365

8466
const [dllBytes, pdbBytes] = await Promise.all([dllBytesPromise, pdbBytesPromise]);

0 commit comments

Comments
 (0)