|
1 | | -import type { FontFace as CSSFontFace, Declaration, Stylesheet } from 'css'; |
2 | | -// @ts-expect-error ignore |
3 | | -import parse from 'css/lib/parse'; |
| 1 | +import postcss from 'postcss'; |
4 | 2 | import { getFontURLs, getWoff2BaseURL } from '../renderer'; |
5 | 3 | import { |
6 | 4 | createElement, |
@@ -116,27 +114,36 @@ function collectUsedFonts(svg: SVGSVGElement) { |
116 | 114 | /** |
117 | 115 | * 解析给定 font-family 对应的 CSS @font-face |
118 | 116 | */ |
119 | | -export async function parseFontFamily(fontFamily: string) { |
| 117 | +async function parseFontFamily(fontFamily: string) { |
120 | 118 | const urls = getFontURLs(fontFamily); |
121 | | - |
122 | 119 | const fontFaces: Partial<FontFaceAttributes>[] = []; |
123 | 120 |
|
124 | 121 | await Promise.allSettled( |
125 | 122 | urls.map(async (url) => { |
126 | | - const css = await fetchWithCache(url) |
| 123 | + const cssText = await fetchWithCache(url) |
127 | 124 | .then((res) => res.text()) |
128 | | - .then((text) => parse(text) as Stylesheet) |
129 | 125 | .catch(() => { |
130 | | - console.error(`Failed to fetch or parse font CSS: ${url}`); |
| 126 | + console.error(`Failed to fetch font CSS: ${url}`); |
131 | 127 | return null; |
132 | 128 | }); |
133 | 129 |
|
134 | | - css?.stylesheet?.rules.forEach((rule) => { |
135 | | - if (rule.type === 'font-face') { |
136 | | - const fontFace = parseFontFace(rule as CSSFontFace); |
137 | | - fontFaces.push(fontFace); |
138 | | - } |
139 | | - }); |
| 130 | + if (!cssText) return; |
| 131 | + |
| 132 | + try { |
| 133 | + const root = postcss.parse(cssText); |
| 134 | + |
| 135 | + root.walkAtRules('font-face', (rule) => { |
| 136 | + const fontFace: Record<string, string> = {}; |
| 137 | + |
| 138 | + rule.walkDecls((decl) => { |
| 139 | + fontFace[decl.prop] = decl.value; |
| 140 | + }); |
| 141 | + |
| 142 | + fontFaces.push(fontFace as Partial<FontFaceAttributes>); |
| 143 | + }); |
| 144 | + } catch (error) { |
| 145 | + console.error(`Failed to parse CSS: ${url}`, error); |
| 146 | + } |
140 | 147 | }), |
141 | 148 | ); |
142 | 149 |
|
@@ -164,24 +171,6 @@ export function getActualLoadedFontFace(fontFamily: string) { |
164 | 171 | return fonts; |
165 | 172 | } |
166 | 173 |
|
167 | | -/** |
168 | | - * 从 css 的 FontFace 规则中提取声明 |
169 | | - */ |
170 | | -function parseFontFace(rule: CSSFontFace) { |
171 | | - const declarations = (rule.declarations || []) as Declaration[]; |
172 | | - const attrs: Record<string, string> = {}; |
173 | | - |
174 | | - declarations.forEach((declaration) => { |
175 | | - const { property, value } = declaration; |
176 | | - if (property && value) { |
177 | | - attrs[property] = value; |
178 | | - } |
179 | | - }); |
180 | | - |
181 | | - // 这里返回 Partial,后面统一 normalize |
182 | | - return attrs as Partial<FontFaceAttributes>; |
183 | | -} |
184 | | - |
185 | 174 | /** |
186 | 175 | * 将不完整的 FontFaceAttributes 补全为完整结构,给后续逻辑使用 |
187 | 176 | */ |
|
0 commit comments