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
This commit is contained in:
parent
6e0c102970
commit
b4236e5142
@ -19,6 +19,7 @@ const config: QuartzConfig = {
|
|||||||
ignorePatterns: ["private", "templates", ".obsidian"],
|
ignorePatterns: ["private", "templates", ".obsidian"],
|
||||||
defaultDateType: "created",
|
defaultDateType: "created",
|
||||||
theme: {
|
theme: {
|
||||||
|
fontOrigin: "googleFonts",
|
||||||
cdnCaching: true,
|
cdnCaching: true,
|
||||||
typography: {
|
typography: {
|
||||||
header: "Schibsted Grotesk",
|
header: "Schibsted Grotesk",
|
||||||
@ -72,7 +73,7 @@ const config: QuartzConfig = {
|
|||||||
filters: [Plugin.RemoveDrafts()],
|
filters: [Plugin.RemoveDrafts()],
|
||||||
emitters: [
|
emitters: [
|
||||||
Plugin.AliasRedirects(),
|
Plugin.AliasRedirects(),
|
||||||
Plugin.ComponentResources({ fontOrigin: "googleFonts" }),
|
Plugin.ComponentResources(),
|
||||||
Plugin.ContentPage(),
|
Plugin.ContentPage(),
|
||||||
Plugin.FolderPage(),
|
Plugin.FolderPage(),
|
||||||
Plugin.TagPage(),
|
Plugin.TagPage(),
|
||||||
|
@ -309,6 +309,8 @@ async function partialRebuildFromEntrypoint(
|
|||||||
}
|
}
|
||||||
await rimraf([...destinationsToDelete])
|
await rimraf([...destinationsToDelete])
|
||||||
|
|
||||||
|
console.log(chalk.green(`Done rebuilding in ${perf.timeSince()}`))
|
||||||
|
|
||||||
toRemove.clear()
|
toRemove.clear()
|
||||||
release()
|
release()
|
||||||
clientRefresh()
|
clientRefresh()
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { i18n } from "../i18n"
|
import { i18n } from "../i18n"
|
||||||
import { FullSlug, joinSegments, pathToRoot } from "../util/path"
|
import { FullSlug, joinSegments, pathToRoot } from "../util/path"
|
||||||
import { JSResourceToScriptElement } from "../util/resources"
|
import { JSResourceToScriptElement } from "../util/resources"
|
||||||
|
import { googleFontHref } from "../util/theme"
|
||||||
import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types"
|
import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types"
|
||||||
|
|
||||||
export default (() => {
|
export default (() => {
|
||||||
@ -21,10 +22,11 @@ export default (() => {
|
|||||||
<head>
|
<head>
|
||||||
<title>{title}</title>
|
<title>{title}</title>
|
||||||
<meta charSet="utf-8" />
|
<meta charSet="utf-8" />
|
||||||
{cfg.theme.cdnCaching && (
|
{cfg.theme.cdnCaching && cfg.theme.fontOrigin === "googleFonts" && (
|
||||||
<>
|
<>
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" />
|
<link rel="preconnect" href="https://fonts.gstatic.com" />
|
||||||
|
<link rel="stylesheet" href={googleFontHref(cfg.theme)} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
@ -8,7 +8,6 @@ import popoverScript from "../../components/scripts/popover.inline"
|
|||||||
import styles from "../../styles/custom.scss"
|
import styles from "../../styles/custom.scss"
|
||||||
import popoverStyle from "../../components/styles/popover.scss"
|
import popoverStyle from "../../components/styles/popover.scss"
|
||||||
import { BuildCtx } from "../../util/ctx"
|
import { BuildCtx } from "../../util/ctx"
|
||||||
import { StaticResources } from "../../util/resources"
|
|
||||||
import { QuartzComponent } from "../../components/types"
|
import { QuartzComponent } from "../../components/types"
|
||||||
import { googleFontHref, joinStyles } from "../../util/theme"
|
import { googleFontHref, joinStyles } from "../../util/theme"
|
||||||
import { Features, transform } from "lightningcss"
|
import { Features, transform } from "lightningcss"
|
||||||
@ -69,13 +68,8 @@ async function joinScripts(scripts: string[]): Promise<string> {
|
|||||||
return res.code
|
return res.code
|
||||||
}
|
}
|
||||||
|
|
||||||
function addGlobalPageResources(
|
function addGlobalPageResources(ctx: BuildCtx, componentResources: ComponentResources) {
|
||||||
ctx: BuildCtx,
|
|
||||||
staticResources: StaticResources,
|
|
||||||
componentResources: ComponentResources,
|
|
||||||
) {
|
|
||||||
const cfg = ctx.cfg.configuration
|
const cfg = ctx.cfg.configuration
|
||||||
const reloadScript = ctx.argv.serve
|
|
||||||
|
|
||||||
// popovers
|
// popovers
|
||||||
if (cfg.enablePopovers) {
|
if (cfg.enablePopovers) {
|
||||||
@ -85,12 +79,12 @@ function addGlobalPageResources(
|
|||||||
|
|
||||||
if (cfg.analytics?.provider === "google") {
|
if (cfg.analytics?.provider === "google") {
|
||||||
const tagId = cfg.analytics.tagId
|
const tagId = cfg.analytics.tagId
|
||||||
staticResources.js.push({
|
|
||||||
src: `https://www.googletagmanager.com/gtag/js?id=${tagId}`,
|
|
||||||
contentType: "external",
|
|
||||||
loadTime: "afterDOMReady",
|
|
||||||
})
|
|
||||||
componentResources.afterDOMLoaded.push(`
|
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 || [];
|
window.dataLayer = window.dataLayer || [];
|
||||||
function gtag() { dataLayer.push(arguments); }
|
function gtag() { dataLayer.push(arguments); }
|
||||||
gtag("js", new Date());
|
gtag("js", new Date());
|
||||||
@ -147,115 +141,72 @@ function addGlobalPageResources(
|
|||||||
document.dispatchEvent(event)
|
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 {
|
// This emitter should not update the `resources` parameter. If it does, partial
|
||||||
fontOrigin: "googleFonts" | "local"
|
// rebuilds may not work as expected.
|
||||||
}
|
export const ComponentResources: QuartzEmitterPlugin = () => {
|
||||||
|
|
||||||
const defaultOptions: Options = {
|
|
||||||
fontOrigin: "googleFonts",
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ComponentResources: QuartzEmitterPlugin<Options> = (opts?: Partial<Options>) => {
|
|
||||||
const { fontOrigin } = { ...defaultOptions, ...opts }
|
|
||||||
return {
|
return {
|
||||||
name: "ComponentResources",
|
name: "ComponentResources",
|
||||||
getQuartzComponents() {
|
getQuartzComponents() {
|
||||||
return []
|
return []
|
||||||
},
|
},
|
||||||
async getDependencyGraph(ctx, content, _resources) {
|
async getDependencyGraph(_ctx, _content, _resources) {
|
||||||
// This emitter adds static resources to the `resources` parameter. One
|
return new DepGraph<FilePath>()
|
||||||
// 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<FilePath>()
|
|
||||||
|
|
||||||
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 emit(ctx, _content, resources): Promise<FilePath[]> {
|
async emit(ctx, _content, _resources): Promise<FilePath[]> {
|
||||||
const promises: Promise<FilePath>[] = []
|
const promises: Promise<FilePath>[] = []
|
||||||
const cfg = ctx.cfg.configuration
|
const cfg = ctx.cfg.configuration
|
||||||
// component specific scripts and styles
|
// component specific scripts and styles
|
||||||
const componentResources = getComponentResources(ctx)
|
const componentResources = getComponentResources(ctx)
|
||||||
let googleFontsStyleSheet = ""
|
let googleFontsStyleSheet = ""
|
||||||
if (fontOrigin === "local") {
|
if (cfg.theme.fontOrigin === "local") {
|
||||||
// let the user do it themselves in css
|
// let the user do it themselves in css
|
||||||
} else if (fontOrigin === "googleFonts") {
|
} else if (cfg.theme.fontOrigin === "googleFonts" && !cfg.theme.cdnCaching) {
|
||||||
if (cfg.theme.cdnCaching) {
|
// when cdnCaching is true, we link to google fonts in Head.tsx
|
||||||
resources.css.push(googleFontHref(cfg.theme))
|
let match
|
||||||
} else {
|
|
||||||
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 (
|
googleFontsStyleSheet = await (
|
||||||
await fetch(googleFontHref(ctx.cfg.configuration.theme))
|
await fetch(googleFontHref(ctx.cfg.configuration.theme))
|
||||||
).text()
|
).text()
|
||||||
|
|
||||||
while ((match = fontSourceRegex.exec(googleFontsStyleSheet)) !== null) {
|
while ((match = fontSourceRegex.exec(googleFontsStyleSheet)) !== null) {
|
||||||
// match[0] is the `url(path)`, match[1] is the `path`
|
// match[0] is the `url(path)`, match[1] is the `path`
|
||||||
const url = match[1]
|
const url = match[1]
|
||||||
// the static name of this file.
|
// the static name of this file.
|
||||||
const [filename, ext] = url.split("/").pop()!.split(".")
|
const [filename, ext] = url.split("/").pop()!.split(".")
|
||||||
|
|
||||||
googleFontsStyleSheet = googleFontsStyleSheet.replace(
|
googleFontsStyleSheet = googleFontsStyleSheet.replace(
|
||||||
url,
|
url,
|
||||||
`https://${cfg.baseUrl}/static/fonts/${filename}.ttf`,
|
`https://${cfg.baseUrl}/static/fonts/${filename}.ttf`,
|
||||||
)
|
)
|
||||||
|
|
||||||
promises.push(
|
promises.push(
|
||||||
fetch(url)
|
fetch(url)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
throw new Error(`Failed to fetch font`)
|
throw new Error(`Failed to fetch font`)
|
||||||
}
|
}
|
||||||
return res.arrayBuffer()
|
return res.arrayBuffer()
|
||||||
})
|
})
|
||||||
.then((buf) =>
|
.then((buf) =>
|
||||||
write({
|
write({
|
||||||
ctx,
|
ctx,
|
||||||
slug: joinSegments("static", "fonts", filename) as FullSlug,
|
slug: joinSegments("static", "fonts", filename) as FullSlug,
|
||||||
ext: `.${ext}`,
|
ext: `.${ext}`,
|
||||||
content: Buffer.from(buf),
|
content: Buffer.from(buf),
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// important that this goes *after* component scripts
|
// important that this goes *after* component scripts
|
||||||
// as the "nav" event gets triggered here and we should make sure
|
// as the "nav" event gets triggered here and we should make sure
|
||||||
// that everyone else had the chance to register a listener for it
|
// that everyone else had the chance to register a listener for it
|
||||||
addGlobalPageResources(ctx, resources, componentResources)
|
addGlobalPageResources(ctx, componentResources)
|
||||||
|
|
||||||
const stylesheet = joinStyles(
|
const stylesheet = joinStyles(
|
||||||
ctx.cfg.configuration.theme,
|
ctx.cfg.configuration.theme,
|
||||||
|
@ -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
|
return staticResources
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ export interface Theme {
|
|||||||
}
|
}
|
||||||
cdnCaching: boolean
|
cdnCaching: boolean
|
||||||
colors: Colors
|
colors: Colors
|
||||||
|
fontOrigin: "googleFonts" | "local"
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ThemeKey = keyof Colors
|
export type ThemeKey = keyof Colors
|
||||||
|
Loading…
Reference in New Issue
Block a user