cssninjaStudio / unplugin-fonts

Universal Webfont loader - Unfonts - based on https://web.dev/optimize-webfont-loading/
MIT License
328 stars 23 forks source link

Feature request: Ability to configure which fonts are preloaded #10

Open justrhysism opened 2 years ago

justrhysism commented 2 years ago

Preloading a few hundred kb of fonts can have a fairly big impact, it would be great if we were able to define a whitelist of fonts which we do want preloaded, and just allow CSS to fetch and swap in less used fonts on-demand.

BenBE commented 1 week ago

First draft for a possible implementation, though I usually keep quite a bit of distance between JS/TS and myself …

diff --git a/src/index.ts b/src/index.ts
index 2c4c6829..0b262925 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -87,7 +87,13 @@ export default createUnplugin<Options | undefined>((userOptions) => {
         handler: (html, ctx) => {
           const tags = getHeadLinkTags(options)
           const files = Object.keys(ctx.bundle ?? {}).filter(key => fontFileRegex.test(key))
+          const { prefetch: wantPrefetch, preload: wantPreload } = options?.custom || {}
           for (const file of files) {
+            if (!(
+              wantPrefetch === true || wantPreload === true ||
+              (wantPrefetch === undefined && wantPreload === undefined)
+            ))
+              continue
             const ext = extname(file)
             tags.push({
               tag: 'link',
@@ -101,7 +107,16 @@ export default createUnplugin<Options | undefined>((userOptions) => {
               },
             })
           }
-          return tags
+          let tagsReturned = tags
+          if (options?.custom?.linkFilter) {
+            const newTags: object[] | boolean = options?.custom?.linkFilter(tags)
+            if (Array.isArray(newTags)) {
+              tagsReturned = newTags
+            } else {
+              tagsReturned = newTags ? tags : []
+            }
+          }
+          return tagsReturned
         },
       },
     },
@@ -121,7 +136,14 @@ function generateVitepressBundle(

   const tags = getHeadLinkTags(options)
   const files = Object.keys(bundle ?? {}).filter(key => fontFileRegex.test(key))
+  const { prefetch: wantPrefetch, preload: wantPreload } = options?.custom || {}
   for (const file of files) {
+    if (!(
+      wantPrefetch === true || wantPreload === true ||
+      (wantPrefetch === undefined && wantPreload === undefined)
+    ))
+      continue
+
     const ext = extname(file)
     tags.push({
       tag: 'link',
@@ -136,7 +158,17 @@ function generateVitepressBundle(
     })
   }

-  for (const tag of tags) {
+  let tagsReturned = tags
+  if (options?.custom?.linkFilter) {
+    const newTags: object[] | boolean = options?.custom?.linkFilter(tags)
+    if (Array.isArray(newTags)) {
+      tagsReturned = newTags
+    } else {
+      tagsReturned = newTags ? tags : []
+    }
+  }
+
+  for (const tag of tagsReturned) {
     vitepressConfig?.site?.head?.push([
       tag.tag,
       tag.attrs?.onload === 'this.rel=\'stylesheet\''
diff --git a/src/types.ts b/src/types.ts
index 9085885a..1f25dc48 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -97,6 +97,13 @@ export interface CustomFonts {
    */
   prefetch?: boolean
   prefetchPrefix?: string
+  /**
+   * Provides a hook for filtering which `<link>` tags should be actually
+   * generated.
+   * @default true
+   */
+  linkFilter?: (tags: object[]) => object[] | boolean
+
   /**
    * @default: 'head-prepend'
    */

If this is generally accepted, I can do a full PR for this.

Should fix #7, #70 and this one.

stafyniaksacha commented 1 week ago

If this is generally accepted, I can do a full PR for this.

Should fix #7, #70 and this one.

I would be happy to review it !

BenBE commented 1 week ago

Any initial thoughts on this patch that I should take care of?