Use System.Reflection.Metadata to generate BootConfig (#17156)

* Use System.Reflection.Metadata to generate BootConfig

* Remove reference to Mono.Cecil
* Remove support for auto embedded css \ js
* Remove blazor.webassembly.js
This commit is contained in:
Pranav K 2019-11-19 10:19:57 -08:00 committed by GitHub
parent 92fce0da09
commit 5bdf75f3e1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 120 additions and 373 deletions

View File

@ -15,10 +15,6 @@ namespace Microsoft.AspNetCore.Blazor.Build.DevServer.Commands
"The path to a file that lists the paths to given referenced dll files",
CommandOptionType.SingleValue);
var embeddedResourcesFile = command.Option("--embedded-resources",
"The path to a file that lists the paths of .NET assemblies that may contain embedded resources (typically, referenced assemblies in their pre-linked states)",
CommandOptionType.SingleValue);
var outputPath = command.Option("--output",
"Path to the output file",
CommandOptionType.SingleValue);
@ -44,14 +40,9 @@ namespace Microsoft.AspNetCore.Blazor.Build.DevServer.Commands
? File.ReadAllLines(referencesFile.Value())
: Array.Empty<string>();
var embeddedResourcesSources = embeddedResourcesFile.HasValue()
? File.ReadAllLines(embeddedResourcesFile.Value())
: Array.Empty<string>();
BootJsonWriter.WriteFile(
mainAssemblyPath.Value,
referencesSources,
embeddedResourcesSources,
linkerEnabledFlag.HasValue(),
outputPath.Value());
return 0;

View File

@ -4,10 +4,9 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.Json;
using Microsoft.AspNetCore.Components;
using Mono.Cecil;
namespace Microsoft.AspNetCore.Blazor.Build
{
@ -16,79 +15,55 @@ namespace Microsoft.AspNetCore.Blazor.Build
public static void WriteFile(
string assemblyPath,
string[] assemblyReferences,
string[] embeddedResourcesSources,
bool linkerEnabled,
string outputPath)
{
var embeddedContent = EmbeddedResourcesProcessor.ExtractEmbeddedResources(
embeddedResourcesSources, Path.GetDirectoryName(outputPath));
var bootJsonText = GetBootJsonContent(
Path.GetFileName(assemblyPath),
GetAssemblyEntryPoint(assemblyPath),
AssemblyName.GetAssemblyName(assemblyPath).Name,
assemblyReferences,
embeddedContent,
linkerEnabled);
var normalizedOutputPath = Path.GetFullPath(outputPath);
Console.WriteLine("Writing boot data to: " + normalizedOutputPath);
File.WriteAllText(normalizedOutputPath, bootJsonText);
}
public static string GetBootJsonContent(string assemblyFileName, string entryPoint, string[] assemblyReferences, IEnumerable<EmbeddedResourceInfo> embeddedContent, bool linkerEnabled)
public static string GetBootJsonContent(string entryAssembly, string[] assemblyReferences, bool linkerEnabled)
{
var data = new BootJsonData(
assemblyFileName,
entryPoint,
entryAssembly,
assemblyReferences,
embeddedContent,
linkerEnabled);
return JsonSerializer.Serialize(data, JsonSerializerOptionsProvider.Options);
}
private static string GetAssemblyEntryPoint(string assemblyPath)
{
using (var assemblyDefinition = AssemblyDefinition.ReadAssembly(assemblyPath))
{
var entryPoint = assemblyDefinition.EntryPoint;
if (entryPoint == null)
{
throw new ArgumentException($"The assembly at {assemblyPath} has no specified entry point.");
}
return $"{entryPoint.DeclaringType.FullName}::{entryPoint.Name}";
}
}
/// <summary>
/// Defines the structure of a Blazor boot JSON file
/// </summary>
class BootJsonData
readonly struct BootJsonData
{
public string Main { get; }
public string EntryPoint { get; }
public IEnumerable<string> AssemblyReferences { get; }
public IEnumerable<string> CssReferences { get; }
public IEnumerable<string> JsReferences { get; }
/// <summary>
/// Gets the name of the assembly with the application entry point
/// </summary>
public string EntryAssembly { get; }
/// <summary>
/// Gets the closure of assemblies to be loaded by Blazor WASM. This includes the application entry assembly.
/// </summary>
public IEnumerable<string> Assemblies { get; }
/// <summary>
/// Gets a value that determines if the linker is enabled.
/// </summary>
public bool LinkerEnabled { get; }
public BootJsonData(
string entrypointAssemblyWithExtension,
string entryPoint,
IEnumerable<string> assemblyReferences,
IEnumerable<EmbeddedResourceInfo> embeddedContent,
string entryAssembly,
IEnumerable<string> assemblies,
bool linkerEnabled)
{
Main = entrypointAssemblyWithExtension;
EntryPoint = entryPoint;
AssemblyReferences = assemblyReferences;
EntryAssembly = entryAssembly;
Assemblies = assemblies;
LinkerEnabled = linkerEnabled;
CssReferences = embeddedContent
.Where(c => c.Kind == EmbeddedResourceKind.Css)
.Select(c => c.RelativePath);
JsReferences = embeddedContent
.Where(c => c.Kind == EmbeddedResourceKind.JavaScript)
.Select(c => c.RelativePath);
}
}
}

