182 lines
8.3 KiB
JavaScript
182 lines
8.3 KiB
JavaScript
|
|
"use strict";
|
||
|
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||
|
|
if (k2 === undefined) k2 = k;
|
||
|
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||
|
|
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||
|
|
desc = { enumerable: true, get: function() { return m[k]; } };
|
||
|
|
}
|
||
|
|
Object.defineProperty(o, k2, desc);
|
||
|
|
}) : (function(o, m, k, k2) {
|
||
|
|
if (k2 === undefined) k2 = k;
|
||
|
|
o[k2] = m[k];
|
||
|
|
}));
|
||
|
|
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||
|
|
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||
|
|
}) : function(o, v) {
|
||
|
|
o["default"] = v;
|
||
|
|
});
|
||
|
|
var __importStar = (this && this.__importStar) || function (mod) {
|
||
|
|
if (mod && mod.__esModule) return mod;
|
||
|
|
var result = {};
|
||
|
|
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||
|
|
__setModuleDefault(result, mod);
|
||
|
|
return result;
|
||
|
|
};
|
||
|
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||
|
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||
|
|
};
|
||
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||
|
|
// @ts-ignore
|
||
|
|
const font_utils_1 = require("next/dist/server/font-utils");
|
||
|
|
// @ts-ignore
|
||
|
|
const Log = __importStar(require("next/dist/build/output/log"));
|
||
|
|
// @ts-ignore
|
||
|
|
const chalk_1 = __importDefault(require("next/dist/compiled/chalk"));
|
||
|
|
const utils_1 = require("./utils");
|
||
|
|
const utils_2 = require("../utils");
|
||
|
|
const cssCache = new Map();
|
||
|
|
const fontCache = new Map();
|
||
|
|
// regexp is based on https://github.com/sindresorhus/escape-string-regexp
|
||
|
|
const reHasRegExp = /[|\\{}()[\]^$+*?.-]/;
|
||
|
|
const reReplaceRegExp = /[|\\{}()[\]^$+*?.-]/g;
|
||
|
|
function escapeStringRegexp(str) {
|
||
|
|
// see also: https://github.com/lodash/lodash/blob/2da024c3b4f9947a48517639de7560457cd4ec6c/escapeRegExp.js#L23
|
||
|
|
if (reHasRegExp.test(str)) {
|
||
|
|
return str.replace(reReplaceRegExp, '\\$&');
|
||
|
|
}
|
||
|
|
return str;
|
||
|
|
}
|
||
|
|
const downloadGoogleFonts = async ({ functionName, data, config, emitFontFile, isDev, isServer, loaderContext, }) => {
|
||
|
|
var _a, _b, _c;
|
||
|
|
const subsets = (config === null || config === void 0 ? void 0 : config.subsets) || [];
|
||
|
|
const { fontFamily, weights, styles, display, preload, selectedVariableAxes, fallback, adjustFontFallback, variable, subsets: callSubsets, } = (0, utils_1.validateData)(functionName, data);
|
||
|
|
if (isServer && preload && !callSubsets && !(config === null || config === void 0 ? void 0 : config.subsets)) {
|
||
|
|
Log.warn(`The ${chalk_1.default.bold('@next/font/google')} font ${chalk_1.default.bold(fontFamily)} has no selected subsets. Please specify subsets in the function call or in your ${chalk_1.default.bold('next.config.js')}, otherwise no fonts will be preloaded. Read more: https://nextjs.org/docs/messages/google-fonts-missing-subsets`);
|
||
|
|
}
|
||
|
|
const fontAxes = (0, utils_1.getFontAxes)(fontFamily, weights, styles, selectedVariableAxes);
|
||
|
|
const url = (0, utils_1.getUrl)(fontFamily, fontAxes, display);
|
||
|
|
// Find fallback font metrics
|
||
|
|
let adjustFontFallbackMetrics;
|
||
|
|
if (adjustFontFallback) {
|
||
|
|
try {
|
||
|
|
const { ascent, descent, lineGap, fallbackFont, sizeAdjust } = (0, font_utils_1.calculateSizeAdjustValues)(require('next/dist/server/google-font-metrics.json')[fontFamily]);
|
||
|
|
adjustFontFallbackMetrics = {
|
||
|
|
fallbackFont,
|
||
|
|
ascentOverride: `${ascent}%`,
|
||
|
|
descentOverride: `${descent}%`,
|
||
|
|
lineGapOverride: `${lineGap}%`,
|
||
|
|
sizeAdjust: `${sizeAdjust}%`,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
catch {
|
||
|
|
Log.error(`Failed to find font override values for font \`${fontFamily}\``);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
const result = {
|
||
|
|
fallbackFonts: fallback,
|
||
|
|
weight: weights.length === 1 && weights[0] !== 'variable'
|
||
|
|
? weights[0]
|
||
|
|
: undefined,
|
||
|
|
style: styles.length === 1 ? styles[0] : undefined,
|
||
|
|
variable,
|
||
|
|
adjustFontFallback: adjustFontFallbackMetrics,
|
||
|
|
};
|
||
|
|
try {
|
||
|
|
const hasCachedCSS = cssCache.has(url);
|
||
|
|
let fontFaceDeclarations = hasCachedCSS
|
||
|
|
? cssCache.get(url)
|
||
|
|
: await (0, utils_1.fetchCSSFromGoogleFonts)(url, fontFamily).catch(() => null);
|
||
|
|
if (!hasCachedCSS) {
|
||
|
|
cssCache.set(url, fontFaceDeclarations);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
cssCache.delete(url);
|
||
|
|
}
|
||
|
|
if (fontFaceDeclarations === null) {
|
||
|
|
(0, utils_2.nextFontError)(`Failed to fetch \`${fontFamily}\` from Google Fonts.`);
|
||
|
|
}
|
||
|
|
// CSS Variables may be set on a body tag, ignore them to keep the CSS module pure
|
||
|
|
fontFaceDeclarations = fontFaceDeclarations.split('body {')[0];
|
||
|
|
// Find font files to download
|
||
|
|
const fontFiles = [];
|
||
|
|
let currentSubset = '';
|
||
|
|
for (const line of fontFaceDeclarations.split('\n')) {
|
||
|
|
// Each @font-face has the subset above it in a comment
|
||
|
|
const newSubset = (_a = /\/\* (.+?) \*\//.exec(line)) === null || _a === void 0 ? void 0 : _a[1];
|
||
|
|
if (newSubset) {
|
||
|
|
currentSubset = newSubset;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
const googleFontFileUrl = (_b = /src: url\((.+?)\)/.exec(line)) === null || _b === void 0 ? void 0 : _b[1];
|
||
|
|
if (googleFontFileUrl &&
|
||
|
|
!fontFiles.some((foundFile) => foundFile.googleFontFileUrl === googleFontFileUrl)) {
|
||
|
|
fontFiles.push({
|
||
|
|
googleFontFileUrl,
|
||
|
|
preloadFontFile: !!preload && (callSubsets !== null && callSubsets !== void 0 ? callSubsets : subsets).includes(currentSubset),
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// Download font files
|
||
|
|
const downloadedFiles = await Promise.all(fontFiles.map(async ({ googleFontFileUrl, preloadFontFile }) => {
|
||
|
|
const hasCachedFont = fontCache.has(googleFontFileUrl);
|
||
|
|
const fontFileBuffer = hasCachedFont
|
||
|
|
? fontCache.get(googleFontFileUrl)
|
||
|
|
: await (0, utils_1.fetchFontFile)(googleFontFileUrl).catch(() => null);
|
||
|
|
if (!hasCachedFont) {
|
||
|
|
fontCache.set(googleFontFileUrl, fontFileBuffer);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
fontCache.delete(googleFontFileUrl);
|
||
|
|
}
|
||
|
|
if (fontFileBuffer === null) {
|
||
|
|
(0, utils_2.nextFontError)(`Failed to fetch \`${fontFamily}\` from Google Fonts.`);
|
||
|
|
}
|
||
|
|
const ext = /\.(woff|woff2|eot|ttf|otf)$/.exec(googleFontFileUrl)[1];
|
||
|
|
// Emit font file to .next/static/media
|
||
|
|
const selfHostedFileUrl = emitFontFile(fontFileBuffer, ext, preloadFontFile);
|
||
|
|
return {
|
||
|
|
googleFontFileUrl,
|
||
|
|
selfHostedFileUrl,
|
||
|
|
};
|
||
|
|
}));
|
||
|
|
// Replace @font-face sources with self-hosted files
|
||
|
|
let updatedCssResponse = fontFaceDeclarations;
|
||
|
|
for (const { googleFontFileUrl, selfHostedFileUrl } of downloadedFiles) {
|
||
|
|
updatedCssResponse = updatedCssResponse.replace(new RegExp(escapeStringRegexp(googleFontFileUrl), 'g'), selfHostedFileUrl);
|
||
|
|
}
|
||
|
|
return {
|
||
|
|
...result,
|
||
|
|
css: updatedCssResponse,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
catch (err) {
|
||
|
|
loaderContext.cacheable(false);
|
||
|
|
if (isDev) {
|
||
|
|
if (isServer) {
|
||
|
|
Log.error(`Failed to download \`${fontFamily}\` from Google Fonts. Using fallback font instead.`);
|
||
|
|
}
|
||
|
|
// In dev we should return the fallback font instead of throwing an error
|
||
|
|
let css = `@font-face {
|
||
|
|
font-family: '${fontFamily} Fallback';
|
||
|
|
src: local("${(_c = adjustFontFallbackMetrics === null || adjustFontFallbackMetrics === void 0 ? void 0 : adjustFontFallbackMetrics.fallbackFont) !== null && _c !== void 0 ? _c : 'Arial'}");`;
|
||
|
|
if (adjustFontFallbackMetrics) {
|
||
|
|
css += `
|
||
|
|
ascent-override:${adjustFontFallbackMetrics.ascentOverride};
|
||
|
|
descent-override:${adjustFontFallbackMetrics.descentOverride};
|
||
|
|
line-gap-override:${adjustFontFallbackMetrics.lineGapOverride};
|
||
|
|
size-adjust:${adjustFontFallbackMetrics.sizeAdjust};`;
|
||
|
|
}
|
||
|
|
css += '\n}';
|
||
|
|
return {
|
||
|
|
...result,
|
||
|
|
css,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
throw err;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
exports.default = downloadGoogleFonts;
|