From 82251915965673abcefa8c98deb720e1f3bac696 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Jeli=CC=81nek?= Date: Sat, 5 Aug 2023 16:05:05 +0200 Subject: [PATCH 1/4] WIP - split font fetching into separate API calls --- playground/nuxt.config.ts | 8 ++- src/module.ts | 104 ++++++++++++++++++++++++-------------- 2 files changed, 72 insertions(+), 40 deletions(-) diff --git a/playground/nuxt.config.ts b/playground/nuxt.config.ts index de09f3a..55e5810 100644 --- a/playground/nuxt.config.ts +++ b/playground/nuxt.config.ts @@ -6,8 +6,12 @@ export default defineNuxtConfig({ ], googleFonts: { families: { - Roboto: true, + Roboto: { + wght: [100, 400], + text: 'Roboto' + }, Mulish: true - } + }, + text: 'Hello World' } }) diff --git a/src/module.ts b/src/module.ts index af928e7..f82b429 100644 --- a/src/module.ts +++ b/src/module.ts @@ -65,12 +65,30 @@ export default defineNuxtModule({ .map(link => parse(String(link.href))) ) + // construct google fonts url - const url = constructURL(merge(options, ...fontsParsed)) + const resultArray = Object.entries(merge(options, ...fontsParsed).families!).map(([font, value]) => { + let currentOptions = options + if(value.text) { + currentOptions = { + ...currentOptions, + text: value.text + } + delete value.text + delete value.families + } + + return { + ...currentOptions, + families: { [font]: value }, + } + }); - if (!url) { - logger.warn('No provided fonts.') + const urls = resultArray.map((result) => constructURL(result)).filter((url) => url !== false) as string[]; + + if (!urls.length) { + logger.warn('No provided fonts.') return } @@ -80,8 +98,10 @@ export default defineNuxtModule({ // download if (options.download) { const outputDir = await resolvePath(options.outputDir) + const outputFonts: string[] = [] try { + for (const url of urls) { const downloader = download(url, { base64: options.base64, overwriting: options.overwriting, @@ -91,7 +111,6 @@ export default defineNuxtModule({ fontsPath: options.fontsPath }) - const outputFonts: string[] = [] downloader.hook('download-css:done', (url) => { logger.success(url) @@ -110,6 +129,8 @@ export default defineNuxtModule({ await downloader.execute() logger.success('Download fonts completed.') logger.log('') + } + if (options.inject) { nuxt.options.css.push(resolve(outputDir, options.stylePath)) @@ -121,7 +142,7 @@ export default defineNuxtModule({ nuxt.options.nitro.publicAssets.push({ dir: outputDir }) } catch (e) { logger.error(e) - } + } return } @@ -158,6 +179,8 @@ export default defineNuxtModule({ // https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types/preload // optionally increase loading priority if (options.preload) { + for (const url of urls) { + head.link.push({ key: 'gf-preload', rel: 'preload', @@ -165,59 +188,64 @@ export default defineNuxtModule({ href: url }) } + } // append CSS if (options.useStylesheet) { + for (const url of urls) { head.link.push({ key: 'gf-style', rel: 'stylesheet', href: url }) - + } return } if (isNuxt2()) { // JS to inject CSS - head.script.push({ + for (const url of urls) { + head.script.push({ + key: 'gf-script', + innerHTML: `(function(){var l=document.createElement('link');l.rel="stylesheet";l.href="${url}";document.querySelector("head").appendChild(l);})();` + }) + + // no-JS fallback + head.noscript.push({ + key: 'gf-noscript', + innerHTML: ``, + tagPosition: 'bodyOpen' + }) + + // Disable sanitazions + // @ts-ignore + head.__dangerouslyDisableSanitizersByTagID = head.__dangerouslyDisableSanitizersByTagID || {} + // @ts-ignore + head.__dangerouslyDisableSanitizersByTagID['gf-script'] = ['innerHTML'] + // @ts-ignore + head.__dangerouslyDisableSanitizersByTagID['gf-noscript'] = ['innerHTML'] + } + return + } + + // JS to inject CSS + for(const url of urls) { + head.script.unshift({ key: 'gf-script', - innerHTML: `(function(){var l=document.createElement('link');l.rel="stylesheet";l.href="${url}";document.querySelector("head").appendChild(l);})();` + children: `(function(){ + var h=document.querySelector("head"); + var m=h.querySelector('meta[name="head:count"]'); + if(m){m.setAttribute('content',Number(m.getAttribute('content'))+1);} + else{m=document.createElement('meta');m.setAttribute('name','head:count');m.setAttribute('content','1');h.append(m);} + var l=document.createElement('link');l.rel='stylesheet';l.href='${url}';h.appendChild(l); + })();` }) // no-JS fallback head.noscript.push({ - key: 'gf-noscript', - innerHTML: ``, + children: ``, tagPosition: 'bodyOpen' }) - - // Disable sanitazions - // @ts-ignore - head.__dangerouslyDisableSanitizersByTagID = head.__dangerouslyDisableSanitizersByTagID || {} - // @ts-ignore - head.__dangerouslyDisableSanitizersByTagID['gf-script'] = ['innerHTML'] - // @ts-ignore - head.__dangerouslyDisableSanitizersByTagID['gf-noscript'] = ['innerHTML'] - - return } - - // JS to inject CSS - head.script.unshift({ - key: 'gf-script', - children: `(function(){ - var h=document.querySelector("head"); - var m=h.querySelector('meta[name="head:count"]'); - if(m){m.setAttribute('content',Number(m.getAttribute('content'))+1);} - else{m=document.createElement('meta');m.setAttribute('name','head:count');m.setAttribute('content','1');h.append(m);} - var l=document.createElement('link');l.rel='stylesheet';l.href='${url}';h.appendChild(l); - })();` - }) - - // no-JS fallback - head.noscript.push({ - children: ``, - tagPosition: 'bodyOpen' - }) } }) From dfc1c4927b5fb4c2e808e047565cbbe9bbe3a0d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Jeli=CC=81nek?= Date: Sat, 5 Aug 2023 16:08:34 +0200 Subject: [PATCH 2/4] WIP code style --- src/module.ts | 104 +++++++++++++++++++++++++------------------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/src/module.ts b/src/module.ts index f82b429..9b9071b 100644 --- a/src/module.ts +++ b/src/module.ts @@ -41,7 +41,7 @@ export default defineNuxtModule({ fontsDir: 'fonts', fontsPath: '../fonts' }, - async setup (options, nuxt) { + async setup(options, nuxt) { // If user hasn't set the display value manually and isn't using // a preload, set the default display value to 'swap' if (options.display === undefined && !options.preload) { @@ -69,7 +69,7 @@ export default defineNuxtModule({ // construct google fonts url const resultArray = Object.entries(merge(options, ...fontsParsed).families!).map(([font, value]) => { let currentOptions = options - if(value.text) { + if (value.text) { currentOptions = { ...currentOptions, text: value.text @@ -77,16 +77,16 @@ export default defineNuxtModule({ delete value.text delete value.families } - + return { - ...currentOptions, - families: { [font]: value }, - } - }); + ...currentOptions, + families: { [font]: value }, + } + }); const urls = resultArray.map((result) => constructURL(result)).filter((url) => url !== false) as string[]; - + if (!urls.length) { logger.warn('No provided fonts.') return @@ -101,35 +101,35 @@ export default defineNuxtModule({ const outputFonts: string[] = [] try { - for (const url of urls) { - const downloader = download(url, { - base64: options.base64, - overwriting: options.overwriting, - outputDir, - stylePath: options.stylePath, - fontsDir: options.fontsDir, - fontsPath: options.fontsPath - }) - - - downloader.hook('download-css:done', (url) => { - logger.success(url) - }) - - downloader.hook('download-font:done', (font) => { - const fontName = font.outputFont.replace(`-${font.outputFont.replace(/.*-/, '')}`, '') - - if (!outputFonts.includes(fontName)) { - outputFonts.push(fontName) - logger.info(fontName) - } - }) - - logger.start('Downloading fonts...') - await downloader.execute() - logger.success('Download fonts completed.') - logger.log('') - } + for (const url of urls) { + const downloader = download(url, { + base64: options.base64, + overwriting: options.overwriting, + outputDir, + stylePath: options.stylePath, + fontsDir: options.fontsDir, + fontsPath: options.fontsPath + }) + + + downloader.hook('download-css:done', (url) => { + logger.success(url) + }) + + downloader.hook('download-font:done', (font) => { + const fontName = font.outputFont.replace(`-${font.outputFont.replace(/.*-/, '')}`, '') + + if (!outputFonts.includes(fontName)) { + outputFonts.push(fontName) + logger.info(fontName) + } + }) + + logger.start('Downloading fonts...') + await downloader.execute() + logger.success('Download fonts completed.') + logger.log('') + } if (options.inject) { @@ -142,7 +142,7 @@ export default defineNuxtModule({ nuxt.options.nitro.publicAssets.push({ dir: outputDir }) } catch (e) { logger.error(e) - } + } return } @@ -181,24 +181,24 @@ export default defineNuxtModule({ if (options.preload) { for (const url of urls) { - head.link.push({ - key: 'gf-preload', - rel: 'preload', - as: 'style', - href: url - }) - } + head.link.push({ + key: 'gf-preload', + rel: 'preload', + as: 'style', + href: url + }) + } } // append CSS if (options.useStylesheet) { for (const url of urls) { - head.link.push({ - key: 'gf-style', - rel: 'stylesheet', - href: url - }) - } + head.link.push({ + key: 'gf-style', + rel: 'stylesheet', + href: url + }) + } return } @@ -229,7 +229,7 @@ export default defineNuxtModule({ } // JS to inject CSS - for(const url of urls) { + for (const url of urls) { head.script.unshift({ key: 'gf-script', children: `(function(){ From da5072f905e502bf19d58ddb7e1947a099856e60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Jeli=CC=81nek?= Date: Sat, 5 Aug 2023 16:16:23 +0200 Subject: [PATCH 3/4] WIP renamed array --- src/module.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/module.ts b/src/module.ts index 9b9071b..42869da 100644 --- a/src/module.ts +++ b/src/module.ts @@ -67,7 +67,7 @@ export default defineNuxtModule({ // construct google fonts url - const resultArray = Object.entries(merge(options, ...fontsParsed).families!).map(([font, value]) => { + const fontOptionsList = Object.entries(merge(options, ...fontsParsed).families!).map(([font, value]) => { let currentOptions = options if (value.text) { currentOptions = { @@ -85,7 +85,7 @@ export default defineNuxtModule({ }); - const urls = resultArray.map((result) => constructURL(result)).filter((url) => url !== false) as string[]; + const urls = fontOptionsList.map((result) => constructURL(result)).filter((url) => url !== false) as string[]; if (!urls.length) { logger.warn('No provided fonts.') From 34c1c63f6b7e040c9c27b5f25acc601badfcba20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Jeli=CC=81nek?= Date: Sat, 5 Aug 2023 16:38:45 +0200 Subject: [PATCH 4/4] removed useless delete and fixed typings --- src/module.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/module.ts b/src/module.ts index 42869da..6ae8586 100644 --- a/src/module.ts +++ b/src/module.ts @@ -1,10 +1,11 @@ import { resolve } from 'pathe' import type { MetaObject } from '@nuxt/schema' import { defineNuxtModule, isNuxt2, resolvePath, useLogger } from '@nuxt/kit' -import { constructURL, download, isValidURL, parse, merge, DownloadOptions, GoogleFonts } from 'google-fonts-helper' +import { constructURL, download, isValidURL, parse, merge, DownloadOptions, GoogleFonts, FamilyWeight, FamilyStyles } from 'google-fonts-helper' import { name, version } from '../package.json' type NuxtAppHead = Required +type FamilyStylesExtended = FamilyStyles & { text?: string } export interface ModuleOptions extends DownloadOptions, GoogleFonts { prefetch?: boolean @@ -67,15 +68,15 @@ export default defineNuxtModule({ // construct google fonts url - const fontOptionsList = Object.entries(merge(options, ...fontsParsed).families!).map(([font, value]) => { + const fontOptionsList = Object.entries(merge(options, ...fontsParsed).families!).map(([font, value]: [string, FamilyStylesExtended|FamilyWeight] ) => { let currentOptions = options - if (value.text) { + if (typeof value === 'object' && !Array.isArray(value) && value.text) { + value currentOptions = { ...currentOptions, text: value.text } delete value.text - delete value.families } return {