70 Matching Annotations
  1. Mar 2023
    1. Streaming allows you to break down the page's HTML into smaller chunks and progressively send those chunks from the server to the client.

  2. hydrogen.shopify.dev hydrogen.shopify.dev
    1. ```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, }); } ```

    1. 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 }) }), }) }

    2. 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.
    1. ```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, }); } ```

    1. Pitfall #1: Server-Side Rendering Attacker-Controlled Initial State


      <script>window.__STATE__ = ${JSON.stringify({ data })}</script>


    1. 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>" }

    2. 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>" }

    3. Sometimes when we render initial state, we dangerously generate a document variable from a JSON string. Vulnerable code looks like this:


      <script>window.__STATE__ = ${JSON.stringify({ data })}</script>


    4. Server-side rendering attacker-controlled initial state
    1. 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__.
  3. Feb 2023
    1. 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);


      ```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 }, ); ```


      ```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); }, }); ```

    1. you're able to serve up the initial render (also called "fully hydrated")

      react initial render什么意思?SPA是初始化所有组件吗?跟路由有没有关系?vue 组件的按需加载与此类似吗?

  4. Dec 2022
    1. 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.
  5. Jun 2022
  6. Mar 2022
  7. Jan 2022
  8. Dec 2021
    1. Under-the-hood working of the streaming SSR server with the new React 14's suspense. A thread. #reactjs #webperf #perfmatters
  9. Oct 2021
    1. 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).
  10. Jun 2021
  11. Sep 2020
  12. Mar 2020
    1. 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.


      • 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
    2. 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)

  13. Dec 2019
  14. Nov 2018
  15. Oct 2018