feat(fonts): fetch before build (#817)
* feat: fetch google fonts before build Signed-off-by: Aaron <29749331+aarnphm@users.noreply.github.com> * Update quartz/plugins/emitters/componentResources.ts * fix: fetching wolff2 Signed-off-by: Aaron <29749331+aarnphm@users.noreply.github.com> * chore: remove request stylesheet Signed-off-by: Aaron <29749331+aarnphm@users.noreply.github.com> * fix: race condition Signed-off-by: Aaron <29749331+aarnphm@users.noreply.github.com> * chore: remove preconnect for static fonts since we are already downloading fonts into public folder Signed-off-by: Aaron <29749331+aarnphm@users.noreply.github.com> * chore: remove deadcode Signed-off-by: Aaron <29749331+aarnphm@users.noreply.github.com> * chore: add options to gate for cdn caching Signed-off-by: Aaron <29749331+aarnphm@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Jacky Zhao <j.zhao2k19@gmail.com> * chore: apply jacky's suggestion Co-authored-by: Jacky Zhao <j.zhao2k19@gmail.com> * chore: add docs and only use one promise Signed-off-by: Aaron <29749331+aarnphm@users.noreply.github.com> * fix: fmt Signed-off-by: Aaron <29749331+aarnphm@users.noreply.github.com> * chore: remove deadcode * chore: final touches Co-authored-by: Jacky Zhao <j.zhao2k19@gmail.com> * revert: changes in theme.ts * fix: styles and remove deadcode Signed-off-by: Aaron <29749331+aarnphm@users.noreply.github.com> --------- Signed-off-by: Aaron <29749331+aarnphm@users.noreply.github.com> Co-authored-by: Jacky Zhao <j.zhao2k19@gmail.com>
This commit is contained in:
		@@ -34,6 +34,7 @@ This part of the configuration concerns anything that can affect the whole site.
 | 
				
			|||||||
- `ignorePatterns`: a list of [glob](<https://en.wikipedia.org/wiki/Glob_(programming)>) patterns that Quartz should ignore and not search through when looking for files inside the `content` folder. See [[private pages]] for more details.
 | 
					- `ignorePatterns`: a list of [glob](<https://en.wikipedia.org/wiki/Glob_(programming)>) patterns that Quartz should ignore and not search through when looking for files inside the `content` folder. See [[private pages]] for more details.
 | 
				
			||||||
- `defaultDateType`: whether to use created, modified, or published as the default date to display on pages and page listings.
 | 
					- `defaultDateType`: whether to use created, modified, or published as the default date to display on pages and page listings.
 | 
				
			||||||
- `theme`: configure how the site looks.
 | 
					- `theme`: configure how the site looks.
 | 
				
			||||||
 | 
					  - `cdnCaching`: Whether to use Google CDN to cache the fonts (generally will be faster). Disable this if you want Quartz to be self-contained. Default to `true`
 | 
				
			||||||
  - `typography`: what fonts to use. Any font available on [Google Fonts](https://fonts.google.com/) works here.
 | 
					  - `typography`: what fonts to use. Any font available on [Google Fonts](https://fonts.google.com/) works here.
 | 
				
			||||||
    - `header`: Font to use for headers
 | 
					    - `header`: Font to use for headers
 | 
				
			||||||
    - `code`: Font for inline and block quotes.
 | 
					    - `code`: Font for inline and block quotes.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,6 +14,7 @@ const config: QuartzConfig = {
 | 
				
			|||||||
    ignorePatterns: ["private", "templates", ".obsidian"],
 | 
					    ignorePatterns: ["private", "templates", ".obsidian"],
 | 
				
			||||||
    defaultDateType: "created",
 | 
					    defaultDateType: "created",
 | 
				
			||||||
    theme: {
 | 
					    theme: {
 | 
				
			||||||
 | 
					      cdnCaching: true,
 | 
				
			||||||
      typography: {
 | 
					      typography: {
 | 
				
			||||||
        header: "Schibsted Grotesk",
 | 
					        header: "Schibsted Grotesk",
 | 
				
			||||||
        body: "Source Sans Pro",
 | 
					        body: "Source Sans Pro",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,8 +30,12 @@ export default (() => {
 | 
				
			|||||||
        <link rel="icon" href={iconPath} />
 | 
					        <link rel="icon" href={iconPath} />
 | 
				
			||||||
        <meta name="description" content={description} />
 | 
					        <meta name="description" content={description} />
 | 
				
			||||||
        <meta name="generator" content="Quartz" />
 | 
					        <meta name="generator" content="Quartz" />
 | 
				
			||||||
 | 
					        {cfg.theme.cdnCaching && (
 | 
				
			||||||
 | 
					          <>
 | 
				
			||||||
            <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" />
 | 
				
			||||||
 | 
					          </>
 | 
				
			||||||
 | 
					        )}
 | 
				
			||||||
        {css.map((href) => (
 | 
					        {css.map((href) => (
 | 
				
			||||||
          <link key={href} href={href} rel="stylesheet" type="text/css" spa-preserve />
 | 
					          <link key={href} href={href} rel="stylesheet" type="text/css" spa-preserve />
 | 
				
			||||||
        ))}
 | 
					        ))}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
import { FilePath, FullSlug } from "../../util/path"
 | 
					import { FilePath, FullSlug, joinSegments } from "../../util/path"
 | 
				
			||||||
import { QuartzEmitterPlugin } from "../types"
 | 
					import { QuartzEmitterPlugin } from "../types"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// @ts-ignore
 | 
					// @ts-ignore
 | 
				
			||||||
@@ -172,27 +172,72 @@ export const ComponentResources: QuartzEmitterPlugin<Options> = (opts?: Partial<
 | 
				
			|||||||
      return []
 | 
					      return []
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    async emit(ctx, _content, resources): Promise<FilePath[]> {
 | 
					    async emit(ctx, _content, resources): Promise<FilePath[]> {
 | 
				
			||||||
 | 
					      const promises: Promise<FilePath>[] = []
 | 
				
			||||||
 | 
					      const cfg = ctx.cfg.configuration
 | 
				
			||||||
      // component specific scripts and styles
 | 
					      // component specific scripts and styles
 | 
				
			||||||
      const componentResources = getComponentResources(ctx)
 | 
					      const componentResources = getComponentResources(ctx)
 | 
				
			||||||
      // 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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (fontOrigin === "googleFonts") {
 | 
					      let googleFontsStyleSheet = ""
 | 
				
			||||||
        resources.css.push(googleFontHref(ctx.cfg.configuration.theme))
 | 
					      if (fontOrigin === "local") {
 | 
				
			||||||
      } else if (fontOrigin === "local") {
 | 
					 | 
				
			||||||
        // let the user do it themselves in css
 | 
					        // 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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          const fontSourceRegex = /url\((https:\/\/fonts.gstatic.com\/s\/[^)]+\.(woff2|ttf))\)/g
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          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(".")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            googleFontsStyleSheet = googleFontsStyleSheet.replace(url, `/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("fonts", filename) as FullSlug,
 | 
				
			||||||
 | 
					                    ext: `.${ext}`,
 | 
				
			||||||
 | 
					                    content: Buffer.from(buf),
 | 
				
			||||||
 | 
					                  }),
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      addGlobalPageResources(ctx, resources, componentResources)
 | 
					      addGlobalPageResources(ctx, resources, componentResources)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const stylesheet = joinStyles(ctx.cfg.configuration.theme, ...componentResources.css, styles)
 | 
					      const stylesheet = joinStyles(
 | 
				
			||||||
 | 
					        ctx.cfg.configuration.theme,
 | 
				
			||||||
 | 
					        ...componentResources.css,
 | 
				
			||||||
 | 
					        googleFontsStyleSheet,
 | 
				
			||||||
 | 
					        styles,
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
      const [prescript, postscript] = await Promise.all([
 | 
					      const [prescript, postscript] = await Promise.all([
 | 
				
			||||||
        joinScripts(componentResources.beforeDOMLoaded),
 | 
					        joinScripts(componentResources.beforeDOMLoaded),
 | 
				
			||||||
        joinScripts(componentResources.afterDOMLoaded),
 | 
					        joinScripts(componentResources.afterDOMLoaded),
 | 
				
			||||||
      ])
 | 
					      ])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const fps = await Promise.all([
 | 
					      promises.push(
 | 
				
			||||||
        write({
 | 
					        write({
 | 
				
			||||||
          ctx,
 | 
					          ctx,
 | 
				
			||||||
          slug: "index" as FullSlug,
 | 
					          slug: "index" as FullSlug,
 | 
				
			||||||
@@ -223,8 +268,9 @@ export const ComponentResources: QuartzEmitterPlugin<Options> = (opts?: Partial<
 | 
				
			|||||||
          ext: ".js",
 | 
					          ext: ".js",
 | 
				
			||||||
          content: postscript,
 | 
					          content: postscript,
 | 
				
			||||||
        }),
 | 
					        }),
 | 
				
			||||||
      ])
 | 
					      )
 | 
				
			||||||
      return fps
 | 
					
 | 
				
			||||||
 | 
					      return await Promise.all(promises)
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@ type WriteOptions = {
 | 
				
			|||||||
  ctx: BuildCtx
 | 
					  ctx: BuildCtx
 | 
				
			||||||
  slug: FullSlug
 | 
					  slug: FullSlug
 | 
				
			||||||
  ext: `.${string}` | ""
 | 
					  ext: `.${string}` | ""
 | 
				
			||||||
  content: string
 | 
					  content: string | Buffer
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const write = async ({ ctx, slug, ext, content }: WriteOptions): Promise<FilePath> => {
 | 
					export const write = async ({ ctx, slug, ext, content }: WriteOptions): Promise<FilePath> => {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,6 +15,7 @@ export interface Theme {
 | 
				
			|||||||
    body: string
 | 
					    body: string
 | 
				
			||||||
    code: string
 | 
					    code: string
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  cdnCaching: boolean
 | 
				
			||||||
  colors: {
 | 
					  colors: {
 | 
				
			||||||
    lightMode: ColorScheme
 | 
					    lightMode: ColorScheme
 | 
				
			||||||
    darkMode: ColorScheme
 | 
					    darkMode: ColorScheme
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user