View File

@ -1,17 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.AspNetCore.Blazor.Build
{
internal class EmbeddedResourceInfo
{
public EmbeddedResourceKind Kind { get; }
public string RelativePath { get; }
public EmbeddedResourceInfo(EmbeddedResourceKind kind, string relativePath)
{
Kind = kind;
RelativePath = relativePath;
}
}
}

View File

@ -1,12 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.AspNetCore.Blazor.Build
{
internal enum EmbeddedResourceKind
{
JavaScript,
Css,
Static
}
}

View File

@ -1,137 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Mono.Cecil;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Microsoft.AspNetCore.Blazor.Build
{
internal class EmbeddedResourcesProcessor
{
const string ContentSubdirName = "_content";
private readonly static Dictionary<string, EmbeddedResourceKind> _knownResourceKindsByNamePrefix = new Dictionary<string, EmbeddedResourceKind>
{
{ "blazor:js:", EmbeddedResourceKind.JavaScript },
{ "blazor:css:", EmbeddedResourceKind.Css },
{ "blazor:file:", EmbeddedResourceKind.Static },
};
/// <summary>
/// Finds Blazor-specific embedded resources in the specified assemblies, writes them
/// to disk, and returns a description of those resources in dependency order.
/// </summary>
/// <param name="referencedAssemblyPaths">The paths to assemblies that may contain embedded resources.</param>
/// <param name="outputDir">The path to the directory where output is being written.</param>
/// <returns>A description of the embedded resources that were written to disk.</returns>
public static IReadOnlyList<EmbeddedResourceInfo> ExtractEmbeddedResources(
IEnumerable<string> referencedAssemblyPaths, string outputDir)
{
// Clean away any earlier state
var contentDir = Path.Combine(outputDir, ContentSubdirName);
if (Directory.Exists(contentDir))
{
Directory.Delete(contentDir, recursive: true);
}
// First, get an ordered list of AssemblyDefinition instances
var referencedAssemblyDefinitions = referencedAssemblyPaths
.Where(path => !Path.GetFileName(path).StartsWith("System.", StringComparison.Ordinal)) // Skip System.* because they are never going to contain embedded resources that we want
.Select(path => AssemblyDefinition.ReadAssembly(path))
.ToList();
referencedAssemblyDefinitions.Sort(OrderWithReferenceSubjectFirst);
// Now process them in turn
return referencedAssemblyDefinitions
.SelectMany(def => ExtractEmbeddedResourcesFromSingleAssembly(def, outputDir))
.ToList()
.AsReadOnly();
}
private static IEnumerable<EmbeddedResourceInfo> ExtractEmbeddedResourcesFromSingleAssembly(
AssemblyDefinition assemblyDefinition, string outputDirPath)
{
var assemblyName = assemblyDefinition.Name.Name;
foreach (var res in assemblyDefinition.MainModule.Resources)
{
if (TryExtractEmbeddedResource(assemblyName, res, outputDirPath, out var extractedResourceInfo))
{
yield return extractedResourceInfo;
}
}
}
private static bool TryExtractEmbeddedResource(string assemblyName, Resource resource, string outputDirPath, out EmbeddedResourceInfo extractedResourceInfo)
{
if (resource is EmbeddedResource embeddedResource)
{
if (TryInterpretLogicalName(resource.Name, out var kind, out var name))
{
// Prefix the output path with the assembly name to ensure no clashes
// Also be invariant to the OS on which the package was built
name = Path.Combine(ContentSubdirName, assemblyName, EnsureHasPathSeparators(name, Path.DirectorySeparatorChar));
// Write the file content to disk, ensuring we don't try to write outside the output root
var outputPath = Path.GetFullPath(Path.Combine(outputDirPath, name));
if (!outputPath.StartsWith(outputDirPath))
{
throw new InvalidOperationException($"Cannot write embedded resource from assembly '{assemblyName}' to '{outputPath}' because it is outside the expected directory {outputDirPath}");
}
WriteResourceFile(embeddedResource, outputPath);
// The URLs we write into the boot json file need to use web-style directory separators
extractedResourceInfo = new EmbeddedResourceInfo(kind, EnsureHasPathSeparators(name, '/'));
return true;
}
}
extractedResourceInfo = null;
return false;
}
private static void WriteResourceFile(EmbeddedResource resource, string outputPath)
{
Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
using (var outputStream = File.OpenWrite(outputPath))
{
resource.GetResourceStream().CopyTo(outputStream);
}
}
private static string EnsureHasPathSeparators(string name, char desiredSeparatorChar) => name
.Replace('\\', desiredSeparatorChar)
.Replace('/', desiredSeparatorChar);
private static bool TryInterpretLogicalName(string logicalName, out EmbeddedResourceKind kind, out string resolvedName)
{
foreach (var kvp in _knownResourceKindsByNamePrefix)
{
if (logicalName.StartsWith(kvp.Key, StringComparison.Ordinal))
{
kind = kvp.Value;
resolvedName = logicalName.Substring(kvp.Key.Length);
return true;
}
}
kind = default;
resolvedName = default;
return false;
}
// For each assembly B that references A, we want the resources from A to be loaded before
// the references for B (because B's resources might depend on A's resources)
private static int OrderWithReferenceSubjectFirst(AssemblyDefinition a, AssemblyDefinition b)
=> AssemblyHasReference(a, b) ? 1
: AssemblyHasReference(b, a) ? -1
: 0;
private static bool AssemblyHasReference(AssemblyDefinition from, AssemblyDefinition to)
=> from.MainModule.AssemblyReferences
.Select(reference => reference.Name)
.Contains(to.Name.Name, StringComparer.Ordinal);
}
}

