惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

J
Java Code Geeks
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
有赞技术团队
有赞技术团队
博客园 - 【当耐特】
云风的 BLOG
云风的 BLOG
Martin Fowler
Martin Fowler
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
量子位
Engineering at Meta
Engineering at Meta
博客园 - 叶小钗
T
The Blog of Author Tim Ferriss
Recent Announcements
Recent Announcements
罗磊的独立博客
B
Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
U
Unit 42
Microsoft Azure Blog
Microsoft Azure Blog
D
Docker
N
Netflix TechBlog - Medium
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
B
Blog RSS Feed
I
InfoQ
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
V
V2EX

Netlify Developers

AI model comparison using Netlify's AI Gateway | Netlify Developers Build an AI agent to automatically process and summarize form submissions | Netlify Developers Build an AI agent to automatically generate relevant images for blog posts | Netlify Developers Prerendering SPA content pages to enable AI agent access | Netlify Developers Identify image optimization opportunities with Netlify Observability | Netlify Developers Fix top 404 page not found errors with Netlify Observability | Netlify Developers Introducing AI Gateway: built-in AI model access on Netlify | Netlify Developers Introducing Observability: your project insights on Netlify | Netlify Developers From first publish to first update with AI agents | Netlify Developers How to use Agent Runners on Netlify | Netlify Developers Add forms to your project with AI + Netlify | Netlify Developers Track Real User Metrics | Netlify Developers Lighthouse performance scores on Netlify | Netlify Developers Review your AI project before you ship | Netlify Developers Using environment variables in AI Projects on Netlify | Netlify Developers Build prototypes and MVPs fast with AI + Netlify | Netlify Developers Pause auto-publishing on Netlify | Netlify Developers Run serverless functions, storage, and more natively in Nuxt dev | Netlify Developers Netlify Office Hours: The AX Arcade challenge | Netlify Developers Netlify Office Hours: Prompting with style | Netlify Developers Netlify Office Hours: RAG Apps with OpenAI + Netlify DB | Netlify Developers How to build a RAG application with Neon, Netlify & OpenAI | Netlify Developers Netlify Office Hours: Netlify DB (powered by Neon) | Netlify Developers Netlify Office Hours: Netlify MCP Server | Netlify Developers Netlify Office Hours: Netlify Vite Plugin | Netlify Developers Building MCPs with Netlify | Netlify Developers Deploying sites from your AI tool | Netlify Developers Adding your domain using Netlify API | Netlify Developers Build a context driven chat bot with Netlify Blob and OpenAI | Netlify Developers Simplify deployments with Netlify’s branch-matching environment variables | Netlify Developers
Partial Prerendering without a framework | Netlify Develo...
2024-05-23 · via Netlify Developers

Partial Prerendering might sound complex, but with Netlify’s Platform Primitives it’s simple to implement in plain static HTML without any framework or even build system, with the help of Netlify Edge Functions.

#TL;DR

This guide explains the concept of PPR (Partial Prerendering) and provides a step-by-step guide you can follow to use this rendering pattern on a site without a framework.

#What is Partial Prerendering?

Next.js implements experimental support for a concept called Partial Prerendering that aims to make pages with mostly static content and a few dynamic parts get useful content in front of the user faster.

The idea is that a static page is served from the edge as fast as possible, with areas of the page left as placeholders for dynamic content. The server will start fetching the dynamic content in parallel with the response stream, and then append the dynamic responses to the response stream from the static shell at the end, with a few script tags that inserts the content into the right empty slots.

#Implementing Partial Prerendering in plain HTML

This example will implement support for Partial Prerendering in a very simple example, with a plain HTML document that has a slot for a dynamically generated time string, and a Netlify Function that returns the current server time. We’ll use an Edge Function to tie it all together.

#The HTML

We’ll start with a simple HTML page with a placeholder for some dynamic content in a public/index.html:

<!DOCTYPE html>

<html>

<head>

<title>PPR</title>

</head>

<body>

<p>Today is: <span data-ppr="/partial/time">Loading...</span></p>

</body>

</html>

Here we use a data attribute to indicate that the content of an element should be loaded from a dynamic path.

We’ll also add a simple netlify.toml file to make sure we publish the right the folder:

[build]

publish = "public"

#The Dynamic Content

We’ll provide a simple Netlify Function as the origin for /partial/time by writing the following to netlify/functions/time.ts

import type { Context } from "@netlify/functions";

const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));

export default async (req: Request, context: Context) => {

// Simulate a slow API

await sleep(2000);

return new Response(`${new Date()}`, {

headers: {

"content-type": "text/html",

},

});

};

export const config = {

path: "/partial/time",

};

This is a simple time function that returns the current time as a string. To better show the Partial Prerendering in action, I’ve inserted a 2 second delay on each response.

#Tying it all together

To make all of this work, we’ll implement Partial Prerendering in an edge function. This uses HTMLRewriter to find all elements that have a data-ppr attribute and inject a script that replaces each one with the dynamic content.

Add this to netlify/edge-functions/ppr.ts:

import type { Config, Context } from "@netlify/edge-functions";

import { HTMLRewriter } from "https://ghuc.cc/worker-tools/html-rewriter/index.ts";

type Partial = {

id: number;

resp: Promise<Response>;

};

export default async (request: Request, context: Context) => {

let id = 0;

const partials: Partial[] = [];

const response = await context.next();

return new HTMLRewriter()

.on("[data-ppr]", {

element(element) {

// For each element with a `data-ppr` attribute, load the dynamic content from the URL and push the response into an array

const src = element.getAttribute("data-ppr");

const url = src.match(/^https?:/) ? src : new URL(src, request.url);

partials.push({

id: ++id,

resp: fetch(url.toString()),

});

element.removeAttribute("data-ppr");

element.setAttribute("id", `ppr-id-${id}`);

},

})

.on("body", {

async element(element) {

element.onEndTag(async (tag) => {

for (const partial of partials) {

const resp = await partial.resp;

const text = await resp.text();

// For each PPR element, inject a script tag that replaces its content with the dynamic data

tag.after(`<script>document.getElementById('ppr-id-${partial.id}').innerHTML = \`${text}\`;</script>`, {

html: true,

});

}

});

},

})

.transform(response);

};

export const config: Config = {

path: "/",

};

#Resources

You should see the loading shell almost instantly, and then the time will pop in after 2 seconds, all over one single HTTP request.

To get your own copy to play with, just click the button below

Deploy to Netlify

Or if you’re following along locally, deploy it all by running:

netlify deploy -p --build

#Is this useful?

It’s still TBD how much this technique really adds, versus a pure client side approach where script tags at the very top of the static payload start fetching the dynamic content, since with HTTP2 they will piggyback over the same connection to the CDN edge node and there’ll be zero overhead - however minimal - from any edge logic.

On slower networks the Partial Prerendering approach will most likely pay off, while on faster connections it’s likely that a client side fetch request will be faster.

In any case, Netlify’s Platform Primitives make it easy to implement any of these approaches, and they can be combined with Netlify’s Fine Grained cache control to make the experiences even faster.