Skip to content

Commit 0ca2ed9

Browse files
authored
[Blazor] Custom JS initializers (#34798)
* Users can create an ES6 module with `<packageName>.lib.module.js` and declare a beforeStart and afterStarted function to integrate into the blazor start process. * In WebAssembly beforeStart receives the BlazorWebAssemblyStartOptions object and any publish extension as part of the method arguments. * In Server beforeStart receives the CircuitStartOptions object and can configure any necessary details. * In Desktop beforeStart does not receive any argument for the time being. * afterStarted receives the Blazor object as argument in all cases. * Callbacks in beforeStart and afterStarted are not invoked in any defined order and are invoked in parallel.
1 parent e1aeac8 commit 0ca2ed9

File tree

44 files changed

+450
-980
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+450
-980
lines changed

src/Components/Authorization/src/AuthorizeRouteView.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Diagnostics.CodeAnalysis;
45
using System.Threading.Tasks;
56
using Microsoft.AspNetCore.Authorization;
67
using Microsoft.AspNetCore.Components.Rendering;
@@ -95,6 +96,10 @@ private void RenderAuthorizeRouteViewCore(RenderTreeBuilder builder)
9596
builder.CloseComponent();
9697
}
9798

99+
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2111:RequiresUnreferencedCode",
100+
Justification = "OpenComponent already has the right set of attributes")]
101+
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2110:RequiresUnreferencedCode",
102+
Justification = "OpenComponent already has the right set of attributes")]
98103
private void RenderContentInDefaultLayout(RenderTreeBuilder builder, RenderFragment content)
99104
{
100105
builder.OpenComponent<LayoutView>(0);

src/Components/Server/src/Builder/ComponentEndpointConventionBuilder.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@ public sealed class ComponentEndpointConventionBuilder : IHubEndpointConventionB
1212
{
1313
private readonly IEndpointConventionBuilder _hubEndpoint;
1414
private readonly IEndpointConventionBuilder _disconnectEndpoint;
15+
private readonly IEndpointConventionBuilder _jsInitializersEndpoint;
1516

16-
internal ComponentEndpointConventionBuilder(IEndpointConventionBuilder hubEndpoint, IEndpointConventionBuilder disconnectEndpoint)
17+
internal ComponentEndpointConventionBuilder(IEndpointConventionBuilder hubEndpoint, IEndpointConventionBuilder disconnectEndpoint, IEndpointConventionBuilder jsInitializersEndpoint)
1718
{
1819
_hubEndpoint = hubEndpoint;
1920
_disconnectEndpoint = disconnectEndpoint;
21+
_jsInitializersEndpoint = jsInitializersEndpoint;
2022
}
2123

2224
/// <summary>
@@ -27,6 +29,7 @@ public void Add(Action<EndpointBuilder> convention)
2729
{
2830
_hubEndpoint.Add(convention);
2931
_disconnectEndpoint.Add(convention);
32+
_jsInitializersEndpoint.Add(convention);
3033
}
3134
}
3235
}

src/Components/Server/src/Builder/ComponentEndpointRouteBuilderExtensions.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@
33

44
using System;
55
using Microsoft.AspNetCore.Components.Server;
6+
using Microsoft.AspNetCore.Hosting;
67
using Microsoft.AspNetCore.Http.Connections;
78
using Microsoft.AspNetCore.Routing;
89
using Microsoft.AspNetCore.SignalR;
10+
using Microsoft.Extensions.DependencyInjection;
11+
using Microsoft.Extensions.Hosting;
912

1013
namespace Microsoft.AspNetCore.Builder
1114
{
@@ -110,7 +113,12 @@ public static ComponentEndpointConventionBuilder MapBlazorHub(
110113
endpoints.CreateApplicationBuilder().UseMiddleware<CircuitDisconnectMiddleware>().Build())
111114
.WithDisplayName("Blazor disconnect");
112115

113-
return new ComponentEndpointConventionBuilder(hubEndpoint, disconnectEndpoint);
116+
var jsInitializersEndpoint = endpoints.Map(
117+
(path.EndsWith('/') ? path : path + "/") + "initializers/",
118+
endpoints.CreateApplicationBuilder().UseMiddleware<CircuitJavaScriptInitializationMiddleware>().Build())
119+
.WithDisplayName("Blazor initializers");
120+
121+
return new ComponentEndpointConventionBuilder(hubEndpoint, disconnectEndpoint, jsInitializersEndpoint);
114122
}
115123
}
116124
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using Microsoft.AspNetCore.Components.Server;
5+
using Microsoft.AspNetCore.Http;
6+
using Microsoft.Extensions.Options;
7+
8+
namespace Microsoft.AspNetCore.Builder
9+
{
10+
internal class CircuitJavaScriptInitializationMiddleware
11+
{
12+
private readonly IList<string> _initializers;
13+
14+
// We don't need the request delegate for anything, however we need to inject it to satisfy the middleware
15+
// contract.
16+
public CircuitJavaScriptInitializationMiddleware(IOptions<CircuitOptions> options, RequestDelegate _)
17+
{
18+
_initializers = options.Value.JavaScriptInitializers;
19+
}
20+
21+
public async Task InvokeAsync(HttpContext context)
22+
{
23+
await context.Response.WriteAsJsonAsync(_initializers);
24+
}
25+
}
26+
}