View File

@ -6,7 +6,9 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Mono.Cecil;
using System.Reflection;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
namespace Microsoft.AspNetCore.Blazor.Build
{
@ -27,19 +29,15 @@ namespace Microsoft.AspNetCore.Blazor.Build
string[] applicationDependencies,
string[] monoBclDirectories)
{
var assembly = new AssemblyEntry(entryPoint, AssemblyDefinition.ReadAssembly(entryPoint));
var entryAssembly = new AssemblyEntry(entryPoint, GetAssemblyName(entryPoint));
var dependencies = applicationDependencies
.Select(a => new AssemblyEntry(a, AssemblyDefinition.ReadAssembly(a)))
.ToArray();
var dependencies = CreateAssemblyLookup(applicationDependencies);
var bcl = monoBclDirectories
.SelectMany(d => Directory.EnumerateFiles(d, "*.dll").Select(f => Path.Combine(d, f)))
.Select(a => new AssemblyEntry(a, AssemblyDefinition.ReadAssembly(a)))
.ToArray();
var bcl = CreateAssemblyLookup(monoBclDirectories
.SelectMany(d => Directory.EnumerateFiles(d, "*.dll").Select(f => Path.Combine(d, f))));
var assemblyResolutionContext = new AssemblyResolutionContext(
assembly,
entryAssembly,
dependencies,
bcl);
@ -47,6 +45,28 @@ namespace Microsoft.AspNetCore.Blazor.Build
var paths = assemblyResolutionContext.Results.Select(r => r.Path);
return paths.Concat(FindPdbs(paths));
static Dictionary<string, AssemblyEntry> CreateAssemblyLookup(IEnumerable<string> assemblyPaths)
{
var dictionary = new Dictionary<string, AssemblyEntry>(StringComparer.Ordinal);
foreach (var path in assemblyPaths)
{
var assemblyName = AssemblyName.GetAssemblyName(path).Name;
if (dictionary.TryGetValue(assemblyName, out var previous))
{
throw new InvalidOperationException($"Multiple assemblies found with the same assembly name '{assemblyName}':" +
Environment.NewLine + string.Join(Environment.NewLine, previous, path));
}
dictionary[assemblyName] = new AssemblyEntry(path, assemblyName);
}
return dictionary;
}
}
private static string GetAssemblyName(string assemblyPath)
{
return AssemblyName.GetAssemblyName(assemblyPath).Name;
}
private static IEnumerable<string> FindPdbs(IEnumerable<string> dllPaths)
@ -59,46 +79,40 @@ namespace Microsoft.AspNetCore.Blazor.Build
public class AssemblyResolutionContext
{
public AssemblyResolutionContext(
AssemblyEntry assembly,
AssemblyEntry[] dependencies,
AssemblyEntry[] bcl)
AssemblyEntry entryAssembly,
Dictionary<string, AssemblyEntry> dependencies,
Dictionary<string, AssemblyEntry> bcl)
{
Assembly = assembly;
EntryAssembly = entryAssembly;
Dependencies = dependencies;
Bcl = bcl;
}
public AssemblyEntry Assembly { get; }
public AssemblyEntry[] Dependencies { get; }
public AssemblyEntry[] Bcl { get; }
public AssemblyEntry EntryAssembly { get; }
public Dictionary<string, AssemblyEntry> Dependencies { get; }
public Dictionary<string, AssemblyEntry> Bcl { get; }
public IList<AssemblyEntry> Results { get; } = new List<AssemblyEntry>();
internal void ResolveAssemblies()
{
var visitedAssemblies = new HashSet<string>();
var pendingAssemblies = new Stack<AssemblyNameReference>();
pendingAssemblies.Push(Assembly.Definition.Name);
var pendingAssemblies = new Stack<string>();
pendingAssemblies.Push(EntryAssembly.Name);
ResolveAssembliesCore();
void ResolveAssembliesCore()
{
while (pendingAssemblies.TryPop(out var current))
{
if (!visitedAssemblies.Contains(current.Name))
if (visitedAssemblies.Add(current))
{
visitedAssemblies.Add(current.Name);
// Not all references will be resolvable within the Mono BCL, particularly
// when building for server-side Blazor as you will be running on CoreCLR
// and therefore may depend on System.* BCL assemblies that aren't present
// in Mono WebAssembly. Skipping unresolved assemblies here is equivalent
// to passing "--skip-unresolved true" to the Mono linker.
var resolved = Resolve(current);
if (resolved != null)
// Not all references will be resolvable within the Mono BCL.
// Skipping unresolved assemblies here is equivalent to passing "--skip-unresolved true" to the Mono linker.
if (Resolve(current) is AssemblyEntry resolved)
{
Results.Add(resolved);
var references = GetAssemblyReferences(resolved);
var references = GetAssemblyReferences(resolved.Path);
foreach (var reference in references)
{
pendingAssemblies.Push(reference);
@ -108,58 +122,70 @@ namespace Microsoft.AspNetCore.Blazor.Build
}
}
IEnumerable<AssemblyNameReference> GetAssemblyReferences(AssemblyEntry current) =>
current.Definition.Modules.SelectMany(m => m.AssemblyReferences);
AssemblyEntry Resolve(AssemblyNameReference current)
AssemblyEntry? Resolve(string assemblyName)
{
if (Assembly.Definition.Name.Name == current.Name)
if (EntryAssembly.Name == assemblyName)
{
return Assembly;
return EntryAssembly;
}
var referencedAssemblyCandidate = FindCandidate(current, Dependencies);
var bclAssemblyCandidate = FindCandidate(current, Bcl);
// Resolution logic. For right now, we will prefer the mono BCL version of a given
// assembly if there is a candidate assembly and an equivalent mono assembly.
if (bclAssemblyCandidate != null)
if (Bcl.TryGetValue(assemblyName, out var assembly) ||
Dependencies.TryGetValue(assemblyName, out assembly))
{
return bclAssemblyCandidate;
}
return referencedAssemblyCandidate;
}
AssemblyEntry FindCandidate(AssemblyNameReference current, AssemblyEntry[] candidates)
{
// Do simple name match. Assume no duplicates.
foreach (var candidate in candidates)
{
if (current.Name == candidate.Definition.Name.Name)
{
return candidate;
}
return assembly;
}
return null;
}
static IReadOnlyList<string> GetAssemblyReferences(string assemblyPath)
{
try
{
using var peReader = new PEReader(File.OpenRead(assemblyPath));
if (!peReader.HasMetadata)
{
return Array.Empty<string>(); // not a managed assembly
}
var metadataReader = peReader.GetMetadataReader();
var references = new List<string>();
foreach (var handle in metadataReader.AssemblyReferences)
{
var reference = metadataReader.GetAssemblyReference(handle);
var referenceName = metadataReader.GetString(reference.Name);
references.Add(referenceName);
}
return references;
}
catch (BadImageFormatException)
{
// not a PE file, or invalid metadata
}
return Array.Empty<string>(); // not a managed assembly
}
}
}
[DebuggerDisplay("{ToString(),nq}")]
public class AssemblyEntry
public readonly struct AssemblyEntry
{
public AssemblyEntry(string path, AssemblyDefinition definition)
public AssemblyEntry(string path, string name)
{
Path = path;
Definition = definition;
Name = name;
}
public string Path { get; set; }
public AssemblyDefinition Definition { get; set; }
public string Path { get; }
public string Name { get; }
public override string ToString() => Definition.FullName;
public override string ToString() => Name;
}
}
}

