diff --git a/Blazor.sln b/Blazor.sln
index c1c5691370..6fc39fe6ca 100644
--- a/Blazor.sln
+++ b/Blazor.sln
@@ -87,6 +87,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.Lang
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.VisualStudio.BlazorExtension", "tooling\Microsoft.VisualStudio.BlazorExtension\Microsoft.VisualStudio.BlazorExtension.csproj", "{9088E4E4-B855-457F-AE9E-D86709A5E1F4}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestContentPackage", "test\testapps\TestContentPackage\TestContentPackage.csproj", "{C57382BC-EE93-49D5-BC40-5C98AF8AA048}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -301,6 +303,14 @@ Global
{9088E4E4-B855-457F-AE9E-D86709A5E1F4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9088E4E4-B855-457F-AE9E-D86709A5E1F4}.Release|Any CPU.Build.0 = Release|Any CPU
{9088E4E4-B855-457F-AE9E-D86709A5E1F4}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
+ {C57382BC-EE93-49D5-BC40-5C98AF8AA048}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C57382BC-EE93-49D5-BC40-5C98AF8AA048}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C57382BC-EE93-49D5-BC40-5C98AF8AA048}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
+ {C57382BC-EE93-49D5-BC40-5C98AF8AA048}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
+ {C57382BC-EE93-49D5-BC40-5C98AF8AA048}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C57382BC-EE93-49D5-BC40-5C98AF8AA048}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C57382BC-EE93-49D5-BC40-5C98AF8AA048}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
+ {C57382BC-EE93-49D5-BC40-5C98AF8AA048}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -340,6 +350,7 @@ Global
{FF25111E-5A3E-48A3-96D8-08A2C5A2A91C} = {ADA3AE29-F6DE-49F6-8C7C-B321508CAE8E}
{43E39257-7DC1-46BD-9BD9-2319A1313D07} = {F563ABB6-85FB-4CFC-B0D2-1D5130E8246D}
{9088E4E4-B855-457F-AE9E-D86709A5E1F4} = {F563ABB6-85FB-4CFC-B0D2-1D5130E8246D}
+ {C57382BC-EE93-49D5-BC40-5C98AF8AA048} = {4AE0D35B-D97A-44D0-8392-C9240377DCCE}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {504DA352-6788-4DC0-8705-82167E72A4D3}
diff --git a/src/Microsoft.AspNetCore.Blazor.Build/Cli/Commands/BuildIndexHtmlCommand.cs b/src/Microsoft.AspNetCore.Blazor.Build/Cli/Commands/BuildIndexHtmlCommand.cs
index 02e188c1cb..d689c59ffb 100644
--- a/src/Microsoft.AspNetCore.Blazor.Build/Cli/Commands/BuildIndexHtmlCommand.cs
+++ b/src/Microsoft.AspNetCore.Blazor.Build/Cli/Commands/BuildIndexHtmlCommand.cs
@@ -18,6 +18,14 @@ namespace Microsoft.AspNetCore.Blazor.Build.Cli.Commands
"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 ");
+
// Set a flag so we know not to emit anything else until the special
// tag is closed
isInBlazorBootTag = true;
@@ -160,6 +178,15 @@ namespace Microsoft.AspNetCore.Blazor.Build
}
}
+ private static void AppendReferenceTags(StringBuilder resultBuilder, IEnumerable urls, string format)
+ {
+ foreach (var url in urls)
+ {
+ resultBuilder.AppendLine();
+ resultBuilder.AppendFormat(format, url);
+ }
+ }
+
private static bool IsBlazorBootTag(HtmlTagToken tag)
=> string.Equals(tag.Name, "script", StringComparison.Ordinal)
&& tag.Attributes.Any(pair =>
diff --git a/src/Microsoft.AspNetCore.Blazor.Build/targets/Blazor.MonoRuntime.props b/src/Microsoft.AspNetCore.Blazor.Build/targets/Blazor.MonoRuntime.props
index b2924b901f..545ad3d3ff 100644
--- a/src/Microsoft.AspNetCore.Blazor.Build/targets/Blazor.MonoRuntime.props
+++ b/src/Microsoft.AspNetCore.Blazor.Build/targets/Blazor.MonoRuntime.props
@@ -11,6 +11,7 @@
-c link -u link -t --verbose
+ dist/_content/dist/_framework/$(BaseBlazorRuntimeOutputPath)_bin/$(BaseBlazorRuntimeOutputPath)asmjs/
diff --git a/src/Microsoft.AspNetCore.Blazor.Build/targets/Blazor.MonoRuntime.targets b/src/Microsoft.AspNetCore.Blazor.Build/targets/Blazor.MonoRuntime.targets
index af1d5c11bb..0b7ebe4696 100644
--- a/src/Microsoft.AspNetCore.Blazor.Build/targets/Blazor.MonoRuntime.targets
+++ b/src/Microsoft.AspNetCore.Blazor.Build/targets/Blazor.MonoRuntime.targets
@@ -168,6 +168,14 @@
+
+ <_BlazorPackageContentOutput Include="@(BlazorPackageContentFile)" Condition="%(SourcePackage) != ''">
+ $(ProjectDir)$(OutputPath)$(BaseBlazorPackageContentOutputPath)%(SourcePackage)\%(RecursiveDir)\%(Filename)%(Extension)
+ PreserveNewest
+
+
+
+
@@ -522,6 +530,8 @@
+
+
<_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)')" />
-
+
<_BlazorIndex Include="$(BlazorIndexHtmlOutputPath)" />
diff --git a/test/Microsoft.AspNetCore.Blazor.Build.Test/IndexHtmlWriterTest.cs b/test/Microsoft.AspNetCore.Blazor.Build.Test/IndexHtmlWriterTest.cs
index a37c7117d2..8442204332 100644
--- a/test/Microsoft.AspNetCore.Blazor.Build.Test/IndexHtmlWriterTest.cs
+++ b/test/Microsoft.AspNetCore.Blazor.Build.Test/IndexHtmlWriterTest.cs
@@ -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.Linq;
using Xunit;
namespace Microsoft.AspNetCore.Blazor.Build.Test
@@ -25,15 +26,16 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
$@"{htmlTemplatePrefix}
{htmlTemplateSuffix}";
- var dependencies = new string[]
- {
- "System.Abc.dll",
- "MyApp.ClassLib.dll",
- };
+ 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", dependencies);
+ "MyNamespace.MyType::MyMethod",
+ assemblyReferences,
+ jsReferences,
+ cssReferences);
// Act & Assert: Start and end is not modified (including formatting)
Assert.StartsWith(htmlTemplatePrefix, instance);
@@ -42,7 +44,9 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
// Assert: Boot tag is correct
var scriptTagText = instance.Substring(htmlTemplatePrefix.Length, instance.Length - htmlTemplatePrefix.Length - htmlTemplateSuffix.Length);
var parsedHtml = new HtmlParser().Parse("" + scriptTagText + "");
- var scriptElem = parsedHtml.Body.QuerySelector("script");
+ var scriptElems = parsedHtml.Body.QuerySelectorAll("script");
+ var linkElems = parsedHtml.Body.QuerySelectorAll("link");
+ var scriptElem = scriptElems[0];
Assert.False(scriptElem.HasChildNodes);
Assert.Equal("_framework/blazor.js", scriptElem.GetAttribute("src"));
Assert.Equal("MyApp.Entrypoint.dll", scriptElem.GetAttribute("main"));
@@ -51,6 +55,16 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
Assert.False(scriptElem.HasAttribute("type"));
Assert.Equal(string.Empty, scriptElem.Attributes["custom1"].Value);
Assert.Equal("value", scriptElem.Attributes["custom2"].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]
@@ -58,14 +72,12 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
{
// Arrange
var htmlTemplate = "
Hello
Some text";
- var dependencies = new string[]
- {
- "System.Abc.dll",
- "MyApp.ClassLib.dll",
- };
+ 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 content = IndexHtmlWriter.GetIndexHtmlContents(
- htmlTemplate, "MyApp.Entrypoint", "MyNamespace.MyType::MyMethod", dependencies);
+ htmlTemplate, "MyApp.Entrypoint", "MyNamespace.MyType::MyMethod", assemblyReferences, jsReferences, cssReferences);
// Assert
Assert.Equal(htmlTemplate, content);
diff --git a/test/Microsoft.AspNetCore.Blazor.E2ETest/Tests/ComponentRenderingTest.cs b/test/Microsoft.AspNetCore.Blazor.E2ETest/Tests/ComponentRenderingTest.cs
index 66006e0773..a3512557b9 100644
--- a/test/Microsoft.AspNetCore.Blazor.E2ETest/Tests/ComponentRenderingTest.cs
+++ b/test/Microsoft.AspNetCore.Blazor.E2ETest/Tests/ComponentRenderingTest.cs
@@ -199,5 +199,34 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
elem => Assert.Equal(typeof(Complex).FullName, elem.Text),
elem => Assert.Equal(typeof(AssemblyHashAlgorithm).FullName, elem.Text));
}
+
+ [Fact]
+ public void CanUseComponentAndStaticContentFromExternalNuGetPackage()
+ {
+ var appElement = MountTestComponent();
+
+ // NuGet packages can use Blazor's JS interop features to provide
+ // .NET code access to browser APIs
+ var showPromptButton = appElement.FindElements(By.TagName("button")).First();
+ showPromptButton.Click();
+ var modal = Browser.SwitchTo().Alert();
+ modal.SendKeys("Some value from test");
+ modal.Accept();
+ var promptResult = appElement.FindElement(By.TagName("strong"));
+ Assert.Equal("Some value from test", promptResult.Text);
+
+ // NuGet packages can also embed entire Blazor components (themselves
+ // authored as Razor files), including static content. The CSS value
+ // here is in a .css file, so if it's correct we know that static content
+ // file was loaded.
+ var specialStyleDiv = appElement.FindElement(By.ClassName("special-style"));
+ Assert.Equal("50px", specialStyleDiv.GetCssValue("padding"));
+
+ // The external Blazor components are fully functional, not just static HTML
+ var externalComponentButton = specialStyleDiv.FindElement(By.TagName("button"));
+ Assert.Equal("Click me", externalComponentButton.Text);
+ externalComponentButton.Click();
+ Assert.Equal("It works", externalComponentButton.Text);
+ }
}
}
diff --git a/test/testapps/BasicTestApp/BasicTestApp.csproj b/test/testapps/BasicTestApp/BasicTestApp.csproj
index 5cb5aa8933..f9e79f9b3d 100644
--- a/test/testapps/BasicTestApp/BasicTestApp.csproj
+++ b/test/testapps/BasicTestApp/BasicTestApp.csproj
@@ -16,4 +16,10 @@
+
+
+
+
+
+
diff --git a/test/testapps/BasicTestApp/ExternalContentPackage.cshtml b/test/testapps/BasicTestApp/ExternalContentPackage.cshtml
new file mode 100644
index 0000000000..49f86823a5
--- /dev/null
+++ b/test/testapps/BasicTestApp/ExternalContentPackage.cshtml
@@ -0,0 +1,38 @@
+@addTagHelper *, TestContentPackage
+@using TestContentPackage
+
+
Functionality and content from an external package
+
+
+ NuGet packages can embed .NET code, which can in turn call Blazor's
+ JS interop features if desired. This can be used to distribute new
+ browser APIs as NuGet packages.
+
+
+
Click the following button to invoke a JavaScript function.
+
+
+
+@if (!string.IsNullOrEmpty(result))
+{
+
Result: @result
+}
+
+
+
+
+ Additionally, NuGet packages can contain Blazor components, and even
+ static resources such as CSS files and images.
+