Support loading embedded resources for server-side execution too

This commit is contained in:
Steve Sanderson 2018-07-16 13:57:01 +01:00
parent 9778b2054a
commit 970f591803
3 changed files with 53 additions and 40 deletions

View File

@ -6,10 +6,16 @@ import { MessagePackHubProtocol } from '@aspnet/signalr-protocol-msgpack';
import { OutOfProcessRenderBatch } from './Rendering/RenderBatch/OutOfProcessRenderBatch'; import { OutOfProcessRenderBatch } from './Rendering/RenderBatch/OutOfProcessRenderBatch';
import { internalFunctions as uriHelperFunctions } from './Services/UriHelper'; import { internalFunctions as uriHelperFunctions } from './Services/UriHelper';
import { renderBatch } from './Rendering/Renderer'; import { renderBatch } from './Rendering/Renderer';
import { fetchBootConfigAsync, loadEmbeddedResourcesAsync } from './BootCommon';
let connection : signalR.HubConnection; let connection : signalR.HubConnection;
function boot() { function boot() {
// In the background, start loading the boot config and any embedded resources
const embeddedResourcesPromise = fetchBootConfigAsync().then(bootConfig => {
return loadEmbeddedResourcesAsync(bootConfig);
});
connection = new signalR.HubConnectionBuilder() connection = new signalR.HubConnectionBuilder()
.withUrl('/_blazor') .withUrl('/_blazor')
.withHubProtocol(new MessagePackHubProtocol()) .withHubProtocol(new MessagePackHubProtocol())
@ -24,13 +30,16 @@ function boot() {
connection.on('JS.Error', unhandledError); connection.on('JS.Error', unhandledError);
connection.start() connection.start()
.then(() => { .then(async () => {
DotNet.attachDispatcher({ DotNet.attachDispatcher({
beginInvokeDotNetFromJS: (callId, assemblyName, methodIdentifier, argsJson) => { beginInvokeDotNetFromJS: (callId, assemblyName, methodIdentifier, argsJson) => {
connection.send('BeginInvokeDotNetFromJS', callId ? callId.toString() : null, assemblyName, methodIdentifier, argsJson); connection.send('BeginInvokeDotNetFromJS', callId ? callId.toString() : null, assemblyName, methodIdentifier, argsJson);
} }
}); });
// Ensure any embedded resources have been loaded before starting the app
await embeddedResourcesPromise;
connection.send( connection.send(
'StartCircuit', 'StartCircuit',
uriHelperFunctions.getLocationHref(), uriHelperFunctions.getLocationHref(),

View File

@ -7,6 +7,7 @@ import { renderBatch } from './Rendering/Renderer';
import { RenderBatch } from './Rendering/RenderBatch/RenderBatch'; import { RenderBatch } from './Rendering/RenderBatch/RenderBatch';
import { SharedMemoryRenderBatch } from './Rendering/RenderBatch/SharedMemoryRenderBatch'; import { SharedMemoryRenderBatch } from './Rendering/RenderBatch/SharedMemoryRenderBatch';
import { Pointer } from './Platform/Platform'; import { Pointer } from './Platform/Platform';
import { fetchBootConfigAsync, loadEmbeddedResourcesAsync } from './BootCommon';
async function boot() { async function boot() {
// Configure environment for execution under Mono WebAssembly with shared-memory rendering // Configure environment for execution under Mono WebAssembly with shared-memory rendering
@ -16,11 +17,8 @@ async function boot() {
}; };
// Fetch the boot JSON file // Fetch the boot JSON file
// Later we might make the location of this configurable (e.g., as an attribute on the <script> const bootConfig = await fetchBootConfigAsync();
// element that's importing this file), but currently there isn't a use case for that. const embeddedResourcesPromise = loadEmbeddedResourcesAsync(bootConfig);
const bootConfigResponse = await fetch('_framework/blazor.boot.json');
const bootConfig: BootJsonData = await bootConfigResponse.json();
const embeddedResourcePromises = startLoadingEmbeddedResources(bootConfig);
if (!bootConfig.linkerEnabled) { if (!bootConfig.linkerEnabled) {
console.info('Blazor is running in dev mode without IL stripping. To make the bundle size significantly smaller, publish the application or see https://go.microsoft.com/fwlink/?linkid=870414'); console.info('Blazor is running in dev mode without IL stripping. To make the bundle size significantly smaller, publish the application or see https://go.microsoft.com/fwlink/?linkid=870414');
@ -38,44 +36,11 @@ async function boot() {
} }
// Before we start running .NET code, be sure embedded content resources are all loaded // Before we start running .NET code, be sure embedded content resources are all loaded
await Promise.all(embeddedResourcePromises) await embeddedResourcesPromise;
// Start up the application // Start up the application
const mainAssemblyName = getAssemblyNameFromUrl(bootConfig.main); const mainAssemblyName = getAssemblyNameFromUrl(bootConfig.main);
platform.callEntryPoint(mainAssemblyName, bootConfig.entryPoint, []); platform.callEntryPoint(mainAssemblyName, bootConfig.entryPoint, []);
} }
function startLoadingEmbeddedResources(bootConfig: BootJsonData) {
const cssLoadingPromises = bootConfig.cssReferences.map(cssReference => {
const linkElement = document.createElement('link');
linkElement.rel = 'stylesheet';
linkElement.href = cssReference;
return loadResourceFromElement(linkElement);
});
const jsLoadingPromises = bootConfig.jsReferences.map(jsReference => {
const scriptElement = document.createElement('script');
scriptElement.src = jsReference;
return loadResourceFromElement(scriptElement);
});
return cssLoadingPromises.concat(jsLoadingPromises);
}
function loadResourceFromElement(element: HTMLElement) {
return new Promise((resolve, reject) => {
element.onload = resolve;
element.onerror = reject;
document.head.appendChild(element);
});
}
// Keep in sync with BootJsonData in Microsoft.AspNetCore.Blazor.Build
interface BootJsonData {
main: string;
entryPoint: string;
assemblyReferences: string[];
cssReferences: string[];
jsReferences: string[];
linkerEnabled: boolean;
}
boot(); boot();

View File

@ -0,0 +1,39 @@
export async function fetchBootConfigAsync() {
// Later we might make the location of this configurable (e.g., as an attribute on the <script>
// element that's importing this file), but currently there isn't a use case for that.
const bootConfigResponse = await fetch('_framework/blazor.boot.json');
return bootConfigResponse.json() as Promise<BootJsonData>;
}
export function loadEmbeddedResourcesAsync(bootConfig: BootJsonData): Promise<any> {
const cssLoadingPromises = bootConfig.cssReferences.map(cssReference => {
const linkElement = document.createElement('link');
linkElement.rel = 'stylesheet';
linkElement.href = cssReference;
return loadResourceFromElement(linkElement);
});
const jsLoadingPromises = bootConfig.jsReferences.map(jsReference => {
const scriptElement = document.createElement('script');
scriptElement.src = jsReference;
return loadResourceFromElement(scriptElement);
});
return Promise.all(cssLoadingPromises.concat(jsLoadingPromises));
}
function loadResourceFromElement(element: HTMLElement) {
return new Promise((resolve, reject) => {
element.onload = resolve;
element.onerror = reject;
document.head.appendChild(element);
});
}
// Keep in sync with BootJsonData in Microsoft.AspNetCore.Blazor.Build
interface BootJsonData {
main: string;
entryPoint: string;
assemblyReferences: string[];
cssReferences: string[];
jsReferences: string[];
linkerEnabled: boolean;
}