exhibitionist-digital / ultra

Zero-Legacy Deno/React Suspense SSR Framework
https://ultrajs.dev
MIT License
2.99k stars 66 forks source link

Is SSR cache HTML escaped in the HTML inline script for client side hydration? #134

Closed jaydenseric closed 2 years ago

jaydenseric commented 2 years ago

Recently I fixed SSR cache data not being HTML escaped within the HTML inline script for client side hydration in Ruck v7.0.0:

https://github.com/jaydenseric/ruck/commit/da7fb7d445128c22a32bd2f1fbf6fd5e1bc12886

Basically, if the JSON contains HTML it could cause the HTML inline script to terminate early and the rest of the JSON would be rendered on the HTML page by the browser. I discovered this when a Ruck app page for a blog post had the blog post markdown that contained a HTML image tag queried from the GitHub gist API, which gets cached during SSR and hydrated on the client.

I tried to see how Ultra handles the same thing, and it seems it doesn’t? Is this where a cache data JSON string is being used as a raw JavaScript value for a HTML inline script?

https://github.com/exhibitionist-digital/ultra/blob/82ea9bebd6abf70a4a7ec97bf5632c847b5d2c49/src/render.ts#L130-L132

I'm not sure how Aleph.js works but it seems they might also have the same issue:

https://github.com/alephjs/aleph.js/blob/19b337b0335e2766cd1df4ad753f9d8352a302e3/server/renderer.ts#L226

jaydenseric commented 2 years ago

I struggled to see how Fresh handles it, but maybe they don't do it right either? Perhaps here?

https://github.com/denoland/fresh/blob/216f1dc1fb72bb7fabbd14354b4cd30d5f98974e/src/server/render.tsx#L244-L246

mashaal commented 2 years ago

Building and hydrating SSR cache is now user controlled -- Here is an example https://github.com/exhibitionist-digital/ultra/blob/main/examples/with-react-query/src/hooks/useDehydrateReactQuery.tsx#L24-L25

I've added a link to the known limitations around dehydrated state.