src/Components/Server/src/CircuitOptions.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4-
using System;
5-
using Microsoft.AspNetCore.Components.Web;
4+
using Microsoft.Extensions.Hosting;
65

76
namespace Microsoft.AspNetCore.Components.Server
87
{
@@ -82,5 +81,7 @@ public sealed class CircuitOptions
8281
/// Gets options for root components within the circuit.
8382
/// </summary>
8483
public CircuitRootComponentOptions RootComponents { get; } = new CircuitRootComponentOptions();
84+
85+
internal IList<string> JavaScriptInitializers { get; } = new List<string>();
8586
}
8687
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Text.Json;
5+
using Microsoft.AspNetCore.Hosting;
6+
using Microsoft.Extensions.Options;
7+
8+
namespace Microsoft.AspNetCore.Components.Server.Circuits
9+
{
10+
internal class CircuitOptionsJavaScriptInitializersConfiguration : IConfigureOptions<CircuitOptions>
11+
{
12+
private readonly IWebHostEnvironment _environment;
13+
14+
public CircuitOptionsJavaScriptInitializersConfiguration(IWebHostEnvironment environment)
15+
{
16+
_environment = environment;
17+
}
18+
19+
public void Configure(CircuitOptions options)
20+
{
21+
var file = _environment.WebRootFileProvider.GetFileInfo($"{_environment.ApplicationName}.modules.json");
22+
if (file.Exists)
23+
{
24+
var initializers = JsonSerializer.Deserialize<string[]>(file.CreateReadStream());
25+
for (var i = 0; i < initializers.Length; i++)
26+
{
27+
var initializer = initializers[i];
28+
options.JavaScriptInitializers.Add(initializer);
29+
}
30+
}
31+
}
32+
}
33+
}

src/Components/Server/src/ComponentHub.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
using Microsoft.AspNetCore.Http;
1414
using Microsoft.AspNetCore.SignalR;
1515
using Microsoft.Extensions.Logging;
16+
using Microsoft.Extensions.Options;
1617

1718
namespace Microsoft.AspNetCore.Components.Server
1819
{

src/Components/Server/src/DependencyInjection/ComponentServiceCollectionExtensions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ public static IServerSideBlazorBuilder AddServerSideBlazor(this IServiceCollecti
8383
services.AddScoped<AuthenticationStateProvider, ServerAuthenticationStateProvider>();
8484

8585
services.TryAddEnumerable(ServiceDescriptor.Singleton<IConfigureOptions<CircuitOptions>, CircuitOptionsJSInteropDetailedErrorsConfiguration>());
86+
services.TryAddEnumerable(ServiceDescriptor.Singleton<IConfigureOptions<CircuitOptions>, CircuitOptionsJavaScriptInitializersConfiguration>());
8687

8788
if (configure != null)
8889
{

src/Components/Server/test/ComponentEndpointRouteBuilderExtensionsTest.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System.Diagnostics;
5-
using System.Threading.Tasks;
65
using Microsoft.AspNetCore.Builder;
6+
using Microsoft.AspNetCore.Hosting;
77
using Microsoft.Extensions.Configuration;
88
using Microsoft.Extensions.DependencyInjection;
9+
using Microsoft.Extensions.FileProviders;
910
using Microsoft.Extensions.Hosting;
1011
using Moq;
1112
using Xunit;
@@ -54,6 +55,9 @@ public void MapBlazorHub_MostGeneralOverload_MapsUnderlyingHub()
5455

5556
private IApplicationBuilder CreateAppBuilder()
5657
{
58+
var environment = new Mock<IWebHostEnvironment>();
59+
environment.SetupGet(e => e.ApplicationName).Returns("app");
60+
environment.SetupGet(e => e.WebRootFileProvider).Returns(new NullFileProvider());
5761
var services = new ServiceCollection();
5862
services.AddSingleton(Mock.Of<IHostApplicationLifetime>());
5963
services.AddLogging();
@@ -64,6 +68,7 @@ private IApplicationBuilder CreateAppBuilder()
6468
services.AddRouting();
6569
services.AddSignalR();
6670
services.AddServerSideBlazor();
71+
services.AddSingleton(environment.Object);
6772
services.AddSingleton<IConfiguration>(new ConfigurationBuilder().Build());
6873

6974
var serviceProvider = services.BuildServiceProvider();

src/Components/Web.JS/dist/Release/blazor.server.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.

0 commit comments

Comments
 (0)