-
Notifications
You must be signed in to change notification settings - Fork 27.4k
/
Copy pathindex.ts
151 lines (138 loc) · 4.79 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import type { FontLoader } from '../../../../../font'
import path from 'path'
import chalk from 'next/dist/compiled/chalk'
import loaderUtils from 'next/dist/compiled/loader-utils3'
import postcssNextFontPlugin from './postcss-next-font'
import { promisify } from 'util'
export default async function nextFontLoader(this: any) {
const nextFontLoaderSpan =
this.currentTraceSpan.traceChild('next-font-loader')
return nextFontLoaderSpan.traceAsyncFn(async () => {
const callback = this.async()
/**
* The next-swc plugin next-transform-font turns font function calls into CSS imports.
* At the end of the import, it adds the call arguments and some additional data as a resourceQuery.
* e.g:
* const inter = Inter({ subset: ['latin'] })
* ->
* import inter from 'next/font/google/target.css?{"import":"Inter","subsets":["latin"]}'
*
* Here we parse the resourceQuery to get the font function name, call arguments, and the path to the file that called the font function.
*/
const {
path: relativeFilePathFromRoot,
import: functionName,
arguments: data,
variableName,
} = JSON.parse(this.resourceQuery.slice(1))
// Throw error if @next/font is used in _document.js
if (/pages[\\/]_document\./.test(relativeFilePathFromRoot)) {
const err = new Error(
`${chalk.bold('Cannot')} be used within ${chalk.cyan(
'pages/_document.js'
)}.`
)
err.name = 'NextFontError'
callback(err)
return
}
const {
isDev,
isServer,
assetPrefix,
fontLoaderPath,
postcss: getPostcss,
} = this.getOptions()
/**
* Emit font files to .next/static/media as [hash].[ext].
*
* If the font should be preloaded, add .p to the filename: [hash].p.[ext]
* NextFontManifestPlugin adds these files to the next/font manifest.
*
* If the font is using a size-adjust fallback font, add -s to the filename: [hash]-s.[ext]
* NextFontManifestPlugin uses this to see if fallback fonts are being used.
* This is used to collect stats on fallback fonts usage by the Google Aurora team.
*/
const emitFontFile = (
content: Buffer,
ext: string,
preload: boolean,
isUsingSizeAdjust?: boolean
) => {
const opts = { context: this.rootContext, content }
const interpolatedName = loaderUtils.interpolateName(
this,
`static/media/[hash]${isUsingSizeAdjust ? '-s' : ''}${
preload ? '.p' : ''
}.${ext}`,
opts
)
const outputPath = `${assetPrefix}/_next/${interpolatedName}`
// Only the client emits the font file
if (!isServer) {
this.emitFile(interpolatedName, content, null)
}
// But both the server and client must get the resulting path
return outputPath
}
try {
// Import the font loader function from either next/font/local or next/font/google
// The font loader function emits font files and returns @font-faces and fallback font metrics
const fontLoader: FontLoader = require(fontLoaderPath).default
let { css, fallbackFonts, adjustFontFallback, weight, style, variable } =
await fontLoader({
functionName,
variableName,
data,
emitFontFile,
resolve: (src: string) =>
promisify(this.resolve)(
path.dirname(
path.join(this.rootContext, relativeFilePathFromRoot)
),
src.startsWith('.') ? src : `./${src}`
),
isDev,
isServer,
loaderContext: this,
})
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 }[] = []
// Generate a hash from the CSS content. Used to generate classnames and font families
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(
postcssNextFontPlugin({
exports,
fontFamilyHash,
fallbackFonts,
weight,
style,
adjustFontFallback,
variable,
})
).process(css, {
from: undefined,
})
const ast = {
type: 'postcss',
version: result.processor.version,
root: result.root,
}
// Return the resulting CSS and send the postcss ast, font exports and the hash to the css-loader in the meta argument.
callback(null, result.css, null, {
exports,
ast,
fontFamilyHash,
})
} catch (err: any) {
callback(err)
}
})
}