299f392d7b
Adds support for generating a fallback font by providing font override metrics for the given local font. Also adds support for providing a CSS variable name that then can be accessed through the `.variable` export, it contains the hashed font family name. ## Bug - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Errors have a helpful link attached, see `contributing.md` ## Feature - [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Documentation added - [ ] Telemetry added. In case of a feature if it's used or not. - [ ] Errors have a helpful link attached, see `contributing.md` ## Documentation / Examples - [ ] Make sure the linting passes by running `pnpm lint` - [ ] The "examples guidelines" are followed from [our contributing doc](https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md) Co-authored-by: JJ Kasper <jj@jjsweb.site>
107 lines
3.2 KiB
TypeScript
107 lines
3.2 KiB
TypeScript
import type { FontLoader } from '../../../../font'
|
|
|
|
import path from 'path'
|
|
import loaderUtils from 'next/dist/compiled/loader-utils3'
|
|
import postcssFontLoaderPlugn from './postcss-font-loader'
|
|
import { promisify } from 'util'
|
|
import chalk from 'next/dist/compiled/chalk'
|
|
|
|
export default async function nextFontLoader(this: any) {
|
|
const fontLoaderSpan = this.currentTraceSpan.traceChild('next-font-loader')
|
|
return fontLoaderSpan.traceAsyncFn(async () => {
|
|
const callback = this.async()
|
|
const {
|
|
isServer,
|
|
assetPrefix,
|
|
fontLoaderOptions,
|
|
postcss: getPostcss,
|
|
} = this.getOptions()
|
|
|
|
const emitFontFile = (content: Buffer, ext: string, preload: boolean) => {
|
|
const opts = { context: this.rootContext, content }
|
|
const interpolatedName = loaderUtils.interpolateName(
|
|
this,
|
|
// Font files ending with .p.(woff|woff2|eot|ttf|otf) are preloaded
|
|
`static/media/[hash]${preload ? '.p' : ''}.${ext}`,
|
|
opts
|
|
)
|
|
const outputPath = `${assetPrefix}/_next/${interpolatedName}`
|
|
if (!isServer) {
|
|
this.emitFile(interpolatedName, content, null)
|
|
}
|
|
return outputPath
|
|
}
|
|
|
|
// next-swc next_font_loaders turns each function call argument into JSON seperated by semicolons
|
|
let [relativeFilePathFromRoot, functionName, ...data] = this.resourceQuery
|
|
.slice(1)
|
|
.split(';')
|
|
data = data.map((value: string) => JSON.parse(value))
|
|
|
|
try {
|
|
const fontLoader: FontLoader = require(path.join(
|
|
this.resourcePath,
|
|
'../loader.js'
|
|
)).default
|
|
let { css, fallbackFonts, adjustFontFallback, weight, style, variable } =
|
|
await fontLoader({
|
|
functionName,
|
|
data,
|
|
config: fontLoaderOptions,
|
|
emitFontFile,
|
|
resolve: (src: string) =>
|
|
promisify(this.resolve)(
|
|
path.dirname(
|
|
path.join(this.rootContext, relativeFilePathFromRoot)
|
|
),
|
|
src
|
|
),
|
|
fs: this.fs,
|
|
})
|
|
|
|
const { postcss } = await getPostcss()
|
|
|
|
// Exports will be exported as is from css-loader instead of a CSS module export
|
|
const exports: { name: any; value: any }[] = []
|
|
const fontFamilyHash = loaderUtils.getHashDigest(
|
|
Buffer.from(css),
|
|
'md5',
|
|
'hex',
|
|
6
|
|
)
|
|
// Add CSS classes, exports and make the font-family localy scoped by turning it unguessable
|
|
const result = await postcss(
|
|
postcssFontLoaderPlugn({
|
|
exports,
|
|
fontFamilyHash,
|
|
fallbackFonts,
|
|
weight,
|
|
style,
|
|
adjustFontFallback,
|
|
variable,
|
|
})
|
|
).process(css, {
|
|
from: undefined,
|
|
})
|
|
|
|
// Reuse ast in css-loader
|
|
const ast = {
|
|
type: 'postcss',
|
|
version: result.processor.version,
|
|
root: result.root,
|
|
}
|
|
callback(null, result.css, null, {
|
|
exports,
|
|
ast,
|
|
fontFamilyHash,
|
|
})
|
|
} catch (err: any) {
|
|
err.stack = false
|
|
err.message = `Font loader error:\n${err.message}`
|
|
err.message += `
|
|
|
|
${chalk.cyan(`Location: ${relativeFilePathFromRoot}`)}`
|
|
callback(err)
|
|
}
|
|
})
|
|
}
|