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

Fix quirks mode warning for SPA template #8495

Merged
merged 8 commits into from
Jan 16, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
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
5 changes: 5 additions & 0 deletions .changeset/wild-timers-impress.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@remix-run/dev": patch
---

Fix quirks mode warning for SPA template and default server entry
brophdawg11 marked this conversation as resolved.
Show resolved Hide resolved
1 change: 1 addition & 0 deletions contributors.yml
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,7 @@
- morinokami
- mrkhosravian
- mrkstwrt
- mrm007
- mskoroglu
- msutkowski
- mtt87
Expand Down
20 changes: 14 additions & 6 deletions integration/helpers/create-fixture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export interface FixtureInit {
config?: Partial<AppConfig>;
useRemixServe?: boolean;
compiler?: "remix" | "vite";
spaMode?: boolean;
}

export type Fixture = Awaited<ReturnType<typeof createFixture>>;
Expand Down Expand Up @@ -59,19 +60,26 @@ export async function createFixture(init: FixtureInit, mode?: ServerMode) {
);
};

let isSpaMode =
compiler === "vite" &&
fse.existsSync(path.join(projectDir, "build/client/index.html"));
let isSpaMode = compiler === "vite" && init.spaMode;

if (isSpaMode) {
let requestDocument = () => {
let html = fse.readFileSync(
path.join(projectDir, "build/client/index.html")
);
return new Response(html, {
headers: {
"Content-Type": "text/html",
},
});
};

return {
projectDir,
build: null,
isSpaMode,
compiler,
requestDocument: () => {
throw new Error("Cannot requestDocument in SPA Mode tests");
},
requestDocument,
requestData: () => {
throw new Error("Cannot requestData in SPA Mode tests");
},
Expand Down
87 changes: 87 additions & 0 deletions integration/spa-mode-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ test.describe("SPA Mode", () => {
test.beforeAll(async () => {
fixture = await createFixture({
compiler: "vite",
spaMode: true,
files: {
"vite.config.ts": js`
import { defineConfig } from "vite";
Expand Down Expand Up @@ -455,5 +456,91 @@ test.describe("SPA Mode", () => {
'Error: You cannot call serverAction() in SPA Mode (routeId: "routes/error")'
);
});

test("prepends DOCTYPE to <html> documents if not present", async () => {
let fixture = await createFixture({
compiler: "vite",
spaMode: true,
files: {
"vite.config.ts": js`
import { defineConfig } from "vite";
import { unstable_vitePlugin as remix } from "@remix-run/dev";

export default defineConfig({
plugins: [remix({ unstable_ssr: false })],
});
`,
"app/root.tsx": js`
import { Outlet, Scripts } from "@remix-run/react";

export default function Root() {
return (
<html lang="en">
<head></head>
<body>
<h1 data-root>Root</h1>
<Scripts />
</body>
</html>
);
}

export function HydrateFallback() {
return (
<html lang="en">
<head></head>
<body>
<h1 data-loading>Loading SPA...</h1>
<Scripts />
</body>
</html>
);
}
`,
},
});
let res = await fixture.requestDocument("/");
expect(await res.text()).toMatch(/^<!DOCTYPE html>\n<html lang="en">/);
});

test("does not prepend DOCTYPE if user is not hydrating the document", async () => {
let fixture = await createFixture({
compiler: "vite",
spaMode: true,
files: {
"vite.config.ts": js`
import { defineConfig } from "vite";
import { unstable_vitePlugin as remix } from "@remix-run/dev";

export default defineConfig({
plugins: [remix({ unstable_ssr: false })],
});
`,
"app/root.tsx": js`
import { Outlet, Scripts } from "@remix-run/react";

export default function Root() {
return (
<div>
<h1 data-root>Root</h1>
<Scripts />
</div>
);
}

export function HydrateFallback() {
return (
<div>
<h1>Loading SPA...</h1>
<Scripts />
</div>
);
}
`,
},
});
let res = await fixture.requestDocument("/");
expect(await res.text()).not.toMatch(/<!DOCTYPE html>/);
});
});
});
5 changes: 4 additions & 1 deletion packages/remix-dev/config/defaults/entry.server.spa.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { AppLoadContext, EntryContext } from "@remix-run/node";
import type { EntryContext } from "@remix-run/node";
import { RemixServer } from "@remix-run/react";
import * as React from "react";
import { renderToString } from "react-dom/server";
Expand All @@ -12,6 +12,9 @@ export default function handleRequest(
let html = renderToString(
<RemixServer context={remixContext} url={request.url} />
);
if (html.startsWith("<html")) {
html = "<!DOCTYPE html>\n" + html;
}
return new Response(html, {
headers: { "Content-Type": "text/html" },
status: responseStatusCode,
Expand Down
5 changes: 4 additions & 1 deletion templates/spa/app/entry.server.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@ export default function handleRequest(
responseHeaders: Headers,
remixContext: EntryContext
) {
const html = renderToString(
let html = renderToString(
<RemixServer context={remixContext} url={request.url} />
);
if (html.startsWith("<html")) {
html = "<!DOCTYPE html>\n" + html;
}
return new Response(html, {
headers: { "Content-Type": "text/html" },
status: responseStatusCode,
Expand Down
Loading