Reference static content from referenced assemblies. Implements #340
This commit is contained in:
parent
05059d9aa3
commit
fef5a52183
|
|
@ -93,6 +93,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmarks", "benchmarks",
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Blazor.Performance", "benchmarks\Microsoft.AspNetCore.Blazor.Performance\Microsoft.AspNetCore.Blazor.Performance.csproj", "{50F6820F-D058-4E68-9E15-801F893F514E}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlazorContent.CSharp", "src\Microsoft.AspNetCore.Blazor.Templates\content\BlazorContent.CSharp\BlazorContent.CSharp.csproj", "{3A457B14-D91B-4FFF-A81A-8F350BDB911F}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
@ -324,6 +326,10 @@ Global
|
|||
{50F6820F-D058-4E68-9E15-801F893F514E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{50F6820F-D058-4E68-9E15-801F893F514E}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{50F6820F-D058-4E68-9E15-801F893F514E}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
|
||||
{3A457B14-D91B-4FFF-A81A-8F350BDB911F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3A457B14-D91B-4FFF-A81A-8F350BDB911F}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3A457B14-D91B-4FFF-A81A-8F350BDB911F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3A457B14-D91B-4FFF-A81A-8F350BDB911F}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
@ -365,6 +371,7 @@ Global
|
|||
{9088E4E4-B855-457F-AE9E-D86709A5E1F4} = {F563ABB6-85FB-4CFC-B0D2-1D5130E8246D}
|
||||
{C57382BC-EE93-49D5-BC40-5C98AF8AA048} = {4AE0D35B-D97A-44D0-8392-C9240377DCCE}
|
||||
{50F6820F-D058-4E68-9E15-801F893F514E} = {36A7DEB7-5F88-4BFB-B57E-79EEC9950E25}
|
||||
{3A457B14-D91B-4FFF-A81A-8F350BDB911F} = {E8EBA72C-D555-43AE-BC98-F0B2D05F6A07}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {504DA352-6788-4DC0-8705-82167E72A4D3}
|
||||
|
|
|
|||
|
|
@ -15,15 +15,11 @@ namespace Microsoft.AspNetCore.Blazor.Build.Cli.Commands
|
|||
CommandOptionType.SingleValue);
|
||||
|
||||
var references = command.Option("--reference",
|
||||
"The path from the _bin folder to a given referenced dll file (Typically just the dll name)",
|
||||
"The path from the _bin folder to a given referenced dll file (typically just the dll name)",
|
||||
CommandOptionType.MultipleValue);
|
||||
|
||||
var jsReferences = command.Option("--js",
|
||||
"Adds a <script> tag with the specified 'src' value",
|
||||
CommandOptionType.MultipleValue);
|
||||
|
||||
var cssReferences = command.Option("--css",
|
||||
"Adds a <link rel=stylesheet> tag with the specified 'href' value",
|
||||
var embeddedResourcesSources = command.Option("--embedded-resources-source",
|
||||
"The path to an assembly that may contain embedded resources (typically a referenced assembly in its pre-linked state)",
|
||||
CommandOptionType.MultipleValue);
|
||||
|
||||
var outputPath = command.Option("--output",
|
||||
|
|
@ -52,8 +48,7 @@ namespace Microsoft.AspNetCore.Blazor.Build.Cli.Commands
|
|||
clientPage.Value(),
|
||||
mainAssemblyPath.Value,
|
||||
references.Values.ToArray(),
|
||||
jsReferences.Values.ToArray(),
|
||||
cssReferences.Values.ToArray(),
|
||||
embeddedResourcesSources.Values.ToArray(),
|
||||
linkerEnabledFlag.HasValue(),
|
||||
outputPath.Value());
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
// 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
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
// 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 index.html 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);
|
||||
}
|
||||
}
|
||||
|
|
@ -19,8 +19,7 @@ namespace Microsoft.AspNetCore.Blazor.Build
|
|||
string path,
|
||||
string assemblyPath,
|
||||
IEnumerable<string> assemblyReferences,
|
||||
IEnumerable<string> jsReferences,
|
||||
IEnumerable<string> cssReferences,
|
||||
IEnumerable<string> embeddedResourcesSources,
|
||||
bool linkerEnabled,
|
||||
string outputPath)
|
||||
{
|
||||
|
|
@ -31,7 +30,9 @@ namespace Microsoft.AspNetCore.Blazor.Build
|
|||
}
|
||||
var assemblyName = Path.GetFileNameWithoutExtension(assemblyPath);
|
||||
var entryPoint = GetAssemblyEntryPoint(assemblyPath);
|
||||
var updatedContent = GetIndexHtmlContents(template, assemblyName, entryPoint, assemblyReferences, jsReferences, cssReferences, linkerEnabled);
|
||||
var embeddedContent = EmbeddedResourcesProcessor.ExtractEmbeddedResources(
|
||||
embeddedResourcesSources, Path.GetDirectoryName(outputPath));
|
||||
var updatedContent = GetIndexHtmlContents(template, assemblyName, entryPoint, assemblyReferences, embeddedContent, linkerEnabled);
|
||||
var normalizedOutputPath = Normalize(outputPath);
|
||||
Console.WriteLine("Writing index to: " + normalizedOutputPath);
|
||||
File.WriteAllText(normalizedOutputPath, updatedContent);
|
||||
|
|
@ -101,8 +102,7 @@ namespace Microsoft.AspNetCore.Blazor.Build
|
|||
string assemblyName,
|
||||
string assemblyEntryPoint,
|
||||
IEnumerable<string> assemblyReferences,
|
||||
IEnumerable<string> jsReferences,
|
||||
IEnumerable<string> cssReferences,
|
||||
IEnumerable<EmbeddedResourceInfo> embeddedContent,
|
||||
bool linkerEnabled)
|
||||
{
|
||||
var resultBuilder = new StringBuilder();
|
||||
|
|
@ -118,10 +118,11 @@ namespace Microsoft.AspNetCore.Blazor.Build
|
|||
while (true)
|
||||
{
|
||||
var token = tokenizer.Get();
|
||||
var tokenCharIndex = token.Position.Position - 1;
|
||||
if (resumeOnNextToken)
|
||||
{
|
||||
resumeOnNextToken = false;
|
||||
currentRangeStartPos = token.Position.Position;
|
||||
currentRangeStartPos = tokenCharIndex;
|
||||
}
|
||||
|
||||
switch (token.Type)
|
||||
|
|
@ -134,7 +135,7 @@ namespace Microsoft.AspNetCore.Blazor.Build
|
|||
{
|
||||
// First, emit the original source text prior to this special tag, since
|
||||
// we want that to be unchanged
|
||||
resultBuilder.Append(htmlTemplate, currentRangeStartPos, token.Position.Position - currentRangeStartPos - 1);
|
||||
resultBuilder.Append(htmlTemplate, currentRangeStartPos, tokenCharIndex - currentRangeStartPos);
|
||||
|
||||
// Instead of emitting the source text for this special tag, emit a fully-
|
||||
// configured Blazor boot script tag
|
||||
|
|
@ -149,11 +150,11 @@ namespace Microsoft.AspNetCore.Blazor.Build
|
|||
// Emit tags to reference any specified JS/CSS files
|
||||
AppendReferenceTags(
|
||||
resultBuilder,
|
||||
cssReferences,
|
||||
embeddedContent.Where(c => c.Kind == EmbeddedResourceKind.Css).Select(c => c.RelativePath),
|
||||
"<link rel=\"stylesheet\" href=\"{0}\" />");
|
||||
AppendReferenceTags(
|
||||
resultBuilder,
|
||||
jsReferences,
|
||||
embeddedContent.Where(c => c.Kind == EmbeddedResourceKind.JavaScript).Select(c => c.RelativePath),
|
||||
"<script src=\"{0}\" defer></script>");
|
||||
|
||||
// Set a flag so we know not to emit anything else until the special
|
||||
|
|
|
|||
|
|
@ -227,8 +227,11 @@
|
|||
|
||||
<!-- Index.html related paths and markers -->
|
||||
|
||||
<!-- /obj/<<configuration>>/<<targetframework>>/blazor/ -->
|
||||
<BlazorIndexHtmlOutputDir>$(BlazorIntermediateOutputPath)</BlazorIndexHtmlOutputDir>
|
||||
|
||||
<!-- /obj/<<configuration>>/<<targetframework>>/blazor/index.html -->
|
||||
<BlazorIndexHtmlOutputPath>$(BlazorIntermediateOutputPath)$(BlazorOutputIndexHtmlName)</BlazorIndexHtmlOutputPath>
|
||||
<BlazorIndexHtmlOutputPath>$(BlazorIndexHtmlOutputDir)$(BlazorOutputIndexHtmlName)</BlazorIndexHtmlOutputPath>
|
||||
|
||||
<!-- /obj/<<configuration>>/<<targetframework>>/blazor/inputs.index.cache -->
|
||||
<BlazorBuildIndexInputsCache>$(BlazorIntermediateOutputPath)inputs.index.cache</BlazorBuildIndexInputsCache>
|
||||
|
|
@ -568,8 +571,6 @@
|
|||
<ItemGroup>
|
||||
<BlazorIndexHtmlInput Include="$(BlazorIndexHtml)" />
|
||||
<BlazorIndexHtmlInput Include="@(BlazorItemOutput->WithMetadataValue('Type','Assembly')->'%(FullPath)')" />
|
||||
<BlazorIndexHtmlInput Include="@(BlazorPackageJsRef->'%(FullPath)')" />
|
||||
<BlazorIndexHtmlInput Include="@(BlazorPackageCssRef->'%(FullPath)')" />
|
||||
<BlazorIndexHtmlInput Include="@(_BlazorLinkingOption)" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
@ -588,26 +589,30 @@
|
|||
<Target
|
||||
Name="_GenerateBlazorIndexHtml"
|
||||
DependsOnTargets="_ResolveBlazorIndexHtmlInputs"
|
||||
Inputs="$(BlazorBuildIndexInputsCache);$(BlazorIndexHtml)"
|
||||
Inputs="$(BlazorBuildIndexInputsCache);$(BlazorIndexHtml);@(_BlazorDependencyInput)"
|
||||
Outputs="$(BlazorIndexHtmlOutputPath)">
|
||||
<ItemGroup>
|
||||
<_UnlinkedAppReferencesPaths Include="@(_BlazorDependencyInput)" />
|
||||
<_AppReferences Include="@(BlazorItemOutput->WithMetadataValue('Type','Assembly')->WithMetadataValue('PrimaryOutput','')->'%(FileName)%(Extension)')" />
|
||||
<_JsReferences Include="@(BlazorPackageJsRef->'_content/%(SourcePackage)/%(RecursiveDir)%(FileName)%(Extension)')" />
|
||||
<_CssReferences Include="@(BlazorPackageCssRef->'_content/%(SourcePackage)/%(RecursiveDir)%(FileName)%(Extension)')" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<_LinkerEnabledFlag Condition="'$(_BlazorShouldLinkApplicationAssemblies)' != ''">--linker-enabled</_LinkerEnabledFlag>
|
||||
</PropertyGroup>
|
||||
|
||||
<Exec Command="$(BlazorBuildExe) build @(IntermediateAssembly) --html-page "$(BlazorIndexHtml)" @(_AppReferences->'--reference "%(Identity)"', ' ') @(_JsReferences->'--js "%(Identity)"', ' ') @(_CssReferences->'--css "%(Identity)"', ' ') $(_LinkerEnabledFlag) --output "$(BlazorIndexHtmlOutputPath)"" />
|
||||
<Exec Command="$(BlazorBuildExe) build @(IntermediateAssembly) --html-page "$(BlazorIndexHtml)" @(_AppReferences->'--reference "%(Identity)"', ' ') @(_UnlinkedAppReferencesPaths->'--embedded-resources-source "%(Identity)"', ' ') $(_LinkerEnabledFlag) --output "$(BlazorIndexHtmlOutputPath)"" />
|
||||
|
||||
<ItemGroup Condition="Exists('$(BlazorIndexHtmlOutputPath)')">
|
||||
<_BlazorIndex Include="$(BlazorIndexHtmlOutputPath)" />
|
||||
<_BlazorIndexEmbeddedContentFile Include="$(BlazorIndexHtmlOutputDir)_content\**\*.*" />
|
||||
<BlazorItemOutput Include="@(_BlazorIndex)">
|
||||
<TargetOutputPath>$(ProjectDir)$(OutputPath)dist/%(FileName)%(Extension)</TargetOutputPath>
|
||||
<Type>EntryPoint</Type>
|
||||
</BlazorItemOutput>
|
||||
<BlazorItemOutput Include="@(_BlazorIndexEmbeddedContentFile)">
|
||||
<TargetOutputPath>$(ProjectDir)$(OutputPath)dist/_content/%(RecursiveDir)%(FileName)%(Extension)</TargetOutputPath>
|
||||
</BlazorItemOutput>
|
||||
<FileWrites Include="$(BlazorIndexHtmlOutputPath)" />
|
||||
<FileWrites Include="@(_BlazorIndexEmbeddedContentFile)" />
|
||||
</ItemGroup>
|
||||
|
||||
</Target>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"$schema": "http://json.schemastore.org/dotnetcli.host",
|
||||
"symbolInfo": {
|
||||
"skipRestore": {
|
||||
"longName": "no-restore",
|
||||
"shortName": ""
|
||||
},
|
||||
"Framework": {
|
||||
"longName": "framework"
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
|
|
@ -0,0 +1,70 @@
|
|||
{
|
||||
"author": "Microsoft",
|
||||
"classifications": [
|
||||
"Web",
|
||||
"Blazor",
|
||||
"Content"
|
||||
],
|
||||
"groupIdentity": "Microsoft.Web.Blazor.Content",
|
||||
"identity": "Microsoft.Web.Blazor.Content.CSharp",
|
||||
"name": "Blazor (content)",
|
||||
"preferNameDirectory": true,
|
||||
"primaryOutputs": [
|
||||
{
|
||||
"path": "BlazorContent.CSharp.csproj"
|
||||
}
|
||||
],
|
||||
"shortName": "blazorcontent",
|
||||
"sourceName": "BlazorContent.CSharp",
|
||||
"sources": [
|
||||
{
|
||||
"source": "./",
|
||||
"target": "./",
|
||||
"exclude": [
|
||||
".template.config/**"
|
||||
]
|
||||
}
|
||||
],
|
||||
"symbols": {
|
||||
"Framework": {
|
||||
"type": "parameter",
|
||||
"description": "The target framework for the project.",
|
||||
"datatype": "choice",
|
||||
"choices": [
|
||||
{
|
||||
"choice": "netcoreapp2.0",
|
||||
"description": "Target netcoreapp2.0"
|
||||
}
|
||||
],
|
||||
"replaces": "netcoreapp2.0",
|
||||
"defaultValue": "netcoreapp2.0"
|
||||
},
|
||||
"HostIdentifier": {
|
||||
"type": "bind",
|
||||
"binding": "HostIdentifier"
|
||||
},
|
||||
"skipRestore": {
|
||||
"type": "parameter",
|
||||
"datatype": "bool",
|
||||
"description": "If specified, skips the automatic restore of the project on create.",
|
||||
"defaultValue": "false"
|
||||
}
|
||||
},
|
||||
"tags": {
|
||||
"language": "C#",
|
||||
"type": "project"
|
||||
},
|
||||
"postActions": [
|
||||
{
|
||||
"condition": "(!skipRestore)",
|
||||
"description": "Restore NuGet packages required by this project.",
|
||||
"manualInstructions": [
|
||||
{
|
||||
"text": "Run 'dotnet restore'"
|
||||
}
|
||||
],
|
||||
"actionId": "210D431B-A78B-4D2F-B762-4ED3E3EA9025",
|
||||
"continueOnError": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web;Microsoft.NET.Sdk.Razor/2.1.0-preview2-30230">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<OutputType>library</OutputType>
|
||||
<IsPackable>true</IsPackable>
|
||||
<BlazorLinkOnBuild>false</BlazorLinkOnBuild>
|
||||
|
||||
<!-- This custom package feed is required only when using nightly builds of Blazor -->
|
||||
<RestoreSources>https://dotnet.myget.org/F/blazor-dev/api/v3/index.json;$(RestoreSources)</RestoreSources>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!-- .js/.css files will be referenced via <script>/<link> tags; other content files will just be included in the app's 'dist' directory without any tags referencing them -->
|
||||
<EmbeddedResource Include="content\**\*.js" LogicalName="blazor:js:%(RecursiveDir)%(Filename)%(Extension)" />
|
||||
<EmbeddedResource Include="content\**\*.css" LogicalName="blazor:css:%(RecursiveDir)%(Filename)%(Extension)" />
|
||||
<EmbeddedResource Include="content\**" Exclude="**\*.js;**\*.css" LogicalName="blazor:file:%(RecursiveDir)%(Filename)%(Extension)" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.1.0-preview2-30230" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Blazor.Browser" Version="0.2.0-preview1-10168" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Blazor.Build" Version="0.2.0-preview1-10168" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<div class="my-component">
|
||||
This Blazor component is defined in the <strong>BlazorContent.CSharp</strong> package.
|
||||
</div>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
using Microsoft.AspNetCore.Blazor.Browser.Interop;
|
||||
|
||||
namespace BlazorContent.CSharp
|
||||
{
|
||||
public class ExampleJsInterop
|
||||
{
|
||||
public static string Prompt(string message)
|
||||
{
|
||||
return RegisteredFunction.Invoke<string>(
|
||||
"BlazorContent.CSharp.ExampleJsInterop.Prompt",
|
||||
message);
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 378 B |
|
|
@ -0,0 +1,6 @@
|
|||
// This file is to show how a content package may provide JavaScript interop features
|
||||
// wrapped in a .NET API
|
||||
|
||||
Blazor.registerFunction('BlazorContent.CSharp.ExampleJsInterop.Prompt', function (message) {
|
||||
return prompt(message, 'Type anything here');
|
||||
});
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
/*
|
||||
This file is to show how CSS and other static resources (such as images) can be
|
||||
used from a content project/package.
|
||||
*/
|
||||
|
||||
.my-component {
|
||||
border: 2px dashed red;
|
||||
padding: 1em;
|
||||
margin: 1em 0;
|
||||
background-image: url('background.png');
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using AngleSharp.Parser.Html;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -27,15 +28,12 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
|
|||
<script type='blazor-boot' custom1 custom2=""value"">some text that should be removed</script>
|
||||
{htmlTemplateSuffix}";
|
||||
var assemblyReferences = new string[] { "System.Abc.dll", "MyApp.ClassLib.dll", };
|
||||
var jsReferences = new string[] { "some/file.js", "another.js" };
|
||||
var cssReferences = new string[] { "my/styles.css" };
|
||||
var instance = IndexHtmlWriter.GetIndexHtmlContents(
|
||||
htmlTemplate,
|
||||
"MyApp.Entrypoint",
|
||||
"MyNamespace.MyType::MyMethod",
|
||||
assemblyReferences,
|
||||
jsReferences,
|
||||
cssReferences,
|
||||
Enumerable.Empty<EmbeddedResourceInfo>(),
|
||||
linkerEnabled: true);
|
||||
|
||||
// Act & Assert: Start and end is not modified (including formatting)
|
||||
|
|
@ -57,16 +55,6 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
|
|||
Assert.Equal(string.Empty, scriptElem.Attributes["custom1"].Value);
|
||||
Assert.Equal("value", scriptElem.Attributes["custom2"].Value);
|
||||
Assert.Equal("true", scriptElem.Attributes["linker-enabled"].Value);
|
||||
|
||||
// Assert: Also contains script tags referencing JS files
|
||||
Assert.Equal(
|
||||
scriptElems.Skip(1).Select(tag => tag.GetAttribute("src")),
|
||||
jsReferences);
|
||||
|
||||
// Assert: Also contains link tags referencing CSS files
|
||||
Assert.Equal(
|
||||
linkElems.Select(tag => tag.GetAttribute("href")),
|
||||
cssReferences);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -79,10 +67,50 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
|
|||
var cssReferences = new string[] { "my/styles.css" };
|
||||
|
||||
var content = IndexHtmlWriter.GetIndexHtmlContents(
|
||||
htmlTemplate, "MyApp.Entrypoint", "MyNamespace.MyType::MyMethod", assemblyReferences, jsReferences, cssReferences, linkerEnabled: true);
|
||||
htmlTemplate, "MyApp.Entrypoint", "MyNamespace.MyType::MyMethod", assemblyReferences, Enumerable.Empty<EmbeddedResourceInfo>(), linkerEnabled: true);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(htmlTemplate, content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InjectsAdditionalTagsForEmbeddedContent()
|
||||
{
|
||||
// Arrange
|
||||
var htmlTemplate = "Start <script id='testboot' type='blazor-boot'></script> End";
|
||||
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"),
|
||||
};
|
||||
|
||||
// Act
|
||||
var resultHtml = IndexHtmlWriter.GetIndexHtmlContents(
|
||||
htmlTemplate,
|
||||
"MyApp.Entrypoint",
|
||||
"MyNamespace.MyType::MyMethod",
|
||||
assemblyReferences: new[] { "Something.dll" },
|
||||
embeddedContent: embeddedContent,
|
||||
linkerEnabled: true);
|
||||
|
||||
// Assert
|
||||
var parsedHtml = new HtmlParser().Parse(resultHtml);
|
||||
var blazorBootScript = parsedHtml.GetElementById("testboot");
|
||||
Assert.NotNull(blazorBootScript);
|
||||
Assert.Equal(
|
||||
"Start "
|
||||
+ blazorBootScript.OuterHtml
|
||||
// First we insert the CSS file tags in order
|
||||
+ Environment.NewLine + "<link rel=\"stylesheet\" href=\"css/first.css\" />"
|
||||
+ Environment.NewLine + "<link rel=\"stylesheet\" href=\"css/second.css\" />"
|
||||
// Then the JS file tags in order, each with 'defer'
|
||||
+ Environment.NewLine + "<script src=\"javascript/first.js\" defer></script>"
|
||||
+ Environment.NewLine + "<script src=\"javascript/second.js\" defer></script>"
|
||||
+ " End",
|
||||
resultHtml);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,11 +13,6 @@
|
|||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\src\Microsoft.AspNetCore.Blazor.Browser\Microsoft.AspNetCore.Blazor.Browser.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Microsoft.AspNetCore.Blazor\Microsoft.AspNetCore.Blazor.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Local alternative to <PackageReference> to the content package -->
|
||||
<Import Project="..\TestContentPackage\build\TestContentPackage.props" />
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\TestContentPackage\TestContentPackage.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
|||
|
|
@ -7,9 +7,14 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Remove="**" />
|
||||
<Content Include="build\**" PackagePath="build" />
|
||||
<Content Include="content\**" PackagePath="content" />
|
||||
<!-- .js files will be referenced via <script> tags -->
|
||||
<EmbeddedResource Include="content\**\*.js" LogicalName="blazor:js:%(RecursiveDir)%(Filename)%(Extension)" />
|
||||
|
||||
<!-- .css files will be referenced via <link rel='Stylesheet'> tags -->
|
||||
<EmbeddedResource Include="content\**\*.css" LogicalName="blazor:css:%(RecursiveDir)%(Filename)%(Extension)" />
|
||||
|
||||
<!-- Any other files will be included in the 'dist' output but without any tags referencing them -->
|
||||
<EmbeddedResource Include="content\**" Exclude="**\*.js;**\*.css" LogicalName="blazor:file:%(RecursiveDir)%(Filename)%(Extension)" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -1,19 +0,0 @@
|
|||
<Project>
|
||||
<PropertyGroup>
|
||||
<!-- Update this to match your package ID exactly -->
|
||||
<_PackageId>TestContentPackage</_PackageId>
|
||||
<_ContentDir>$(MSBuildThisFileDirectory)..\content\</_ContentDir>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<!-- All files under "content" will be included with the Blazor app build output -->
|
||||
<BlazorPackageContentFile Include="$(_ContentDir)**" SourcePackage="$(_PackageId)" />
|
||||
|
||||
<!-- We'll generate a <script> tag importing each of the following JavaScript files -->
|
||||
<!-- Change the "Include" pattern if you don't want to include all .js files. -->
|
||||
<BlazorPackageJsRef Include="$(_ContentDir)**\*.js" SourcePackage="$(_PackageId)" />
|
||||
|
||||
<!-- We'll generate a <link> tag importing each of the following CSS files -->
|
||||
<!-- Change the "Include" pattern if you don't want to include all .css files. -->
|
||||
<BlazorPackageCssRef Include="$(_ContentDir)**\*.css" SourcePackage="$(_PackageId)" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Loading…
Reference in New Issue