- Sep 2023
-
geoffrich.net geoffrich.net
-
On subsequent page loads using client-side navigation, we can allow the slow data to be streamed in. Client-side navigation will only occur if JavaScript is available, so there are no downsides to using promise streaming. If the user doesn’t have JavaScript, each navigation will trigger a full page load, and we will again wait for all data to resolve.We can switch between these two behaviors using the isDataRequest property on the RequestEvent passed to the load function. When this property is false, the request is for the HTML for the initial page load, and we should wait for all data to resolve. If the property is true, then the request is from SvelteKit’s client-side router and we can stream the data in.
js export async function load({isDataRequest}) { const slowData = getSlowData(); return { nested: { slow: isDataRequest ? slowData : await slowData } }; }
-
We can use Promise.race to give our promise a few hundred milliseconds to resolve. Promise.race takes an array of promises, and resolves when any one of those promises resolve. We can pass our delay call and our data fetching call, and conditionally await the result depending on which one resolves first.
In this example, we race two promises: a 200ms delay and the actual data call we want to make. If the delay resolves first, then the data call is taking longer than 200ms and we should go ahead and render the page with partial data. If the data call resolves first, then we got the data under the time limit and we can render the page with complete data.
```js const TIME_TO_RESOLVE_MS = 200; export async function load() { const slowData = getSlowData();
const result = await Promise.race([delay(TIME_TO_RESOLVE_MS), slowData]);
return { nested: { slow: result ? result : slowData } }; }
async function getSlowData() { // randomly delay either 50ms or 1s // this simulates variable API response times await delay(Math.random() < 0.5 ? 50 : 1000); return '😴'; }
function delay(ms) { return new Promise(res => setTimeout(res, ms)); } ```
Tags
Annotators
URL
-
- Aug 2023
-
joyofcode.xyz joyofcode.xyz
Tags
Annotators
URL
-
-
telefunc.com telefunc.comTelefunc1
-
-
Tags
Annotators
URL
-
-
blog.logrocket.com blog.logrocket.com
-
-
SvelteKit will automatically await the fetchPost call before it starts rendering the page, since it’s at the top level. However, it won’t wait for the nested fetchComments call to complete – the page will render and data.streamed.comments will be a promise that will resolve as the request completes. We can show a loading state in the corresponding +page.svelte using Svelte’s await block:
<script lang="ts"> import type { PageData } from './$types'; export let data: PageData; </script> <article> {data.post} </article>js export const load: PageServerLoad = () => { return { post: fetchPost(), streamed: { comments: fetchComments() } }; };
```svelte{#await data.streamed.comments} Loading... {:then value} <br />
-
{#each value as comment}
- {comment} {/each}
{/await} ```
Tags
Annotators
URL
-
-
stackoverflow.com stackoverflow.com
- Jul 2023
-
github.com github.com
Tags
Annotators
URL
-
-
github.com github.com
-
kit.svelte.dev kit.svelte.dev
Tags
Annotators
URL
-
- Jun 2023
-
docs.astro.build docs.astro.build
Tags
Annotators
URL
-
-
docs.astro.build docs.astro.build
Tags
Annotators
URL
-
-
Tags
Annotators
URL
-
-
www.enterspeed.com www.enterspeed.com
-
marmelab.com marmelab.com
-
stackoverflow.com stackoverflow.com
-
Tags
Annotators
URL
-
-
jasonformat.com jasonformat.com
Tags
Annotators
URL
-
-
astro.build astro.build
Tags
Annotators
URL
-
- May 2023
- Apr 2023
-
Tags
Annotators
URL
-
-
twitter.com twitter.com
Tags
Annotators
URL
-
-
blog.somewhatabstract.com blog.somewhatabstract.com
-
sergiodxa.com sergiodxa.com
Tags
Annotators
URL
-
- Mar 2023
-
beta.nextjs.org beta.nextjs.org
-
Streaming allows you to break down the page's HTML into smaller chunks and progressively send those chunks from the server to the client.
-
-
www.telerik.com www.telerik.com
Tags
Annotators
URL
-
-
www.telerik.com www.telerik.com
-
hydrogen.shopify.dev hydrogen.shopify.devRoadmap1
-
```js import {defer} from "@shopify/remix-oxygen";
export async function loader({ params: {handle}, context: {storefront} }) { const {product} = storefront.query({ query:
#graphql query Product( $country: CountryCode, $language: LanguageCode, $handle: String! ) @inContext(country: $country, language: $language) product(handle: $handle) { id title }
, variables: {handle}, cache: storefront.CacheLong() }); const {productRecommendations} = storefront.query({ query:#graphql query ProductRecommendations( $country: CountryCode, $language: LanguageCode, $handle: String! ) @inContext(country: $country, language: $language) productRecommendations(handle: $handle) { id title } }
, variables: {handle} }); if (!product) { throw new Response('Not Found', { status: 404, }); } return defer({ product: await product, productRecommendations, }); } ```
Tags
Annotators
URL
-
-
www.jacobparis.com www.jacobparis.com
-
The loader defers a promise that will resolve only when the json's progress has hit 100.
js export async function loader({ params }: LoaderArgs) { if (!params.hash) return redirect("/") const pathname = path.join( "public", "items", `${params.hash}.json`, ) const file = fs.readFileSync(pathname) if (!file) return redirect("/") const item = JSON.parse(file.toString()) if (!item) return redirect("/") if (item.progress === 100) { return defer({ promise: item, }) } return defer({ promise: new Promise((resolve) => { const interval = setInterval(() => { const file = fs.readFileSync(pathname) if (!file) return const item = JSON.parse(file.toString()) if (!item) return if (item.progress === 100) { clearInterval(interval) resolve(item) } return }) }), }) }
-
Defer is a feature of Remix that allows you to return an unresolved Promise from a loader. The page will server-side render without waiting for the promise to resolve, and then when it finally does, the client will re-render with the new data.
-
-
gist.github.com gist.github.com
-
-
What could be happening is dates being parsed with a different timezone during SSR and CSR for example.
Tags
Annotators
URL
-
-
blog.dwac.dev blog.dwac.dev
-
document.implementation.createHTMLDocument() which can stream dynamic HTML content directly into the page DOM
-
-
www.youtube.com www.youtube.com
-
-
Tags
Annotators
URL
-
-
github.com github.com
-
```js import { renderToReadableStream } from 'react-dom/server'; import type { EntryContext } from '@remix-run/cloudflare'; import { RemixServer } from '@remix-run/react'; import { renderHeadToString } from 'remix-island'; import { Head } from './root';
const readableString = (value: string) => { const te = new TextEncoder(); return new ReadableStream({ start(controller) { controller.enqueue(te.encode(value)); controller.close(); }, }); };
export default async function handleRequest( request: Request, responseStatusCode: number, responseHeaders: Headers, remixContext: EntryContext, ) { const { readable, writable } = new TransformStream(); const head = readableString(
<!DOCTYPE html><html><head>${renderHeadToString({ request, remixContext, Head, })}</head><body><div id="root">
, ); const end = readableString(</div></body></html>
);const body = await renderToReadableStream( <RemixServer context={remixContext} url={request.url} />, );
Promise.resolve() .then(() => head.pipeTo(writable, { preventClose: true })) .then(() => body.pipeTo(writable, { preventClose: true })) .then(() => end.pipeTo(writable));
responseHeaders.set('Content-Type', 'text/html');
return new Response(readable, { status: responseStatusCode, headers: responseHeaders, }); } ```
Tags
Annotators
URL
-
-
-
Pitfall #1: Server-Side Rendering Attacker-Controlled Initial State
```html
<script>window.__STATE__ = ${JSON.stringify({ data })}</script>```
-
-
thomasnguyen.site thomasnguyen.site
-
One option is to use the serialize-javascript NPM module to escape the rendered JSON.
html { username: "pwned", bio: "</script><script>alert('XSS Vulnerability!')</script>" }
-
This is risky because JSON.stringify() will blindly turn any data you give it into a string (so long as it is valid JSON) which will be rendered in the page. If { data } has fields that un-trusted users can edit like usernames or bios, they can inject something like this:
json { username: "pwned", bio: "</script><script>alert('XSS Vulnerability!')</script>" }
-
Sometimes when we render initial state, we dangerously generate a document variable from a JSON string. Vulnerable code looks like this:
```html
<script>window.__STATE__ = ${JSON.stringify({ data })}</script>```
-
Server-side rendering attacker-controlled initial state
-
-
www.freecodecamp.org www.freecodecamp.org
-
To pass along the state, the template attaches state to window.__STATE__ inside a <script> tag.Now you can read state on the client side by accessing window.__STATE__.
-
-
www.youtube.com www.youtube.com
-
-
www.youtube.com www.youtube.com
Tags
Annotators
URL
-
-
ogzhanolguncu.com ogzhanolguncu.com
Tags
Annotators
URL
-
-
dev.to dev.to
-
tanstack.com tanstack.com
Tags
Annotators
URL
-
-
react-query-v3.tanstack.com react-query-v3.tanstack.comSSR1
Tags
Annotators
URL
-
-
Tags
Annotators
URL
-
- Feb 2023
-
betterprogramming.pub betterprogramming.pub
-
www.youtube.com www.youtube.com
-
-
www.aboutmonica.com www.aboutmonica.com
-
patterns.dev patterns.dev
Tags
Annotators
URL
-
-
patterns.dev patterns.dev
Tags
Annotators
URL
-
-
patterns.dev patterns.dev
Tags
Annotators
URL
-
-
patterns.dev patterns.dev
-
-
beta.reactjs.org beta.reactjs.org
-
mxstbr.com mxstbr.com
Tags
Annotators
URL
-
-
www.joshwcomeau.com www.joshwcomeau.com
Tags
Annotators
URL
-
-
marcoghiani.com marcoghiani.com
-
-
Node.js
js import { renderToPipeableStream } from "react-dom/server.node"; import React from "react"; import http from "http"; const App = () => ( <html> <body> <h1>Hello World</h1> <p>This is an example.</p> </body> </html> ); var didError = false; http .createServer(function (req, res) { const stream = renderToPipeableStream(<App />, { onShellReady() { res.statusCode = didError ? 500 : 200; res.setHeader("Content-type", "text/html"); res.setHeader("Cache-Control", "no-transform"); stream.pipe(res); }, onShellError(error) { res.statusCode = 500; res.send( '<!doctype html><p>Loading...</p><script src="clientrender.js"></script>', ); }, onAllReady() { }, onError(err) { didError = true; console.error(err); }, }); }) .listen(3000);
Deno
```js import { renderToReadableStream } from "https://esm.run/react-dom/server"; import * as React from "https://esm.run/react";
const App = () => ( <html> <body>
Hello World
This is an example.
</body> </html> );const headers = { headers: { "Content-Type": "text/html", "Cache-Control": "no-transform", }, };
Deno.serve( async (req) => { return new Response(await renderToReadableStream(<App />), headers); }, { port: 3000 }, ); ```
Bun
```js import { renderToReadableStream } from "react-dom/server"; const headers = { headers: { "Content-Type": "text/html", }, };
const App = () => ( <html> <body>
Hello World
This is an example.
</body> </html> );Bun.serve({ port: 3000, async fetch(req) { return new Response(await renderToReadableStream(<App />), headers); }, }); ```
-
-
blog.logrocket.com blog.logrocket.com
-
prateeksurana.me prateeksurana.me
-
suspense.vercel.app suspense.vercel.app
Tags
Annotators
URL
-
-
suspense-npm.vercel.app suspense-npm.vercel.app
Tags
Annotators
URL
-
-
unicorn-utterances.com unicorn-utterances.com
-
you're able to serve up the initial render (also called "fully hydrated")
react initial render什么意思?SPA是初始化所有组件吗?跟路由有没有关系?vue 组件的按需加载与此类似吗?
Tags
Annotators
URL
-
- Dec 2022
-
stackoverflow.com stackoverflow.com
-
I had been wrapping my components with an improper tag that is, NextJS is not comfortable having a p tag wrapping your divs, sections etc so it will yell "Hydration failed because the initial UI does not match what was rendered on the server". So I solved this problem by examining how my elements were wrapping each other.
-
- Jun 2022
-
Tags
Annotators
URL
-
- Mar 2022
-
dunglas.fr dunglas.fr
Tags
Annotators
URL
-
- Jan 2022
-
stackoverflow.com stackoverflow.com
-
SSR is used for pages as well, but prerendering means that rendering happens at build time instead of when a visitor visits the page.
-
- Dec 2021
-
twitter.com twitter.comTwitter1
-
Under-the-hood working of the streaming SSR server with the new React 14's suspense. A thread. #reactjs #webperf #perfmatters
-
- Oct 2021
-
kit.svelte.dev kit.svelte.dev
-
This function allows you to modify (or replace) a fetch request for an external resource that happens inside a load function that runs on the server (or during pre-rendering). For example, your load function might make a request to a public URL like https://api.yourapp.com when the user performs a client-side navigation to the respective page, but during SSR it might make sense to hit the API directly (bypassing whatever proxies and load balancers sit between it and the public internet).
-
- Jun 2021
-
kit.svelte.dev kit.svelte.dev
-
When fetch runs on the server, the resulting response will be serialized and inlined into the rendered HTML. This allows the subsequent client-side load to access identical data immediately without an additional network request.
-
- Sep 2020
-
www.digitalocean.com www.digitalocean.com
- Mar 2020
-
paramaggarwal.substack.com paramaggarwal.substack.com
-
Javascript, APIs and Markup — this stack is all about finding middleground from the chaos of SSR+SPA. It is about stepping back and asking yourself, what parts of my page change and what parts don’t change?
JavaScript, APIs and Markup (JAM Stack) - middleground between SSR + SPA.
Advantages:
- The parts that don’t change often are pre-rendered on the server and saved to static HTML files. Anything else is implemented in JS and run on the client using API calls.
- Avoids too much data transfer (like the hydration data for SSR), therefore finds a good tradeoff to ship web content
- Allows to leverage the power and cost of Content delivery networks (CDNs) to effectively serve your content
- With serverless apps your APIs will never need a server to SSH into and manage
-
Somewhere on this path to render pages on the fly (SSR) and render pages on the client (SPA) we forgot about the performance of our webpages. We were trying to build apps. But the web is about presenting content first and foremost!
Website performance break with Client-side Rendering (SSR) and Single-page App (SPA)
-
- Dec 2019
-
arkwright.github.io arkwright.github.ioArkwrite1
- Nov 2018
- Oct 2018
-
levelup.gitconnected.com levelup.gitconnected.com