Skip to content

Commit 147c392

Browse files
authored
Add support for configuration (#19544)
* Add support for configuration Fixes #18675
1 parent 0006fdf commit 147c392

28 files changed

+384
-98
lines changed

src/Components/Web.JS/dist/Release/blazor.server.js

Lines changed: 3 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Components/Web.JS/dist/Release/blazor.webassembly.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Components/Web.JS/src/Boot.WebAssembly.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ import * as Environment from './Environment';
44
import { monoPlatform } from './Platform/Mono/MonoPlatform';
55
import { renderBatch } from './Rendering/Renderer';
66
import { SharedMemoryRenderBatch } from './Rendering/RenderBatch/SharedMemoryRenderBatch';
7-
import { Pointer } from './Platform/Platform';
87
import { shouldAutoStart } from './BootCommon';
98
import { setEventDispatcher } from './Rendering/RendererEventDispatcher';
109
import { WebAssemblyResourceLoader } from './Platform/WebAssemblyResourceLoader';
10+
import { WebAssemblyConfigLoader } from './Platform/WebAssemblyConfigLoader';
11+
import { BootConfigResult } from './Platform/BootConfig';
12+
import { Pointer } from './Platform/Platform';
1113

1214
let started = false;
1315

@@ -38,7 +40,12 @@ async function boot(options?: any): Promise<void> {
3840
});
3941

