Skip to content

Commit 7ce48ee

Browse files
author
Adrian Bece
committed
New modes & refactor
1 parent ffc1692 commit 7ce48ee

20 files changed

+159
-102
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules

.npmignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.gitignore

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
The MIT License (MIT)
22

3-
Copyright (c) 2020 Adrian Bece
3+
Copyright (c) 2021 Adrian Bece
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

README.md

Lines changed: 46 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,19 @@
22
<img src="https://res.cloudinary.com/dazdt97d3/image/upload/c_scale,q_auto:best,w_200/v1606558223/omni-logo.jpg" alt="Omni font loader logo">
33
<br/><br/>
44
<h1>Gatsby Omni Font Loader</h1>
5+
</div>
56

6-
Performant asynchronous font loading & Flash Of Unstyled Text (FOUT) handling plugin for Gatsby.
7+
* Simple way to add webfonts or custom fonts to Gatsby project
8+
* Performant asynchronous font loading can be enabled
9+
* Font loading listener can be enabled
10+
* Flash Of Unstyled Text (FOUT) handling support
711

12+
<div align="center">
813
<br/>
9-
<img src="https://badgen.net/github/tag/codeAdrian/gatsby-omni-font-loader" />
10-
&nbsp;
11-
<img src="https://badgen.net/npm/dt/gatsby-omni-font-loader" />
12-
&nbsp;
13-
<img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg" />
14+
<img src="https://badgen.net/github/tag/codeAdrian/gatsby-omni-font-loader" /> <img src="https://badgen.net/npm/dt/gatsby-omni-font-loader" /> <img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg" />
1415
<br/><br/>
1516

16-
<img src="https://badgen.net/github/stars/codeAdrian/gatsby-omni-font-loader" />
17-
&nbsp;
18-
<img src="https://badgen.net/github/open-issues/codeAdrian/gatsby-omni-font-loader" />
19-
&nbsp;
20-
<img src="https://badgen.net/github/closed-issues/codeAdrian/gatsby-omni-font-loader" />
21-
&nbsp;
22-
<img src="https://badgen.net/github/last-commit/codeAdrian/gatsby-omni-font-loader/main" />
23-
&nbsp;
24-
<img src="https://badgen.net/github/license/codeAdrian/gatsby-omni-font-loader" />
25-
&nbsp;
26-
<img src="https://badgen.net/packagephobia/install/gatsby-omni-font-loader" />
17+
<img src="https://badgen.net/github/stars/codeAdrian/gatsby-omni-font-loader" /> <img src="https://badgen.net/github/open-issues/codeAdrian/gatsby-omni-font-loader" /> <img src="https://badgen.net/github/closed-issues/codeAdrian/gatsby-omni-font-loader" /> <img src="https://badgen.net/github/last-commit/codeAdrian/gatsby-omni-font-loader/main" /> <img src="https://badgen.net/github/license/codeAdrian/gatsby-omni-font-loader" /> <img src="https://badgen.net/packagephobia/install/gatsby-omni-font-loader" />
2718
</div>
2819
<br/><br/>
2920