View File

@ -27,12 +27,8 @@
<ItemGroup>
<ProjectReference Condition="'$(BuildNodeJS)' != 'false' and '$(BuildingInsideVisualStudio)' != 'true'" Include="$(RepoRoot)src\Components\Web.JS\Microsoft.AspNetCore.Components.Web.JS.npmproj" ReferenceOutputAssembly="false" />
<Reference Include="Microsoft.AspNetCore.Components" />
<Reference Include="Microsoft.Extensions.CommandLineUtils.Sources" />
<Reference Include="Microsoft.Extensions.FileProviders.Composite" />
<Reference Include="Microsoft.Extensions.FileProviders.Physical" />
<Reference Include="Mono.Cecil" />
<Reference Include="System.CodeDom" />
<Reference Include="System.Reflection.Metadata" />
</ItemGroup>
<ItemGroup>

View File

@ -623,14 +623,12 @@
Inputs="$(BlazorBuildBootJsonInputsCache);@(_BlazorDependencyInput)"
Outputs="$(BlazorBootJsonIntermediateOutputPath)">
<ItemGroup>
<_UnlinkedAppReferencesPaths Include="@(_BlazorDependencyInput)" />
<_AppReferences Include="@(BlazorItemOutput->WithMetadataValue('Type','Assembly')->WithMetadataValue('PrimaryOutput','')->'%(FileName)%(Extension)')" />
<_AppReferences Include="@(BlazorItemOutput->WithMetadataValue('Type','Assembly')->'%(FileName)%(Extension)')" />
<_AppReferences Include="@(BlazorItemOutput->WithMetadataValue('Type','Pdb')->'%(FileName)%(Extension)')" Condition="'$(BlazorEnableDebugging)' == 'true'" />
</ItemGroup>
<PropertyGroup>
<_LinkerEnabledFlag Condition="'$(_BlazorShouldLinkApplicationAssemblies)' != ''">--linker-enabled</_LinkerEnabledFlag>
<_ReferencesArg Condition="'@(_AppReferences)' != ''">--references &quot;$(BlazorBootJsonReferencesFilePath)&quot;</_ReferencesArg>
<_EmbeddedResourcesArg Condition="'@(_UnlinkedAppReferencesPaths)' != ''">--embedded-resources &quot;$(BlazorEmbeddedResourcesConfigFilePath)&quot;</_EmbeddedResourcesArg>
</PropertyGroup>
<WriteLinesToFile
@ -638,13 +636,7 @@
Lines="@(_AppReferences)"
Overwrite="true" />
<WriteLinesToFile
Condition="'@(_UnlinkedAppReferencesPaths)' != ''"
File="$(BlazorEmbeddedResourcesConfigFilePath)"
Lines="@(_UnlinkedAppReferencesPaths)"
Overwrite="true" />
<Exec Command="$(BlazorBuildExe) write-boot-json &quot;@(IntermediateAssembly)&quot; $(_ReferencesArg) $(_EmbeddedResourcesArg) $(_LinkerEnabledFlag) --output &quot;$(BlazorBootJsonIntermediateOutputPath)&quot;" />
<Exec Command="$(BlazorBuildExe) write-boot-json &quot;@(IntermediateAssembly)&quot; $(_ReferencesArg) $(_LinkerEnabledFlag) --output &quot;$(BlazorBootJsonIntermediateOutputPath)&quot;" />
<ItemGroup Condition="Exists('$(BlazorBootJsonIntermediateOutputPath)')">
<_BlazorBootJson Include="$(BlazorBootJsonIntermediateOutputPath)" />

