Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Blazor Web project interactive options improvements. Rename render modes. #50684

Merged
merged 23 commits into from
Sep 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
2ae708e
Add new template flag
SteveSandersonMS Sep 13, 2023
95872c1
Implement interactive-at-root for server only apps
SteveSandersonMS Sep 13, 2023
5ad6634
Fix h1 focus for empty apps
SteveSandersonMS Sep 13, 2023
538ca67
Make the new flag enabled only when an interactive mode is specified
SteveSandersonMS Sep 13, 2023
87f3653
Remove workaround for Counter on wasm now we have AddAdditionalAssemb…
SteveSandersonMS Sep 13, 2023
cb93014
Make Program.Main.cs consistent
SteveSandersonMS Sep 13, 2023
dccdcb9
Make root-level interactivity work for WebAssembly and Auto too
SteveSandersonMS Sep 13, 2023
de7331d
Fix some typos in template baselines
SteveSandersonMS Sep 13, 2023
20f0bd5
Add new template baselines
SteveSandersonMS Sep 13, 2023
b47ecb1
Switch from checkboxes to dropdowns
SteveSandersonMS Sep 14, 2023
f5512f4
Update templatestrings
SteveSandersonMS Sep 14, 2023
8fb3733
Test updates to match
SteveSandersonMS Sep 14, 2023
7a8ab5c
Rename the render modes
SteveSandersonMS Sep 14, 2023
58f26c2
Test fixes
SteveSandersonMS Sep 14, 2023
c1bb9e0
Rename other APIs by adding Interactive
SteveSandersonMS Sep 14, 2023
19f09f3
Project template updates after API renames
SteveSandersonMS Sep 14, 2023
91dd628
Fix typo
SteveSandersonMS Sep 14, 2023
a3c10f3
More test updates
SteveSandersonMS Sep 14, 2023
416db9c
Yet more renames
SteveSandersonMS Sep 14, 2023
8d6dcb3
Clarify meaning of Auto in VS
SteveSandersonMS Sep 14, 2023
fbd860f
Update templatestrings
SteveSandersonMS Sep 14, 2023
1b6149f
Rename --interactivity to --interactive
SteveSandersonMS Sep 14, 2023
66e26a8
Revert "Rename --interactivity to --interactive"
SteveSandersonMS Sep 15, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ internal class RazorComponentDataSourceOptions
.Create(
equals: (x, y) => (x,y) switch
{
(ServerRenderMode, ServerRenderMode) => true,
(WebAssemblyRenderMode, WebAssemblyRenderMode) => true,
(InteractiveServerRenderMode, InteractiveServerRenderMode) => true,
(InteractiveWebAssemblyRenderMode, InteractiveWebAssemblyRenderMode) => true,
_ => false,
},
getHashCode: obj => obj switch
{
ServerRenderMode => 1,
WebAssemblyRenderMode => 2,
InteractiveServerRenderMode => 1,
InteractiveWebAssemblyRenderMode => 2,
_ => throw new InvalidOperationException($"Unknown render mode: {obj}"),
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,8 @@ private void UpdateEndpoints()
if (!found)
{
throw new InvalidOperationException($"Unable to find a provider for the render mode: {renderMode.GetType().FullName}. This generally " +
"means that a call to 'AddWebAssemblyComponents' or 'AddServerComponents' is missing. " +
"For example, change builder.Services.AddRazorComponents() to builder.Services.AddRazorComponents().AddServerComponents().");
"means that a call to 'AddInteractiveWebAssemblyComponents' or 'AddInteractiveServerComponents' is missing. " +
"For example, change builder.Services.AddRazorComponents() to builder.Services.AddRazorComponents().AddInteractiveServerComponents().");
}
}

Expand Down
18 changes: 9 additions & 9 deletions src/Components/Endpoints/src/Discovery/ComponentInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,20 +51,20 @@ private string GetDebuggerDisplay()

