1
1
import { HtmlTagDescriptor , ResolvedConfig } from 'vite'
2
- import { sync as glob } from 'glob'
3
- import { chain as _ } from 'lodash'
2
+ import { sync as glob } from 'fast-glob'
4
3
5
4
type CustomFontFace = {
6
5
src : string [ ]
7
- name ? : string
8
- weight ? : number | string
9
- style ? : string
10
- display ? : 'auto' | 'block' | 'swap' | 'fallback' | 'optional'
6
+ name : string
7
+ weight : number | string
8
+ style : string
9
+ display : 'auto' | 'block' | 'swap' | 'fallback' | 'optional'
11
10
local ?: string | string [ ]
12
11
}
13
12
@@ -96,37 +95,30 @@ const resolveStyle = (styleOrSrc?: string) => {
96
95
return 'normal'
97
96
}
98
97
99
- const createFontFaceCSS = ( options : CustomFontFace ) => {
98
+ const createFontFaceCSS = ( { name , src , local , weight , style , display } : CustomFontFace ) => {
100
99
// --- Format sources.
101
- const srcs = _ ( options . src )
102
- . castArray ( )
100
+ const srcs = ( Array . isArray ( src ) ? src : [ src ] )
103
101
. filter ( Boolean )
104
102
. map ( ( url ) => {
105
103
let format = url . split ( '.' ) . pop ( )
106
104
if ( format === 'ttf' ) format = 'truetype'
107
105
return `url('${ url } ') format('${ format } ')`
108
106
} )
109
107
. join ( ',\n\t\t' )
110
- . value ( )
111
108
112
109
// --- Format local.
113
- const local = _ ( options . local )
114
- . castArray ( )
110
+ const locals = ( Array . isArray ( local ) ? local : [ local ] )
115
111
. filter ( Boolean )
116
112
. map ( x => `local('${ x } ')` )
117
113
. join ( ', ' )
118
- . value ( )
119
-
120
- // --- Merge local and sources.
121
- const src = [ srcs , local ] . filter ( Boolean ) . join ( ', ' )
122
114
123
115
// --- Return CSS rule as string.
124
116
return `@font-face {
125
- font-family: '${ options . name } ';
126
- src: ${ src } ;
127
- font-weight: ${ resolveWeight ( options . weight || srcs ) } ;
128
- font-style: ${ resolveStyle ( options . style ?? srcs ) } ;
129
- font-display: ${ options . display ?? 'auto' } ;
117
+ font-family: '${ name } ';
118
+ src: ${ [ srcs , locals ] . filter ( Boolean ) . join ( ',' ) } ;
119
+ font-weight: ${ weight } ;
120
+ font-style: ${ style } ;
121
+ font-display: ${ display } ;
130
122
}`
131
123
}
132
124
@@ -158,37 +150,39 @@ export default (options: CustomFonts, config: ResolvedConfig) => {
158
150
159
151
// --- Cast as array of `CustomFontFamily`.
160
152
if ( ! Array . isArray ( families ) ) {
161
- families = _ ( families )
162
- . map ( ( family , name ) => ( Array . isArray ( family ) || typeof family === 'string' )
153
+ families = Object . entries ( families )
154
+ . map ( ( [ name , family ] ) => ( Array . isArray ( family ) || typeof family === 'string' )
163
155
? { name, src : family }
164
156
: { name, ...family } ,
165
157
)
166
- . value ( )
167
158
}
168
159
169
160
// --- Iterate over font families and their faces.
170
161
for ( const { name, src, local } of families ) {
162
+ const facesGrouped : Record < string , string [ ] > = { } ;
163
+
171
164
// --- Resolve glob(s) and group faces with the same name.
172
- const faces = _ ( src )
173
- . castArray ( )
174
- . map ( x => glob ( x , { nodir : true , root : config . root , absolute : true } ) )
175
- . flatten ( )
176
- . groupBy ( x => x . match ( / ( .* ) \. ( \w | \d ) + $ / ) ?. [ 1 ] . toLowerCase ( ) )
165
+ ( Array . isArray ( src ) ? src : [ src ] )
166
+ . flatMap ( x => glob ( x , { absolute : true , cwd : config . root , onlyFiles : true } ) )
177
167
. filter ( Boolean )
178
- . map ( src => ( {
168
+ . forEach ( ( src ) => {
169
+ const srcNoExt = src . match ( / ( .* ) \. ( \w | \d ) + $ / ) ?. [ 1 ] . toLowerCase ( )
170
+ if ( srcNoExt ) facesGrouped [ srcNoExt ] = ( facesGrouped [ srcNoExt ] ?? [ ] ) . concat ( src )
171
+ } )
172
+
173
+ const faces = Object . entries ( facesGrouped )
174
+ . map ( ( [ srcNoExt , src ] ) => ( {
179
175
name,
180
176
src,
181
- weight : resolveWeight ( src [ 0 ] ) ,
182
- style : resolveStyle ( src [ 0 ] ) ,
177
+ weight : resolveWeight ( srcNoExt ) ,
178
+ style : resolveStyle ( srcNoExt ) ,
183
179
display,
184
180
local,
185
181
} ) )
186
- . value ( )
187
182
188
- const hrefs = _ ( faces )
183
+ const hrefs = faces
189
184
. flatMap ( face => face . src )
190
185
. map ( src => src . replace ( config . root , '.' ) )
191
- . value ( )
192
186
193
187
// --- Generate `<link>` tags.
194
188
if ( preload ) tags . push ( ...hrefs . map ( createFontFaceLink ) )
@@ -197,6 +191,11 @@ export default (options: CustomFonts, config: ResolvedConfig) => {
197
191
for ( const face of faces ) css . push ( createFontFaceCSS ( face ) )
198
192
}
199
193
194
+ console . log ( {
195
+ tags,
196
+ css : css . join ( '\n\n' ) ,
197
+ } )
198
+
200
199
// --- Return tags and CSS.
201
200
return {
202
201
tags,
0 commit comments