View File

@ -3,8 +3,6 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Linq;
using Xunit;
namespace Microsoft.AspNetCore.Blazor.Build.Test
@ -15,48 +13,16 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
public void ProducesJsonReferencingAssemblyAndDependencies()
{
// Arrange/Act
var assemblyReferences = new string[] { "System.Abc.dll", "MyApp.ClassLib.dll", };
var assemblyReferences = new string[] { "MyApp.EntryPoint.dll", "System.Abc.dll", "MyApp.ClassLib.dll", };
var content = BootJsonWriter.GetBootJsonContent(
"MyApp.Entrypoint.dll",
"MyNamespace.MyType::MyMethod",
assemblyReferences,
Enumerable.Empty<EmbeddedResourceInfo>(),
linkerEnabled: true);
// Assert
var parsedContent = JsonConvert.DeserializeObject<JObject>(content);
Assert.Equal("MyApp.Entrypoint.dll", parsedContent["main"].Value<string>());
Assert.Equal("MyNamespace.MyType::MyMethod", parsedContent["entryPoint"].Value<string>());
Assert.Equal(assemblyReferences, parsedContent["assemblyReferences"].Values<string>());
}
[Fact]
public void IncludesReferencesToEmbeddedContent()
{
// Arrange/Act
var embeddedContent = new[]
{
new EmbeddedResourceInfo(EmbeddedResourceKind.Static, "my/static/file"),
new EmbeddedResourceInfo(EmbeddedResourceKind.Css, "css/first.css"),
new EmbeddedResourceInfo(EmbeddedResourceKind.JavaScript, "javascript/first.js"),
new EmbeddedResourceInfo(EmbeddedResourceKind.Css, "css/second.css"),
new EmbeddedResourceInfo(EmbeddedResourceKind.JavaScript, "javascript/second.js"),
};
var content = BootJsonWriter.GetBootJsonContent(
"MyApp.Entrypoint",
"MyNamespace.MyType::MyMethod",
assemblyReferences: new[] { "Something.dll" },
embeddedContent: embeddedContent,
linkerEnabled: true);
// Assert
var parsedContent = JsonConvert.DeserializeObject<JObject>(content);
Assert.Equal(
new[] { "css/first.css", "css/second.css" },
parsedContent["cssReferences"].Values<string>());
Assert.Equal(
new[] { "javascript/first.js", "javascript/second.js" },
parsedContent["jsReferences"].Values<string>());
Assert.Equal("MyApp.Entrypoint.dll", parsedContent["entryAssembly"].Value<string>());
Assert.Equal(assemblyReferences, parsedContent["assemblies"].Values<string>());
}
}
}

