如何正确预加载文件名经过哈希处理且样式位于 CDN 中的字体?
How to correctly preload a font whose filename is hashed, and whose style is in a CDN?
我想预加载 Material 图标字体感谢:
<link rel="preload" href="https://fonts.gstatic.com/s/materialicons/v125/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2" as="font" type="font/woff2" crossorigin="anonymous">
事实上,它有效!
然而,在文件名中,我们有一个hash/UUID:v125/flUhRq6tzZclQEJ-Vdg-IuiaDsNc
;因此,如果 Google 发布了一个新版本,例如 v126/sjboabchdiamblq-Abf-abvichef
,那么我的预加载将不起作用!
有关更多详细信息,我使用他们的 CDN 是这样的:
<link
href="https://fonts.googleapis.com/icon?family=Material+Icons"
rel="stylesheet"
/>
哪个returns这个CSS:
@font-face {
font-family: 'Material Icons';
font-style: normal;
font-weight: 400;
src: url(https://fonts.gstatic.com/s/materialicons/v125/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2) format('woff2');
}
.material-icons {
font-family: 'Material Icons';
[...]
}
注意:我正在使用 Angular,我希望立即开始加载字体,而不是在加载应用程序时开始,即当 Material 图标为 [=28] 时=],即使 CSS 文件立即加载,字体也不会开始加载,直到显示 Material 图标。
我找到了解决方案,感谢 https://www.npmjs.com/package/@angular-builders/custom-webpack, and using a library for mMaterial Icons (https://www.npmjs.com/package/material-icons)
此构建器允许在构建过程后转换 index.html。
- 在 index.html 中添加经典预加载(在开发中有效)
<link rel="preload" href="/material-icons.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="preload" href="/material-icons-outlined.woff2" as="font" type="font/woff2" crossorigin="anonymous">
- 像这样在 angular.json 中添加
"indexTransform": "index-html-transform.js"
:
"configurations": {
"production": {
[...],
"indexTransform": "index-html-transform.js"
}
}
- 创建index-html-transform.js:
const fs = require("fs");
/**
* @param {string} indexHtmlSource
* @return {string}
*/
const setMaterialIconsFontsPreloading = (indexHtmlSource) => {
const allOutputFilenames = fs.readdirSync("./dist/essai-preload-mat-icons");
const requiredMatIconsFontsMatches = indexHtmlSource.matchAll(/(material-icons.*)\.woff2/g);
/**
* @exemple `['material-icons', 'material-icons-outlined']`
*/
const requiredIconTypes = [...requiredMatIconsFontsMatches].map((match) => match[1]);
return requiredIconTypes.reduce((previousIndexHtml, requiredIconType) => {
/**
* @exemple `'material-icons-outlined.woff2'`
*/
const inputFilename = `${requiredIconType}.woff2`;
/**
* @exemple `'material-icons-outlined.125af8545b6.woff2'`
*/
const outputFilename = allOutputFilenames.find((outputFilenameItem) => outputFilenameItem.match(`^${requiredIconType}\.\w+\.woff2$`));
return previousIndexHtml.replace(inputFilename, outputFilename);
}, indexHtmlSource);
}
/**
*
* @param {{ configuration?: string; project: string; target: string;}} targetOptions
* @param {string} indexHtmlSource
* @returns {string} The final index.html to serve.
*/
module.exports = (targetOptions, indexHtmlSource) => {
return setMaterialIconsFontsPreloading(indexHtmlSource);
};
我想预加载 Material 图标字体感谢:
<link rel="preload" href="https://fonts.gstatic.com/s/materialicons/v125/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2" as="font" type="font/woff2" crossorigin="anonymous">
事实上,它有效!
然而,在文件名中,我们有一个hash/UUID:v125/flUhRq6tzZclQEJ-Vdg-IuiaDsNc
;因此,如果 Google 发布了一个新版本,例如 v126/sjboabchdiamblq-Abf-abvichef
,那么我的预加载将不起作用!
有关更多详细信息,我使用他们的 CDN 是这样的:
<link
href="https://fonts.googleapis.com/icon?family=Material+Icons"
rel="stylesheet"
/>
哪个returns这个CSS:
@font-face {
font-family: 'Material Icons';
font-style: normal;
font-weight: 400;
src: url(https://fonts.gstatic.com/s/materialicons/v125/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2) format('woff2');
}
.material-icons {
font-family: 'Material Icons';
[...]
}
注意:我正在使用 Angular,我希望立即开始加载字体,而不是在加载应用程序时开始,即当 Material 图标为 [=28] 时=],即使 CSS 文件立即加载,字体也不会开始加载,直到显示 Material 图标。
我找到了解决方案,感谢 https://www.npmjs.com/package/@angular-builders/custom-webpack, and using a library for mMaterial Icons (https://www.npmjs.com/package/material-icons)
此构建器允许在构建过程后转换 index.html。
- 在 index.html 中添加经典预加载(在开发中有效)
<link rel="preload" href="/material-icons.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="preload" href="/material-icons-outlined.woff2" as="font" type="font/woff2" crossorigin="anonymous">
- 像这样在 angular.json 中添加
"indexTransform": "index-html-transform.js"
:
"configurations": {
"production": {
[...],
"indexTransform": "index-html-transform.js"
}
}
- 创建index-html-transform.js:
const fs = require("fs");
/**
* @param {string} indexHtmlSource
* @return {string}
*/
const setMaterialIconsFontsPreloading = (indexHtmlSource) => {
const allOutputFilenames = fs.readdirSync("./dist/essai-preload-mat-icons");
const requiredMatIconsFontsMatches = indexHtmlSource.matchAll(/(material-icons.*)\.woff2/g);
/**
* @exemple `['material-icons', 'material-icons-outlined']`
*/
const requiredIconTypes = [...requiredMatIconsFontsMatches].map((match) => match[1]);
return requiredIconTypes.reduce((previousIndexHtml, requiredIconType) => {
/**
* @exemple `'material-icons-outlined.woff2'`
*/
const inputFilename = `${requiredIconType}.woff2`;
/**
* @exemple `'material-icons-outlined.125af8545b6.woff2'`
*/
const outputFilename = allOutputFilenames.find((outputFilenameItem) => outputFilenameItem.match(`^${requiredIconType}\.\w+\.woff2$`));
return previousIndexHtml.replace(inputFilename, outputFilename);
}, indexHtmlSource);
}
/**
*
* @param {{ configuration?: string; project: string; target: string;}} targetOptions
* @param {string} indexHtmlSource
* @returns {string} The final index.html to serve.
*/
module.exports = (targetOptions, indexHtmlSource) => {
return setMaterialIconsFontsPreloading(indexHtmlSource);
};