private string GetRenderMode()
{
if (RenderMode is ServerRenderMode { Prerender: var server })
if (RenderMode is InteractiveServerRenderMode { Prerender: var server })
{
var size = (nameof(ServerRenderMode).Length - "RenderModeComparer".Length);
return $"RenderModeComparer = {nameof(ServerRenderMode)[0..size]}, Prerendered = {server}";
var size = (nameof(InteractiveServerRenderMode).Length - "RenderModeComparer".Length);
return $"RenderModeComparer = {nameof(InteractiveServerRenderMode)[0..size]}, Prerendered = {server}";
}
if (RenderMode is WebAssemblyRenderMode { Prerender: var wasm })
if (RenderMode is InteractiveWebAssemblyRenderMode { Prerender: var wasm })
{
var size = (nameof(WebAssemblyRenderMode).Length - "RenderModeComparer".Length);
return $"RenderModeComparer = {nameof(WebAssemblyRenderMode)[0..size]}, Prerendered = {wasm}";
var size = (nameof(InteractiveWebAssemblyRenderMode).Length - "RenderModeComparer".Length);
return $"RenderModeComparer = {nameof(InteractiveWebAssemblyRenderMode)[0..size]}, Prerendered = {wasm}";
}
if (RenderMode is AutoRenderMode { Prerender: var auto })
if (RenderMode is InteractiveAutoRenderMode { Prerender: var auto })
{
var size = (nameof(AutoRenderMode).Length - "RenderModeComparer".Length);
return $"RenderModeComparer = {nameof(AutoRenderMode)[0..size]}, Prerendered = {auto}";
var size = (nameof(InteractiveAutoRenderMode).Length - "RenderModeComparer".Length);
return $"RenderModeComparer = {nameof(InteractiveAutoRenderMode)[0..size]}, Prerendered = {auto}";
}

return "RenderModeComparer = Unknown, Prerendered = Unknown";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,15 @@ public ISet<IComponentRenderMode> GetDeclaredRenderModesByDiscoveredComponents()
var component = Components[i];
switch (component.RenderMode)
{
case ServerRenderMode:
set.Add(RenderMode.Server);
case InteractiveServerRenderMode:
set.Add(RenderMode.InteractiveServer);
break;
case WebAssemblyRenderMode:
set.Add(RenderMode.WebAssembly);
case InteractiveWebAssemblyRenderMode:
set.Add(RenderMode.InteractiveWebAssembly);
break;
case AutoRenderMode:
set.Add(RenderMode.Server);
set.Add(RenderMode.WebAssembly);
case InteractiveAutoRenderMode:
set.Add(RenderMode.InteractiveServer);
set.Add(RenderMode.InteractiveWebAssembly);
break;
default:
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ internal static void UpdateSaveStateRenderMode(HttpContext httpContext, ICompone
{
var currentInvocation = mode switch
{
ServerRenderMode => InvokedRenderModes.Mode.Server,
WebAssemblyRenderMode => InvokedRenderModes.Mode.WebAssembly,
AutoRenderMode => throw new NotImplementedException("TODO: To be able to support AutoRenderMode, we have to serialize persisted state in both WebAssembly and Server formats, or unify the two formats."),
InteractiveServerRenderMode => InvokedRenderModes.Mode.Server,
InteractiveWebAssemblyRenderMode => InvokedRenderModes.Mode.WebAssembly,
InteractiveAutoRenderMode => throw new NotImplementedException("TODO: To be able to support InteractiveAutoRenderMode, we have to serialize persisted state in both WebAssembly and Server formats, or unify the two formats."),
_ => throw new ArgumentException(Resources.FormatUnsupportedRenderMode(mode), nameof(mode)),
};

Expand All @@ -88,9 +88,9 @@ internal static void UpdateSaveStateRenderMode(HttpContext httpContext, ICompone

private static bool ModeEnablesPrerendering(IComponentRenderMode? mode) => mode switch
{
ServerRenderMode { Prerender: true } => true,
WebAssemblyRenderMode { Prerender: true } => true,
AutoRenderMode { Prerender: true } => true,
InteractiveServerRenderMode { Prerender: true } => true,
InteractiveWebAssemblyRenderMode { Prerender: true } => true,
InteractiveAutoRenderMode { Prerender: true } => true,
_ => false
};

Expand Down
24 changes: 12 additions & 12 deletions src/Components/Endpoints/src/Rendering/SSRRenderModeBoundary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ public SSRRenderModeBoundary(
_renderMode = renderMode;
_prerender = renderMode switch
{
ServerRenderMode mode => mode.Prerender,
WebAssemblyRenderMode mode => mode.Prerender,
AutoRenderMode mode => mode.Prerender,
InteractiveServerRenderMode mode => mode.Prerender,
InteractiveWebAssemblyRenderMode mode => mode.Prerender,
InteractiveAutoRenderMode mode => mode.Prerender,
_ => throw new ArgumentException($"Server-side rendering does not support the render mode '{renderMode}'.", nameof(renderMode))
};
}
Expand All @@ -65,14 +65,14 @@ private static void AssertRenderModeIsConfigured(HttpContext httpContext, Type c
var configuredModes = configuredRenderModesMetadata.ConfiguredRenderModes;

// We have to allow for specified rendermodes being subclases of the known types
if (renderMode is ServerRenderMode || renderMode is AutoRenderMode)
if (renderMode is InteractiveServerRenderMode || renderMode is InteractiveAutoRenderMode)
{
AssertRenderModeIsConfigured<ServerRenderMode>(componentType, renderMode, configuredModes, "AddServerRenderMode");
AssertRenderModeIsConfigured<InteractiveServerRenderMode>(componentType, renderMode, configuredModes, "AddInteractiveServerRenderMode");
}

if (renderMode is WebAssemblyRenderMode || renderMode is AutoRenderMode)
if (renderMode is InteractiveWebAssemblyRenderMode || renderMode is InteractiveAutoRenderMode)
{
AssertRenderModeIsConfigured<WebAssemblyRenderMode>(componentType, renderMode, configuredModes, "AddWebAssemblyRenderMode");
AssertRenderModeIsConfigured<InteractiveWebAssemblyRenderMode>(componentType, renderMode, configuredModes, "AddInteractiveWebAssemblyRenderMode");
}
}

Expand Down Expand Up @@ -165,13 +165,13 @@ public ComponentMarker ToMarker(HttpContext httpContext, int sequence, object? k

var marker = _renderMode switch
{
ServerRenderMode server => ComponentMarker.Create(ComponentMarker.ServerMarkerType, server.Prerender, _markerKey),
WebAssemblyRenderMode webAssembly => ComponentMarker.Create(ComponentMarker.WebAssemblyMarkerType, webAssembly.Prerender, _markerKey),
AutoRenderMode auto => ComponentMarker.Create(ComponentMarker.AutoMarkerType, auto.Prerender, _markerKey),
InteractiveServerRenderMode server => ComponentMarker.Create(ComponentMarker.ServerMarkerType, server.Prerender, _markerKey),
InteractiveWebAssemblyRenderMode webAssembly => ComponentMarker.Create(ComponentMarker.WebAssemblyMarkerType, webAssembly.Prerender, _markerKey),
InteractiveAutoRenderMode auto => ComponentMarker.Create(ComponentMarker.AutoMarkerType, auto.Prerender, _markerKey),
_ => throw new UnreachableException($"Unknown render mode {_renderMode.GetType().FullName}"),
};

if (_renderMode is ServerRenderMode or AutoRenderMode)
if (_renderMode is InteractiveServerRenderMode or InteractiveAutoRenderMode)
{
// Lazy because we don't actually want to require a whole chain of services including Data Protection
// to be required unless you actually use Server render mode.
Expand All @@ -181,7 +181,7 @@ public ComponentMarker ToMarker(HttpContext httpContext, int sequence, object? k
serverComponentSerializer.SerializeInvocation(ref marker, invocationId, _componentType, parameters);
}

if (_renderMode is WebAssemblyRenderMode or AutoRenderMode)
if (_renderMode is InteractiveWebAssemblyRenderMode or InteractiveAutoRenderMode)
{
WebAssemblyComponentSerializer.SerializeInvocation(ref marker, _componentType, parameters);
}
Expand Down
32 changes: 16 additions & 16 deletions src/Components/Endpoints/test/EndpointHtmlRendererTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public async Task CanRender_ParameterlessComponent_ClientMode()
var writer = new StringWriter();

// Act
var result = await renderer.PrerenderComponentAsync(httpContext, typeof(SimpleComponent), new WebAssemblyRenderMode(prerender: false), ParameterView.Empty);
var result = await renderer.PrerenderComponentAsync(httpContext, typeof(SimpleComponent), new InteractiveWebAssemblyRenderMode(prerender: false), ParameterView.Empty);
await renderer.Dispatcher.InvokeAsync(() => result.WriteTo(writer, HtmlEncoder.Default));
var content = writer.ToString();
var match = Regex.Match(content, ComponentPattern);
Expand All @@ -76,7 +76,7 @@ public async Task CanPrerender_ParameterlessComponent_ClientMode()
var writer = new StringWriter();

// Act
var result = await renderer.PrerenderComponentAsync(httpContext, typeof(SimpleComponent), RenderMode.WebAssembly, ParameterView.Empty);
var result = await renderer.PrerenderComponentAsync(httpContext, typeof(SimpleComponent), RenderMode.InteractiveWebAssembly, ParameterView.Empty);
await renderer.Dispatcher.InvokeAsync(() => result.WriteTo(writer, HtmlEncoder.Default));
var content = writer.ToString();
var match = Regex.Match(content, PrerenderedComponentPattern, RegexOptions.Multiline);
Expand Down Expand Up @@ -115,7 +115,7 @@ public async Task CanRender_ComponentWithParameters_ClientMode()

// Act
var result = await renderer.PrerenderComponentAsync(httpContext, typeof(GreetingComponent),
new WebAssemblyRenderMode(prerender: false),
new InteractiveWebAssemblyRenderMode(prerender: false),
ParameterView.FromDictionary(new Dictionary<string, object>
{
{ "Name", "Daniel" }
Expand Down Expand Up @@ -152,7 +152,7 @@ public async Task CanRender_ComponentWithNullParameters_ClientMode()

// Act
var result = await renderer.PrerenderComponentAsync(httpContext, typeof(GreetingComponent),
new WebAssemblyRenderMode(prerender: false),
new InteractiveWebAssemblyRenderMode(prerender: false),
ParameterView.FromDictionary(new Dictionary<string, object>
{
{ "Name", null }
Expand Down Expand Up @@ -187,7 +187,7 @@ public async Task CanPrerender_ComponentWithParameters_ClientMode()

// Act
var result = await renderer.PrerenderComponentAsync(httpContext, typeof(GreetingComponent),
RenderMode.WebAssembly,
RenderMode.InteractiveWebAssembly,
ParameterView.FromDictionary(new Dictionary<string, object>
{
{ "Name", "Daniel" }
Expand Down Expand Up @@ -236,7 +236,7 @@ public async Task CanPrerender_ComponentWithNullParameters_ClientMode()

// Act
var result = await renderer.PrerenderComponentAsync(httpContext, typeof(GreetingComponent),
RenderMode.WebAssembly,
RenderMode.InteractiveWebAssembly,
ParameterView.FromDictionary(new Dictionary<string, object>
{
{ "Name", null }
Expand Down Expand Up @@ -300,7 +300,7 @@ public async Task CanRender_ParameterlessComponent_ServerMode()
.ToTimeLimitedDataProtector();

// Act
var result = await renderer.PrerenderComponentAsync(httpContext, typeof(SimpleComponent), new ServerRenderMode(false), ParameterView.Empty);
var result = await renderer.PrerenderComponentAsync(httpContext, typeof(SimpleComponent), new InteractiveServerRenderMode(false), ParameterView.Empty);
var content = await renderer.Dispatcher.InvokeAsync(() => HtmlContentToString(result));
var match = Regex.Match(content, ComponentPattern);

Expand Down Expand Up @@ -332,7 +332,7 @@ public async Task CanPrerender_ParameterlessComponent_ServerMode()
.ToTimeLimitedDataProtector();

// Act
var result = await renderer.PrerenderComponentAsync(httpContext, typeof(SimpleComponent), RenderMode.Server, ParameterView.Empty);
var result = await renderer.PrerenderComponentAsync(httpContext, typeof(SimpleComponent), RenderMode.InteractiveServer, ParameterView.Empty);
var content = await renderer.Dispatcher.InvokeAsync(() => HtmlContentToString(result));
var match = Regex.Match(content, PrerenderedComponentPattern, RegexOptions.Multiline);

Expand Down Expand Up @@ -376,8 +376,8 @@ public async Task Prerender_ServerAndClientComponentUpdatesInvokedPrerenderModes

// Act
var parameters = ParameterView.FromDictionary(new Dictionary<string, object> { { "Name", "SomeName" } });
var server = await renderer.PrerenderComponentAsync(httpContext, typeof(GreetingComponent), RenderMode.Server, parameters);
var client = await renderer.PrerenderComponentAsync(httpContext, typeof(GreetingComponent), RenderMode.WebAssembly, parameters);
var server = await renderer.PrerenderComponentAsync(httpContext, typeof(GreetingComponent), RenderMode.InteractiveServer, parameters);
var client = await renderer.PrerenderComponentAsync(httpContext, typeof(GreetingComponent), RenderMode.InteractiveWebAssembly, parameters);

// Assert
var (_, mode) = Assert.Single(httpContext.Items, (kvp) => kvp.Value is InvokedRenderModes);
Expand All @@ -393,11 +393,11 @@ public async Task CanRenderMultipleServerComponents()
.ToTimeLimitedDataProtector();

// Act
var firstResult = await renderer.PrerenderComponentAsync(httpContext, typeof(SimpleComponent), new ServerRenderMode(true), ParameterView.Empty);
var firstResult = await renderer.PrerenderComponentAsync(httpContext, typeof(SimpleComponent), new InteractiveServerRenderMode(true), ParameterView.Empty);
var firstComponent = await renderer.Dispatcher.InvokeAsync(() => HtmlContentToString(firstResult));
var firstMatch = Regex.Match(firstComponent, PrerenderedComponentPattern, RegexOptions.Multiline);

var secondResult = await renderer.PrerenderComponentAsync(httpContext, typeof(SimpleComponent), new ServerRenderMode(false), ParameterView.Empty);
var secondResult = await renderer.PrerenderComponentAsync(httpContext, typeof(SimpleComponent), new InteractiveServerRenderMode(false), ParameterView.Empty);
var secondComponent = await renderer.Dispatcher.InvokeAsync(() => HtmlContentToString(secondResult));
var secondMatch = Regex.Match(secondComponent, ComponentPattern);

Expand Down Expand Up @@ -451,7 +451,7 @@ public async Task CanRender_ComponentWithParameters_ServerMode()

// Act
var parameters = ParameterView.FromDictionary(new Dictionary<string, object> { { "Name", "SomeName" } });
var result = await renderer.PrerenderComponentAsync(httpContext, typeof(GreetingComponent), new ServerRenderMode(false), parameters);
var result = await renderer.PrerenderComponentAsync(httpContext, typeof(GreetingComponent), new InteractiveServerRenderMode(false), parameters);
var content = await renderer.Dispatcher.InvokeAsync(() => HtmlContentToString(result));
var match = Regex.Match(content, ComponentPattern);

Expand Down Expand Up @@ -490,7 +490,7 @@ public async Task CanRender_ComponentWithNullParameters_ServerMode()

// Act
var parameters = ParameterView.FromDictionary(new Dictionary<string, object> { { "Name", null } });
var result = await renderer.PrerenderComponentAsync(httpContext, typeof(GreetingComponent), new ServerRenderMode(false), parameters);
var result = await renderer.PrerenderComponentAsync(httpContext, typeof(GreetingComponent), new InteractiveServerRenderMode(false), parameters);
var content = await renderer.Dispatcher.InvokeAsync(() => HtmlContentToString(result));
var match = Regex.Match(content, ComponentPattern);

Expand Down Expand Up @@ -529,7 +529,7 @@ public async Task CanPrerender_ComponentWithParameters_ServerPrerenderedMode()

// Act
var parameters = ParameterView.FromDictionary(new Dictionary<string, object> { { "Name", "SomeName" } });
var result = await renderer.PrerenderComponentAsync(httpContext, typeof(GreetingComponent), RenderMode.Server, parameters);
var result = await renderer.PrerenderComponentAsync(httpContext, typeof(GreetingComponent), RenderMode.InteractiveServer, parameters);
var content = await renderer.Dispatcher.InvokeAsync(() => HtmlContentToString(result));
var match = Regex.Match(content, PrerenderedComponentPattern, RegexOptions.Multiline);

Expand Down Expand Up @@ -580,7 +580,7 @@ public async Task CanPrerender_ComponentWithNullParameters_ServerPrerenderedMode

// Act
var parameters = ParameterView.FromDictionary(new Dictionary<string, object> { { "Name", null } });
var result = await renderer.PrerenderComponentAsync(httpContext, typeof(GreetingComponent), RenderMode.Server, parameters);
var result = await renderer.PrerenderComponentAsync(httpContext, typeof(GreetingComponent), RenderMode.InteractiveServer, parameters);
var content = await renderer.Dispatcher.InvokeAsync(() => HtmlContentToString(result));
var match = Regex.Match(content, PrerenderedComponentPattern, RegexOptions.Multiline);

Expand Down
4 changes: 2 additions & 2 deletions src/Components/Endpoints/test/HotReloadServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -187,15 +187,15 @@ private static RazorComponentEndpointDataSource<TComponent> CreateDataSource<TCo
}
else
{
result.Options.ConfiguredRenderModes.Add(new ServerRenderMode());
result.Options.ConfiguredRenderModes.Add(new InteractiveServerRenderMode());
}

return result;
}

private class StaticComponent : ComponentBase { }

[RenderModeServer]
[RenderModeInteractiveServer]
private class ServerComponent : ComponentBase { }

private class MockEndpointProvider : RenderModeEndpointProvider
Expand Down
Loading
Loading