View File

@ -1,2 +1,3 @@
node_modules/
dist/Debug/
dist/Release/blazor.webassembly.js

File diff suppressed because one or more lines are too long

View File

@ -2,7 +2,6 @@ import '@dotnet/jsinterop';
import './GlobalExports';
import * as Environment from './Environment';
import { monoPlatform } from './Platform/Mono/MonoPlatform';
import { getAssemblyNameFromUrl } from './Platform/Url';
import { renderBatch } from './Rendering/Renderer';
import { SharedMemoryRenderBatch } from './Rendering/RenderBatch/SharedMemoryRenderBatch';
import { Pointer } from './Platform/Platform';
@ -39,15 +38,13 @@ async function boot(options?: any): Promise<void> {
// Fetch the boot JSON file
const bootConfig = await fetchBootConfigAsync();
const embeddedResourcesPromise = loadEmbeddedResourcesAsync(bootConfig);
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');
}
// Determine the URLs of the assemblies we want to load, then begin fetching them all
const loadAssemblyUrls = [bootConfig.main]
.concat(bootConfig.assemblyReferences)
const loadAssemblyUrls = bootConfig.assemblies
.map(filename => `_framework/_bin/${filename}`);
try {
@ -56,12 +53,8 @@ async function boot(options?: any): Promise<void> {
throw new Error(`Failed to start platform. Reason: ${ex}`);
}
// Before we start running .NET code, be sure embedded content resources are all loaded
await embeddedResourcesPromise;
// Start up the application
const mainAssemblyName = getAssemblyNameFromUrl(bootConfig.main);
platform.callEntryPoint(mainAssemblyName);
platform.callEntryPoint(bootConfig.entryAssembly);
}
async function fetchBootConfigAsync() {
@ -71,36 +64,10 @@ async function fetchBootConfigAsync() {
return bootConfigResponse.json() as Promise<BootJsonData>;
}
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[];
entryAssembly: string;
assemblies: string[];
linkerEnabled: boolean;
}