Skip to content

Pre-rendered resource routes saved to disk incorrectly #12844

@mattrothenberg

Description

@mattrothenberg

I'm using React Router as a...

library

Reproduction

  • Create a resource route that returns a PNG response
export async function loader() {
  const image = await someFunctionThatCreatesAnImage();

  return new Response(image, {
    status: 200,
    headers: {
      "Content-Type": "image/png",
    },
  });
}
  • See that the route works fine when the app is running
  • Pre-render that route
  • Observe that the PNG file saved on disk is corrupt/broken

System Info

System:
    OS: macOS 14.6.1
    CPU: (12) arm64 Apple M2 Max
    Memory: 24.34 GB / 64.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Yarn: 1.22.19 - ~/.asdf/shims/yarn
    npm: 10.8.2 - ~/Library/Application Support/Herd/config/nvm/versions/node/v20.18.1/bin/npm
    bun: 1.1.33 - ~/.bun/bin/bun
  Browsers:
    Brave Browser: 129.1.70.119
    Chrome: 131.0.6778.265
    Safari: 17.6
  npmPackages:
    @react-router/dev: ^7.1.3 => 7.1.1 
    @react-router/node: ^7.1.3 => 7.1.1 
    @react-router/serve: ^7.1.3 => 7.1.1 
    react-router: ^7.1.3 => 7.1.1 
    vite: ^5.4.7 => 5.4.11

Used Package Manager

npm

Expected Behavior

The file saved to disk should be a valid PNG file.

Actual Behavior

The file saved to disk is a textual representation of a PNG, because of this code (I believe):

let text = await response.text();
validatePrerenderedResponse(response, text, "Prerender", normalizedPath);
// Write out the resource route file
let outdir = path.relative(process.cwd(), clientBuildDirectory);
let outfile = path.join(outdir, ...normalizedPath.split("/"));
await fse.ensureDir(path.dirname(outfile));
await fse.outputFile(outfile, text);

Using response.text() won't work for resource routes that return non-text responses.

There might be a legitimate reason why .text() is used here, but I was curious if it would be a better heuristic to use the content type of the returned response to determine what kind of method to use. Something along these lines.

Image

I hope this is helpful!

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions