Skip to content

Commit 12eaf56

Browse files
authored
(#65) Fix CORS on navigation
1 parent 5fc82a9 commit 12eaf56

File tree

7 files changed

+77
-18
lines changed

7 files changed

+77
-18
lines changed

bifrost/renderer/bifrost/onAfterRenderClient.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ import { PageContextClient } from "vike/types";
22
import "../../lib/type";
33
import { Turbolinks } from "../../lib/turbolinks";
44

5-
export default async function bifrostOnAfterRenderClient(
5+
export default function bifrostOnAfterRenderClient(
66
pageContext: PageContextClient
77
) {
88
if (!pageContext.isHydration && !pageContext.errorWhileRendering) {
9-
await Turbolinks._vikeAfterRender(pageContext._turbolinksVisit, false);
9+
Turbolinks._vikeAfterRender(pageContext._turbolinksVisit, false);
1010
}
1111
}

bifrost/renderer/wrapped/onBeforeRender.client.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,15 @@ export default async function wrappedOnBeforeRender(
5151
*/
5252
const resp = await fetch(pageContext.urlParsed.href, {
5353
headers: { ...pageContext.config.proxyHeaders, accept: "text/html" },
54-
});
54+
}).catch(() => {});
55+
56+
if (!resp) {
57+
// hard reload. can happen on cors errors when redirected to external page
58+
window.location.href = pageContext.urlParsed.href;
59+
// stop vike rendering to let navigation happen
60+
await new Promise(() => {});
61+
return;
62+
}
5563

5664
if (resp.redirected) {
5765
const parsedUrl = new URL(resp.url);

tests/alb/index.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ const BIFROST_PATHS = [
2121
"/redirect-page",
2222
"/auto-navigate",
2323
"/proxy-to",
24+
"/cors-test",
2425
"/",
2526
];
2627

tests/e2e/specs/e2e.spec.ts

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,30 @@ test.describe("redirects", () => {
436436
await customProxy.goBack();
437437
});
438438

439+
test("on client navigation, redirect to external url", async ({ page }) => {
440+
const externalUrl = "http://localhost:5555/cors-test";
441+
ensureAllNetworkSucceeds(page);
442+
const customProxy = new CustomProxyPage(page, {
443+
title: "first page",
444+
links: [
445+
{
446+
redirectTo: {
447+
url: externalUrl,
448+
title: "external",
449+
},
450+
},
451+
],
452+
});
453+
await customProxy.goto();
454+
await customProxy.clickLink("external", {
455+
browserReload: true,
456+
waitFor: 0,
457+
});
458+
459+
// back button works as expected
460+
await customProxy.goBack();
461+
});
462+
439463
test("sets cookies along the way", async ({ page, context, baseURL }) => {
440464
ensureAllNetworkSucceeds(page);
441465
const customProxy = new CustomProxyPage(page, {
@@ -1042,12 +1066,15 @@ test.describe("back button restoration", () => {
10421066
await customProxy.goto();
10431067
const edit = page.getByRole("link").first();
10441068

1045-
await page.evaluate((rRoot: any) => {
1046-
rRoot.appendChild(document.createTextNode("edit1"));
1047-
document.addEventListener("turbolinks:before-cache", () => {
1048-
rRoot.appendChild(document.createTextNode("edit2"));
1049-
});
1050-
}, await edit.elementHandle());
1069+
await page.evaluate(
1070+
(rRoot: any) => {
1071+
rRoot.appendChild(document.createTextNode("edit1"));
1072+
document.addEventListener("turbolinks:before-cache", () => {
1073+
rRoot.appendChild(document.createTextNode("edit2"));
1074+
});
1075+
},
1076+
await edit.elementHandle()
1077+
);
10511078
await expect(edit).toContainText("edit1");
10521079
await expect(edit).not.toContainText("edit2");
10531080

@@ -1065,12 +1092,15 @@ test.describe("back button restoration", () => {
10651092
await page.goto("./vite-page");
10661093
await waitForTurbolinksInit(page);
10671094
const edit = page.getByRole("link").first();
1068-
await page.evaluate((rRoot: any) => {
1069-
rRoot.appendChild(document.createTextNode("edit1"));
1070-
document.addEventListener("turbolinks:before-cache", () => {
1071-
rRoot.appendChild(document.createTextNode("edit2"));
1072-
});
1073-
}, await edit.elementHandle());
1095+
await page.evaluate(
1096+
(rRoot: any) => {
1097+
rRoot.appendChild(document.createTextNode("edit1"));
1098+
document.addEventListener("turbolinks:before-cache", () => {
1099+
rRoot.appendChild(document.createTextNode("edit2"));
1100+
});
1101+
},
1102+
await edit.elementHandle()
1103+
);
10741104

10751105
await expect(edit).toContainText("edit1");
10761106
await expect(edit).not.toContainText("edit2");

tests/fake-backend/index.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,12 @@ app.get(["/custom", "/custom-:id"], async (req, res) => {
2727
}
2828
if ("redirectTo" in data) {
2929
res.status(302);
30-
res.setHeader("location", `${publicUrl}${toPath(data.redirectTo)}`);
30+
31+
res.setHeader(
32+
"location",
33+
("url" in data.redirectTo && data.redirectTo.url) ||
34+
`${publicUrl}${toPath(data.redirectTo)}`
35+
);
3136
if (data.cookies) {
3237
for (const [key, val] of Object.entries(data.cookies)) {
3338
res.setHeader("set-cookie", key + "=" + val);
@@ -80,7 +85,10 @@ app.get("/script-wrapped", async (req, res) => {
8085
res.setHeader("X-REACT-LAYOUT", "no_layout");
8186
}
8287
res.setHeader("Content-Type", "text/html");
83-
res.status(200).type("text/html").send("<script>console.log('script-only')</script>");
88+
res
89+
.status(200)
90+
.type("text/html")
91+
.send("<script>console.log('script-only')</script>");
8492
});
8593

8694
app.get("/json-wrapped", async (req, res) => {

tests/fake-backend/page-builder.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ type LinkOptions = {
55
};
66
export type PageDataOk = {
77
endpoint?: string;
8+
url?: string;
89
title: string;
910
bodyAttrs?: string;
1011
layout?: string;
@@ -29,7 +30,7 @@ export function toPath(data: PageData) {
2930
}
3031
return (
3132
`/${"endpoint" in data ? data!.endpoint : "custom"}?page=` +
32-
encodeURI(JSON.stringify(data))
33+
encodeURIComponent(JSON.stringify(data))
3334
);
3435
}
3536
export enum Turbolinks {

tests/vite/server/index.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,17 @@ async function startServer() {
5555
);
5656
});
5757

58+
app.get("/cors-test", async (req, res) => {
59+
res.header("Access-Control-Allow-Origin", "http://localhost:5555");
60+
res.header("Access-Control-Allow-Credentials", "true");
61+
res
62+
.status(200)
63+
.type("text/html")
64+
.send(
65+
"<html><head><title>external</title></head><body>CORS test page from Vite server</body></html>"
66+
);
67+
});
68+
5869
app.register(viteProxyPlugin, {
5970
upstream: UPSTREAM,
6071
host: HOST,

0 commit comments

Comments
 (0)