Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Include individual text values for each font #149

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions playground/nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@ export default defineNuxtConfig({
],
googleFonts: {
families: {
Roboto: true,
Roboto: {
wght: [100, 400],
text: 'Roboto'
},
Mulish: true
}
},
text: 'Hello World'
}
})
181 changes: 105 additions & 76 deletions src/module.ts
Original file line number Diff line number Diff line change
@@ -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<MetaObject>
type FamilyStylesExtended = FamilyStyles & { text?: string }

export interface ModuleOptions extends DownloadOptions, GoogleFonts {
prefetch?: boolean
Expand Down Expand Up @@ -41,7 +42,7 @@ export default defineNuxtModule<ModuleOptions>({
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) {
Expand All @@ -65,12 +66,30 @@ export default defineNuxtModule<ModuleOptions>({
.map(link => parse(String(link.href)))
)


// construct google fonts url
const url = constructURL(merge(options, ...fontsParsed))
const fontOptionsList = Object.entries(merge(options, ...fontsParsed).families!).map(([font, value]: [string, FamilyStylesExtended|FamilyWeight] ) => {
let currentOptions = options
if (typeof value === 'object' && !Array.isArray(value) && value.text) {
value
currentOptions = {
...currentOptions,
text: value.text
}
delete value.text
}

if (!url) {
logger.warn('No provided fonts.')
return {
...currentOptions,
families: { [font]: value },
}
});


const urls = fontOptionsList.map((result) => constructURL(result)).filter((url) => url !== false) as string[];

if (!urls.length) {
logger.warn('No provided fonts.')
return
}

Expand All @@ -80,36 +99,39 @@ export default defineNuxtModule<ModuleOptions>({
// download
if (options.download) {
const outputDir = await resolvePath(options.outputDir)
const outputFonts: string[] = []

try {
const downloader = download(url, {
base64: options.base64,
overwriting: options.overwriting,
outputDir,
stylePath: options.stylePath,
fontsDir: options.fontsDir,
fontsPath: options.fontsPath
})

const outputFonts: string[] = []

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)
}
})
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...')
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add outside for

await downloader.execute()
logger.success('Download fonts completed.')
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add outside for

logger.log('')
}

logger.start('Downloading fonts...')
await downloader.execute()
logger.success('Download fonts completed.')
logger.log('')

if (options.inject) {
nuxt.options.css.push(resolve(outputDir, options.stylePath))
Expand Down Expand Up @@ -158,66 +180,73 @@ export default defineNuxtModule<ModuleOptions>({
// https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types/preload
// optionally increase loading priority
if (options.preload) {
head.link.push({
key: 'gf-preload',
rel: 'preload',
as: 'style',
href: url
})
for (const url of urls) {

head.link.push({
key: 'gf-preload',
rel: 'preload',
as: 'style',
href: url
})
}
}

// append CSS
if (options.useStylesheet) {
head.link.push({
key: 'gf-style',
rel: 'stylesheet',
href: url
})

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);})();`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe create a script to create the stylesheet.
In case of several url this script will be duplicated.

})

// no-JS fallback
head.noscript.push({
key: 'gf-noscript',
innerHTML: `<link rel="stylesheet" href="${url}">`,
tagPosition: 'bodyOpen'
})

// Disable sanitazions
// @ts-ignore
head.__dangerouslyDisableSanitizersByTagID = head.__dangerouslyDisableSanitizersByTagID || {}
// @ts-ignore
head.__dangerouslyDisableSanitizersByTagID['gf-script'] = ['innerHTML']
// @ts-ignore
head.__dangerouslyDisableSanitizersByTagID['gf-noscript'] = ['innerHTML']
Comment on lines +221 to +227
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add outside for

}
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);
})();`
Comment on lines +236 to +242
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe create a script to create the stylesheet.
In case of several url this script will be duplicated.

})

// no-JS fallback
head.noscript.push({
key: 'gf-noscript',
innerHTML: `<link rel="stylesheet" href="${url}">`,
children: `<link rel="stylesheet" href="${url}">`,
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: `<link rel="stylesheet" href="${url}">`,
tagPosition: 'bodyOpen'
})
}
})