From b4236e5142c31829cf809c0fbc8370ac22b6d1ba Mon Sep 17 00:00:00 2001
From: kabirgh <15871468+kabirgh@users.noreply.github.com>
Date: Sun, 10 Mar 2024 00:42:23 +0000
Subject: [PATCH] feat(perf:fast-rebuilds): Stop mutating resources param in
ComponentResources emitter (#977)
* Stop mutating resources param in ComponentResources emitter
* Add done rebuilding log for fast rebuilds
* Move google font loading to Head component
* Simplify code and fix comment
---
quartz.config.ts | 3 +-
quartz/build.ts | 2 +
quartz/components/Head.tsx | 4 +-
quartz/plugins/emitters/componentResources.ts | 143 ++++++------------
quartz/plugins/index.ts | 17 +++
quartz/util/theme.ts | 1 +
6 files changed, 72 insertions(+), 98 deletions(-)
diff --git a/quartz.config.ts b/quartz.config.ts
index 2cdadb740..4b98325dd 100644
--- a/quartz.config.ts
+++ b/quartz.config.ts
@@ -19,6 +19,7 @@ const config: QuartzConfig = {
ignorePatterns: ["private", "templates", ".obsidian"],
defaultDateType: "created",
theme: {
+ fontOrigin: "googleFonts",
cdnCaching: true,
typography: {
header: "Schibsted Grotesk",
@@ -72,7 +73,7 @@ const config: QuartzConfig = {
filters: [Plugin.RemoveDrafts()],
emitters: [
Plugin.AliasRedirects(),
- Plugin.ComponentResources({ fontOrigin: "googleFonts" }),
+ Plugin.ComponentResources(),
Plugin.ContentPage(),
Plugin.FolderPage(),
Plugin.TagPage(),
diff --git a/quartz/build.ts b/quartz/build.ts
index d72b8ddf4..972a7e850 100644
--- a/quartz/build.ts
+++ b/quartz/build.ts
@@ -309,6 +309,8 @@ async function partialRebuildFromEntrypoint(
}
await rimraf([...destinationsToDelete])
+ console.log(chalk.green(`Done rebuilding in ${perf.timeSince()}`))
+
toRemove.clear()
release()
clientRefresh()
diff --git a/quartz/components/Head.tsx b/quartz/components/Head.tsx
index 3cb6bea66..46ba5e002 100644
--- a/quartz/components/Head.tsx
+++ b/quartz/components/Head.tsx
@@ -1,6 +1,7 @@
import { i18n } from "../i18n"
import { FullSlug, joinSegments, pathToRoot } from "../util/path"
import { JSResourceToScriptElement } from "../util/resources"
+import { googleFontHref } from "../util/theme"
import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types"
export default (() => {
@@ -21,10 +22,11 @@ export default (() => {
{title}
- {cfg.theme.cdnCaching && (
+ {cfg.theme.cdnCaching && cfg.theme.fontOrigin === "googleFonts" && (
<>
+
>
)}
diff --git a/quartz/plugins/emitters/componentResources.ts b/quartz/plugins/emitters/componentResources.ts
index eae496ea0..0bccb6075 100644
--- a/quartz/plugins/emitters/componentResources.ts
+++ b/quartz/plugins/emitters/componentResources.ts
@@ -8,7 +8,6 @@ import popoverScript from "../../components/scripts/popover.inline"
import styles from "../../styles/custom.scss"
import popoverStyle from "../../components/styles/popover.scss"
import { BuildCtx } from "../../util/ctx"
-import { StaticResources } from "../../util/resources"
import { QuartzComponent } from "../../components/types"
import { googleFontHref, joinStyles } from "../../util/theme"
import { Features, transform } from "lightningcss"
@@ -69,13 +68,8 @@ async function joinScripts(scripts: string[]): Promise {
return res.code
}
-function addGlobalPageResources(
- ctx: BuildCtx,
- staticResources: StaticResources,
- componentResources: ComponentResources,
-) {
+function addGlobalPageResources(ctx: BuildCtx, componentResources: ComponentResources) {
const cfg = ctx.cfg.configuration
- const reloadScript = ctx.argv.serve
// popovers
if (cfg.enablePopovers) {
@@ -85,12 +79,12 @@ function addGlobalPageResources(
if (cfg.analytics?.provider === "google") {
const tagId = cfg.analytics.tagId
- staticResources.js.push({
- src: `https://www.googletagmanager.com/gtag/js?id=${tagId}`,
- contentType: "external",
- loadTime: "afterDOMReady",
- })
componentResources.afterDOMLoaded.push(`
+ const gtagScript = document.createElement("script")
+ gtagScript.src = "https://www.googletagmanager.com/gtag/js?id=${tagId}"
+ gtagScript.async = true
+ document.head.appendChild(gtagScript)
+
window.dataLayer = window.dataLayer || [];
function gtag() { dataLayer.push(arguments); }
gtag("js", new Date());
@@ -147,115 +141,72 @@ function addGlobalPageResources(
document.dispatchEvent(event)
`)
}
-
- let wsUrl = `ws://localhost:${ctx.argv.wsPort}`
-
- if (ctx.argv.remoteDevHost) {
- wsUrl = `wss://${ctx.argv.remoteDevHost}:${ctx.argv.wsPort}`
- }
-
- if (reloadScript) {
- staticResources.js.push({
- loadTime: "afterDOMReady",
- contentType: "inline",
- script: `
- const socket = new WebSocket('${wsUrl}')
- // reload(true) ensures resources like images and scripts are fetched again in firefox
- socket.addEventListener('message', () => document.location.reload(true))
- `,
- })
- }
}
-interface Options {
- fontOrigin: "googleFonts" | "local"
-}
-
-const defaultOptions: Options = {
- fontOrigin: "googleFonts",
-}
-
-export const ComponentResources: QuartzEmitterPlugin = (opts?: Partial) => {
- const { fontOrigin } = { ...defaultOptions, ...opts }
+// This emitter should not update the `resources` parameter. If it does, partial
+// rebuilds may not work as expected.
+export const ComponentResources: QuartzEmitterPlugin = () => {
return {
name: "ComponentResources",
getQuartzComponents() {
return []
},
- async getDependencyGraph(ctx, content, _resources) {
- // This emitter adds static resources to the `resources` parameter. One
- // important resource this emitter adds is the code to start a websocket
- // connection and listen to rebuild messages, which triggers a page reload.
- // The resources parameter with the reload logic is later used by the
- // ContentPage emitter while creating the final html page. In order for
- // the reload logic to be included, and so for partial rebuilds to work,
- // we need to run this emitter for all markdown files.
- const graph = new DepGraph()
-
- for (const [_tree, file] of content) {
- const sourcePath = file.data.filePath!
- const slug = file.data.slug!
- graph.addEdge(sourcePath, joinSegments(ctx.argv.output, slug + ".html") as FilePath)
- }
-
- return graph
+ async getDependencyGraph(_ctx, _content, _resources) {
+ return new DepGraph()
},
- async emit(ctx, _content, resources): Promise {
+ async emit(ctx, _content, _resources): Promise {
const promises: Promise[] = []
const cfg = ctx.cfg.configuration
// component specific scripts and styles
const componentResources = getComponentResources(ctx)
let googleFontsStyleSheet = ""
- if (fontOrigin === "local") {
+ if (cfg.theme.fontOrigin === "local") {
// let the user do it themselves in css
- } else if (fontOrigin === "googleFonts") {
- if (cfg.theme.cdnCaching) {
- resources.css.push(googleFontHref(cfg.theme))
- } else {
- let match
+ } else if (cfg.theme.fontOrigin === "googleFonts" && !cfg.theme.cdnCaching) {
+ // when cdnCaching is true, we link to google fonts in Head.tsx
+ let match
- const fontSourceRegex = /url\((https:\/\/fonts.gstatic.com\/s\/[^)]+\.(woff2|ttf))\)/g
+ const fontSourceRegex = /url\((https:\/\/fonts.gstatic.com\/s\/[^)]+\.(woff2|ttf))\)/g
- googleFontsStyleSheet = await (
- await fetch(googleFontHref(ctx.cfg.configuration.theme))
- ).text()
+ googleFontsStyleSheet = await (
+ await fetch(googleFontHref(ctx.cfg.configuration.theme))
+ ).text()
- while ((match = fontSourceRegex.exec(googleFontsStyleSheet)) !== null) {
- // match[0] is the `url(path)`, match[1] is the `path`
- const url = match[1]
- // the static name of this file.
- const [filename, ext] = url.split("/").pop()!.split(".")
+ while ((match = fontSourceRegex.exec(googleFontsStyleSheet)) !== null) {
+ // match[0] is the `url(path)`, match[1] is the `path`
+ const url = match[1]
+ // the static name of this file.
+ const [filename, ext] = url.split("/").pop()!.split(".")
- googleFontsStyleSheet = googleFontsStyleSheet.replace(
- url,
- `https://${cfg.baseUrl}/static/fonts/${filename}.ttf`,
- )
+ googleFontsStyleSheet = googleFontsStyleSheet.replace(
+ url,
+ `https://${cfg.baseUrl}/static/fonts/${filename}.ttf`,
+ )
- promises.push(
- fetch(url)
- .then((res) => {
- if (!res.ok) {
- throw new Error(`Failed to fetch font`)
- }
- return res.arrayBuffer()
- })
- .then((buf) =>
- write({
- ctx,
- slug: joinSegments("static", "fonts", filename) as FullSlug,
- ext: `.${ext}`,
- content: Buffer.from(buf),
- }),
- ),
- )
- }
+ promises.push(
+ fetch(url)
+ .then((res) => {
+ if (!res.ok) {
+ throw new Error(`Failed to fetch font`)
+ }
+ return res.arrayBuffer()
+ })
+ .then((buf) =>
+ write({
+ ctx,
+ slug: joinSegments("static", "fonts", filename) as FullSlug,
+ ext: `.${ext}`,
+ content: Buffer.from(buf),
+ }),
+ ),
+ )
}
}
// important that this goes *after* component scripts
// as the "nav" event gets triggered here and we should make sure
// that everyone else had the chance to register a listener for it
- addGlobalPageResources(ctx, resources, componentResources)
+ addGlobalPageResources(ctx, componentResources)
const stylesheet = joinStyles(
ctx.cfg.configuration.theme,
diff --git a/quartz/plugins/index.ts b/quartz/plugins/index.ts
index f35d05353..554b1170b 100644
--- a/quartz/plugins/index.ts
+++ b/quartz/plugins/index.ts
@@ -18,6 +18,23 @@ export function getStaticResourcesFromPlugins(ctx: BuildCtx) {
}
}
+ // if serving locally, listen for rebuilds and reload the page
+ if (ctx.argv.serve) {
+ const wsUrl = ctx.argv.remoteDevHost
+ ? `wss://${ctx.argv.remoteDevHost}:${ctx.argv.wsPort}`
+ : `ws://localhost:${ctx.argv.wsPort}`
+
+ staticResources.js.push({
+ loadTime: "afterDOMReady",
+ contentType: "inline",
+ script: `
+ const socket = new WebSocket('${wsUrl}')
+ // reload(true) ensures resources like images and scripts are fetched again in firefox
+ socket.addEventListener('message', () => document.location.reload(true))
+ `,
+ })
+ }
+
return staticResources
}
diff --git a/quartz/util/theme.ts b/quartz/util/theme.ts
index 49cc9cce8..d3bfb9a0d 100644
--- a/quartz/util/theme.ts
+++ b/quartz/util/theme.ts
@@ -22,6 +22,7 @@ export interface Theme {
}
cdnCaching: boolean
colors: Colors
+ fontOrigin: "googleFonts" | "local"
}
export type ThemeKey = keyof Colors