Skip to content

Commit 6c02b7a

Browse files
fix: prerendering binary files (#13035) (#13039)
Co-authored-by: Tomer Aberbach <[email protected]>
1 parent 5811466 commit 6c02b7a

File tree

4 files changed

+40
-3
lines changed

4 files changed

+40
-3
lines changed

.changeset/thick-meals-shout.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@react-router/dev": patch
3+
---
4+
5+
Fix prerendering of binary files

contributors.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,7 @@
314314
- tobias-edwards
315315
- tom-sherman
316316
- tomasr8
317+
- TomerAberbach
317318
- tony-sn
318319
- TooTallNate
319320
- torztomasz

integration/vite-prerender-test.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,8 @@ test.describe("Prerendering", () => {
381381
});
382382

383383
test("Pre-renders resource routes with file extensions", async () => {
384+
const base64Png =
385+
"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";
384386
fixture = await createFixture({
385387
prerender: true,
386388
files: {
@@ -399,6 +401,18 @@ test.describe("Prerendering", () => {
399401
});
400402
}
401403
`,
404+
"app/routes/image[.png].tsx": js`
405+
export function loader() {
406+
return new Response(
407+
Buffer.from("${base64Png}", 'base64'),
408+
{
409+
headers: {
410+
'Content-Type': 'image/png',
411+
}
412+
},
413+
);
414+
}
415+
`,
402416
},
403417
});
404418
appFixture = await createAppFixture(fixture);
@@ -409,13 +423,25 @@ test.describe("Prerendering", () => {
409423
"about.data",
410424
"about/index.html",
411425
"favicon.ico",
426+
"image.png",
427+
"image.png.data",
412428
"index.html",
413429
"json.json",
414430
"json.json.data",
415431
"text.txt",
416432
"text.txt.data",
417433
]);
418434

435+
expect(
436+
await fs.promises.readFile(path.join(clientDir, "json.json"), "utf8")
437+
).toEqual('{"hello":"world"}');
438+
expect(
439+
await fs.promises.readFile(path.join(clientDir, "text.txt"), "utf8")
440+
).toEqual("Hello, world");
441+
expect(
442+
await fs.promises.readFile(path.join(clientDir, "image.png"), "base64")
443+
).toEqual(base64Png);
444+
419445
let res = await fixture.requestResource("/json.json");
420446
expect(await res.json()).toEqual({ hello: "world" });
421447

@@ -437,6 +463,11 @@ test.describe("Prerendering", () => {
437463
data: "Hello, world",
438464
},
439465
});
466+
467+
res = await fixture.requestResource("/image.png");
468+
expect(Buffer.from(await res.arrayBuffer()).toString("base64")).toBe(
469+
base64Png
470+
);
440471
});
441472

442473
test("Adds leading slashes if omitted in config", async () => {

packages/react-router-dev/vite/plugin.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2510,21 +2510,21 @@ async function prerenderResourceRoute(
25102510
.replace(/\/$/g, "");
25112511
let request = new Request(`http://localhost${normalizedPath}`, requestInit);
25122512
let response = await handler(request);
2513-
let text = await response.text();
2513+
let content = Buffer.from(await response.arrayBuffer());
25142514

25152515
if (response.status !== 200) {
25162516
throw new Error(
25172517
`Prerender (resource): Received a ${response.status} status code from ` +
25182518
`\`entry.server.tsx\` while prerendering the \`${normalizedPath}\` ` +
2519-
`path.\n${text}`
2519+
`path.\n${content.toString('utf8')}`
25202520
);
25212521
}
25222522

25232523
// Write out the resource route file
25242524
let outdir = path.relative(process.cwd(), clientBuildDirectory);
25252525
let outfile = path.join(outdir, ...normalizedPath.split("/"));
25262526
await fse.ensureDir(path.dirname(outfile));
2527-
await fse.outputFile(outfile, text);
2527+
await fse.outputFile(outfile, content);
25282528
viteConfig.logger.info(
25292529
`Prerender (resource): ${prerenderPath} -> ${colors.bold(outfile)}`
25302530
);

0 commit comments

Comments
 (0)