From a7372079817fb1a1e69b2632405d759f9c5e913d Mon Sep 17 00:00:00 2001
From: Jacky Zhao <j.zhao2k19@gmail.com>
Date: Sun, 16 Mar 2025 21:17:31 +0000
Subject: [PATCH] perf: incremental rebuild (--fastRebuild v2 but default) (#1841)
---
quartz/plugins/emitters/ogImage.tsx | 87 +++++++++++++++++++++++++++----------------
1 files changed, 54 insertions(+), 33 deletions(-)
diff --git a/quartz/plugins/emitters/ogImage.tsx b/quartz/plugins/emitters/ogImage.tsx
index 056976a..f31cc4b 100644
--- a/quartz/plugins/emitters/ogImage.tsx
+++ b/quartz/plugins/emitters/ogImage.tsx
@@ -4,10 +4,12 @@
import { FullSlug, getFileExtension } from "../../util/path"
import { ImageOptions, SocialImageOptions, defaultImage, getSatoriFonts } from "../../util/og"
import sharp from "sharp"
-import satori from "satori"
+import satori, { SatoriOptions } from "satori"
import { loadEmoji, getIconCode } from "../../util/emoji"
import { Readable } from "stream"
import { write } from "./helpers"
+import { BuildCtx } from "../../util/ctx"
+import { QuartzPluginData } from "../vfile"
const defaultOptions: SocialImageOptions = {
colorScheme: "lightMode",
@@ -42,6 +44,41 @@
return sharp(Buffer.from(svg)).webp({ quality: 40 })
}
+async function processOgImage(
+ ctx: BuildCtx,
+ fileData: QuartzPluginData,
+ fonts: SatoriOptions["fonts"],
+ fullOptions: SocialImageOptions,
+) {
+ const cfg = ctx.cfg.configuration
+ const slug = fileData.slug!
+ const titleSuffix = cfg.pageTitleSuffix ?? ""
+ const title =
+ (fileData.frontmatter?.title ?? i18n(cfg.locale).propertyDefaults.title) + titleSuffix
+ const description =
+ fileData.frontmatter?.socialDescription ??
+ fileData.frontmatter?.description ??
+ unescapeHTML(fileData.description?.trim() ?? i18n(cfg.locale).propertyDefaults.description)
+
+ const stream = await generateSocialImage(
+ {
+ title,
+ description,
+ fonts,
+ cfg,
+ fileData,
+ },
+ fullOptions,
+ )
+
+ return write({
+ ctx,
+ content: stream,
+ slug: `${slug}-og-image` as FullSlug,
+ ext: ".webp",
+ })
+}
+
export const CustomOgImagesEmitterName = "CustomOgImages"
export const CustomOgImages: QuartzEmitterPlugin<Partial<SocialImageOptions>> = (userOpts) => {
const fullOptions = { ...defaultOptions, ...userOpts }
@@ -58,39 +95,23 @@
const fonts = await getSatoriFonts(headerFont, bodyFont)
for (const [_tree, vfile] of content) {
- // if this file defines socialImage, we can skip
- if (vfile.data.frontmatter?.socialImage !== undefined) {
- continue
+ if (vfile.data.frontmatter?.socialImage !== undefined) continue
+ yield processOgImage(ctx, vfile.data, fonts, fullOptions)
+ }
+ },
+ async *partialEmit(ctx, _content, _resources, changeEvents) {
+ const cfg = ctx.cfg.configuration
+ const headerFont = cfg.theme.typography.header
+ const bodyFont = cfg.theme.typography.body
+ const fonts = await getSatoriFonts(headerFont, bodyFont)
+
+ // find all slugs that changed or were added
+ for (const changeEvent of changeEvents) {
+ if (!changeEvent.file) continue
+ if (changeEvent.file.data.frontmatter?.socialImage !== undefined) continue
+ if (changeEvent.type === "add" || changeEvent.type === "change") {
+ yield processOgImage(ctx, changeEvent.file.data, fonts, fullOptions)
}
-
- const slug = vfile.data.slug!
- const titleSuffix = cfg.pageTitleSuffix ?? ""
- const title =
- (vfile.data.frontmatter?.title ?? i18n(cfg.locale).propertyDefaults.title) + titleSuffix
- const description =
- vfile.data.frontmatter?.socialDescription ??
- vfile.data.frontmatter?.description ??
- unescapeHTML(
- vfile.data.description?.trim() ?? i18n(cfg.locale).propertyDefaults.description,
- )
-
- const stream = await generateSocialImage(
- {
- title,
- description,
- fonts,
- cfg,
- fileData: vfile.data,
- },
- fullOptions,
- )
-
- yield write({
- ctx,
- content: stream,
- slug: `${slug}-og-image` as FullSlug,
- ext: ".webp",
- })
}
},
externalResources: (ctx) => {
--
Gitblit v1.10.0