@@ -56,6 +47,9 @@ Add the following snippet to `gatsby-config.js` plugins array.
5647
/* Plugin options */
5748
options: {
5849

50+
/* Font loading mode */
51+
mode: "async",
52+
5953
/* Enable font loading listener to handle FOUT */
6054
enableListener: true,
6155

@@ -101,24 +95,24 @@ Add the following snippet to `gatsby-config.js` plugins array.
10195
</tr>
10296
</thead>
10397
<tbody>
98+
<tr>
99+
</tr>
100+
<td>mode</td>
101+
<td>Can be set to `"async"` (default) or `"render-blocking"`. In `async` mode, fonts are loaded in optimal way, but FOUT is visible. In `render-blocking` mode FOUT will happen in rare cases, but the font files will become render-blocking.</td>
102+
<td>async</td>
104103
<tr>
105104
<td>enableListener</td>
106-
<td>Enable font loading listener to handle Flash Of Unstyled Text. If enabled, CSS classes will be applied to HTML once each font has finished loading.</td>
105+
<td>Works in `async` mode. Enable font loading listener to handle Flash Of Unstyled Text. If enabled, CSS classes will be applied to HTML once each font has finished loading.</td>
107106
<td>false</td>
108107
</tr>
109-
<tr>
110-
<td>preconnect</td>
111-
<td>URLs used for preconnect meta. Base URL where <strong>font files</strong> are hosted.</td>
112-
<td>[]</td>
113-
</tr>
114108
<tr>
115109
<td>interval</td>
116-
<td>Font listener interval (in ms). Default is 300ms. Recommended: >=300ms. </td>
110+
<td>Works if `enableListener` is `true`. Font listener interval (in ms). Default is 300ms. Recommended: >=300ms. </td>
117111
<td>300</td>
118112
</tr>
119113
<tr>
120114
<td>timeout</td>
121-
<td>Font listener timeout value (in ms). Default is 30s (30000ms). Listener will no longer check for loaded fonts after timeout, fonts will still be loaded and displayed, but without handling FOUT.</td>
115+
<td>Works if `enableListener` is `true`. Font listener timeout value (in ms). Default is 30s (30000ms). Listener will no longer check for loaded fonts after timeout, fonts will still be loaded and displayed, but without handling FOUT.</td>
122116
<td>30000</td>
123117
</tr>
124118
<tr>
@@ -131,9 +125,36 @@ Add the following snippet to `gatsby-config.js` plugins array.
131125
<td>Web fonts config. File link should point to font CSS file. Array of <code>{name: "Font name", file: "https://url-to-font-css.path"}</code> objects.</td>
132126
<td>[]</td>
133127
</tr>
128+
<tr>
129+
<td>preconnect</td>
130+
<td>URLs used for preconnect meta. Base URL where <strong>font files</strong> are hosted.</td>
131+
<td>[]</td>
132+
</tr>
133+
<tr>
134+
<td>preload</td>
135+
<td>Additional URLs used for preload meta. Preload for URLs provided under `file` attribute of `custom` and `web` fonts are automatically generated.</td>
136+
<td>[]</td>
137+
</tr>
134138
<tbody>
135139
</table>
136140

141+
## Async mode vs Render-blocking mode
142+
### Async mode
143+
Load font stylesheets and files in low-priority mode. If you want to add fonts in a performant way, handle FOUT on your own and make sure that the page render times are low, you should use `async` mode.
144+
145+
__Pros:__ Performance, content is displayed before font files are downloaded and parsed
146+
<br/>
147+
__Cons:__ FOUT needs to be handled
148+
149+
### Render-blocking mode
150+
Load font stylesheets and files in high-priority mode. If you want to use this plugin as a simple way to add fonts to your project as you would do in any other project, without any performance optimizations and FOUT handling, you should use `render-blocking` mode.
151+
152+
__Pros:__ Simple markup, FOUT won't occur in most cases
153+
<br/>
154+
__Cons:__ Font stylesheets and font files can delay first content paint time
155+
156+
157+
137158
## Handling FOUT with Font loading listener
138159

139160
When loading fonts asynchronously, Flash Of Unstyled Text (FOUT) might happen because fonts load few moments later after page is displayed to the user.

components/FontListener.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ declare var document: { fonts: any }
66

77
interface Props {
88
fontNames: string[]
9-
interval?: number
10-
timeout?: number
9+
interval: number
10+
timeout: number
1111
}
1212

1313
export const FontListener: React.FC<Props> = ({
1414
fontNames,
15-
interval = 300,
16-
timeout = 30000,
15+
interval,
16+
timeout,
1717
}) => {
1818
const [hasLoaded, setHasLoaded] = useState<Boolean>(false)
1919
const [loadedFonts, setLoadedFonts] = useState<string[]>([])

consts/defaults.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export const INTERVAL_DEFAULT = 300
2+
3+
export const TIMEOUT_DEFAULT = 30000
4+
5+
export const MODE_DEFAULT = "async"

consts/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from "./defaults"

gatsby-browser.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,23 @@
11
import React from "react"
22
import { AsyncFonts, FontListener } from "./components"
3+
import { INTERVAL_DEFAULT, MODE_DEFAULT, TIMEOUT_DEFAULT } from "./consts"
34
import { getFontFiles, getFontNames } from "./utils"
45

56
export const wrapRootElement = (
67
{ element },
7-
{ custom = [], web = [], enableListener, interval, timeout }
8+
{
9+
custom = [],
10+
web = [],
11+
enableListener,
12+
interval = INTERVAL_DEFAULT,
13+
timeout = TIMEOUT_DEFAULT,
14+
mode = MODE_DEFAULT,
15+
}
816
) => {
17+
if (mode !== "async") {
18+
return element
19+
}
20+
921
const allFonts = [...custom, ...web]
1022
const fontFiles = getFontFiles(allFonts)
1123
const fontNames = getFontNames(allFonts)

gatsby-ssr.js

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,34 @@
1-
import {
2-
getFontConfig,
3-
getFontFiles,
4-
getFontNames,
5-
getTestFonts,
6-
} from "./utils"
1+
import { MODE_DEFAULT } from "./consts"
2+
import { getFontConfig, getTestFonts } from "./generators"
3+
import { getFontFiles, getFontNames } from "./utils"
74

85
export const onRenderBody = (
96
{ setHeadComponents, setPostBodyComponents },
10-
{ enableListener, preconnect = [], web = [], custom = [] }
7+
{
8+
enableListener,
9+
preconnect = [],
10+
preload = [],
11+
web = [],
12+
custom = [],
13+
mode = MODE_DEFAULT,
14+
}
1115
) => {
1216
const allFonts = [...web, ...custom]
13-
const preload = getFontFiles(allFonts)
17+
const allPreloads = preload.concat(getFontFiles(allFonts))
1418
const fontNames = getFontNames(allFonts)
1519

16-
const preloadConfig = getFontConfig(preconnect, preload)
20+
const preloadConfig = getFontConfig(
21+
preconnect,
22+
allPreloads,
23+
mode === "async" ? [] : allFonts
24+
)
1725

18-
if (enableListener && Boolean(allFonts.length)) {
26+
if (enableListener && Boolean(allFonts.length) && mode === "async") {
1927
const testFontConfig = getTestFonts(fontNames)
2028
setPostBodyComponents(testFontConfig)
2129
}
2230

23-
if(preloadConfig && Boolean(preloadConfig.length)) {
31+
if (preloadConfig && Boolean(preloadConfig.length)) {
2432
setHeadComponents(preloadConfig)
2533
}
2634
}

generators/getFontConfig.tsx

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import React from "react"
2+
import { arrayCheck, kebabCase } from "../utils"
3+
4+
export const getFontConfig = (
5+
preconnectConfig: string[],
6+
preloadConfig: string[],
7+
renderBlockingFonts?: { name: string | string[]; file: string }[]
8+
) => {
9+
const headComponents = []
10+
11+
if (arrayCheck(preconnectConfig)) {
12+
preconnectConfig.forEach(href => {
13+
headComponents.push(
14+
<link
15+
key={`preconnect-${href}`}
16+
rel="preconnect"
17+
href={href}
18+
crossOrigin="true"
19+
/>
20+
)
21+
})
22+
}
23+
24+
if (arrayCheck(preloadConfig)) {
25+
preloadConfig.forEach(href => {
26+
headComponents.push(
27+
<link key={`preload-${href}`} rel="preload" as="style" href={href} />
28+
)
29+
})
30+
}
31+
32+
if (arrayCheck(renderBlockingFonts)) {
33+
renderBlockingFonts.forEach(({ name, file }) => {
34+
const key = Array.isArray(name)
35+
? name.map(n => kebabCase(n)).join("-")
36+
: kebabCase(name)
37+
headComponents.push(
38+
<link key={`render-blocking-${key}`} href={file} rel="stylesheet" />
39+
)
40+
})
41+
}
42+
43+
return headComponents
44+
}
File renamed without changes.

generators/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from "./getFontConfig"
2+
export * from "./getTestFonts"

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,6 @@
2828
},
2929
"peerDependencies": {
3030
"gatsby": ">=1",
31-
"react-helmet": "^6.1.0"
31+
"react-helmet": ">=6.0.0"
3232
}
3333
}

utils/arrayCheck.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export const arrayCheck = (arr?: unknown) =>
2+
arr && Array.isArray(arr) && Boolean(arr.length)

utils/getFontConfig.tsx

Lines changed: 0 additions & 39 deletions
This file was deleted.

utils/getFontFiles.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export const getFontFiles = (allFonts: { file: string }[]) =>
2+
allFonts.map(({ file }) => file)

utils/getFontNames.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export const getFontNames = (allFonts: { name: string }[]) => {
2+
const fontNames = []
3+
allFonts.forEach(({ name }) =>
4+
Array.isArray(name) ? fontNames.push(...name) : fontNames.push(name)
5+
)
6+
return fontNames
7+
}

utils/index.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1-
export * from "./getFontConfig"
2-
export * from "./getTestFonts"
3-
export * from "./utils"
1+
export * from "./arrayCheck"
2+
export * from "./kebabCase"
3+
export * from "./getFontFiles"
4+
export * from "./getFontNames"

utils/kebabCase.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export const kebabCase = (str: string) =>
2+
str
3+
.match(/[A-Z]{2,}(?=[A-Z][a-z0-9]*|\b)|[A-Z]?[a-z0-9]*|[A-Z]|[0-9]+/g)
4+
.filter(Boolean)
5+
.map(x => x.toLowerCase())
6+
.join("-")

utils/utils.ts

Lines changed: 0 additions & 17 deletions
This file was deleted.

0 commit comments

Comments
 (0)