fix: parse parallelization chunk arg, inline b64 for og image

This commit is contained in:
Jacky Zhao 2025-03-16 15:12:40 -07:00
parent a737207981
commit e86544064c
4 changed files with 49 additions and 35 deletions

View file

@ -1,7 +1,7 @@
import { QuartzEmitterPlugin } from "../types"
import { i18n } from "../../i18n"
import { unescapeHTML } from "../../util/escape"
import { FullSlug, getFileExtension } from "../../util/path"
import { FullSlug, getFileExtension, joinSegments, QUARTZ } from "../../util/path"
import { ImageOptions, SocialImageOptions, defaultImage, getSatoriFonts } from "../../util/og"
import sharp from "sharp"
import satori, { SatoriOptions } from "satori"
@ -10,6 +10,8 @@ import { Readable } from "stream"
import { write } from "./helpers"
import { BuildCtx } from "../../util/ctx"
import { QuartzPluginData } from "../vfile"
import fs from "node:fs/promises"
import chalk from "chalk"
const defaultOptions: SocialImageOptions = {
colorScheme: "lightMode",
@ -28,7 +30,25 @@ async function generateSocialImage(
userOpts: SocialImageOptions,
): Promise<Readable> {
const { width, height } = userOpts
const imageComponent = userOpts.imageStructure(cfg, userOpts, title, description, fonts, fileData)
const iconPath = joinSegments(QUARTZ, "static", "icon.png")
let iconBase64: string | undefined = undefined
try {
const iconData = await fs.readFile(iconPath)
iconBase64 = `data:image/png;base64,${iconData.toString("base64")}`
} catch (err) {
console.warn(chalk.yellow(`Warning: Could not find icon at ${iconPath}`))
}
const imageComponent = userOpts.imageStructure({
cfg,
userOpts,
title,
description,
fonts,
fileData,
iconBase64,
})
const svg = await satori(imageComponent, {
width,
height,

View file

@ -172,7 +172,7 @@ export async function parseMarkdown(ctx: BuildCtx, fps: FilePath[]): Promise<Pro
workerType: "thread",
})
const errorHandler = (err: any) => {
console.error(`${err}`.replace(/^error:\s*/i, ""))
console.error(err)
process.exit(1)
}
@ -201,7 +201,7 @@ export async function parseMarkdown(ctx: BuildCtx, fps: FilePath[]): Promise<Pro
const markdownToHtmlPromises: WorkerPromise<ProcessedContent[]>[] = []
processedFiles = 0
for (const [mdChunk, _] of mdResults) {
for (const mdChunk of mdResults) {
markdownToHtmlPromises.push(pool.exec("processHtml", [serializableCtx, mdChunk]))
}
const results: ProcessedContent[][] = await Promise.all(

View file

@ -35,7 +35,7 @@ export class QuartzLogger {
const truncated = truncate(output, columns)
process.stdout.write(truncated)
this.spinnerIndex = (this.spinnerIndex + 1) % this.spinnerChars.length
}, 20)
}, 50)
}
}

View file

@ -13,6 +13,7 @@ import chalk from "chalk"
const defaultHeaderWeight = [700]
const defaultBodyWeight = [400]
export async function getSatoriFonts(headerFont: FontSpecification, bodyFont: FontSpecification) {
// Get all weights for header and body fonts
const headerWeights: FontWeight[] = (
@ -134,21 +135,12 @@ export type SocialImageOptions = {
excludeRoot: boolean
/**
* JSX to use for generating image. See satori docs for more info (https://github.com/vercel/satori)
* @param cfg global quartz config
* @param userOpts options that can be set by user
* @param title title of current page
* @param description description of current page
* @param fonts global font that can be used for styling
* @param fileData full fileData of current page
* @returns prepared jsx to be used for generating image
*/
imageStructure: (
cfg: GlobalConfiguration,
userOpts: UserOpts,
title: string,
description: string,
fonts: SatoriOptions["fonts"],
fileData: QuartzPluginData,
options: ImageOptions & {
userOpts: UserOpts
iconBase64?: string
},
) => JSXInternal.Element
}
@ -178,17 +170,17 @@ export type ImageOptions = {
}
// This is the default template for generated social image.
export const defaultImage: SocialImageOptions["imageStructure"] = (
cfg: GlobalConfiguration,
{ colorScheme }: UserOpts,
title: string,
description: string,
_fonts: SatoriOptions["fonts"],
fileData: QuartzPluginData,
) => {
export const defaultImage: SocialImageOptions["imageStructure"] = ({
cfg,
userOpts,
title,
description,
fileData,
iconBase64,
}) => {
const { colorScheme } = userOpts
const fontBreakPoint = 32
const useSmallerFont = title.length > fontBreakPoint
const iconPath = `https://${cfg.baseUrl}/static/icon.png`
// Format date if available
const rawDate = getDate(cfg, fileData)
@ -226,14 +218,16 @@ export const defaultImage: SocialImageOptions["imageStructure"] = (
marginBottom: "0.5rem",
}}
>
<img
src={iconPath}
width={56}
height={56}
style={{
borderRadius: "50%",
}}
/>
{iconBase64 && (
<img
src={iconBase64}
width={56}
height={56}
style={{
borderRadius: "50%",
}}
/>
)}
<div
style={{
display: "flex",