4042
// Fetch the resources and prepare the Mono runtime
41-
const resourceLoader = await WebAssemblyResourceLoader.initAsync();
43+
const bootConfigResult = await BootConfigResult.initAsync();
44+
45+
const [resourceLoader] = await Promise.all([
46+
WebAssemblyResourceLoader.initAsync(bootConfigResult.bootConfig),
47+
WebAssemblyConfigLoader.initAsync(bootConfigResult)]);
48+
4249
try {
4350
await platform.start(resourceLoader);
4451
} catch (ex) {
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
export class BootConfigResult {
2+
private constructor(public bootConfig: BootJsonData, public applicationEnvironment: string) {
3+
}
4+
5+
static async initAsync(): Promise<BootConfigResult> {
6+
const bootConfigResponse = await fetch('_framework/blazor.boot.json', {
7+
method: 'GET',
8+
credentials: 'include',
9+
cache: 'no-cache'
10+
});
11+
12+
// While we can expect an ASP.NET Core hosted application to include the environment, other
13+
// hosts may not. Assume 'Production' in the absenc of any specified value.
14+
const applicationEnvironment = bootConfigResponse.headers.get('Blazor-Environment') || 'Production';
15+
const bootConfig: BootJsonData = await bootConfigResponse.json();
16+
17+
return new BootConfigResult(bootConfig, applicationEnvironment);
18+
};
19+
}
20+
21+
// Keep in sync with bootJsonData in Microsoft.AspNetCore.Components.WebAssembly.Build
22+
export interface BootJsonData {
23+
readonly entryAssembly: string;
24+
readonly resources: ResourceGroups;
25+
readonly debugBuild: boolean;
26+
readonly linkerEnabled: boolean;
27+
readonly cacheBootResources: boolean;
28+
readonly config: string[];
29+
}
30+
31+
export interface ResourceGroups {
32+
readonly assembly: ResourceList;
33+
readonly pdb?: ResourceList;
34+
readonly runtime: ResourceList;
35+
}
36+
37+
export type ResourceList = { [name: string]: string };
38+

src/Components/Web.JS/src/Platform/Mono/MonoPlatform.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import { System_Object, System_String, System_Array, Pointer, Platform } from '../Platform';
21
import { attachDebuggerHotkey, hasDebuggingEnabled } from './MonoDebugger';
32
import { showErrorNotification } from '../../BootErrors';
43
import { WebAssemblyResourceLoader, LoadingResource } from '../WebAssemblyResourceLoader';
4+
import { Platform, System_Array, Pointer, System_Object, System_String } from '../Platform';
55

6-
let mono_string_get_utf8: (managedString: System_String) => Mono.Utf8Ptr;
6+
let mono_string_get_utf8: (managedString: System_String) => Pointer;
77
let mono_wasm_add_assembly: (name: string, heapAddress: number, length: number) => void;
88
const appBinDirName = 'appBinDir';
99
const uint64HighOrderShift = Math.pow(2, 32);
@@ -47,7 +47,7 @@ export const monoPlatform: Platform = {
4747
// FIXME this is unsafe, cuz raw objects could be GC'd.
4848

4949
const utf8 = mono_string_get_utf8(managedString);
50-
const res = Module.UTF8ToString(utf8);
50+
const res = (<any>window['Module']).UTF8ToString(utf8);
5151
Module._free(utf8 as any);
5252
return res;
5353
},
@@ -168,7 +168,7 @@ function createEmscriptenModuleInstance(resourceLoader: WebAssemblyResourceLoade
168168
};
169169
module.preRun = [];
170170
module.postRun = [];
171-
module.preloadPlugins = [];
171+
(module as any).preloadPlugins = [];
172172

173173
// Override the mechanism for fetching the main wasm file so we can connect it to our cache
174174
module.instantiateWasm = (imports, successCallback): WebAssembly.Exports => {
@@ -258,10 +258,10 @@ function getArrayDataPointer<T>(array: System_Array<T>): number {
258258
return <number><any>array + 12; // First byte from here is length, then following bytes are entries
259259
}
260260

261-
function bindStaticMethod(assembly: string, typeName: string, method: string) : (...args: any[]) => any {
261+
function bindStaticMethod(assembly: string, typeName: string, method: string) {
262262
// Fully qualified name looks like this: "[debugger-test] Math:IntAdd"
263263
const fqn = `[${assembly}] ${typeName}:${method}`;
264-
return Module.mono_bind_static_method(fqn);
264+
return BINDING.bind_static_method(fqn);
265265
}
266266

267267
function attachInteropInvoker(): void {

src/Components/Web.JS/src/Platform/Mono/MonoTypes.d.ts

Lines changed: 0 additions & 31 deletions
This file was deleted.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { Pointer, System_String } from '../Platform';
2+
3+
// Mono uses this global to hang various debugging-related items on
4+
5+
declare interface MONO {
6+
loaded_files: string[];
7+
mono_wasm_runtime_ready (): void;
8+
mono_wasm_setenv (name: string, value: string): void;
9+
}
10+
11+
// Mono uses this global to hold low-level interop APIs
12+
declare interface BINDING {
13+
js_string_to_mono_string(jsString: string): System_String;
14+
js_typed_array_to_array(array: Uint8Array): Pointer;
15+
js_typed_array_to_array<T>(array: Array<T>): Pointer;
16+
conv_string(dotnetString: System_String | null): string | null;
17+
bind_static_method(fqn: string, signature?: string): Function;
18+
}
19+
20+
declare global {
21+
var MONO: MONO;
22+
var BINDING: BINDING;
23+
}

src/Components/Web.JS/src/Platform/Platform.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { WebAssemblyResourceLoader } from "./WebAssemblyResourceLoader";
1+
import { WebAssemblyResourceLoader } from './WebAssemblyResourceLoader';
22

33
export interface Platform {
44
start(resourceLoader: WebAssemblyResourceLoader): Promise<void>;
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { BootConfigResult } from './BootConfig';
2+
import { System_String, Pointer } from './Platform';
3+
4+
export class WebAssemblyConfigLoader {
5+
static async initAsync(bootConfigResult: BootConfigResult): Promise<void> {
6+
window['Blazor']._internal.getApplicationEnvironment = () => BINDING.js_string_to_mono_string(bootConfigResult.applicationEnvironment);
7+
8+
const configFiles = await Promise.all((bootConfigResult.bootConfig.config || [])
9+
.filter(name => name === 'appsettings.json' || name === `appsettings.${bootConfigResult.applicationEnvironment}.json`)
10+
.map(async name => ({ name, content: await getConfigBytes(name) })));
11+
12+
window['Blazor']._internal.getConfig = (dotNetFileName: System_String) : Pointer | undefined => {
13+
const fileName = BINDING.conv_string(dotNetFileName);
14+
const resolvedFile = configFiles.find(f => f.name === fileName);
15+
return resolvedFile ? BINDING.js_typed_array_to_array(resolvedFile.content) : undefined;
16+
};
17+
18+
async function getConfigBytes(file: string): Promise<Uint8Array> {
19+
const response = await fetch(file, {
20+
method: 'GET',
21+
credentials: 'include',
22+
cache: 'no-cache'
23+
});
24+
25+
return new Uint8Array(await response.arrayBuffer());
26+
}
27+
}
28+
}

src/Components/Web.JS/src/Platform/WebAssemblyResourceLoader.ts

Lines changed: 5 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,18 @@
11
import { toAbsoluteUri } from '../Services/NavigationManager';
2+
import { BootJsonData, ResourceList } from './BootConfig';
23
const networkFetchCacheMode = 'no-cache';
34

45
export class WebAssemblyResourceLoader {
56
private usedCacheKeys: { [key: string]: boolean } = {};
67
private networkLoads: { [name: string]: LoadLogEntry } = {};
78
private cacheLoads: { [name: string]: LoadLogEntry } = {};
89

9-
static async initAsync(): Promise<WebAssemblyResourceLoader> {
10-
const bootConfigResponse = await fetch('_framework/blazor.boot.json', {
11-
method: 'GET',
12-
credentials: 'include',
13-
cache: networkFetchCacheMode
14-
});
15-
const bootConfig: BootJsonData = await bootConfigResponse.json();
10+
static async initAsync(bootConfig: BootJsonData): Promise<WebAssemblyResourceLoader> {
1611
const cache = await getCacheToUseIfEnabled(bootConfig);
17-
1812
return new WebAssemblyResourceLoader(bootConfig, cache);
1913
}
2014

21-
constructor (public readonly bootConfig: BootJsonData, private cacheIfUsed: Cache | null)
22-
{
15+
constructor(readonly bootConfig: BootJsonData, readonly cacheIfUsed: Cache | null) {
2316
}
2417

2518
loadResources(resources: ResourceList, url: (name: string) => string): LoadingResource[] {
@@ -36,7 +29,7 @@ export class WebAssemblyResourceLoader {
3629
? this.loadResourceWithCaching(this.cacheIfUsed, name, url, contentHash)
3730
: fetch(url, { cache: networkFetchCacheMode, integrity: this.bootConfig.cacheBootResources ? contentHash : undefined });
3831

39-
return { name, url, response };
32+
return { name, url, response };
4033
}
4134

4235
logToConsole() {
@@ -166,7 +159,7 @@ function countTotalBytes(loads: LoadLogEntry[]) {
166159
}
167160

168161
function toDataSizeString(byteCount: number) {
169-
return `${(byteCount / (1024*1024)).toFixed(2)} MB`;
162+
return `${(byteCount / (1024 * 1024)).toFixed(2)} MB`;
170163
}
171164

172165
function getPerformanceEntry(url: string): PerformanceResourceTiming | undefined {
@@ -175,21 +168,6 @@ function getPerformanceEntry(url: string): PerformanceResourceTiming | undefined
175168
}
176169
}
177170

178-
// Keep in sync with bootJsonData in Microsoft.AspNetCore.Blazor.Build
179-
interface BootJsonData {
180-
readonly entryAssembly: string;
181-
readonly resources: ResourceGroups;
182-
readonly debugBuild: boolean;
183-
readonly linkerEnabled: boolean;
184-
readonly cacheBootResources: boolean;
185-
}
186-
187-
interface ResourceGroups {
188-
readonly assembly: ResourceList;
189-
readonly pdb?: ResourceList;
190-
readonly runtime: ResourceList;
191-
}
192-
193171
interface LoadLogEntry {
194172
responseBytes: number | undefined;
195173
}
@@ -199,5 +177,3 @@ export interface LoadingResource {
199177
url: string;
200178
response: Promise<Response>;
201179
}
202-
203-
type ResourceList = { [name: string]: string };

0 commit comments

Comments
 (0)