diff --git a/package-lock.json b/package-lock.json index 3dff9d248bee..5a95006858b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19332,7 +19332,7 @@ }, "src/JSInterop/Microsoft.JSInterop.JS/src": { "name": "@microsoft/dotnet-js-interop", - "version": "8.0.0-dev", + "version": "9.0.0-ci", "license": "MIT", "devDependencies": { "@typescript-eslint/eslint-plugin": "^6.15.0", @@ -19833,7 +19833,7 @@ }, "src/SignalR/clients/ts/signalr": { "name": "@microsoft/signalr", - "version": "5.0.0-dev", + "version": "9.0.0-ci", "license": "MIT", "dependencies": { "abort-controller": "^3.0.0", @@ -19845,7 +19845,7 @@ }, "src/SignalR/clients/ts/signalr-protocol-msgpack": { "name": "@microsoft/signalr-protocol-msgpack", - "version": "5.0.0-dev", + "version": "9.0.0-ci", "license": "MIT", "dependencies": { "@microsoft/signalr": "*", diff --git a/src/Components/Web.JS/src/Services/NavigationManager.ts b/src/Components/Web.JS/src/Services/NavigationManager.ts index 5fbb223f8653..47104cea3646 100644 --- a/src/Components/Web.JS/src/Services/NavigationManager.ts +++ b/src/Components/Web.JS/src/Services/NavigationManager.ts @@ -248,7 +248,9 @@ async function onBrowserInitiatedPopState(state: PopStateEvent) { await navigateHistoryWithoutPopStateCallback(delta); } - await notifyLocationChanged(false); + // We don't know if popstate was triggered for a navigation that can be handled by the client-side router, + // so we treat it as a intercepted link to be safe. + await notifyLocationChanged(/* interceptedLink */ true); } async function notifyLocationChanged(interceptedLink: boolean, internalDestinationHref?: string) { diff --git a/src/Components/test/E2ETest/Tests/GlobalInteractivityTest.cs b/src/Components/test/E2ETest/Tests/GlobalInteractivityTest.cs new file mode 100644 index 000000000000..edd2f0bc3656 --- /dev/null +++ b/src/Components/test/E2ETest/Tests/GlobalInteractivityTest.cs @@ -0,0 +1,28 @@ +using Components.TestServer.RazorComponents; +using Microsoft.AspNetCore.Components.E2ETest.Infrastructure; +using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures; +using Microsoft.AspNetCore.E2ETesting; +using OpenQA.Selenium; +using TestServer; +using Xunit.Abstractions; + +namespace Microsoft.AspNetCore.Components.E2ETests.Tests; + +public class GlobalInteractivityTest( + BrowserFixture browserFixture, + BasicTestAppServerSiteFixture> serverFixture, + ITestOutputHelper output) + : ServerTestBase>>(browserFixture, serverFixture, output) +{ + [Fact] + public void CanFindStaticallyRenderedPageAfterClickingBrowserBackButtonOnDynamicallyRenderedPage() + { + Navigate("/subdir/static"); + + Browser.Click(By.CssSelector("a[href=dynamic]")); + Browser.Navigate().Back(); + + var heading = Browser.Exists(By.TagName("h1")); + Browser.Equal("Statically Rendered", () => heading.Text); + } +} diff --git a/src/Components/test/testassets/Components.TestServer/Program.cs b/src/Components/test/testassets/Components.TestServer/Program.cs index 0c3367d21480..ca2d7b1aeb7f 100644 --- a/src/Components/test/testassets/Components.TestServer/Program.cs +++ b/src/Components/test/testassets/Components.TestServer/Program.cs @@ -34,7 +34,8 @@ public static async Task Main(string[] args) ["Blazor web with server-side blazor root component"] = (BuildWebHost>(CreateAdditionalArgs(args)), "/subdir"), ["Hosted client-side blazor"] = (BuildWebHost(CreateAdditionalArgs(args)), "/subdir"), ["Hot Reload"] = (BuildWebHost(CreateAdditionalArgs(args)), "/subdir"), - ["Dev server client-side blazor"] = CreateDevServerHost(CreateAdditionalArgs(args)) + ["Dev server client-side blazor"] = CreateDevServerHost(CreateAdditionalArgs(args)), + ["Global Interactivity"] = (BuildWebHost>(CreateAdditionalArgs(args)), "/subdir"), }; var mainHost = BuildWebHost(args); diff --git a/src/Components/test/testassets/Components.TestServer/RazorComponents/GlobalInteractivityApp.razor b/src/Components/test/testassets/Components.TestServer/RazorComponents/GlobalInteractivityApp.razor new file mode 100644 index 000000000000..0682bca04818 --- /dev/null +++ b/src/Components/test/testassets/Components.TestServer/RazorComponents/GlobalInteractivityApp.razor @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + +@code { + [CascadingParameter] + private HttpContext HttpContext { get; set; } = default!; + + // Statically render pages in the "/Account" subdirectory like we do in the Blazor Web template with Individaul auth. + private IComponentRenderMode? RenderModeForPage => HttpContext.Request.Path.StartsWithSegments("/static") + ? null + : RenderMode.InteractiveAuto; +} diff --git a/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/Static.razor b/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/Static.razor new file mode 100644 index 000000000000..dd3c7cc235a1 --- /dev/null +++ b/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/Static.razor @@ -0,0 +1,8 @@ +@page "/static" + +@* This should be statically rendered by GlobalInteractivityApp. *@ +

Statically Rendered

+ +
    +
  • Dynamic page
  • +
diff --git a/src/Components/test/testassets/Components.WasmMinimal/Pages/Dynamic.razor b/src/Components/test/testassets/Components.WasmMinimal/Pages/Dynamic.razor new file mode 100644 index 000000000000..8678edcb5b34 --- /dev/null +++ b/src/Components/test/testassets/Components.WasmMinimal/Pages/Dynamic.razor @@ -0,0 +1,13 @@ +@using Microsoft.AspNetCore.Components.Routing +@using Microsoft.AspNetCore.Components.Web + +@rendermode RenderMode.InteractiveWebAssembly + +@page "/dynamic" + +

Dynamically Rendered

+ +
    +
  • Static page
  • +
  • Another dynamic page
  • +
diff --git a/src/Components/test/testassets/Components.WasmMinimal/Routes.razor b/src/Components/test/testassets/Components.WasmMinimal/Routes.razor new file mode 100644 index 000000000000..ec39646aa5a5 --- /dev/null +++ b/src/Components/test/testassets/Components.WasmMinimal/Routes.razor @@ -0,0 +1,9 @@ +@using Microsoft.AspNetCore.Components.Routing + + + + + + + There's nothing here +