fontaine 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -13
- package/dist/index.cjs +11 -11
- package/dist/index.mjs +10 -4
- package/package.json +9 -9
package/README.md
CHANGED
|
@@ -7,13 +7,11 @@
|
|
|
7
7
|
|
|
8
8
|
> Automatic font fallback based on font metrics
|
|
9
9
|
|
|
10
|
-
- [✨ Changelog](https://github.com/
|
|
11
|
-
- [▶️ Online playground](https://stackblitz.com/github/
|
|
10
|
+
- [✨ Changelog](https://github.com/unjs/fontaine/blob/main/CHANGELOG.md)
|
|
11
|
+
- [▶️ Online playground](https://stackblitz.com/github/unjs/fontaine/tree/main/playground)
|
|
12
12
|
|
|
13
13
|
## Features
|
|
14
14
|
|
|
15
|
-
**⚠️ `fontaine` is under active development. ⚠️**
|
|
16
|
-
|
|
17
15
|
- 💪 Reduces CLS by using local font fallbacks with crafted font metrics.
|
|
18
16
|
- ✨ Generates font metrics and overrides automatically.
|
|
19
17
|
- ⚡️ Pure CSS, zero runtime overhead.
|
|
@@ -51,7 +49,7 @@ yarn add -D fontaine
|
|
|
51
49
|
import { FontaineTransform } from 'fontaine'
|
|
52
50
|
|
|
53
51
|
const options = {
|
|
54
|
-
fallbacks: ['BlinkMacSystemFont', 'Segoe UI', '
|
|
52
|
+
fallbacks: ['BlinkMacSystemFont', 'Segoe UI', 'Helvetica Neue', 'Arial', 'Noto Sans'],
|
|
55
53
|
// You may need to resolve assets like `/fonts/Roboto.woff2` to a particular directory
|
|
56
54
|
resolvePath: (id) => 'file:///path/to/public/dir' + id,
|
|
57
55
|
}
|
|
@@ -89,9 +87,8 @@ export default {
|
|
|
89
87
|
/* This additional font-face declaration will be added to your CSS. */
|
|
90
88
|
@font-face {
|
|
91
89
|
font-family: 'Roboto override';
|
|
92
|
-
src: local('BlinkMacSystemFont'), local('Segoe UI'), local('
|
|
93
|
-
'
|
|
94
|
-
), local('Arial'), local('Noto Sans');
|
|
90
|
+
src: local('BlinkMacSystemFont'), local('Segoe UI'), local('Helvetica Neue'),
|
|
91
|
+
local('Arial'), local('Noto Sans');
|
|
95
92
|
ascent-override: 92.7734375%;
|
|
96
93
|
descent-override: 24.4140625%;
|
|
97
94
|
line-gap-override: 0%;
|
|
@@ -120,7 +117,8 @@ Then, whenever you use `font-family: 'Roboto'`, `fontaine` will add the override
|
|
|
120
117
|
This would not have been possible without:
|
|
121
118
|
|
|
122
119
|
- amazing tooling and generated metrics from [capsizecss](https://seek-oss.github.io/capsize/)
|
|
123
|
-
- suggestion and algorithm from [Katie Hempenius](https://katiehempenius.com/) & [Kara Erickson](https://github.com/kara) on the Google Aurora team - see [notes on calculating font metric overrides](https://docs.google.com/document/d/e/2PACX-1vRsazeNirATC7lIj2aErSHpK26hZ6dA9GsQ069GEbq5fyzXEhXbvByoftSfhG82aJXmrQ_sJCPBqcx_/pub)
|
|
120
|
+
- suggestion and algorithm from [Katie Hempenius](https://katiehempenius.com/) & [Kara Erickson](https://github.com/kara) on the Google Aurora team - see [notes on calculating font metric overrides](https://docs.google.com/document/d/e/2PACX-1vRsazeNirATC7lIj2aErSHpK26hZ6dA9GsQ069GEbq5fyzXEhXbvByoftSfhG82aJXmrQ_sJCPBqcx_/pub)
|
|
121
|
+
- package name suggestion from [**@clemcode**](https://github.com/clemcode)
|
|
124
122
|
|
|
125
123
|
## License
|
|
126
124
|
|
|
@@ -134,7 +132,7 @@ Published under [MIT License](./LICENCE).
|
|
|
134
132
|
[npm-version-href]: https://npmjs.com/package/fontaine
|
|
135
133
|
[npm-downloads-src]: https://img.shields.io/npm/dm/fontaine?style=flat-square
|
|
136
134
|
[npm-downloads-href]: https://npmjs.com/package/fontaine
|
|
137
|
-
[github-actions-src]: https://img.shields.io/github/workflow/status/
|
|
138
|
-
[github-actions-href]: https://github.com/
|
|
139
|
-
[codecov-src]: https://img.shields.io/codecov/c/gh/
|
|
140
|
-
[codecov-href]: https://codecov.io/gh/
|
|
135
|
+
[github-actions-src]: https://img.shields.io/github/workflow/status/unjs/fontaine/ci/main?style=flat-square
|
|
136
|
+
[github-actions-href]: https://github.com/unjs/fontaine/actions?query=workflow%3Aci
|
|
137
|
+
[codecov-src]: https://img.shields.io/codecov/c/gh/unjs/fontaine/main?style=flat-square
|
|
138
|
+
[codecov-href]: https://codecov.io/gh/unjs/fontaine
|
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
-
|
|
5
3
|
const unplugin = require('unplugin');
|
|
6
4
|
const magicRegexp = require('magic-regexp');
|
|
7
5
|
const MagicString = require('magic-string');
|
|
@@ -9,10 +7,7 @@ const node_url = require('node:url');
|
|
|
9
7
|
const unpack = require('@capsizecss/unpack');
|
|
10
8
|
const ufo = require('ufo');
|
|
11
9
|
const scule = require('scule');
|
|
12
|
-
|
|
13
|
-
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e["default"] : e; }
|
|
14
|
-
|
|
15
|
-
const MagicString__default = /*#__PURE__*/_interopDefaultLegacy(MagicString);
|
|
10
|
+
const pathe = require('pathe');
|
|
16
11
|
|
|
17
12
|
const parseFontFace = (css) => {
|
|
18
13
|
const fontFamily = css.match(FAMILY_RE)?.groups.fontFamily;
|
|
@@ -103,6 +98,11 @@ const FontaineTransform = unplugin.createUnplugin(
|
|
|
103
98
|
(options) => {
|
|
104
99
|
const cssContext = options.css = options.css || {};
|
|
105
100
|
cssContext.value = "";
|
|
101
|
+
options.resolvePath = options.resolvePath || ((id) => id);
|
|
102
|
+
function readMetricsFromId(path, importer) {
|
|
103
|
+
const resolvedPath = pathe.isAbsolute(importer) && path.startsWith(".") ? pathe.join(importer, path) : options.resolvePath(path);
|
|
104
|
+
return readMetrics(resolvedPath);
|
|
105
|
+
}
|
|
106
106
|
return {
|
|
107
107
|
name: "fontaine-transform",
|
|
108
108
|
enforce: "pre",
|
|
@@ -111,7 +111,7 @@ const FontaineTransform = unplugin.createUnplugin(
|
|
|
111
111
|
return pathname.endsWith(".css") || id.endsWith(".css");
|
|
112
112
|
},
|
|
113
113
|
async transform(code, id) {
|
|
114
|
-
const s = new
|
|
114
|
+
const s = new MagicString(code);
|
|
115
115
|
const faceRanges = [];
|
|
116
116
|
for (const match of code.matchAll(FONT_FACE_RE)) {
|
|
117
117
|
const matchContent = match[0];
|
|
@@ -121,9 +121,7 @@ const FontaineTransform = unplugin.createUnplugin(
|
|
|
121
121
|
const { family, source } = parseFontFace(matchContent);
|
|
122
122
|
if (!family)
|
|
123
123
|
continue;
|
|
124
|
-
const metrics = await getMetricsForFamily(family) ||
|
|
125
|
-
options.resolvePath ? options.resolvePath(source) : source
|
|
126
|
-
).catch(() => null) : null);
|
|
124
|
+
const metrics = await getMetricsForFamily(family) || source && await readMetricsFromId(source, id).catch(() => null);
|
|
127
125
|
if (metrics) {
|
|
128
126
|
const fontFace = generateFontFace(metrics, {
|
|
129
127
|
name: generateOverrideName(family),
|
|
@@ -139,7 +137,9 @@ const FontaineTransform = unplugin.createUnplugin(
|
|
|
139
137
|
continue;
|
|
140
138
|
if (faceRanges.some(([start, end]) => index > start && index < end))
|
|
141
139
|
continue;
|
|
142
|
-
const families = matchContent.split(",").map((f) => f.trim());
|
|
140
|
+
const families = matchContent.split(",").map((f) => f.trim()).filter((f) => !f.startsWith("var("));
|
|
141
|
+
if (!families.length)
|
|
142
|
+
continue;
|
|
143
143
|
s.overwrite(
|
|
144
144
|
index,
|
|
145
145
|
index + matchContent.length,
|
package/dist/index.mjs
CHANGED
|
@@ -5,6 +5,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
5
5
|
import { fromFile, fromUrl } from '@capsizecss/unpack';
|
|
6
6
|
import { parseURL } from 'ufo';
|
|
7
7
|
import { camelCase } from 'scule';
|
|
8
|
+
import { isAbsolute, join } from 'pathe';
|
|
8
9
|
|
|
9
10
|
const parseFontFace = (css) => {
|
|
10
11
|
const fontFamily = css.match(FAMILY_RE)?.groups.fontFamily;
|
|
@@ -95,6 +96,11 @@ const FontaineTransform = createUnplugin(
|
|
|
95
96
|
(options) => {
|
|
96
97
|
const cssContext = options.css = options.css || {};
|
|
97
98
|
cssContext.value = "";
|
|
99
|
+
options.resolvePath = options.resolvePath || ((id) => id);
|
|
100
|
+
function readMetricsFromId(path, importer) {
|
|
101
|
+
const resolvedPath = isAbsolute(importer) && path.startsWith(".") ? join(importer, path) : options.resolvePath(path);
|
|
102
|
+
return readMetrics(resolvedPath);
|
|
103
|
+
}
|
|
98
104
|
return {
|
|
99
105
|
name: "fontaine-transform",
|
|
100
106
|
enforce: "pre",
|
|
@@ -113,9 +119,7 @@ const FontaineTransform = createUnplugin(
|
|
|
113
119
|
const { family, source } = parseFontFace(matchContent);
|
|
114
120
|
if (!family)
|
|
115
121
|
continue;
|
|
116
|
-
const metrics = await getMetricsForFamily(family) ||
|
|
117
|
-
options.resolvePath ? options.resolvePath(source) : source
|
|
118
|
-
).catch(() => null) : null);
|
|
122
|
+
const metrics = await getMetricsForFamily(family) || source && await readMetricsFromId(source, id).catch(() => null);
|
|
119
123
|
if (metrics) {
|
|
120
124
|
const fontFace = generateFontFace(metrics, {
|
|
121
125
|
name: generateOverrideName(family),
|
|
@@ -131,7 +135,9 @@ const FontaineTransform = createUnplugin(
|
|
|
131
135
|
continue;
|
|
132
136
|
if (faceRanges.some(([start, end]) => index > start && index < end))
|
|
133
137
|
continue;
|
|
134
|
-
const families = matchContent.split(",").map((f) => f.trim());
|
|
138
|
+
const families = matchContent.split(",").map((f) => f.trim()).filter((f) => !f.startsWith("var("));
|
|
139
|
+
if (!families.length)
|
|
140
|
+
continue;
|
|
135
141
|
s.overwrite(
|
|
136
142
|
index,
|
|
137
143
|
index + matchContent.length,
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fontaine",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Automatic font fallback based on font metrics",
|
|
5
|
-
"repository": "
|
|
5
|
+
"repository": "unjs/fontaine",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"fonts",
|
|
8
8
|
"cls",
|
|
@@ -49,10 +49,10 @@
|
|
|
49
49
|
"@capsizecss/metrics": "^0.3.0",
|
|
50
50
|
"@capsizecss/unpack": "^0.1.0",
|
|
51
51
|
"magic-regexp": "^0.5.0",
|
|
52
|
-
"magic-string": "^0.26.
|
|
53
|
-
"pathe": "^0.3.
|
|
52
|
+
"magic-string": "^0.26.7",
|
|
53
|
+
"pathe": "^0.3.9",
|
|
54
54
|
"scule": "^0.3.2",
|
|
55
|
-
"ufo": "^0.8.
|
|
55
|
+
"ufo": "^0.8.6",
|
|
56
56
|
"unplugin": "^0.9.6"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
@@ -60,14 +60,14 @@
|
|
|
60
60
|
"@release-it/conventional-changelog": "latest",
|
|
61
61
|
"@types/node": "latest",
|
|
62
62
|
"@types/serve-handler": "^6.1.1",
|
|
63
|
-
"@
|
|
64
|
-
"
|
|
63
|
+
"@typescript-eslint/eslint-plugin": "^5.40.0",
|
|
64
|
+
"@typescript-eslint/parser": "^5.40.0",
|
|
65
|
+
"@vitest/coverage-c8": "^0.24.3",
|
|
65
66
|
"conventional-changelog-conventionalcommits": "latest",
|
|
66
67
|
"eslint": "latest",
|
|
67
68
|
"eslint-config-prettier": "latest",
|
|
68
69
|
"eslint-plugin-prettier": "latest",
|
|
69
70
|
"execa": "^6.1.0",
|
|
70
|
-
"expect-type": "latest",
|
|
71
71
|
"get-port-please": "^2.6.1",
|
|
72
72
|
"husky": "latest",
|
|
73
73
|
"lint-staged": "latest",
|
|
@@ -83,5 +83,5 @@
|
|
|
83
83
|
"resolutions": {
|
|
84
84
|
"fontaine": "link:."
|
|
85
85
|
},
|
|
86
|
-
"packageManager": "pnpm@7.
|
|
86
|
+
"packageManager": "pnpm@7.13.4"
|
|
87
87
|
}
|