vitejs / vite

Next generation frontend tooling. It's fast!
http://vite.dev
MIT License
68.09k stars 6.13k forks source link

ssrLoadModule html-escapes single quote to ' #15662

Open mkilpatrick opened 9 months ago

mkilpatrick commented 9 months ago

Describe the bug

When calling ssrLoadModule the resulting HTML, when passed to ReactDOMServer.renderToString, results in ' (single quote) being html-escaped to '. It results in the error:

Warning: Prop style did not match. Server: "" Client: "background-image:url('/src/assets/images/tacos-1.avif')"

Actual code

<div style={{ backgroundImage: `url('${tacosUrl}')` }}>

Server-rendered HTML

<div style="background-image:url(&#x27;/src/assets/images/tacos-1.avif&#x27;)">

Reproduction

N/A

Steps to reproduce

No response

System Info

System:
    OS: macOS 12.6
    CPU: (10) arm64 Apple M1 Max
    Memory: 954.27 MB / 64.00 GB
    Shell: 5.2.26 - /usr/local/bin/bash
  Binaries:
    Node: 18.18.2 - ~/.nvm/versions/node/v18.18.2/bin/node
    Yarn: 1.22.19 - /opt/homebrew/bin/yarn
    npm: 9.4.1 - /opt/homebrew/bin/npm
    pnpm: 8.8.0 - /opt/homebrew/bin/pnpm
  Browsers:
    Chrome: 120.0.6099.234
    Safari: 16.4.1
  npmPackages:
    @vitejs/plugin-react: ^4.2.1 => 4.2.1 
    vite: ^5.0.11 => 5.0.11

Used Package Manager

npm

Logs

No response

Validations

hi-ogawa commented 9 months ago

Hey, could this be actually the legitimate html escape done by renderToString? I cannot say for sure since there isn't a reproduction, but my quick repro (without Vite) shows something like following, so your issue might not be related to Vite? Please let me know if I mis-understood your issue and I would appreciate if you can provide a reproduction to help investigation further.

https://stackblitz.com/edit/github-nr2ezh?file=repro.js

/*
node ./repro.js
{
  result: '<div style="background-image:url(&#x27;/anything&#x27;)"></div>'
}
*/

async function main() {
  const React = await import('react');
  const ReactDOMServer = await import('react-dom/server');

  const el = React.createElement('div', {
    style: { backgroundImage: `url('/anything')` },
  });
  const result = ReactDOMServer.renderToString(el);
  console.log({ result });
}

main();

Btw, there is react ssr template here https://github.com/bluwy/create-vite-extra/tree/master/template-ssr-react-ts so it might help when you want to investigate issues based on bare bone setup without frameworks.

github-actions[bot] commented 9 months ago

Hello @mkilpatrick. Please provide a minimal reproduction using a GitHub repository or StackBlitz. Issues marked with need reproduction will be closed if they have no activity within 3 days.

mkilpatrick commented 9 months ago

It happens when calling transformIndexHtml on html where the app-html has already been replaced. The result is a little different from my original issue description. You can see that the server html is missing the background-image property completely. Diff here.

https://stackblitz.com/edit/github-cf1cao?file=server.js

hi-ogawa commented 9 months ago

Thanks for clarifying the issue with reproduction. According to https://github.com/vitejs/vite/pull/15345#issuecomment-1855550194, currently it's not intended to apply transformIndexHtml after the whole server render. It seems some different issue can manifest depending on configuration https://github.com/vitejs/vite/issues/15214.

For now, I added "pending triage" label back since this specific style url issue might have a different cause.


I tried to simplify the issue to transformIndexHtml only, but this seems to work fine:

https://stackblitz.com/edit/vitejs-vite-hggc63?file=repro.mjs

import { createServer } from 'vite';

const server = await createServer();

const html = `
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
  </head>
  <body>
    <div style="background-image:url(/vite.svg)"></div>
  </body>
</html>
`;

const html2 = await server.transformIndexHtml('/', html);