From 5f7caf2765cc88e3f2fe62417e1b2828c96c4f47 Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Wed, 21 Sep 2022 10:50:28 +0200 Subject: [PATCH 01/76] v12.3.2-canary.0 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-config-next/package.json | 4 ++-- packages/eslint-plugin-next/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next-swc/package.json | 2 +- packages/next/package.json | 14 +++++++------- packages/react-dev-overlay/package.json | 2 +- packages/react-refresh-utils/package.json | 2 +- pnpm-lock.yaml | 14 +++++++------- 16 files changed, 29 insertions(+), 29 deletions(-) diff --git a/lerna.json b/lerna.json index 34bd0fd6ae494..258e54c72d1ac 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "12.3.1" + "version": "12.3.2-canary.0" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index 2e9cd6d4a4538..a7ab39f0a1820 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "12.3.1", + "version": "12.3.2-canary.0", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index 4757609169e5e..532fc3a72ca14 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "12.3.1", + "version": "12.3.2-canary.0", "description": "ESLint configuration used by NextJS.", "main": "index.js", "license": "MIT", @@ -9,7 +9,7 @@ "directory": "packages/eslint-config-next" }, "dependencies": { - "@next/eslint-plugin-next": "12.3.1", + "@next/eslint-plugin-next": "12.3.2-canary.0", "@rushstack/eslint-patch": "^1.1.3", "@typescript-eslint/parser": "^5.21.0", "eslint-import-resolver-node": "^0.3.6", diff --git a/packages/eslint-plugin-next/package.json b/packages/eslint-plugin-next/package.json index 043622086d7e8..801d903f99073 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "12.3.1", + "version": "12.3.2-canary.0", "description": "ESLint plugin for NextJS.", "main": "lib/index.js", "license": "MIT", diff --git a/packages/next-bundle-analyzer/package.json b/packages/next-bundle-analyzer/package.json index 0d8e54ecf68bd..72318cd3d97e2 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "12.3.1", + "version": "12.3.2-canary.0", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index b785bc248a393..b0c701219b952 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "12.3.1", + "version": "12.3.2-canary.0", "license": "MIT", "dependencies": { "chalk": "4.1.0", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index bdfa78165e98c..e38620f1710ce 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "12.3.1", + "version": "12.3.2-canary.0", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index 4f3494b43cdac..c0ea228acc6a3 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "12.3.1", + "version": "12.3.2-canary.0", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index 52916bd81e180..6009f7375f19b 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "12.3.1", + "version": "12.3.2-canary.0", "repository": { "url": "vercel/next.js", "directory": "packages/next-plugin-storybook" diff --git a/packages/next-polyfill-module/package.json b/packages/next-polyfill-module/package.json index 1edfe30cda574..b065aee308e64 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "12.3.1", + "version": "12.3.2-canary.0", "description": "A standard library polyfill for ES Modules supporting browsers (Edge 16+, Firefox 60+, Chrome 61+, Safari 10.1+)", "main": "dist/polyfill-module.js", "license": "MIT", diff --git a/packages/next-polyfill-nomodule/package.json b/packages/next-polyfill-nomodule/package.json index 4cde648288553..d1a32f050530e 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "12.3.1", + "version": "12.3.2-canary.0", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index 6c30933d68b1f..cad052d086abe 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "12.3.1", + "version": "12.3.2-canary.0", "private": true, "scripts": { "build-native": "napi build --platform -p next-swc-napi --cargo-name next_swc_napi native --features plugin", diff --git a/packages/next/package.json b/packages/next/package.json index 79c76b77cf1fc..543cb1ac2aed2 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "12.3.1", + "version": "12.3.2-canary.0", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -68,7 +68,7 @@ ] }, "dependencies": { - "@next/env": "12.3.1", + "@next/env": "12.3.2-canary.0", "@swc/helpers": "0.4.11", "caniuse-lite": "^1.0.30001406", "postcss": "8.4.14", @@ -119,11 +119,11 @@ "@hapi/accept": "5.0.2", "@napi-rs/cli": "2.7.0", "@napi-rs/triples": "1.1.0", - "@next/polyfill-module": "12.3.1", - "@next/polyfill-nomodule": "12.3.1", - "@next/react-dev-overlay": "12.3.1", - "@next/react-refresh-utils": "12.3.1", - "@next/swc": "12.3.1", + "@next/polyfill-module": "12.3.2-canary.0", + "@next/polyfill-nomodule": "12.3.2-canary.0", + "@next/react-dev-overlay": "12.3.2-canary.0", + "@next/react-refresh-utils": "12.3.2-canary.0", + "@next/swc": "12.3.2-canary.0", "@segment/ajv-human-errors": "2.1.2", "@taskr/clear": "1.1.0", "@taskr/esnext": "1.1.0", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index c83baa837d4b3..50fe5926156a2 100644 --- a/packages/react-dev-overlay/package.json +++ b/packages/react-dev-overlay/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-dev-overlay", - "version": "12.3.1", + "version": "12.3.2-canary.0", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index c1f20f24ec94a..907be4826daff 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "12.3.1", + "version": "12.3.2-canary.0", "description": "An experimental package providing utilities for React Refresh.", "repository": { "url": "vercel/next.js", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4da886576a755..aee0111858f5a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -367,7 +367,7 @@ importers: packages/eslint-config-next: specifiers: - '@next/eslint-plugin-next': 12.3.1 + '@next/eslint-plugin-next': 12.3.2-canary.0 '@rushstack/eslint-patch': ^1.1.3 '@typescript-eslint/parser': ^5.21.0 eslint-import-resolver-node: ^0.3.6 @@ -423,12 +423,12 @@ importers: '@hapi/accept': 5.0.2 '@napi-rs/cli': 2.7.0 '@napi-rs/triples': 1.1.0 - '@next/env': 12.3.1 - '@next/polyfill-module': 12.3.1 - '@next/polyfill-nomodule': 12.3.1 - '@next/react-dev-overlay': 12.3.1 - '@next/react-refresh-utils': 12.3.1 - '@next/swc': 12.3.1 + '@next/env': 12.3.2-canary.0 + '@next/polyfill-module': 12.3.2-canary.0 + '@next/polyfill-nomodule': 12.3.2-canary.0 + '@next/react-dev-overlay': 12.3.2-canary.0 + '@next/react-refresh-utils': 12.3.2-canary.0 + '@next/swc': 12.3.2-canary.0 '@segment/ajv-human-errors': 2.1.2 '@swc/helpers': 0.4.11 '@taskr/clear': 1.1.0 From 2b9afcfea3ce1f43833da26324b88693f2b11c8c Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Wed, 21 Sep 2022 15:47:31 +0200 Subject: [PATCH 02/76] Change flight querystring to header (#40752) --- .../client/components/app-router.client.tsx | 34 +++++---- packages/next/server/app-render.tsx | 26 +++++-- packages/next/server/base-server.ts | 2 +- packages/next/server/next-server.ts | 3 +- packages/next/server/web/adapter.ts | 19 +++-- packages/next/server/web/next-url.ts | 74 +------------------ test/e2e/app-dir/app/middleware.js | 2 +- test/e2e/app-dir/index.test.ts | 19 ++++- test/e2e/app-dir/rsc-basic.test.ts | 47 +++++++----- test/e2e/switchable-runtime/index.test.ts | 22 +++--- 10 files changed, 111 insertions(+), 137 deletions(-) diff --git a/packages/next/client/components/app-router.client.tsx b/packages/next/client/components/app-router.client.tsx index d788d719dda63..f933f4d1bb0b3 100644 --- a/packages/next/client/components/app-router.client.tsx +++ b/packages/next/client/components/app-router.client.tsx @@ -29,11 +29,9 @@ import { } from './hooks-client-context' import { useReducerWithReduxDevtools } from './use-reducer-with-devtools' -function urlToUrlWithoutFlightParameters(url: string): URL { +function urlToUrlWithoutFlightMarker(url: string): URL { const urlWithoutFlightParameters = new URL(url, location.origin) - urlWithoutFlightParameters.searchParams.delete('__flight__') - urlWithoutFlightParameters.searchParams.delete('__flight_router_state_tree__') - urlWithoutFlightParameters.searchParams.delete('__flight_prefetch__') + // TODO-APP: handle .rsc for static export case return urlWithoutFlightParameters } @@ -45,22 +43,26 @@ export async function fetchServerResponse( flightRouterState: FlightRouterState, prefetch?: true ): Promise<[FlightData: FlightData, canonicalUrlOverride: URL | undefined]> { - const flightUrl = new URL(url) - const searchParams = flightUrl.searchParams - // Enable flight response - searchParams.append('__flight__', '1') - // Provide the current router state - searchParams.append( - '__flight_router_state_tree__', - JSON.stringify(flightRouterState) - ) + const headers: { + __flight__: '1' + __flight_router_state_tree__: string + __flight_prefetch__?: '1' + } = { + // Enable flight response + __flight__: '1', + // Provide the current router state + __flight_router_state_tree__: JSON.stringify(flightRouterState), + } if (prefetch) { - searchParams.append('__flight_prefetch__', '1') + // Enable prefetch response + headers.__flight_prefetch__ = '1' } - const res = await fetch(flightUrl.toString()) + const res = await fetch(url.toString(), { + headers, + }) const canonicalUrl = res.redirected - ? urlToUrlWithoutFlightParameters(res.url) + ? urlToUrlWithoutFlightMarker(res.url) : undefined // Handle the `fetch` readable stream that can be unwrapped by `React.use`. diff --git a/packages/next/server/app-render.tsx b/packages/next/server/app-render.tsx index 8d47e3411cbab..12a87e12a84f6 100644 --- a/packages/next/server/app-render.tsx +++ b/packages/next/server/app-render.tsx @@ -1,4 +1,4 @@ -import type { IncomingMessage, ServerResponse } from 'http' +import type { IncomingHttpHeaders, IncomingMessage, ServerResponse } from 'http' import type { LoadComponentsReturnType } from './load-components' import type { ServerRuntime } from '../types' @@ -493,6 +493,20 @@ function getScriptNonceFromHeader(cspHeaderValue: string): string | undefined { return nonce } +const FLIGHT_PARAMETERS = [ + '__flight__', + '__flight_router_state_tree__', + '__flight_prefetch__', +] as const + +function headersWithoutFlight(headers: IncomingHttpHeaders) { + const newHeaders = { ...headers } + for (const param of FLIGHT_PARAMETERS) { + delete newHeaders[param] + } + return newHeaders +} + export async function renderToHTMLOrFlight( req: IncomingMessage, res: ServerResponse, @@ -545,8 +559,8 @@ export async function renderToHTMLOrFlight( ComponentMod, } = renderOpts - const isFlight = query.__flight__ !== undefined - const isPrefetch = query.__flight_prefetch__ !== undefined + const isFlight = req.headers.__flight__ !== undefined + const isPrefetch = req.headers.__flight_prefetch__ !== undefined // Handle client-side navigation to pages directory if (isFlight && isPagesDir) { @@ -569,8 +583,8 @@ export async function renderToHTMLOrFlight( * Router state provided from the client-side router. Used to handle rendering from the common layout down. */ const providedFlightRouterState: FlightRouterState = isFlight - ? query.__flight_router_state_tree__ - ? JSON.parse(query.__flight_router_state_tree__ as string) + ? req.headers.__flight_router_state_tree__ + ? JSON.parse(req.headers.__flight_router_state_tree__ as string) : {} : undefined @@ -584,7 +598,7 @@ export async function renderToHTMLOrFlight( | typeof import('../client/components/hot-reloader.client').default | null - const headers = req.headers + const headers = headersWithoutFlight(req.headers) // TODO-APP: fix type of req // @ts-expect-error const cookies = req.cookies diff --git a/packages/next/server/base-server.ts b/packages/next/server/base-server.ts index cccb74732abed..788aadf661377 100644 --- a/packages/next/server/base-server.ts +++ b/packages/next/server/base-server.ts @@ -1032,7 +1032,7 @@ export default abstract class Server { // Don't delete query.__flight__ yet, it still needs to be used in renderToHTML later const isFlightRequest = Boolean( - this.serverComponentManifest && query.__flight__ + this.serverComponentManifest && req.headers.__flight__ ) // we need to ensure the status code if /404 is visited directly diff --git a/packages/next/server/next-server.ts b/packages/next/server/next-server.ts index 4ca035f980095..57ca093018fba 100644 --- a/packages/next/server/next-server.ts +++ b/packages/next/server/next-server.ts @@ -825,7 +825,7 @@ export default class NextNodeServer extends BaseServer { if ( this.nextConfig.experimental.appDir && - (renderOpts.isAppPath || query.__flight__) + (renderOpts.isAppPath || req.headers.__flight__) ) { const isPagesDir = !renderOpts.isAppPath return appRenderToHTMLOrFlight( @@ -981,7 +981,6 @@ export default class NextNodeServer extends BaseServer { __nextDataReq: query.__nextDataReq, __nextLocale: query.__nextLocale, __nextDefaultLocale: query.__nextDefaultLocale, - __flight__: query.__flight__, } as NextParsedUrlQuery) : query), // For appDir params is excluded. diff --git a/packages/next/server/web/adapter.ts b/packages/next/server/web/adapter.ts index 0a03f3f8936c5..c808a2b02f823 100644 --- a/packages/next/server/web/adapter.ts +++ b/packages/next/server/web/adapter.ts @@ -35,6 +35,12 @@ class NextRequestHint extends NextRequest { } } +const FLIGHT_PARAMETERS = [ + '__flight__', + '__flight_router_state_tree__', + '__flight_prefetch__', +] as const + export async function adapter(params: { handler: NextMiddleware page: string @@ -58,11 +64,12 @@ export async function adapter(params: { requestUrl.pathname = '/' } - // Preserve flight data. - const flightSearchParameters = requestUrl.flightSearchParameters + const requestHeaders = fromNodeHeaders(params.request.headers) // Parameters should only be stripped for middleware if (!isEdgeRendering) { - requestUrl.flightSearchParameters = undefined + for (const param of FLIGHT_PARAMETERS) { + requestHeaders.delete(param) + } } // Strip internal query parameters off the request. @@ -74,7 +81,7 @@ export async function adapter(params: { init: { body: params.request.body, geo: params.request.geo, - headers: fromNodeHeaders(params.request.headers), + headers: requestHeaders, ip: params.request.ip, method: params.request.method, nextConfig: params.request.nextConfig, @@ -112,8 +119,6 @@ export async function adapter(params: { if (rewriteUrl.host === request.nextUrl.host) { rewriteUrl.buildId = buildId || rewriteUrl.buildId - rewriteUrl.flightSearchParameters = - flightSearchParameters || rewriteUrl.flightSearchParameters response.headers.set('x-middleware-rewrite', String(rewriteUrl)) } @@ -151,8 +156,6 @@ export async function adapter(params: { if (redirectURL.host === request.nextUrl.host) { redirectURL.buildId = buildId || redirectURL.buildId - redirectURL.flightSearchParameters = - flightSearchParameters || redirectURL.flightSearchParameters response.headers.set('Location', String(redirectURL)) } diff --git a/packages/next/server/web/next-url.ts b/packages/next/server/web/next-url.ts index 5f05ec8e8ddb8..9ed9fc34a4a2c 100644 --- a/packages/next/server/web/next-url.ts +++ b/packages/next/server/web/next-url.ts @@ -15,12 +15,6 @@ interface Options { } } -const FLIGHT_PARAMETERS = [ - '__flight__', - '__flight_router_state_tree__', - '__flight_prefetch__', -] as const - const REGEX_LOCALHOST_HOSTNAME = /(?!^https?:\/\/)(127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}|::1|localhost)/ @@ -31,28 +25,6 @@ function parseURL(url: string | URL, base?: string | URL) { ) } -function parseFlightParameters( - searchParams: URLSearchParams -): Record | undefined { - let flightSearchParameters: Record = {} - let flightSearchParametersUpdated = false - for (const name of FLIGHT_PARAMETERS) { - const value = searchParams.get(name) - if (value === null) { - continue - } - - flightSearchParameters[name] = value - flightSearchParametersUpdated = true - } - - if (!flightSearchParametersUpdated) { - return undefined - } - - return flightSearchParameters -} - const Internal = Symbol('NextURLInternal') export class NextURL { @@ -118,9 +90,6 @@ export class NextURL { this[Internal].buildId = pathnameInfo.buildId this[Internal].locale = pathnameInfo.locale ?? defaultLocale this[Internal].trailingSlash = pathnameInfo.trailingSlash - this[Internal].flightSearchParameters = parseFlightParameters( - this[Internal].url.searchParams - ) } private formatPathname() { @@ -137,22 +106,7 @@ export class NextURL { } private formatSearch() { - const flightSearchParameters = this[Internal].flightSearchParameters - // If no flight parameters are set, return the search string as is. - // This is a fast path to ensure URLSearchParams only has to be recreated on Flight requests. - if (!flightSearchParameters) { - return this[Internal].url.search - } - - // Create separate URLSearchParams to ensure the original search string is not modified. - const searchParams = new URLSearchParams(this[Internal].url.searchParams) - // If any exist this loop is always limited to the amount of FLIGHT_PARAMETERS. - for (const name in flightSearchParameters) { - searchParams.set(name, flightSearchParameters[name]) - } - - const params = searchParams.toString() - return params === '' ? '' : `?${params}` + return this[Internal].url.search } public get buildId() { @@ -163,32 +117,6 @@ export class NextURL { this[Internal].buildId = buildId } - public get flightSearchParameters() { - return this[Internal].flightSearchParameters - } - - public set flightSearchParameters( - flightSearchParams: Record | undefined - ) { - if (flightSearchParams) { - for (const name of FLIGHT_PARAMETERS) { - // Ensure only the provided values are set - if (flightSearchParams[name]) { - this[Internal].url.searchParams.set(name, flightSearchParams[name]) - } else { - // Delete the ones that are not provided as flightData should be overridden. - this[Internal].url.searchParams.delete(name) - } - } - } else { - for (const name of FLIGHT_PARAMETERS) { - this[Internal].url.searchParams.delete(name) - } - } - - this[Internal].flightSearchParameters = flightSearchParams - } - public get locale() { return this[Internal].locale ?? '' } diff --git a/test/e2e/app-dir/app/middleware.js b/test/e2e/app-dir/app/middleware.js index 4dfacac7fc684..8057bba59bfa1 100644 --- a/test/e2e/app-dir/app/middleware.js +++ b/test/e2e/app-dir/app/middleware.js @@ -20,7 +20,7 @@ export function middleware(request) { : 'redirect' const internal = ['__flight__', '__flight_router_state_tree__'] - if (internal.some((name) => request.nextUrl.searchParams.has(name))) { + if (internal.some((name) => request.headers.has(name))) { return NextResponse[method](new URL('/internal/failure', request.url)) } diff --git a/test/e2e/app-dir/index.test.ts b/test/e2e/app-dir/index.test.ts index 9dc1ef82d10b5..93bb4ed7ddeab 100644 --- a/test/e2e/app-dir/index.test.ts +++ b/test/e2e/app-dir/index.test.ts @@ -38,13 +38,28 @@ describe('app dir', () => { it('should use application/octet-stream for flight', async () => { const res = await fetchViaHTTP( next.url, - '/dashboard/deployments/123?__flight__' + '/dashboard/deployments/123', + {}, + { + headers: { + __flight__: '1', + }, + } ) expect(res.headers.get('Content-Type')).toBe('application/octet-stream') }) it('should use application/octet-stream for flight with edge runtime', async () => { - const res = await fetchViaHTTP(next.url, '/dashboard?__flight__') + const res = await fetchViaHTTP( + next.url, + '/dashboard', + {}, + { + headers: { + __flight__: '1', + }, + } + ) expect(res.headers.get('Content-Type')).toBe('application/octet-stream') }) diff --git a/test/e2e/app-dir/rsc-basic.test.ts b/test/e2e/app-dir/rsc-basic.test.ts index 4d5196ffcad32..95b2f3457717b 100644 --- a/test/e2e/app-dir/rsc-basic.test.ts +++ b/test/e2e/app-dir/rsc-basic.test.ts @@ -94,7 +94,8 @@ describe('app dir - react server components', () => { '__nextDefaultLocale', '__nextIsNotFound', '__flight__', - '__flight_router_path__', + '__flight_router_state_tree__', + '__flight_prefetch__', ] const hasNextInternalQuery = inlineFlightContents.some((content) => @@ -110,14 +111,15 @@ describe('app dir - react server components', () => { beforePageLoad(page) { page.on('request', (request) => { requestsCount++ - const url = request.url() - if ( - url.includes('__flight__=1') && - // Prefetches also include `__flight__` - !url.includes('__flight_prefetch__=1') - ) { - hasFlightRequest = true - } + return request.allHeaders().then((headers) => { + if ( + headers.__flight__ === '1' && + // Prefetches also include `__flight__` + headers.__flight_prefetch__ !== '1' + ) { + hasFlightRequest = true + } + }) }) }, }) @@ -215,14 +217,14 @@ describe('app dir - react server components', () => { const browser = await webdriver(next.url, '/root', { beforePageLoad(page) { page.on('request', (request) => { - const url = request.url() - if ( - url.includes('__flight__=1') && - // Prefetches also include `__flight__` - !url.includes('__flight_prefetch__=1') - ) { - hasFlightRequest = true - } + return request.allHeaders().then((headers) => { + if ( + headers.__flight__ === '1' && + headers.__flight_prefetch__ !== '1' + ) { + hasFlightRequest = true + } + }) }) }, }) @@ -336,7 +338,16 @@ describe('app dir - react server components', () => { }) it('should support streaming for flight response', async () => { - await fetchViaHTTP(next.url, '/?__flight__=1').then(async (response) => { + await fetchViaHTTP( + next.url, + '/', + {}, + { + headers: { + __flight__: '1', + }, + } + ).then(async (response) => { const result = await resolveStreamResponse(response) expect(result).toContain('component:index.server') }) diff --git a/test/e2e/switchable-runtime/index.test.ts b/test/e2e/switchable-runtime/index.test.ts index 774efac58a711..153cc5abde65f 100644 --- a/test/e2e/switchable-runtime/index.test.ts +++ b/test/e2e/switchable-runtime/index.test.ts @@ -119,10 +119,11 @@ describe('Switchable runtime', () => { const browser = await webdriver(context.appPort, '/node', { beforePageLoad(page) { page.on('request', (request) => { - const url = request.url() - if (/\?__flight__=1/.test(url)) { - flightRequest = url - } + return request.allHeaders().then((headers) => { + if (headers.__flight__ === '1') { + flightRequest = request.url() + } + }) }) }, }) @@ -136,7 +137,7 @@ describe('Switchable runtime', () => { () => browser.eval('document.documentElement.innerHTML'), /This is a SSR RSC page/ ) - expect(flightRequest).toContain('/node-rsc-ssr?__flight__=1') + expect(flightRequest).toContain('/node-rsc-ssr') }) it.skip('should support client side navigation to ssg rsc pages', async () => { @@ -678,10 +679,11 @@ describe('Switchable runtime', () => { const browser = await webdriver(context.appPort, '/node', { beforePageLoad(page) { page.on('request', (request) => { - const url = request.url() - if (/\?__flight__=1/.test(url)) { - flightRequest = url - } + request.allHeaders().then((headers) => { + if (headers.__flight__ === '1') { + flightRequest = request.url() + } + }) }) }, }) @@ -691,7 +693,7 @@ describe('Switchable runtime', () => { expect(await browser.elementByCss('body').text()).toContain( 'This is a SSR RSC page.' ) - expect(flightRequest).toContain('/node-rsc-ssr?__flight__=1') + expect(flightRequest).toContain('/node-rsc-ssr') }) it.skip('should support client side navigation to ssg rsc pages', async () => { From 244b629730352bea51f265413c6249aa4263fb75 Mon Sep 17 00:00:00 2001 From: Shu Ding Date: Wed, 21 Sep 2022 19:14:29 +0200 Subject: [PATCH 03/76] Skip copying next-swc debug files during testing (#40761) I have next-swc compiled locally inside the folder so there're a lot of files there (totally unexpected). And then the `fs.copy` takes 28433 ms... by filtering it out it's only 1s. ## 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) --- test/lib/create-next-install.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/lib/create-next-install.js b/test/lib/create-next-install.js index 5b4d5eedd513f..224cb1824ad0e 100644 --- a/test/lib/create-next-install.js +++ b/test/lib/create-next-install.js @@ -51,7 +51,8 @@ async function createNextInstall( !item.includes('node_modules') && !item.includes('.DS_Store') && // Exclude Rust compilation files - !/next[\\/]build[\\/]swc[\\/]target/.test(item) + !/next[\\/]build[\\/]swc[\\/]target/.test(item) && + !/next-swc[\\/]target/.test(item) ) }, }) From 51b728fbf490626062e4fff9c7483f73b2bec8d7 Mon Sep 17 00:00:00 2001 From: Rishabh Poddar Date: Wed, 21 Sep 2022 23:43:07 +0530 Subject: [PATCH 04/76] Updates with-supertokens example app (#40707) - Updates supertokens-node and supertokens-auth-react dependencies. - Uses separate Email verification recipe instead of using it inside the ThirdPartyEmailPassword recipe (as per the update) - Uses guard instead of guard (as per the lib update) --- .../with-supertokens/config/backendConfig.ts | 4 ++++ .../with-supertokens/config/frontendConfig.ts | 5 ++--- examples/with-supertokens/package.json | 4 ++-- examples/with-supertokens/pages/_app.tsx | 6 ++++-- examples/with-supertokens/pages/index.tsx | 21 ++++++++++++------- 5 files changed, 25 insertions(+), 15 deletions(-) diff --git a/examples/with-supertokens/config/backendConfig.ts b/examples/with-supertokens/config/backendConfig.ts index 8df31f407d87c..86910f5928230 100644 --- a/examples/with-supertokens/config/backendConfig.ts +++ b/examples/with-supertokens/config/backendConfig.ts @@ -1,4 +1,5 @@ import ThirdPartyEmailPasswordNode from 'supertokens-node/recipe/thirdpartyemailpassword' +import EmailVerificationNode from 'supertokens-node/recipe/emailverification' import SessionNode from 'supertokens-node/recipe/session' import { appInfo } from './appInfo' import { AuthConfig } from '../interfaces' @@ -11,6 +12,9 @@ export let backendConfig = (): AuthConfig => { }, appInfo, recipeList: [ + EmailVerificationNode.init({ + mode: 'REQUIRED', + }), ThirdPartyEmailPasswordNode.init({ providers: [ // We have provided you with development keys which you can use for testing. diff --git a/examples/with-supertokens/config/frontendConfig.ts b/examples/with-supertokens/config/frontendConfig.ts index 92036971ee75a..95c6e274ac70c 100644 --- a/examples/with-supertokens/config/frontendConfig.ts +++ b/examples/with-supertokens/config/frontendConfig.ts @@ -1,4 +1,5 @@ import ThirdPartyEmailPasswordReact from 'supertokens-auth-react/recipe/thirdpartyemailpassword' +import EmailVerificationReact from 'supertokens-auth-react/recipe/emailverification' import SessionReact from 'supertokens-auth-react/recipe/session' import { appInfo } from './appInfo' import Router from 'next/router' @@ -7,10 +8,8 @@ export let frontendConfig = () => { return { appInfo, recipeList: [ + EmailVerificationReact.init(), ThirdPartyEmailPasswordReact.init({ - emailVerificationFeature: { - mode: 'REQUIRED', - }, signInAndUpFeature: { providers: [ ThirdPartyEmailPasswordReact.Google.init(), diff --git a/examples/with-supertokens/package.json b/examples/with-supertokens/package.json index 2b86accf4cf4e..d82cc60d7a0b1 100644 --- a/examples/with-supertokens/package.json +++ b/examples/with-supertokens/package.json @@ -9,8 +9,8 @@ "next": "latest", "react": "^18.2.0", "react-dom": "^18.2.0", - "supertokens-auth-react": "^0.24.7", - "supertokens-node": "^11.2.0" + "supertokens-auth-react": "^0.26.0", + "supertokens-node": "^12.0.0" }, "devDependencies": { "@types/react": "18.0.17", diff --git a/examples/with-supertokens/pages/_app.tsx b/examples/with-supertokens/pages/_app.tsx index 8d012ba7c21d6..262f0ec750fea 100644 --- a/examples/with-supertokens/pages/_app.tsx +++ b/examples/with-supertokens/pages/_app.tsx @@ -1,10 +1,12 @@ import '../styles/globals.css' import React from 'react' import { useEffect } from 'react' -import SuperTokensReact, { SuperTokensWrapper } from 'supertokens-auth-react' +import SuperTokensReact, { + SuperTokensWrapper, + redirectToAuth, +} from 'supertokens-auth-react' import * as SuperTokensConfig from '../config/frontendConfig' import Session from 'supertokens-auth-react/recipe/session' -import { redirectToAuth } from 'supertokens-auth-react/recipe/thirdpartyemailpassword' if (typeof window !== 'undefined') { SuperTokensReact.init(SuperTokensConfig.frontendConfig()) diff --git a/examples/with-supertokens/pages/index.tsx b/examples/with-supertokens/pages/index.tsx index 6dbce9fe5eeee..1e7494dda97b9 100644 --- a/examples/with-supertokens/pages/index.tsx +++ b/examples/with-supertokens/pages/index.tsx @@ -1,13 +1,15 @@ import React from 'react' import Head from 'next/head' import styles from '../styles/Home.module.css' -import ThirdPartyEmailPassword, { - ThirdPartyEmailPasswordAuth, -} from 'supertokens-auth-react/recipe/thirdpartyemailpassword' +import ThirdPartyEmailPassword from 'supertokens-auth-react/recipe/thirdpartyemailpassword' import supertokensNode from 'supertokens-node' import { backendConfig } from '../config/backendConfig' import Session from 'supertokens-node/recipe/session' -import { useSessionContext } from 'supertokens-auth-react/recipe/session' +import { + SessionAuth, + useSessionContext, +} from 'supertokens-auth-react/recipe/session' +import { redirectToAuth } from 'supertokens-auth-react' export async function getServerSideProps(context) { // this runs on the backend, so we must call init on supertokens-node SDK @@ -18,7 +20,10 @@ export async function getServerSideProps(context) { } catch (err) { if (err.type === Session.Error.TRY_REFRESH_TOKEN) { return { props: { fromSupertokens: 'needs-refresh' } } - } else if (err.type === Session.Error.UNAUTHORISED) { + } else if ( + err.type === Session.Error.UNAUTHORISED || + err.type === Session.Error.INVALID_CLAIMS + ) { return { props: {} } } else { throw err @@ -35,7 +40,7 @@ function ProtectedPage({ userId }) { async function logoutClicked() { await ThirdPartyEmailPassword.signOut() - ThirdPartyEmailPassword.redirectToAuth() + redirectToAuth() } async function fetchUserData() { @@ -173,8 +178,8 @@ function ProtectedPage({ userId }) { export default function Home(props) { return ( - + - + ) } From 806db1a27b021cf5712b510c30685051492847d9 Mon Sep 17 00:00:00 2001 From: Henrik Wenz Date: Wed, 21 Sep 2022 20:21:24 +0200 Subject: [PATCH 05/76] chore: refactor with-typestyle example (#40740) ## Changes see commits ## Documentation / Examples - [x] Make sure the linting passes by running `pnpm lint` - [x] The "examples guidelines" are followed from [our contributing doc](https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md) --- examples/with-typestyle/package.json | 11 ++++-- examples/with-typestyle/pages/_document.js | 24 ------------ examples/with-typestyle/pages/_document.tsx | 37 +++++++++++++++++++ .../pages/{index.js => index.tsx} | 3 +- examples/with-typestyle/tsconfig.json | 20 ++++++++++ 5 files changed, 66 insertions(+), 29 deletions(-) delete mode 100644 examples/with-typestyle/pages/_document.js create mode 100644 examples/with-typestyle/pages/_document.tsx rename examples/with-typestyle/pages/{index.js => index.tsx} (50%) create mode 100644 examples/with-typestyle/tsconfig.json diff --git a/examples/with-typestyle/package.json b/examples/with-typestyle/package.json index f430e316d608c..4254c891bd345 100644 --- a/examples/with-typestyle/package.json +++ b/examples/with-typestyle/package.json @@ -7,8 +7,13 @@ }, "dependencies": { "next": "latest", - "react": "^17.0.2", - "react-dom": "^17.0.2", - "typestyle": "^2.0.1" + "react": "^18.2.0", + "react-dom": "^18.2.0", + "typestyle": "^2.4.0" + }, + "devDependencies": { + "@types/node": "18.7.18", + "@types/react": "16.9.17", + "typescript": "4.8.2" } } diff --git a/examples/with-typestyle/pages/_document.js b/examples/with-typestyle/pages/_document.js deleted file mode 100644 index fada64089114f..0000000000000 --- a/examples/with-typestyle/pages/_document.js +++ /dev/null @@ -1,24 +0,0 @@ -import Document, { Html, Head, Main, NextScript } from 'next/document' -import { getStyles } from 'typestyle' - -export default class MyDocument extends Document { - static async getInitialProps({ renderPage }) { - const page = await renderPage() - const styleTags = getStyles() - return { ...page, styleTags } - } - - render() { - return ( - - - - - -
- - - - ) - } -} diff --git a/examples/with-typestyle/pages/_document.tsx b/examples/with-typestyle/pages/_document.tsx new file mode 100644 index 0000000000000..190e838b162f8 --- /dev/null +++ b/examples/with-typestyle/pages/_document.tsx @@ -0,0 +1,37 @@ +import Document, { + Html, + Head, + Main, + NextScript, + DocumentInitialProps, + DocumentContext, +} from 'next/document' +import { getStyles } from 'typestyle' + +export default function MyDocument() { + return ( + + + +
+ + + + ) +} + +MyDocument.getInitialProps = async ( + ctx: DocumentContext +): Promise => { + const initialProps = await Document.getInitialProps(ctx) + const styleTags = getStyles() + return { + ...initialProps, + styles: ( + <> + {initialProps.styles} + + + ), + } +} diff --git a/examples/with-typestyle/pages/index.js b/examples/with-typestyle/pages/index.tsx similarity index 50% rename from examples/with-typestyle/pages/index.js rename to examples/with-typestyle/pages/index.tsx index 95768737e0227..0621cca54cf37 100644 --- a/examples/with-typestyle/pages/index.js +++ b/examples/with-typestyle/pages/index.tsx @@ -1,8 +1,7 @@ import { style } from 'typestyle' const className = style({ color: 'red' }) -const RedText = ({ text }) =>
{text}
export default function Home() { - return + return
Hello Next.js!
} diff --git a/examples/with-typestyle/tsconfig.json b/examples/with-typestyle/tsconfig.json new file mode 100644 index 0000000000000..50bcb22f653d7 --- /dev/null +++ b/examples/with-typestyle/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "incremental": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve" + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], + "exclude": ["node_modules"] +} From fc179d14aee09c25a401d0e27684b1abdeefb6af Mon Sep 17 00:00:00 2001 From: Henrik Wenz Date: Wed, 21 Sep 2022 20:29:25 +0200 Subject: [PATCH 06/76] chore: migrate missing document of with-geist-ui example to typescript (#40743) ## Documentation / Examples - [x] Make sure the linting passes by running `pnpm lint` - [x] The "examples guidelines" are followed from [our contributing doc](https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md) --- examples/with-geist-ui/pages/_document.js | 33 ------------------- examples/with-geist-ui/pages/_document.tsx | 38 ++++++++++++++++++++++ 2 files changed, 38 insertions(+), 33 deletions(-) delete mode 100644 examples/with-geist-ui/pages/_document.js create mode 100644 examples/with-geist-ui/pages/_document.tsx diff --git a/examples/with-geist-ui/pages/_document.js b/examples/with-geist-ui/pages/_document.js deleted file mode 100644 index 8ff3141143ca0..0000000000000 --- a/examples/with-geist-ui/pages/_document.js +++ /dev/null @@ -1,33 +0,0 @@ -import Document, { Html, Head, Main, NextScript } from 'next/document' -import { CssBaseline } from '@geist-ui/core' - -class MyDocument extends Document { - static async getInitialProps(ctx) { - const initialProps = await Document.getInitialProps(ctx) - const styles = CssBaseline.flush() - - return { - ...initialProps, - styles: ( - <> - {initialProps.styles} - {styles} - - ), - } - } - - render() { - return ( - - - -
- - - - ) - } -} - -export default MyDocument diff --git a/examples/with-geist-ui/pages/_document.tsx b/examples/with-geist-ui/pages/_document.tsx new file mode 100644 index 0000000000000..4223a62279661 --- /dev/null +++ b/examples/with-geist-ui/pages/_document.tsx @@ -0,0 +1,38 @@ +import Document, { + Html, + Head, + Main, + NextScript, + DocumentContext, + DocumentInitialProps, +} from 'next/document' +import { CssBaseline } from '@geist-ui/core' + +export default function MyDocument() { + return ( + + + +
+ + + + ) +} + +MyDocument.getInitialProps = async ( + ctx: DocumentContext +): Promise => { + const initialProps = await Document.getInitialProps(ctx) + const styles = CssBaseline.flush() + + return { + ...initialProps, + styles: ( + <> + {initialProps.styles} + {styles} + + ), + } +} From c5f1e2f76d7928d705ee4b4bdc0729afdf48ded4 Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Wed, 21 Sep 2022 11:29:52 -0700 Subject: [PATCH 07/76] Add test case for /404 client transition (#40734) This adds a test case verifying client transitions to `/404` or `/_error` are working properly. Test deployment with patched reproduction can be seen here https://router-bug-repro-4bozmev4p-ijjk-testing.vercel.app/blocked Closes: https://github.com/vercel/next.js/issues/40667 --- test/e2e/basepath.test.ts | 30 ++++++++++++++++++++++++++++++ test/e2e/basepath/pages/404.js | 5 +++++ 2 files changed, 35 insertions(+) create mode 100644 test/e2e/basepath/pages/404.js diff --git a/test/e2e/basepath.test.ts b/test/e2e/basepath.test.ts index 7ffb321495c3e..bac6b630cd4fe 100644 --- a/test/e2e/basepath.test.ts +++ b/test/e2e/basepath.test.ts @@ -97,6 +97,36 @@ describe('basePath', () => { afterAll(() => next.destroy()) const runTests = (isDev = false, isDeploy = false) => { + it('should navigate to /404 correctly client-side', async () => { + const browser = await webdriver(next.url, `${basePath}/slug-1`) + await check( + () => browser.eval('document.documentElement.innerHTML'), + /slug-1/ + ) + + await browser.eval('next.router.push("/404", "/slug-2")') + await check( + () => browser.eval('document.documentElement.innerHTML'), + /page could not be found/ + ) + expect(await browser.eval('location.pathname')).toBe(`${basePath}/slug-2`) + }) + + it('should navigate to /_error correctly client-side', async () => { + const browser = await webdriver(next.url, `${basePath}/slug-1`) + await check( + () => browser.eval('document.documentElement.innerHTML'), + /slug-1/ + ) + + await browser.eval('next.router.push("/_error", "/slug-2")') + await check( + () => browser.eval('document.documentElement.innerHTML'), + /page could not be found/ + ) + expect(await browser.eval('location.pathname')).toBe(`${basePath}/slug-2`) + }) + it('should navigate to external site and back', async () => { const browser = await webdriver(next.url, `${basePath}/external-and-back`) const initialText = await browser.elementByCss('p').text() diff --git a/test/e2e/basepath/pages/404.js b/test/e2e/basepath/pages/404.js new file mode 100644 index 0000000000000..a4d7c60867f3b --- /dev/null +++ b/test/e2e/basepath/pages/404.js @@ -0,0 +1,5 @@ +import NextError from 'next/error' + +export default function Page() { + return +} From 6d4f263121d8453957250b5b1f06779707b7e932 Mon Sep 17 00:00:00 2001 From: Shu Ding Date: Wed, 21 Sep 2022 20:45:33 +0200 Subject: [PATCH 08/76] Improved bundling strategy for the server graph (#40739) This PR changes the external module resolution to eagerly bundle node_modules, and some specific Next.js internal modules, if on the `WEBPACK_LAYERS.server` layer. While resolving corresponding packages, we use the `react-server` export condition (fallbacks to default). A follow-up PR will be adding a Next.js option to opt-out specific packages from being bundled on the server layer. ## 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` - [x] 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) --- .../core/src/react_server_components.rs | 8 +- packages/next/build/webpack-config.ts | 121 ++++++++++++++---- .../build/webpack/loaders/next-app-loader.ts | 3 + .../plugins/flight-client-entry-plugin.ts | 4 +- .../client/components/hooks-server-context.ts | 7 + .../next/client/components/hooks-server.ts | 19 +-- .../static-generation-async-storage.ts | 18 +++ packages/next/export/worker.ts | 4 +- packages/next/server/app-render.tsx | 55 ++++---- .../app/app/hooks/use-pathname/server/page.js | 4 +- .../app/app/hooks/use-router/server/page.js | 4 +- .../hooks/use-search-params/server/page.js | 4 +- test/e2e/app-dir/app/app/style.css | 2 +- test/e2e/app-dir/index.test.ts | 3 +- test/e2e/app-dir/rsc-basic.test.ts | 22 +++- .../react-server/3rd-party-package/client.js | 15 +++ .../react-server/3rd-party-package/page.js | 16 +++ .../app/react-server/client-detector.js | 3 + .../rsc-basic/app/react-server/detector.js | 5 + .../rsc-basic/app/react-server/page.js | 13 ++ .../conditional-exports/index.js | 1 + .../conditional-exports/index.server.js | 1 + .../conditional-exports/package.json | 15 +++ .../conditional-exports/subpath.js | 1 + .../conditional-exports/subpath.server.js | 1 + 25 files changed, 260 insertions(+), 89 deletions(-) create mode 100644 packages/next/client/components/static-generation-async-storage.ts create mode 100644 test/e2e/app-dir/rsc-basic/app/react-server/3rd-party-package/client.js create mode 100644 test/e2e/app-dir/rsc-basic/app/react-server/3rd-party-package/page.js create mode 100644 test/e2e/app-dir/rsc-basic/app/react-server/client-detector.js create mode 100644 test/e2e/app-dir/rsc-basic/app/react-server/detector.js create mode 100644 test/e2e/app-dir/rsc-basic/app/react-server/page.js create mode 100644 test/e2e/app-dir/rsc-basic/node_modules_bak/conditional-exports/index.js create mode 100644 test/e2e/app-dir/rsc-basic/node_modules_bak/conditional-exports/index.server.js create mode 100644 test/e2e/app-dir/rsc-basic/node_modules_bak/conditional-exports/package.json create mode 100644 test/e2e/app-dir/rsc-basic/node_modules_bak/conditional-exports/subpath.js create mode 100644 test/e2e/app-dir/rsc-basic/node_modules_bak/conditional-exports/subpath.server.js diff --git a/packages/next-swc/crates/core/src/react_server_components.rs b/packages/next-swc/crates/core/src/react_server_components.rs index af5e959f2c6e1..669f2f1f754b8 100644 --- a/packages/next-swc/crates/core/src/react_server_components.rs +++ b/packages/next-swc/crates/core/src/react_server_components.rs @@ -395,8 +395,14 @@ pub fn server_components( JsWord::from("client-only"), JsWord::from("react-dom/client"), JsWord::from("react-dom/server"), + // TODO-APP: JsWord::from("next/router"), + // TODO-APP: Rule out client hooks. + ], + invalid_client_imports: vec![ + JsWord::from("server-only"), + // TODO-APP: Rule out server hooks such as `useCookies`, `useHeaders`, + // `usePreviewData`. ], - invalid_client_imports: vec![JsWord::from("server-only")], invalid_server_react_dom_apis: vec![ JsWord::from("findDOMNode"), JsWord::from("flushSync"), diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts index 6aaa9ceeccae6..48d71e8f4b1ee 100644 --- a/packages/next/build/webpack-config.ts +++ b/packages/next/build/webpack-config.ts @@ -831,6 +831,14 @@ export default async function getBaseWebpackConfig( [COMPILER_NAMES.edgeServer]: ['browser', 'module', 'main'], } + const reactAliases = { + react: reactDir, + 'react-dom$': reactDomDir, + 'react-dom/server$': `${reactDomDir}/server`, + 'react-dom/server.browser$': `${reactDomDir}/server.browser`, + 'react-dom/client$': `${reactDomDir}/client`, + } + const resolveConfig = { // Disable .mjs for node_modules bundling extensions: isNodeServer @@ -843,11 +851,8 @@ export default async function getBaseWebpackConfig( alias: { next: NEXT_PROJECT_ROOT, - react: `${reactDir}`, - 'react-dom$': `${reactDomDir}`, - 'react-dom/server$': `${reactDomDir}/server`, - 'react-dom/server.browser$': `${reactDomDir}/server.browser`, - 'react-dom/client$': `${reactDomDir}/client`, + ...reactAliases, + 'styled-jsx/style$': require.resolve(`styled-jsx/style`), 'styled-jsx$': require.resolve(`styled-jsx`), @@ -977,6 +982,7 @@ export default async function getBaseWebpackConfig( context: string, request: string, dependencyType: string, + layer: string | null, getResolve: ( options: any ) => ( @@ -1001,14 +1007,47 @@ export default async function getBaseWebpackConfig( return `commonjs next/dist/lib/import-next-warning` } + const resolveWithReactServerCondition = + layer === WEBPACK_LAYERS.server + ? getResolve({ + // If React is aliased to another channel during Next.js' local development, + // we need to provide that alias to webpack's resolver. + alias: process.env.__NEXT_REACT_CHANNEL + ? { + ...reactAliases, + 'react/package.json': `${reactDir}/package.json`, + 'react/jsx-runtime': `${reactDir}/jsx-runtime`, + 'react/jsx-dev-runtime': `${reactDir}/jsx-dev-runtime`, + 'react-dom/package.json': `${reactDomDir}/package.json`, + } + : false, + conditionNames: ['react-server'], + }) + : null + + // Special internal modules that must be bundled for Server Components. + if (layer === WEBPACK_LAYERS.server) { + if (!isLocal && /^react(?:$|\/)/.test(request)) { + const [resolved] = await resolveWithReactServerCondition!( + context, + request + ) + return resolved + } + if ( + request === + 'next/dist/compiled/react-server-dom-webpack/writer.browser.server' + ) { + return + } + } + // Relative requires don't need custom resolution, because they // are relative to requests we've already resolved here. // Absolute requires (require('/foo')) are extremely uncommon, but // also have no need for customization as they're already resolved. if (!isLocal) { - // styled-jsx is also marked as externals here to avoid being - // bundled in client components for RSC. - if (/^(?:next$|styled-jsx$|react(?:$|\/))/.test(request)) { + if (/^(?:next$|react(?:$|\/))/.test(request)) { return `commonjs ${request}` } @@ -1122,9 +1161,22 @@ export default async function getBaseWebpackConfig( return } - // Anything else that is standard JavaScript within `node_modules` - // can be externalized. if (/node_modules[/\\].*\.[mc]?js$/.test(res)) { + if (layer === WEBPACK_LAYERS.server) { + try { + const [resolved] = await resolveWithReactServerCondition!( + context, + request + ) + return resolved + } catch (err) { + // The `react-server` condition is not matched, fallback. + return + } + } + + // Anything else that is standard JavaScript within `node_modules` + // can be externalized. return `${externalType} ${request}` } @@ -1176,11 +1228,17 @@ export default async function getBaseWebpackConfig( context, request, dependencyType, + contextInfo, getResolve, }: { context: string request: string dependencyType: string + contextInfo: { + issuer: string + issuerLayer: string | null + compiler: string + } getResolve: ( options: any ) => ( @@ -1193,24 +1251,31 @@ export default async function getBaseWebpackConfig( ) => void ) => void }) => - handleExternals(context, request, dependencyType, (options) => { - const resolveFunction = getResolve(options) - return (resolveContext: string, requestToResolve: string) => - new Promise((resolve, reject) => { - resolveFunction( - resolveContext, - requestToResolve, - (err, result, resolveData) => { - if (err) return reject(err) - if (!result) return resolve([null, false]) - const isEsm = /\.js$/i.test(result) - ? resolveData?.descriptionFileData?.type === 'module' - : /\.mjs$/i.test(result) - resolve([result, isEsm]) - } - ) - }) - }), + handleExternals( + context, + request, + dependencyType, + contextInfo.issuerLayer, + (options) => { + const resolveFunction = getResolve(options) + return (resolveContext: string, requestToResolve: string) => + new Promise((resolve, reject) => { + resolveFunction( + resolveContext, + requestToResolve, + (err, result, resolveData) => { + if (err) return reject(err) + if (!result) return resolve([null, false]) + const isEsm = /\.js$/i.test(result) + ? resolveData?.descriptionFileData?.type === + 'module' + : /\.mjs$/i.test(result) + resolve([result, isEsm]) + } + ) + }) + } + ), ] : [ // When the 'serverless' target is used all node_modules will be compiled into the output bundles diff --git a/packages/next/build/webpack/loaders/next-app-loader.ts b/packages/next/build/webpack/loaders/next-app-loader.ts index 3153b835c7db5..c3adb305a4e5f 100644 --- a/packages/next/build/webpack/loaders/next-app-loader.ts +++ b/packages/next/build/webpack/loaders/next-app-loader.ts @@ -191,6 +191,9 @@ const nextAppLoader: webpack.LoaderDefinitionFunction<{ : 'null' } + export const serverHooks = require('next/dist/client/components/hooks-server-context.js') + + export const renderToReadableStream = require('next/dist/compiled/react-server-dom-webpack/writer.browser.server').renderToReadableStream export const __next_app_webpack_require__ = __webpack_require__ ` diff --git a/packages/next/build/webpack/plugins/flight-client-entry-plugin.ts b/packages/next/build/webpack/plugins/flight-client-entry-plugin.ts index c4cb536d04afb..e6ae570200318 100644 --- a/packages/next/build/webpack/plugins/flight-client-entry-plugin.ts +++ b/packages/next/build/webpack/plugins/flight-client-entry-plugin.ts @@ -59,11 +59,11 @@ export class FlightClientEntryPlugin { ) compiler.hooks.finishMake.tapPromise(PLUGIN_NAME, (compilation) => { - return this.createClientEndpoints(compiler, compilation) + return this.createClientEntries(compiler, compilation) }) } - async createClientEndpoints(compiler: any, compilation: any) { + async createClientEntries(compiler: any, compilation: any) { const promises: Array< ReturnType > = [] diff --git a/packages/next/client/components/hooks-server-context.ts b/packages/next/client/components/hooks-server-context.ts index 81d288381be0e..fffcbcb89c22c 100644 --- a/packages/next/client/components/hooks-server-context.ts +++ b/packages/next/client/components/hooks-server-context.ts @@ -1,6 +1,13 @@ // @ts-expect-error createServerContext exists on experimental channel import { createServerContext } from 'react' +// createServerContext exists in react@experimental + react-dom@experimental +if (typeof createServerContext === 'undefined') { + throw new Error( + '"app" directory requires React.createServerContext which is not available in the version of React you are using. Please update to react@experimental and react-dom@experimental.' + ) +} + export class DynamicServerError extends Error { constructor(type: string) { super(`Dynamic server usage: ${type}`) diff --git a/packages/next/client/components/hooks-server.ts b/packages/next/client/components/hooks-server.ts index 7a47daa19e54c..5d4faa258a31e 100644 --- a/packages/next/client/components/hooks-server.ts +++ b/packages/next/client/components/hooks-server.ts @@ -1,4 +1,3 @@ -import type { AsyncLocalStorage } from 'async_hooks' import { useContext } from 'react' import { HeadersContext, @@ -6,23 +5,7 @@ import { CookiesContext, DynamicServerError, } from './hooks-server-context' - -export interface StaticGenerationStore { - inUse?: boolean - pathname?: string - revalidate?: number - fetchRevalidate?: number - isStaticGeneration?: boolean -} - -export let staticGenerationAsyncStorage: - | AsyncLocalStorage - | StaticGenerationStore = {} - -if (process.env.NEXT_RUNTIME !== 'edge' && typeof window === 'undefined') { - staticGenerationAsyncStorage = - new (require('async_hooks').AsyncLocalStorage)() -} +import { staticGenerationAsyncStorage } from './static-generation-async-storage' function useStaticGenerationBailout(reason: string) { const staticGenerationStore = diff --git a/packages/next/client/components/static-generation-async-storage.ts b/packages/next/client/components/static-generation-async-storage.ts new file mode 100644 index 0000000000000..f3abd89db0413 --- /dev/null +++ b/packages/next/client/components/static-generation-async-storage.ts @@ -0,0 +1,18 @@ +import type { AsyncLocalStorage } from 'async_hooks' + +export interface StaticGenerationStore { + inUse?: boolean + pathname?: string + revalidate?: number + fetchRevalidate?: number + isStaticGeneration?: boolean +} + +export let staticGenerationAsyncStorage: + | AsyncLocalStorage + | StaticGenerationStore = {} + +if (process.env.NEXT_RUNTIME !== 'edge' && typeof window === 'undefined') { + staticGenerationAsyncStorage = + new (require('async_hooks').AsyncLocalStorage)() +} diff --git a/packages/next/export/worker.ts b/packages/next/export/worker.ts index f7d1cb230cea2..e27ab26c863a6 100644 --- a/packages/next/export/worker.ts +++ b/packages/next/export/worker.ts @@ -388,9 +388,7 @@ export default async function exportPage({ // and bail when dynamic dependencies are detected // only fully static paths are fully generated here if (isAppDir) { - const { - DynamicServerError, - } = require('../client/components/hooks-server-context') + const { DynamicServerError } = components.ComponentMod.serverHooks const { renderToHTMLOrFlight } = require('../server/app-render') as typeof import('../server/app-render') diff --git a/packages/next/server/app-render.tsx b/packages/next/server/app-render.tsx index 12a87e12a84f6..98f26356a741e 100644 --- a/packages/next/server/app-render.tsx +++ b/packages/next/server/app-render.tsx @@ -3,10 +3,11 @@ import type { LoadComponentsReturnType } from './load-components' import type { ServerRuntime } from '../types' // TODO-APP: change to React.use once it becomes stable +// @ts-ignore import React, { experimental_use as use } from 'react' + import { ParsedUrlQuery, stringify as stringifyQuery } from 'querystring' import { createFromReadableStream } from 'next/dist/compiled/react-server-dom-webpack' -import { renderToReadableStream } from 'next/dist/compiled/react-server-dom-webpack/writer.browser.server' import { NextParsedUrlQuery } from './request-meta' import RenderResult from './render-result' import { @@ -103,15 +104,15 @@ let isFetchPatched = false // we patch fetch to collect cache information used for // determining if a page is static or not -function patchFetch() { +function patchFetch(ComponentMod: any) { if (isFetchPatched) return isFetchPatched = true const { DynamicServerError } = - require('../client/components/hooks-server-context') as typeof import('../client/components/hooks-server-context') + ComponentMod.serverHooks as typeof import('../client/components/hooks-server-context') const { staticGenerationAsyncStorage } = - require('../client/components/hooks-server') as typeof import('../client/components/hooks-server') + require('../client/components/static-generation-async-storage') as typeof import('../client/components/static-generation-async-storage') const origFetch = (global as any).fetch @@ -224,6 +225,7 @@ function useFlightResponse( function createServerComponentRenderer( ComponentToRender: React.ComponentType, ComponentMod: { + renderToReadableStream: any __next_app_webpack_require__?: any __next_rsc__?: { __webpack_require__?: any @@ -259,7 +261,7 @@ function createServerComponentRenderer( let RSCStream: ReadableStream const createRSCStream = () => { if (!RSCStream) { - RSCStream = renderToReadableStream( + RSCStream = ComponentMod.renderToReadableStream( , serverComponentManifest, { @@ -516,10 +518,19 @@ export async function renderToHTMLOrFlight( isPagesDir: boolean, isStaticGeneration: boolean = false ): Promise { - patchFetch() + const { + buildManifest, + subresourceIntegrityManifest, + serverComponentManifest, + serverCSSManifest = {}, + supportsDynamicHTML, + ComponentMod, + } = renderOpts + + patchFetch(ComponentMod) const { staticGenerationAsyncStorage } = - require('../client/components/hooks-server') as typeof import('../client/components/hooks-server') + require('../client/components/static-generation-async-storage') as typeof import('../client/components/static-generation-async-storage') if ( !('getStore' in staticGenerationAsyncStorage) && @@ -538,27 +549,11 @@ export async function renderToHTMLOrFlight( : staticGenerationAsyncStorage const { CONTEXT_NAMES } = - require('../client/components/hooks-server-context') as typeof import('../client/components/hooks-server-context') - - // @ts-expect-error createServerContext exists in react@experimental + react-dom@experimental - if (typeof React.createServerContext === 'undefined') { - throw new Error( - '"app" directory requires React.createServerContext which is not available in the version of React you are using. Please update to react@experimental and react-dom@experimental.' - ) - } + ComponentMod.serverHooks as typeof import('../client/components/hooks-server-context') // don't modify original query object query = Object.assign({}, query) - const { - buildManifest, - subresourceIntegrityManifest, - serverComponentManifest, - serverCSSManifest = {}, - supportsDynamicHTML, - ComponentMod, - } = renderOpts - const isFlight = req.headers.__flight__ !== undefined const isPrefetch = req.headers.__flight_prefetch__ !== undefined @@ -570,9 +565,13 @@ export async function renderToHTMLOrFlight( // Empty so that the client-side router will do a full page navigation. const flightData: FlightData = pathname + (search ? `?${search}` : '') return new FlightRenderResult( - renderToReadableStream(flightData, serverComponentManifest, { - onError: flightDataRendererErrorHandler, - }).pipeThrough(createBufferedTransformStream()) + ComponentMod.renderToReadableStream( + flightData, + serverComponentManifest, + { + onError: flightDataRendererErrorHandler, + } + ).pipeThrough(createBufferedTransformStream()) ) } @@ -1057,7 +1056,7 @@ export async function renderToHTMLOrFlight( ).slice(1), ] - const readable = renderToReadableStream( + const readable = ComponentMod.renderToReadableStream( flightData, serverComponentManifest, { diff --git a/test/e2e/app-dir/app/app/hooks/use-pathname/server/page.js b/test/e2e/app-dir/app/app/hooks/use-pathname/server/page.js index 9c4c9543406a6..bb5ab57464994 100644 --- a/test/e2e/app-dir/app/app/hooks/use-pathname/server/page.js +++ b/test/e2e/app-dir/app/app/hooks/use-pathname/server/page.js @@ -1,8 +1,8 @@ -import { usePathname } from 'next/dist/client/components/hooks-client' +// import { usePathname } from 'next/dist/client/components/hooks-client' export default function Page() { // This should throw an error. - usePathname() + // usePathname() return null } diff --git a/test/e2e/app-dir/app/app/hooks/use-router/server/page.js b/test/e2e/app-dir/app/app/hooks/use-router/server/page.js index ca3f10a333cbb..18a79712d065f 100644 --- a/test/e2e/app-dir/app/app/hooks/use-router/server/page.js +++ b/test/e2e/app-dir/app/app/hooks/use-router/server/page.js @@ -1,8 +1,8 @@ -import { useRouter } from 'next/dist/client/components/hooks-client' +// import { useRouter } from 'next/dist/client/components/hooks-client' export default function Page() { // This should throw an error. - useRouter() + // useRouter() return null } diff --git a/test/e2e/app-dir/app/app/hooks/use-search-params/server/page.js b/test/e2e/app-dir/app/app/hooks/use-search-params/server/page.js index 3468f385f6a66..65c6fe8d91162 100644 --- a/test/e2e/app-dir/app/app/hooks/use-search-params/server/page.js +++ b/test/e2e/app-dir/app/app/hooks/use-search-params/server/page.js @@ -1,8 +1,8 @@ -import { useSearchParams } from 'next/dist/client/components/hooks-client' +// import { useSearchParams } from 'next/dist/client/components/hooks-client' export default function Page() { // This should throw an error. - useSearchParams() + // useSearchParams() return null } diff --git a/test/e2e/app-dir/app/app/style.css b/test/e2e/app-dir/app/app/style.css index 0b8fbd008481a..3a94c07339f95 100644 --- a/test/e2e/app-dir/app/app/style.css +++ b/test/e2e/app-dir/app/app/style.css @@ -1,3 +1,3 @@ body { - font-size: xx-large; + font-size: large; } diff --git a/test/e2e/app-dir/index.test.ts b/test/e2e/app-dir/index.test.ts index 93bb4ed7ddeab..b73d3942772c4 100644 --- a/test/e2e/app-dir/index.test.ts +++ b/test/e2e/app-dir/index.test.ts @@ -780,7 +780,8 @@ describe('app dir', () => { }) describe('next/router', () => { - it('should always return null when accessed from /app', async () => { + // `useRouter` should not be accessible in server components. + it.skip('should always return null when accessed from /app', async () => { const browser = await webdriver(next.url, '/old-router') try { diff --git a/test/e2e/app-dir/rsc-basic.test.ts b/test/e2e/app-dir/rsc-basic.test.ts index 95b2f3457717b..273bc663f410e 100644 --- a/test/e2e/app-dir/rsc-basic.test.ts +++ b/test/e2e/app-dir/rsc-basic.test.ts @@ -44,7 +44,7 @@ describe('app dir - react server components', () => { }, packageJson: { scripts: { - setup: `cp -r ./node_modules_bak/non-isomorphic-text ./node_modules; cp -r ./node_modules_bak/random-module-instance ./node_modules`, + setup: `cp -r ./node_modules_bak/* ./node_modules`, build: 'yarn setup && next build', dev: 'yarn setup && next dev', start: 'next start', @@ -398,6 +398,26 @@ describe('app dir - react server components', () => { ) }) + it('should resolve the subset react in server components based on the react-server condition', async () => { + await fetchViaHTTP(next.url, '/react-server').then(async (response) => { + const result = await resolveStreamResponse(response) + expect(result).toContain('Server: subset') + expect(result).toContain('Client: full') + }) + }) + + it('should resolve 3rd party package exports based on the react-server condition', async () => { + await fetchViaHTTP(next.url, '/react-server/3rd-party-package').then( + async (response) => { + const result = await resolveStreamResponse(response) + expect(result).toContain('Server: index.react-server') + expect(result).toContain('Server subpath: subpath.react-server') + expect(result).toContain('Client: index.default') + expect(result).toContain('Client subpath: subpath.default') + } + ) + }) + if (!isNextDev) { it('should generate edge SSR manifests for Node.js', async () => { const distServerDir = path.join(distDir, 'server') diff --git a/test/e2e/app-dir/rsc-basic/app/react-server/3rd-party-package/client.js b/test/e2e/app-dir/rsc-basic/app/react-server/3rd-party-package/client.js new file mode 100644 index 0000000000000..ae07e30fa6ce8 --- /dev/null +++ b/test/e2e/app-dir/rsc-basic/app/react-server/3rd-party-package/client.js @@ -0,0 +1,15 @@ +'client' + +import v from 'conditional-exports' +import v1 from 'conditional-exports/subpath' + +export default function Client() { + return ( + <> + {`Client: ${v}`} +
+ {`Client subpath: ${v1}`} +
+ + ) +} diff --git a/test/e2e/app-dir/rsc-basic/app/react-server/3rd-party-package/page.js b/test/e2e/app-dir/rsc-basic/app/react-server/3rd-party-package/page.js new file mode 100644 index 0000000000000..33141e12f7685 --- /dev/null +++ b/test/e2e/app-dir/rsc-basic/app/react-server/3rd-party-package/page.js @@ -0,0 +1,16 @@ +import v from 'conditional-exports' +import v1 from 'conditional-exports/subpath' + +import Client from './client' + +export default function Page() { + return ( +
+ {`Server: ${v}`} +
+ {`Server subpath: ${v1}`} +
+ +
+ ) +} diff --git a/test/e2e/app-dir/rsc-basic/app/react-server/client-detector.js b/test/e2e/app-dir/rsc-basic/app/react-server/client-detector.js new file mode 100644 index 0000000000000..47c07de636fbc --- /dev/null +++ b/test/e2e/app-dir/rsc-basic/app/react-server/client-detector.js @@ -0,0 +1,3 @@ +'client' + +export { default } from './detector' diff --git a/test/e2e/app-dir/rsc-basic/app/react-server/detector.js b/test/e2e/app-dir/rsc-basic/app/react-server/detector.js new file mode 100644 index 0000000000000..63cd22b647d54 --- /dev/null +++ b/test/e2e/app-dir/rsc-basic/app/react-server/detector.js @@ -0,0 +1,5 @@ +import React from 'react' + +export default function Detector() { + return 'useState' in React ? 'full' : 'subset' +} diff --git a/test/e2e/app-dir/rsc-basic/app/react-server/page.js b/test/e2e/app-dir/rsc-basic/app/react-server/page.js new file mode 100644 index 0000000000000..7f006ada27686 --- /dev/null +++ b/test/e2e/app-dir/rsc-basic/app/react-server/page.js @@ -0,0 +1,13 @@ +import Detector from './detector' +import ClientDetector from './client-detector' + +export default function Page() { + return ( +
+ Server: +
+ Client: +
+
+ ) +} diff --git a/test/e2e/app-dir/rsc-basic/node_modules_bak/conditional-exports/index.js b/test/e2e/app-dir/rsc-basic/node_modules_bak/conditional-exports/index.js new file mode 100644 index 0000000000000..3a7bb344a967a --- /dev/null +++ b/test/e2e/app-dir/rsc-basic/node_modules_bak/conditional-exports/index.js @@ -0,0 +1 @@ +module.exports = 'index.default' diff --git a/test/e2e/app-dir/rsc-basic/node_modules_bak/conditional-exports/index.server.js b/test/e2e/app-dir/rsc-basic/node_modules_bak/conditional-exports/index.server.js new file mode 100644 index 0000000000000..5618abfbec839 --- /dev/null +++ b/test/e2e/app-dir/rsc-basic/node_modules_bak/conditional-exports/index.server.js @@ -0,0 +1 @@ +module.exports = 'index.react-server' diff --git a/test/e2e/app-dir/rsc-basic/node_modules_bak/conditional-exports/package.json b/test/e2e/app-dir/rsc-basic/node_modules_bak/conditional-exports/package.json new file mode 100644 index 0000000000000..addc598c8fcfd --- /dev/null +++ b/test/e2e/app-dir/rsc-basic/node_modules_bak/conditional-exports/package.json @@ -0,0 +1,15 @@ +{ + "name": "conditional-exports", + "main": "index.js", + "exports": { + ".": { + "react-server": "./index.server.js", + "default": "./index.js" + }, + "./subpath": { + "react-server": "./subpath.server.js", + "default": "./subpath.js" + }, + "./package.json": "./package.json" + } +} diff --git a/test/e2e/app-dir/rsc-basic/node_modules_bak/conditional-exports/subpath.js b/test/e2e/app-dir/rsc-basic/node_modules_bak/conditional-exports/subpath.js new file mode 100644 index 0000000000000..11d27846911c8 --- /dev/null +++ b/test/e2e/app-dir/rsc-basic/node_modules_bak/conditional-exports/subpath.js @@ -0,0 +1 @@ +module.exports = 'subpath.default' diff --git a/test/e2e/app-dir/rsc-basic/node_modules_bak/conditional-exports/subpath.server.js b/test/e2e/app-dir/rsc-basic/node_modules_bak/conditional-exports/subpath.server.js new file mode 100644 index 0000000000000..11acc618fbd0f --- /dev/null +++ b/test/e2e/app-dir/rsc-basic/node_modules_bak/conditional-exports/subpath.server.js @@ -0,0 +1 @@ +module.exports = 'subpath.react-server' From 11dd1de655bfdab82d96b7bfe76c6fa1ef70337d Mon Sep 17 00:00:00 2001 From: Shu Ding Date: Wed, 21 Sep 2022 21:30:46 +0200 Subject: [PATCH 09/76] Remove unnecessary experimental flag (#40766) `config.experimental.serverComponents` is currently required to be enabled or disabled together with `config.experimental.appDir` (which means `serverComponents === appDir` otherwise it will throw) so there is no reason to keep both of them. This PR removes `serverComponents` from Next.js and only rely on `appDir` instead. ## 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) --- packages/next/build/index.ts | 14 ++++---------- packages/next/build/swc/options.js | 2 +- packages/next/build/webpack-config.ts | 16 ++++------------ packages/next/export/index.ts | 4 ++-- packages/next/server/base-server.ts | 2 +- packages/next/server/config-schema.ts | 3 --- packages/next/server/config-shared.ts | 2 -- packages/next/server/dev/hot-reloader.ts | 3 +-- packages/next/server/dev/next-dev-server.ts | 4 +--- packages/next/server/next-server.ts | 4 ++-- test/e2e/app-dir/app-alias/next.config.js | 1 - test/e2e/app-dir/app-prefetch/next.config.js | 1 - test/e2e/app-dir/app-rendering/next.config.js | 1 - test/e2e/app-dir/app-static/next.config.js | 1 - test/e2e/app-dir/app/next.config.js | 1 - test/e2e/app-dir/asset-prefix/next.config.js | 1 - test/e2e/app-dir/rsc-basic/next.config.js | 1 - test/e2e/app-dir/trailingslash/next.config.js | 1 - test/e2e/switchable-runtime/next.config.js | 1 - .../react-streaming/app/next.config.js | 1 - .../unsupported-native-module/next.config.js | 4 +--- 21 files changed, 17 insertions(+), 51 deletions(-) diff --git a/packages/next/build/index.ts b/packages/next/build/index.ts index 898072e333e3d..29f82ca095d84 100644 --- a/packages/next/build/index.ts +++ b/packages/next/build/index.ts @@ -270,11 +270,7 @@ export default async function build( setGlobal('phase', PHASE_PRODUCTION_BUILD) setGlobal('distDir', distDir) - // We enable concurrent features (Fizz-related rendering architecture) when - // using React 18 or experimental. const hasReactRoot = !!process.env.__NEXT_REACT_ROOT - const hasServerComponents = - hasReactRoot && !!config.experimental.serverComponents const { target } = config const buildId: string = await nextBuildSpan @@ -814,7 +810,7 @@ export default async function build( BUILD_MANIFEST, PRERENDER_MANIFEST, path.join(SERVER_DIRECTORY, MIDDLEWARE_MANIFEST), - ...(hasServerComponents + ...(appDir ? [ path.join(SERVER_DIRECTORY, FLIGHT_MANIFEST + '.js'), path.join(SERVER_DIRECTORY, FLIGHT_MANIFEST + '.json'), @@ -912,10 +908,8 @@ export default async function build( let edgeServerResult: SingleCompilerResult | null = null if (isLikeServerless) { - if (config.experimental.serverComponents) { - throw new Error( - 'Server Components are not supported in serverless mode.' - ) + if (appDir) { + throw new Error('`appDir` is not supported in serverless mode.') } // Build client first @@ -1357,7 +1351,7 @@ export default async function build( pageRuntime, edgeInfo, pageType, - hasServerComponents, + hasServerComponents: !!appDir, }) } ) diff --git a/packages/next/build/swc/options.js b/packages/next/build/swc/options.js index 2c7d1c13fd7ed..9cfc10bd9bfc5 100644 --- a/packages/next/build/swc/options.js +++ b/packages/next/build/swc/options.js @@ -118,7 +118,7 @@ function getBaseSWCOptions({ modularizeImports: nextConfig?.experimental?.modularizeImports, relay: nextConfig?.compiler?.relay, emotion: getEmotionOptions(nextConfig, development), - serverComponents: nextConfig?.experimental?.serverComponents + serverComponents: nextConfig?.experimental?.appDir ? { isServer: !!isServerLayer, } diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts index 48d71e8f4b1ee..07cc82f4b4ab1 100644 --- a/packages/next/build/webpack-config.ts +++ b/packages/next/build/webpack-config.ts @@ -544,22 +544,16 @@ export default async function getBaseWebpackConfig( '`experimental.runtime` requires React 18 to be installed.' ) } - if (config.experimental.serverComponents) { + if (config.experimental.appDir) { throw new Error( - '`experimental.serverComponents` requires React 18 to be installed.' + '`experimental.appDir` requires React 18 to be installed.' ) } } - if (!config.experimental.appDir && config.experimental.serverComponents) { - throw new Error( - '`experimental.serverComponents` requires experimental.appDir to be enabled.' - ) - } } const hasConcurrentFeatures = hasReactRoot - const hasServerComponents = - hasConcurrentFeatures && !!config.experimental.serverComponents + const hasServerComponents = !!config.experimental.appDir const disableOptimizedLoading = hasConcurrentFeatures ? true : config.experimental.disableOptimizedLoading @@ -1812,7 +1806,7 @@ export default async function getBaseWebpackConfig( } = require('./webpack/plugins/nextjs-require-cache-hot-reloader') const devPlugins = [ new NextJsRequireCacheHotReloader({ - hasServerComponents: config.experimental.serverComponents, + hasServerComponents, }), ] @@ -1881,11 +1875,9 @@ export default async function getBaseWebpackConfig( }, }), !!config.experimental.appDir && - hasServerComponents && isClient && new AppBuildManifestPlugin({ dev }), hasServerComponents && - !!config.experimental.appDir && (isClient ? new FlightManifestPlugin({ dev, diff --git a/packages/next/export/index.ts b/packages/next/export/index.ts index 1f35bc9e56e88..8a5d48ab17a69 100644 --- a/packages/next/export/index.ts +++ b/packages/next/export/index.ts @@ -388,7 +388,7 @@ export default async function exportApp( nextScriptWorkers: nextConfig.experimental.nextScriptWorkers, optimizeFonts: nextConfig.optimizeFonts as FontConfig, largePageDataBytes: nextConfig.experimental.largePageDataBytes, - serverComponents: nextConfig.experimental.serverComponents, + serverComponents: !!nextConfig.experimental.appDir, } const { serverRuntimeConfig, publicRuntimeConfig } = nextConfig @@ -613,7 +613,7 @@ export default async function exportApp( nextConfig.experimental.disableOptimizedLoading, parentSpanId: pageExportSpan.id, httpAgentOptions: nextConfig.httpAgentOptions, - serverComponents: nextConfig.experimental.serverComponents, + serverComponents: !!nextConfig.experimental.appDir, appPaths: options.appPaths || [], }) diff --git a/packages/next/server/base-server.ts b/packages/next/server/base-server.ts index 788aadf661377..125116f80afa7 100644 --- a/packages/next/server/base-server.ts +++ b/packages/next/server/base-server.ts @@ -363,7 +363,7 @@ export default abstract class Server { this.buildId = this.getBuildId() this.minimalMode = minimalMode || !!process.env.NEXT_PRIVATE_MINIMAL_MODE - const serverComponents = this.nextConfig.experimental.serverComponents + const serverComponents = !!this.nextConfig.experimental.appDir this.serverComponentManifest = serverComponents ? this.getServerComponentManifest() : undefined diff --git a/packages/next/server/config-schema.ts b/packages/next/server/config-schema.ts index d22bb9d61c491..1592d0624e8a8 100644 --- a/packages/next/server/config-schema.ts +++ b/packages/next/server/config-schema.ts @@ -342,9 +342,6 @@ const configSchema = { scrollRestoration: { type: 'boolean', }, - serverComponents: { - type: 'boolean', - }, sharedPool: { type: 'boolean', }, diff --git a/packages/next/server/config-shared.ts b/packages/next/server/config-shared.ts index 769fe0bb6fedc..d0612a7d4fb35 100644 --- a/packages/next/server/config-shared.ts +++ b/packages/next/server/config-shared.ts @@ -114,7 +114,6 @@ export interface ExperimentalConfig { esmExternals?: boolean | 'loose' isrMemoryCacheSize?: number runtime?: Exclude - serverComponents?: boolean fullySpecified?: boolean urlImports?: NonNullable['buildHttp'] outputFileTracingRoot?: string @@ -570,7 +569,6 @@ export const defaultConfig: NextConfig = { // default to 50MB limit isrMemoryCacheSize: 50 * 1024 * 1024, incrementalCacheHandlerPath: undefined, - serverComponents: false, fullySpecified: false, outputFileTracingRoot: process.env.NEXT_PRIVATE_OUTPUT_TRACE_ROOT || '', swcTraceProfiling: false, diff --git a/packages/next/server/dev/hot-reloader.ts b/packages/next/server/dev/hot-reloader.ts index e4ebb99edcfad..cdf1c7c00904a 100644 --- a/packages/next/server/dev/hot-reloader.ts +++ b/packages/next/server/dev/hot-reloader.ts @@ -217,8 +217,7 @@ export default class HotReloader { this.config = config this.hasReactRoot = !!process.env.__NEXT_REACT_ROOT - this.hasServerComponents = - this.hasReactRoot && !!config.experimental.serverComponents + this.hasServerComponents = this.hasReactRoot && !!config.experimental.appDir this.previewProps = previewProps this.rewrites = rewrites this.hotReloaderSpan = trace('hot-reloader', undefined, { diff --git a/packages/next/server/dev/next-dev-server.ts b/packages/next/server/dev/next-dev-server.ts index 8c66ad17dfe14..9128481ca70b2 100644 --- a/packages/next/server/dev/next-dev-server.ts +++ b/packages/next/server/dev/next-dev-server.ts @@ -1347,11 +1347,9 @@ export default class DevServer extends Server { clientOnly: false, }) - const serverComponents = this.nextConfig.experimental.serverComponents - // When the new page is compiled, we need to reload the server component // manifest. - if (serverComponents) { + if (this.nextConfig.experimental.appDir) { this.serverComponentManifest = super.getServerComponentManifest() this.serverCSSManifest = super.getServerCSSManifest() } diff --git a/packages/next/server/next-server.ts b/packages/next/server/next-server.ts index 57ca093018fba..3a077b90aa16e 100644 --- a/packages/next/server/next-server.ts +++ b/packages/next/server/next-server.ts @@ -1003,12 +1003,12 @@ export default class NextNodeServer extends BaseServer { } protected getServerComponentManifest() { - if (!this.nextConfig.experimental.serverComponents) return undefined + if (!this.nextConfig.experimental.appDir) return undefined return require(join(this.distDir, 'server', FLIGHT_MANIFEST + '.json')) } protected getServerCSSManifest() { - if (!this.nextConfig.experimental.serverComponents) return undefined + if (!this.nextConfig.experimental.appDir) return undefined return require(join( this.distDir, 'server', diff --git a/test/e2e/app-dir/app-alias/next.config.js b/test/e2e/app-dir/app-alias/next.config.js index b76b309cf1e35..a928ea943ce24 100644 --- a/test/e2e/app-dir/app-alias/next.config.js +++ b/test/e2e/app-dir/app-alias/next.config.js @@ -1,7 +1,6 @@ module.exports = { experimental: { appDir: true, - serverComponents: true, legacyBrowsers: false, browsersListForSwc: true, }, diff --git a/test/e2e/app-dir/app-prefetch/next.config.js b/test/e2e/app-dir/app-prefetch/next.config.js index b76b309cf1e35..a928ea943ce24 100644 --- a/test/e2e/app-dir/app-prefetch/next.config.js +++ b/test/e2e/app-dir/app-prefetch/next.config.js @@ -1,7 +1,6 @@ module.exports = { experimental: { appDir: true, - serverComponents: true, legacyBrowsers: false, browsersListForSwc: true, }, diff --git a/test/e2e/app-dir/app-rendering/next.config.js b/test/e2e/app-dir/app-rendering/next.config.js index 3f98f92f3198e..cfa3ac3d7aa94 100644 --- a/test/e2e/app-dir/app-rendering/next.config.js +++ b/test/e2e/app-dir/app-rendering/next.config.js @@ -1,6 +1,5 @@ module.exports = { experimental: { appDir: true, - serverComponents: true, }, } diff --git a/test/e2e/app-dir/app-static/next.config.js b/test/e2e/app-dir/app-static/next.config.js index 087742808cea7..091213d1e209e 100644 --- a/test/e2e/app-dir/app-static/next.config.js +++ b/test/e2e/app-dir/app-static/next.config.js @@ -1,7 +1,6 @@ module.exports = { experimental: { appDir: true, - serverComponents: true, legacyBrowsers: false, browsersListForSwc: true, }, diff --git a/test/e2e/app-dir/app/next.config.js b/test/e2e/app-dir/app/next.config.js index ab7d00811f2d4..e8bb0d14c3bf0 100644 --- a/test/e2e/app-dir/app/next.config.js +++ b/test/e2e/app-dir/app/next.config.js @@ -1,7 +1,6 @@ module.exports = { experimental: { appDir: true, - serverComponents: true, legacyBrowsers: false, browsersListForSwc: true, sri: { diff --git a/test/e2e/app-dir/asset-prefix/next.config.js b/test/e2e/app-dir/asset-prefix/next.config.js index e4b609fda5927..787a2d28c0d3b 100644 --- a/test/e2e/app-dir/asset-prefix/next.config.js +++ b/test/e2e/app-dir/asset-prefix/next.config.js @@ -1,7 +1,6 @@ module.exports = { experimental: { appDir: true, - serverComponents: true, legacyBrowsers: false, browsersListForSwc: true, }, diff --git a/test/e2e/app-dir/rsc-basic/next.config.js b/test/e2e/app-dir/rsc-basic/next.config.js index eab44b6855ae3..d642b23a9be0c 100644 --- a/test/e2e/app-dir/rsc-basic/next.config.js +++ b/test/e2e/app-dir/rsc-basic/next.config.js @@ -5,7 +5,6 @@ module.exports = { }, experimental: { appDir: true, - serverComponents: true, }, rewrites: async () => { return { diff --git a/test/e2e/app-dir/trailingslash/next.config.js b/test/e2e/app-dir/trailingslash/next.config.js index a4194e110b517..9a45bcda76776 100644 --- a/test/e2e/app-dir/trailingslash/next.config.js +++ b/test/e2e/app-dir/trailingslash/next.config.js @@ -1,7 +1,6 @@ module.exports = { experimental: { appDir: true, - serverComponents: true, legacyBrowsers: false, browsersListForSwc: true, }, diff --git a/test/e2e/switchable-runtime/next.config.js b/test/e2e/switchable-runtime/next.config.js index a055cc5ad2bc5..b286c63398651 100644 --- a/test/e2e/switchable-runtime/next.config.js +++ b/test/e2e/switchable-runtime/next.config.js @@ -3,7 +3,6 @@ module.exports = { reactStrictMode: true, experimental: { appDir: true, - serverComponents: true, }, async rewrites() { return { diff --git a/test/integration/react-streaming/app/next.config.js b/test/integration/react-streaming/app/next.config.js index b4a9d15711768..f6ddb0bd70fd2 100644 --- a/test/integration/react-streaming/app/next.config.js +++ b/test/integration/react-streaming/app/next.config.js @@ -5,7 +5,6 @@ module.exports = { // }, // pageExtensions: ['js', 'ts', 'jsx'], // .tsx won't be treat as page, experimental: { - // serverComponents: true, runtime: 'nodejs', }, } diff --git a/test/integration/react-streaming/unsupported-native-module/next.config.js b/test/integration/react-streaming/unsupported-native-module/next.config.js index 060d50f525d62..e289c86facd62 100644 --- a/test/integration/react-streaming/unsupported-native-module/next.config.js +++ b/test/integration/react-streaming/unsupported-native-module/next.config.js @@ -1,5 +1,3 @@ module.exports = { - experimental: { - serverComponents: true, - }, + experimental: {}, } From 97b31873e174a35bb07533b9e8829013c16549bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Born=C3=B6?= Date: Wed, 21 Sep 2022 22:35:49 +0200 Subject: [PATCH 10/76] next-swc: add next-font-loaders to crates/core (#40221) For some context: https://vercel.slack.com/archives/CGU8HUTUH/p1662124179102509 Transforms call expressions of imported functions, only affects imports specified in SWC options. Each argument is turned into JSON and appended to the import as a query. The query can be read in a webpack loader, i.e. the call expression is only evaluated at build time ### Transform From ```tsx import { Fn } from "package" const res = Fn(1, "2", { three: true }) ``` To ```tsx import res from 'package?Fn;1;"2";{"three":true}' ``` ### Visitors #### NextFontLoaders (mod.rs) Creates several visitors that updates the state and reports errors. This is where the AST is mutated. After all other visitors are done the call expressions and original imports are removed. The newly generated imports are added instead. #### FontFunctionsCollector Finds imports from the specified packages. Function calls of these imports should be transformed. #### FontImportsGenerator Creates import declarations, call expression arguments are turned into JSON and added to the import as a query. #### FindFunctionsOutsideModuleScope Makes sure that there's no reference of the functions anywhere else but the module scope. Co-authored-by: JJ Kasper --- packages/next-swc/crates/core/src/lib.rs | 10 + .../find_functions_outside_module_scope.rs | 31 +++ .../font_functions_collector.rs | 68 ++++++ .../font_imports_generator.rs | 220 ++++++++++++++++++ .../crates/core/src/next_font_loaders/mod.rs | 77 ++++++ packages/next-swc/crates/core/tests/errors.rs | 14 +- .../next-font-loaders/import-all/input.js | 1 + .../next-font-loaders/import-all/output.js | 0 .../import-all/output.stderr | 6 + .../next-font-loaders/not-const/input.js | 11 + .../next-font-loaders/not-const/output.js | 4 + .../next-font-loaders/not-const/output.stderr | 14 ++ .../next-font-loaders/not-ident/input.js | 11 + .../next-font-loaders/not-ident/output.js | 1 + .../next-font-loaders/not-ident/output.stderr | 12 + .../next-font-loaders/options-object/input.js | 13 ++ .../options-object/output.js | 18 ++ .../options-object/output.stderr | 24 ++ .../next-font-loaders/spread-arg/input.js | 4 + .../next-font-loaders/spread-arg/output.js | 2 + .../spread-arg/output.stderr | 12 + .../next-font-loaders/wrong-scope/input.js | 24 ++ .../next-font-loaders/wrong-scope/output.js | 20 ++ .../wrong-scope/output.stderr | 30 +++ .../next-swc/crates/core/tests/fixture.rs | 12 + .../next-font-loaders/default-import/input.js | 3 + .../default-import/output.js | 1 + .../next-font-loaders/exports/input.js | 8 + .../next-font-loaders/exports/output.js | 5 + .../next-font-loaders/font-options/input.js | 11 + .../next-font-loaders/font-options/output.js | 3 + .../next-font-loaders/import-as/input.js | 6 + .../next-font-loaders/import-as/output.js | 2 + .../next-font-loaders/many-args/input.js | 3 + .../next-font-loaders/many-args/output.js | 1 + .../next-font-loaders/multiple-calls/input.js | 12 + .../multiple-calls/output.js | 3 + .../multiple-font-downloaders/input.js | 12 + .../multiple-font-downloaders/output.js | 3 + .../next-font-loaders/multiple-fonts/input.js | 11 + .../multiple-fonts/output.js | 3 + .../multiple-imports/input.js | 12 + .../multiple-imports/output.js | 3 + .../next-font-loaders/no-args/input.js | 3 + .../next-font-loaders/no-args/output.js | 1 + packages/next-swc/crates/core/tests/full.rs | 1 + 46 files changed, 745 insertions(+), 1 deletion(-) create mode 100644 packages/next-swc/crates/core/src/next_font_loaders/find_functions_outside_module_scope.rs create mode 100644 packages/next-swc/crates/core/src/next_font_loaders/font_functions_collector.rs create mode 100644 packages/next-swc/crates/core/src/next_font_loaders/font_imports_generator.rs create mode 100644 packages/next-swc/crates/core/src/next_font_loaders/mod.rs create mode 100644 packages/next-swc/crates/core/tests/errors/next-font-loaders/import-all/input.js create mode 100644 packages/next-swc/crates/core/tests/errors/next-font-loaders/import-all/output.js create mode 100644 packages/next-swc/crates/core/tests/errors/next-font-loaders/import-all/output.stderr create mode 100644 packages/next-swc/crates/core/tests/errors/next-font-loaders/not-const/input.js create mode 100644 packages/next-swc/crates/core/tests/errors/next-font-loaders/not-const/output.js create mode 100644 packages/next-swc/crates/core/tests/errors/next-font-loaders/not-const/output.stderr create mode 100644 packages/next-swc/crates/core/tests/errors/next-font-loaders/not-ident/input.js create mode 100644 packages/next-swc/crates/core/tests/errors/next-font-loaders/not-ident/output.js create mode 100644 packages/next-swc/crates/core/tests/errors/next-font-loaders/not-ident/output.stderr create mode 100644 packages/next-swc/crates/core/tests/errors/next-font-loaders/options-object/input.js create mode 100644 packages/next-swc/crates/core/tests/errors/next-font-loaders/options-object/output.js create mode 100644 packages/next-swc/crates/core/tests/errors/next-font-loaders/options-object/output.stderr create mode 100644 packages/next-swc/crates/core/tests/errors/next-font-loaders/spread-arg/input.js create mode 100644 packages/next-swc/crates/core/tests/errors/next-font-loaders/spread-arg/output.js create mode 100644 packages/next-swc/crates/core/tests/errors/next-font-loaders/spread-arg/output.stderr create mode 100644 packages/next-swc/crates/core/tests/errors/next-font-loaders/wrong-scope/input.js create mode 100644 packages/next-swc/crates/core/tests/errors/next-font-loaders/wrong-scope/output.js create mode 100644 packages/next-swc/crates/core/tests/errors/next-font-loaders/wrong-scope/output.stderr create mode 100644 packages/next-swc/crates/core/tests/fixture/next-font-loaders/default-import/input.js create mode 100644 packages/next-swc/crates/core/tests/fixture/next-font-loaders/default-import/output.js create mode 100644 packages/next-swc/crates/core/tests/fixture/next-font-loaders/exports/input.js create mode 100644 packages/next-swc/crates/core/tests/fixture/next-font-loaders/exports/output.js create mode 100644 packages/next-swc/crates/core/tests/fixture/next-font-loaders/font-options/input.js create mode 100644 packages/next-swc/crates/core/tests/fixture/next-font-loaders/font-options/output.js create mode 100644 packages/next-swc/crates/core/tests/fixture/next-font-loaders/import-as/input.js create mode 100644 packages/next-swc/crates/core/tests/fixture/next-font-loaders/import-as/output.js create mode 100644 packages/next-swc/crates/core/tests/fixture/next-font-loaders/many-args/input.js create mode 100644 packages/next-swc/crates/core/tests/fixture/next-font-loaders/many-args/output.js create mode 100644 packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-calls/input.js create mode 100644 packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-calls/output.js create mode 100644 packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-font-downloaders/input.js create mode 100644 packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-font-downloaders/output.js create mode 100644 packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-fonts/input.js create mode 100644 packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-fonts/output.js create mode 100644 packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-imports/input.js create mode 100644 packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-imports/output.js create mode 100644 packages/next-swc/crates/core/tests/fixture/next-font-loaders/no-args/input.js create mode 100644 packages/next-swc/crates/core/tests/fixture/next-font-loaders/no-args/output.js diff --git a/packages/next-swc/crates/core/src/lib.rs b/packages/next-swc/crates/core/src/lib.rs index 4ebe788b24e1b..3d3bca8aca192 100644 --- a/packages/next-swc/crates/core/src/lib.rs +++ b/packages/next-swc/crates/core/src/lib.rs @@ -36,6 +36,7 @@ use serde::Deserialize; use std::cell::RefCell; use std::rc::Rc; use std::{path::PathBuf, sync::Arc}; +use swc_core::ecma::atoms::JsWord; use swc_core::{ base::config::ModuleConfig, @@ -51,6 +52,7 @@ mod auto_cjs; pub mod disallow_re_export_all_in_page; pub mod hook_optimizer; pub mod next_dynamic; +pub mod next_font_loaders; pub mod next_ssg; pub mod page_config; pub mod react_remove_properties; @@ -109,6 +111,9 @@ pub struct TransformOptions { #[serde(default)] pub modularize_imports: Option, + + #[serde(default)] + pub font_loaders: Option>, } pub fn custom_before_pass<'a, C: Comments + 'a>( @@ -211,6 +216,11 @@ where match &opts.modularize_imports { Some(config) => Either::Left(modularize_imports::modularize_imports(config.clone())), None => Either::Right(noop()), + }, + match &opts.font_loaders { + Some(font_loaders) => + Either::Left(next_font_loaders::next_font_loaders(font_loaders.clone())), + None => Either::Right(noop()), } ) } diff --git a/packages/next-swc/crates/core/src/next_font_loaders/find_functions_outside_module_scope.rs b/packages/next-swc/crates/core/src/next_font_loaders/find_functions_outside_module_scope.rs new file mode 100644 index 0000000000000..f83742d205436 --- /dev/null +++ b/packages/next-swc/crates/core/src/next_font_loaders/find_functions_outside_module_scope.rs @@ -0,0 +1,31 @@ +use swc_core::common::errors::HANDLER; +use swc_core::ecma::ast::*; +use swc_core::ecma::visit::noop_visit_type; +use swc_core::ecma::visit::Visit; + +pub struct FindFunctionsOutsideModuleScope<'a> { + pub state: &'a super::State, +} + +impl<'a> Visit for FindFunctionsOutsideModuleScope<'a> { + noop_visit_type!(); + + fn visit_ident(&mut self, ident: &Ident) { + if self.state.font_functions.get(&ident.to_id()).is_some() + && self + .state + .font_functions_in_allowed_scope + .get(&ident.span.lo) + .is_none() + { + HANDLER.with(|handler| { + handler + .struct_span_err( + ident.span, + "Font loaders must be called and assigned to a const in the module scope", + ) + .emit() + }); + } + } +} diff --git a/packages/next-swc/crates/core/src/next_font_loaders/font_functions_collector.rs b/packages/next-swc/crates/core/src/next_font_loaders/font_functions_collector.rs new file mode 100644 index 0000000000000..e8fdfce66f0e6 --- /dev/null +++ b/packages/next-swc/crates/core/src/next_font_loaders/font_functions_collector.rs @@ -0,0 +1,68 @@ +use swc_core::common::errors::HANDLER; +use swc_core::ecma::ast::*; +use swc_core::ecma::atoms::JsWord; +use swc_core::ecma::visit::noop_visit_type; +use swc_core::ecma::visit::Visit; + +pub struct FontFunctionsCollector<'a> { + pub font_loaders: &'a [JsWord], + pub state: &'a mut super::State, +} + +impl<'a> Visit for FontFunctionsCollector<'a> { + noop_visit_type!(); + + fn visit_import_decl(&mut self, import_decl: &ImportDecl) { + if self.font_loaders.contains(&import_decl.src.value) { + self.state + .removeable_module_items + .insert(import_decl.span.lo); + for specifier in &import_decl.specifiers { + match specifier { + ImportSpecifier::Named(ImportNamedSpecifier { + local, imported, .. + }) => { + self.state + .font_functions_in_allowed_scope + .insert(local.span.lo); + + let function_name = if let Some(ModuleExportName::Ident(ident)) = imported { + ident.sym.clone() + } else { + local.sym.clone() + }; + self.state.font_functions.insert( + local.to_id(), + super::FontFunction { + loader: import_decl.src.value.clone(), + function_name: Some(function_name), + }, + ); + } + ImportSpecifier::Default(ImportDefaultSpecifier { local, .. }) => { + self.state + .font_functions_in_allowed_scope + .insert(local.span.lo); + self.state.font_functions.insert( + local.to_id(), + super::FontFunction { + loader: import_decl.src.value.clone(), + function_name: None, + }, + ); + } + ImportSpecifier::Namespace(_) => { + HANDLER.with(|handler| { + handler + .struct_span_err( + import_decl.span, + "Font loaders can't have namespace imports", + ) + .emit() + }); + } + } + } + } + } +} diff --git a/packages/next-swc/crates/core/src/next_font_loaders/font_imports_generator.rs b/packages/next-swc/crates/core/src/next_font_loaders/font_imports_generator.rs new file mode 100644 index 0000000000000..6f8e3bb340712 --- /dev/null +++ b/packages/next-swc/crates/core/src/next_font_loaders/font_imports_generator.rs @@ -0,0 +1,220 @@ +use serde_json::Value; +use swc_core::common::errors::HANDLER; +use swc_core::common::{Spanned, DUMMY_SP}; +use swc_core::ecma::ast::*; +use swc_core::ecma::atoms::JsWord; +use swc_core::ecma::visit::{noop_visit_type, Visit}; + +pub struct FontImportsGenerator<'a> { + pub state: &'a mut super::State, +} + +impl<'a> FontImportsGenerator<'a> { + fn check_call_expr(&mut self, call_expr: &CallExpr) -> Option { + if let Callee::Expr(callee_expr) = &call_expr.callee { + if let Expr::Ident(ident) = &**callee_expr { + if let Some(font_function) = self.state.font_functions.get(&ident.to_id()) { + self.state + .font_functions_in_allowed_scope + .insert(ident.span.lo); + + let json: Result, ()> = call_expr + .args + .iter() + .map(|expr_or_spread| { + if let Some(span) = expr_or_spread.spread { + HANDLER.with(|handler| { + handler + .struct_span_err(span, "Font loaders don't accept spreads") + .emit() + }); + } + + expr_to_json(&*expr_or_spread.expr) + }) + .collect(); + + if let Ok(json) = json { + let mut json_values: Vec = + json.iter().map(|value| value.to_string()).collect(); + let function_name = match &font_function.function_name { + Some(function) => String::from(&**function), + None => String::new(), + }; + let mut values = vec![function_name]; + values.append(&mut json_values); + + return Some(ImportDecl { + src: Str { + value: JsWord::from(format!( + "{}?{}", + font_function.loader, + values.join(";") + )), + raw: None, + span: DUMMY_SP, + }, + specifiers: vec![], + type_only: false, + asserts: None, + span: DUMMY_SP, + }); + } + } + } + } + + None + } + + fn check_var_decl(&mut self, var_decl: &VarDecl) { + if let Some(decl) = var_decl.decls.get(0) { + let ident = match &decl.name { + Pat::Ident(ident) => Ok(ident.id.clone()), + pattern => Err(pattern), + }; + if let Some(expr) = &decl.init { + if let Expr::Call(call_expr) = &**expr { + let import_decl = self.check_call_expr(call_expr); + + if let Some(mut import_decl) = import_decl { + self.state.removeable_module_items.insert(var_decl.span.lo); + + match var_decl.kind { + VarDeclKind::Const => {} + _ => { + HANDLER.with(|handler| { + handler + .struct_span_err( + var_decl.span, + "Font loader calls must be assigned to a const", + ) + .emit() + }); + } + } + + match ident { + Ok(ident) => { + import_decl.specifiers = + vec![ImportSpecifier::Default(ImportDefaultSpecifier { + span: DUMMY_SP, + local: ident, + })]; + + self.state + .font_imports + .push(ModuleItem::ModuleDecl(ModuleDecl::Import(import_decl))); + } + Err(pattern) => { + HANDLER.with(|handler| { + handler + .struct_span_err( + pattern.span(), + "Font loader calls must be assigned to an identifier", + ) + .emit() + }); + } + } + } + } + } + } + } +} + +impl<'a> Visit for FontImportsGenerator<'a> { + noop_visit_type!(); + + fn visit_module_item(&mut self, item: &ModuleItem) { + if let ModuleItem::Stmt(Stmt::Decl(Decl::Var(var_decl))) = item { + self.check_var_decl(var_decl); + } + } +} + +fn object_lit_to_json(object_lit: &ObjectLit) -> Value { + let mut values = serde_json::Map::new(); + for prop in &object_lit.props { + match prop { + PropOrSpread::Prop(prop) => match &**prop { + Prop::KeyValue(key_val) => { + let key = match &key_val.key { + PropName::Ident(ident) => Ok(String::from(&*ident.sym)), + key => { + HANDLER.with(|handler| { + handler + .struct_span_err(key.span(), "Unexpected object key type") + .emit() + }); + Err(()) + } + }; + let val = expr_to_json(&*key_val.value); + if let (Ok(key), Ok(val)) = (key, val) { + values.insert(key, val); + } + } + key => HANDLER.with(|handler| { + handler.struct_span_err(key.span(), "Unexpected key").emit(); + }), + }, + PropOrSpread::Spread(spread_span) => HANDLER.with(|handler| { + handler + .struct_span_err(spread_span.dot3_token, "Unexpected spread") + .emit(); + }), + } + } + + Value::Object(values) +} + +fn expr_to_json(expr: &Expr) -> Result { + match expr { + Expr::Lit(Lit::Str(str)) => Ok(Value::String(String::from(&*str.value))), + Expr::Lit(Lit::Bool(Bool { value, .. })) => Ok(Value::Bool(*value)), + Expr::Lit(Lit::Num(Number { value, .. })) => { + Ok(Value::Number(serde_json::Number::from_f64(*value).unwrap())) + } + Expr::Object(object_lit) => Ok(object_lit_to_json(object_lit)), + Expr::Array(ArrayLit { + elems, + span: array_span, + .. + }) => { + let elements: Result, ()> = elems + .iter() + .map(|e| { + if let Some(expr) = e { + match expr.spread { + Some(spread_span) => HANDLER.with(|handler| { + handler + .struct_span_err(spread_span, "Unexpected spread") + .emit(); + Err(()) + }), + None => expr_to_json(&*expr.expr), + } + } else { + HANDLER.with(|handler| { + handler + .struct_span_err(*array_span, "Unexpected empty value in array") + .emit(); + Err(()) + }) + } + }) + .collect(); + + elements.map(Value::Array) + } + lit => HANDLER.with(|handler| { + handler + .struct_span_err(lit.span(), "Unexpected value") + .emit(); + Err(()) + }), + } +} diff --git a/packages/next-swc/crates/core/src/next_font_loaders/mod.rs b/packages/next-swc/crates/core/src/next_font_loaders/mod.rs new file mode 100644 index 0000000000000..4acf0c9ab2a44 --- /dev/null +++ b/packages/next-swc/crates/core/src/next_font_loaders/mod.rs @@ -0,0 +1,77 @@ +use fxhash::FxHashSet; +use swc_core::{ + common::{collections::AHashMap, BytePos, Spanned}, + ecma::{ + ast::Id, + visit::{as_folder, noop_visit_mut_type, Fold, VisitMut, VisitWith}, + }, + ecma::{ast::ModuleItem, atoms::JsWord}, +}; + +mod find_functions_outside_module_scope; +mod font_functions_collector; +mod font_imports_generator; + +pub fn next_font_loaders(font_loaders: Vec) -> impl Fold + VisitMut { + as_folder(NextFontLoaders { + font_loaders, + state: State { + ..Default::default() + }, + }) +} + +#[derive(Debug)] +pub struct FontFunction { + loader: JsWord, + function_name: Option, +} +#[derive(Debug, Default)] +pub struct State { + font_functions: AHashMap, + removeable_module_items: FxHashSet, + font_imports: Vec, + font_functions_in_allowed_scope: FxHashSet, +} + +struct NextFontLoaders { + font_loaders: Vec, + state: State, +} + +impl VisitMut for NextFontLoaders { + noop_visit_mut_type!(); + + fn visit_mut_module_items(&mut self, items: &mut Vec) { + // Find imported functions from font loaders + let mut functions_collector = font_functions_collector::FontFunctionsCollector { + font_loaders: &self.font_loaders, + state: &mut self.state, + }; + items.visit_with(&mut functions_collector); + + if !self.state.removeable_module_items.is_empty() { + // Generate imports from font function calls + let mut import_generator = font_imports_generator::FontImportsGenerator { + state: &mut self.state, + }; + items.visit_with(&mut import_generator); + + // Find font function refs in wrong scope + let mut wrong_scope = + find_functions_outside_module_scope::FindFunctionsOutsideModuleScope { + state: &self.state, + }; + items.visit_with(&mut wrong_scope); + + // Remove marked module items + items.retain(|item| !self.state.removeable_module_items.contains(&item.span_lo())); + + // Add font imports + let mut new_items = Vec::new(); + new_items.append(&mut self.state.font_imports); + new_items.append(items); + *items = new_items; + } + } +} diff --git a/packages/next-swc/crates/core/tests/errors.rs b/packages/next-swc/crates/core/tests/errors.rs index 5571406e6a22b..83df8f2851280 100644 --- a/packages/next-swc/crates/core/tests/errors.rs +++ b/packages/next-swc/crates/core/tests/errors.rs @@ -1,6 +1,7 @@ use next_swc::{ disallow_re_export_all_in_page::disallow_re_export_all_in_page, next_dynamic::next_dynamic, - next_ssg::next_ssg, react_server_components::server_components, + next_font_loaders::next_font_loaders, next_ssg::next_ssg, + react_server_components::server_components, }; use std::path::PathBuf; use swc_core::{ @@ -94,3 +95,14 @@ fn react_server_components_client_graph_errors(input: PathBuf) { &output, ); } + +#[fixture("tests/errors/next-font-loaders/**/input.js")] +fn next_font_loaders_errors(input: PathBuf) { + let output = input.parent().unwrap().join("output.js"); + test_fixture_allowing_error( + syntax(), + &|_tr| next_font_loaders(vec!["@next/font/google".into(), "cool-fonts".into()]), + &input, + &output, + ); +} diff --git a/packages/next-swc/crates/core/tests/errors/next-font-loaders/import-all/input.js b/packages/next-swc/crates/core/tests/errors/next-font-loaders/import-all/input.js new file mode 100644 index 0000000000000..27cc0a2526ce1 --- /dev/null +++ b/packages/next-swc/crates/core/tests/errors/next-font-loaders/import-all/input.js @@ -0,0 +1 @@ +import * as googleFonts from '@next/font/google' diff --git a/packages/next-swc/crates/core/tests/errors/next-font-loaders/import-all/output.js b/packages/next-swc/crates/core/tests/errors/next-font-loaders/import-all/output.js new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/packages/next-swc/crates/core/tests/errors/next-font-loaders/import-all/output.stderr b/packages/next-swc/crates/core/tests/errors/next-font-loaders/import-all/output.stderr new file mode 100644 index 0000000000000..c9d0e143c7c65 --- /dev/null +++ b/packages/next-swc/crates/core/tests/errors/next-font-loaders/import-all/output.stderr @@ -0,0 +1,6 @@ + + x Font loaders can't have namespace imports + ,-[input.js:1:1] + 1 | import * as googleFonts from '@next/font/google' + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + `---- diff --git a/packages/next-swc/crates/core/tests/errors/next-font-loaders/not-const/input.js b/packages/next-swc/crates/core/tests/errors/next-font-loaders/not-const/input.js new file mode 100644 index 0000000000000..11316faab0959 --- /dev/null +++ b/packages/next-swc/crates/core/tests/errors/next-font-loaders/not-const/input.js @@ -0,0 +1,11 @@ +import { Inter } from '@next/font/google' + +var i = 10 +var inter1 = Inter({ + variant: '400', +}) + +var i2 = 20 +let inter2 = Inter({ + variant: '400', +}) diff --git a/packages/next-swc/crates/core/tests/errors/next-font-loaders/not-const/output.js b/packages/next-swc/crates/core/tests/errors/next-font-loaders/not-const/output.js new file mode 100644 index 0000000000000..7048782e0b9d9 --- /dev/null +++ b/packages/next-swc/crates/core/tests/errors/next-font-loaders/not-const/output.js @@ -0,0 +1,4 @@ +import inter1 from '@next/font/google?Inter;{"variant":"400"}'; +import inter2 from '@next/font/google?Inter;{"variant":"400"}'; +var i = 10; +var i2 = 20; diff --git a/packages/next-swc/crates/core/tests/errors/next-font-loaders/not-const/output.stderr b/packages/next-swc/crates/core/tests/errors/next-font-loaders/not-const/output.stderr new file mode 100644 index 0000000000000..f1ca698810bc9 --- /dev/null +++ b/packages/next-swc/crates/core/tests/errors/next-font-loaders/not-const/output.stderr @@ -0,0 +1,14 @@ + + x Font loader calls must be assigned to a const + ,-[input.js:4:1] + 4 | ,-> var inter1 = Inter({ + 5 | | variant: '400', + 6 | `-> }) + `---- + + x Font loader calls must be assigned to a const + ,-[input.js:9:1] + 9 | ,-> let inter2 = Inter({ + 10 | | variant: '400', + 11 | `-> }) + `---- diff --git a/packages/next-swc/crates/core/tests/errors/next-font-loaders/not-ident/input.js b/packages/next-swc/crates/core/tests/errors/next-font-loaders/not-ident/input.js new file mode 100644 index 0000000000000..835fb846f93c1 --- /dev/null +++ b/packages/next-swc/crates/core/tests/errors/next-font-loaders/not-ident/input.js @@ -0,0 +1,11 @@ +import { Inter } from '@next/font/google' + +const { a } = Inter({ + variant: '400', +}) + +const [b] = Inter({ + variant: '400', +}) + +const { e } = {} diff --git a/packages/next-swc/crates/core/tests/errors/next-font-loaders/not-ident/output.js b/packages/next-swc/crates/core/tests/errors/next-font-loaders/not-ident/output.js new file mode 100644 index 0000000000000..ac0e441683cdc --- /dev/null +++ b/packages/next-swc/crates/core/tests/errors/next-font-loaders/not-ident/output.js @@ -0,0 +1 @@ +const { e } = {}; diff --git a/packages/next-swc/crates/core/tests/errors/next-font-loaders/not-ident/output.stderr b/packages/next-swc/crates/core/tests/errors/next-font-loaders/not-ident/output.stderr new file mode 100644 index 0000000000000..f8e4344e9c441 --- /dev/null +++ b/packages/next-swc/crates/core/tests/errors/next-font-loaders/not-ident/output.stderr @@ -0,0 +1,12 @@ + + x Font loader calls must be assigned to an identifier + ,-[input.js:3:1] + 3 | const { a } = Inter({ + : ^^^^^ + `---- + + x Font loader calls must be assigned to an identifier + ,-[input.js:7:1] + 7 | const [b] = Inter({ + : ^^^ + `---- diff --git a/packages/next-swc/crates/core/tests/errors/next-font-loaders/options-object/input.js b/packages/next-swc/crates/core/tests/errors/next-font-loaders/options-object/input.js new file mode 100644 index 0000000000000..98c18015f2293 --- /dev/null +++ b/packages/next-swc/crates/core/tests/errors/next-font-loaders/options-object/input.js @@ -0,0 +1,13 @@ +import { ABeeZee } from '@next/font/google' + +const a = fn({ 10: 'hello' }) +const a = ABeeZee({ 10: 'hello' }) + +const a = fn({ variant: [i1] }) +const a = ABeeZee({ variant: [i1] }) + +const a = fn({ variant: () => {} }) +const a = ABeeZee({ variant: () => {} }) + +const a = fn({ ...{} }) +const a = ABeeZee({ ...{} }) diff --git a/packages/next-swc/crates/core/tests/errors/next-font-loaders/options-object/output.js b/packages/next-swc/crates/core/tests/errors/next-font-loaders/options-object/output.js new file mode 100644 index 0000000000000..073b736199d28 --- /dev/null +++ b/packages/next-swc/crates/core/tests/errors/next-font-loaders/options-object/output.js @@ -0,0 +1,18 @@ +import a from "@next/font/google?ABeeZee;{}"; +import a from "@next/font/google?ABeeZee;{}"; +import a from "@next/font/google?ABeeZee;{}"; +import a from "@next/font/google?ABeeZee;{}"; +const a = fn({ + 10: 'hello' +}); +const a = fn({ + variant: [ + i1 + ] +}); +const a = fn({ + variant: ()=>{} +}); +const a = fn({ + ...{} +}); diff --git a/packages/next-swc/crates/core/tests/errors/next-font-loaders/options-object/output.stderr b/packages/next-swc/crates/core/tests/errors/next-font-loaders/options-object/output.stderr new file mode 100644 index 0000000000000..ec93d2affb8c1 --- /dev/null +++ b/packages/next-swc/crates/core/tests/errors/next-font-loaders/options-object/output.stderr @@ -0,0 +1,24 @@ + + x Unexpected object key type + ,-[input.js:4:1] + 4 | const a = ABeeZee({ 10: 'hello' }) + : ^^ + `---- + + x Unexpected value + ,-[input.js:7:1] + 7 | const a = ABeeZee({ variant: [i1] }) + : ^^ + `---- + + x Unexpected value + ,-[input.js:10:1] + 10 | const a = ABeeZee({ variant: () => {} }) + : ^^^^^^^^ + `---- + + x Unexpected spread + ,-[input.js:13:1] + 13 | const a = ABeeZee({ ...{} }) + : ^^^ + `---- diff --git a/packages/next-swc/crates/core/tests/errors/next-font-loaders/spread-arg/input.js b/packages/next-swc/crates/core/tests/errors/next-font-loaders/spread-arg/input.js new file mode 100644 index 0000000000000..2f16f3375aedc --- /dev/null +++ b/packages/next-swc/crates/core/tests/errors/next-font-loaders/spread-arg/input.js @@ -0,0 +1,4 @@ +import { Inter } from '@next/font/google' + +const a = fn(...{}, ...[]) +const inter = Inter(...{}, ...[]) diff --git a/packages/next-swc/crates/core/tests/errors/next-font-loaders/spread-arg/output.js b/packages/next-swc/crates/core/tests/errors/next-font-loaders/spread-arg/output.js new file mode 100644 index 0000000000000..786e60366018d --- /dev/null +++ b/packages/next-swc/crates/core/tests/errors/next-font-loaders/spread-arg/output.js @@ -0,0 +1,2 @@ +import inter from "@next/font/google?Inter;{};[]"; +const a = fn(...{}, ...[]); diff --git a/packages/next-swc/crates/core/tests/errors/next-font-loaders/spread-arg/output.stderr b/packages/next-swc/crates/core/tests/errors/next-font-loaders/spread-arg/output.stderr new file mode 100644 index 0000000000000..29b46cdfe6061 --- /dev/null +++ b/packages/next-swc/crates/core/tests/errors/next-font-loaders/spread-arg/output.stderr @@ -0,0 +1,12 @@ + + x Font loaders don't accept spreads + ,-[input.js:4:1] + 4 | const inter = Inter(...{}, ...[]) + : ^^^ + `---- + + x Font loaders don't accept spreads + ,-[input.js:4:1] + 4 | const inter = Inter(...{}, ...[]) + : ^^^ + `---- diff --git a/packages/next-swc/crates/core/tests/errors/next-font-loaders/wrong-scope/input.js b/packages/next-swc/crates/core/tests/errors/next-font-loaders/wrong-scope/input.js new file mode 100644 index 0000000000000..ee86a223e6409 --- /dev/null +++ b/packages/next-swc/crates/core/tests/errors/next-font-loaders/wrong-scope/input.js @@ -0,0 +1,24 @@ +import { Aladin } from '@next/font/google' + +Aladin({}) + +let b +const a = (b = Aladin({ variant: '400' })) + +function Hello() { + const a = Aladin({ + variant: '400', + }) +} + +class C { + constructor() { + Aladin({ + variant: '400', + }) + } +} + +{ + Aladin({}) +} diff --git a/packages/next-swc/crates/core/tests/errors/next-font-loaders/wrong-scope/output.js b/packages/next-swc/crates/core/tests/errors/next-font-loaders/wrong-scope/output.js new file mode 100644 index 0000000000000..4ed290cf5baa1 --- /dev/null +++ b/packages/next-swc/crates/core/tests/errors/next-font-loaders/wrong-scope/output.js @@ -0,0 +1,20 @@ +Aladin({}); +let b; +const a = b = Aladin({ + variant: '400' +}); +function Hello() { + const a = Aladin({ + variant: '400' + }); +} +class C { + constructor(){ + Aladin({ + variant: '400' + }); + } +} +{ + Aladin({}); +} diff --git a/packages/next-swc/crates/core/tests/errors/next-font-loaders/wrong-scope/output.stderr b/packages/next-swc/crates/core/tests/errors/next-font-loaders/wrong-scope/output.stderr new file mode 100644 index 0000000000000..120dbbad406c2 --- /dev/null +++ b/packages/next-swc/crates/core/tests/errors/next-font-loaders/wrong-scope/output.stderr @@ -0,0 +1,30 @@ + + x Font loaders must be called and assigned to a const in the module scope + ,-[input.js:3:1] + 3 | Aladin({}) + : ^^^^^^ + `---- + + x Font loaders must be called and assigned to a const in the module scope + ,-[input.js:6:1] + 6 | const a = (b = Aladin({ variant: '400' })) + : ^^^^^^ + `---- + + x Font loaders must be called and assigned to a const in the module scope + ,-[input.js:9:3] + 9 | const a = Aladin({ + : ^^^^^^ + `---- + + x Font loaders must be called and assigned to a const in the module scope + ,-[input.js:16:5] + 16 | Aladin({ + : ^^^^^^ + `---- + + x Font loaders must be called and assigned to a const in the module scope + ,-[input.js:23:3] + 23 | Aladin({}) + : ^^^^^^ + `---- diff --git a/packages/next-swc/crates/core/tests/fixture.rs b/packages/next-swc/crates/core/tests/fixture.rs index ff6b8a230f13c..2df79b9a0002e 100644 --- a/packages/next-swc/crates/core/tests/fixture.rs +++ b/packages/next-swc/crates/core/tests/fixture.rs @@ -1,6 +1,7 @@ use next_swc::{ amp_attributes::amp_attributes, next_dynamic::next_dynamic, + next_font_loaders::next_font_loaders, next_ssg::next_ssg, page_config::page_config_test, react_remove_properties::remove_properties, @@ -248,3 +249,14 @@ fn react_server_components_client_graph_fixture(input: PathBuf) { &output, ); } + +#[fixture("tests/fixture/next-font-loaders/**/input.js")] +fn next_font_loaders_fixture(input: PathBuf) { + let output = input.parent().unwrap().join("output.js"); + test_fixture( + syntax(), + &|_tr| next_font_loaders(vec!["@next/font/google".into(), "cool-fonts".into()]), + &input, + &output, + ); +} diff --git a/packages/next-swc/crates/core/tests/fixture/next-font-loaders/default-import/input.js b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/default-import/input.js new file mode 100644 index 0000000000000..d1673816d856c --- /dev/null +++ b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/default-import/input.js @@ -0,0 +1,3 @@ +import cool from 'cool-fonts' + +const font = cool({ prop: true }) diff --git a/packages/next-swc/crates/core/tests/fixture/next-font-loaders/default-import/output.js b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/default-import/output.js new file mode 100644 index 0000000000000..dddf305e87bc5 --- /dev/null +++ b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/default-import/output.js @@ -0,0 +1 @@ +import font from 'cool-fonts?;{"prop":true}'; diff --git a/packages/next-swc/crates/core/tests/fixture/next-font-loaders/exports/input.js b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/exports/input.js new file mode 100644 index 0000000000000..dfaf75ad16bf9 --- /dev/null +++ b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/exports/input.js @@ -0,0 +1,8 @@ +import React from 'react' +import { Abel, Inter } from '@next/font/google' + +const firaCode = Abel() +const inter = Inter() + +export { firaCode } +export default inter diff --git a/packages/next-swc/crates/core/tests/fixture/next-font-loaders/exports/output.js b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/exports/output.js new file mode 100644 index 0000000000000..c852f5621a5cb --- /dev/null +++ b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/exports/output.js @@ -0,0 +1,5 @@ +import firaCode from "@next/font/google?Abel"; +import inter from "@next/font/google?Inter"; +import React from 'react'; +export { firaCode }; +export default inter; diff --git a/packages/next-swc/crates/core/tests/fixture/next-font-loaders/font-options/input.js b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/font-options/input.js new file mode 100644 index 0000000000000..6506b7c4ab879 --- /dev/null +++ b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/font-options/input.js @@ -0,0 +1,11 @@ +import React from 'react' +import { Fira_Code } from '@next/font/google' + +const firaCode = Fira_Code({ + variant: '400', + fallback: ['system-ui', { key: false }, []], + preload: true, + key: { key2: {} }, +}) + +console.log(firaCode) diff --git a/packages/next-swc/crates/core/tests/fixture/next-font-loaders/font-options/output.js b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/font-options/output.js new file mode 100644 index 0000000000000..3e921aeb54bf0 --- /dev/null +++ b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/font-options/output.js @@ -0,0 +1,3 @@ +import firaCode from '@next/font/google?Fira_Code;{"fallback":["system-ui",{"key":false},[]],"key":{"key2":{}},"preload":true,"variant":"400"}'; +import React from 'react'; +console.log(firaCode); diff --git a/packages/next-swc/crates/core/tests/fixture/next-font-loaders/import-as/input.js b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/import-as/input.js new file mode 100644 index 0000000000000..98a23c5752cbc --- /dev/null +++ b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/import-as/input.js @@ -0,0 +1,6 @@ +import React from 'react' +import { Acme as a } from 'cool-fonts' + +const acme1 = a({ + variant: '400', +}) diff --git a/packages/next-swc/crates/core/tests/fixture/next-font-loaders/import-as/output.js b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/import-as/output.js new file mode 100644 index 0000000000000..a1e93892abaa6 --- /dev/null +++ b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/import-as/output.js @@ -0,0 +1,2 @@ +import acme1 from 'cool-fonts?Acme;{"variant":"400"}'; +import React from 'react'; diff --git a/packages/next-swc/crates/core/tests/fixture/next-font-loaders/many-args/input.js b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/many-args/input.js new file mode 100644 index 0000000000000..9745fd807b4a9 --- /dev/null +++ b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/many-args/input.js @@ -0,0 +1,3 @@ +import { Geo } from '@next/font/google' + +const geo = Geo('test', [1], { a: 2 }, 3) diff --git a/packages/next-swc/crates/core/tests/fixture/next-font-loaders/many-args/output.js b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/many-args/output.js new file mode 100644 index 0000000000000..fb4b3804ff6eb --- /dev/null +++ b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/many-args/output.js @@ -0,0 +1 @@ +import geo from '@next/font/google?Geo;"test";[1.0];{"a":2.0};3.0'; diff --git a/packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-calls/input.js b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-calls/input.js new file mode 100644 index 0000000000000..91f5be7cb56d9 --- /dev/null +++ b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-calls/input.js @@ -0,0 +1,12 @@ +import React from 'react' +import { Inter } from '@next/font/google' + +const inter = Inter({ + variant: '900', + display: 'swap', +}) + +const inter = Inter({ + variant: '900', + display: 'swap', +}) diff --git a/packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-calls/output.js b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-calls/output.js new file mode 100644 index 0000000000000..32af21eb3d17d --- /dev/null +++ b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-calls/output.js @@ -0,0 +1,3 @@ +import inter from '@next/font/google?Inter;{"display":"swap","variant":"900"}'; +import inter from '@next/font/google?Inter;{"display":"swap","variant":"900"}'; +import React from 'react'; diff --git a/packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-font-downloaders/input.js b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-font-downloaders/input.js new file mode 100644 index 0000000000000..3fc947f12667a --- /dev/null +++ b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-font-downloaders/input.js @@ -0,0 +1,12 @@ +import React from 'react' +import { Inter } from '@next/font/google' +import { Fira_Code } from 'cool-fonts' + +const inter = Inter({ + variant: '900', +}) + +const fira = Fira_Code({ + variant: '400', + display: 'swap', +}) diff --git a/packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-font-downloaders/output.js b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-font-downloaders/output.js new file mode 100644 index 0000000000000..b85bbd333f678 --- /dev/null +++ b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-font-downloaders/output.js @@ -0,0 +1,3 @@ +import inter from '@next/font/google?Inter;{"variant":"900"}'; +import fira from 'cool-fonts?Fira_Code;{"display":"swap","variant":"400"}'; +import React from 'react'; diff --git a/packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-fonts/input.js b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-fonts/input.js new file mode 100644 index 0000000000000..14b5cd6c716f2 --- /dev/null +++ b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-fonts/input.js @@ -0,0 +1,11 @@ +import React from 'react' +import { Fira_Code, Inter } from '@next/font/google' + +const firaCode = Fira_Code({ + variant: '400', + fallback: ['system-ui'], +}) +const inter = Inter({ + variant: '900', + display: 'swap', +}) diff --git a/packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-fonts/output.js b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-fonts/output.js new file mode 100644 index 0000000000000..88a0f1bb6b416 --- /dev/null +++ b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-fonts/output.js @@ -0,0 +1,3 @@ +import firaCode from '@next/font/google?Fira_Code;{"fallback":["system-ui"],"variant":"400"}'; +import inter from '@next/font/google?Inter;{"display":"swap","variant":"900"}'; +import React from 'react'; diff --git a/packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-imports/input.js b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-imports/input.js new file mode 100644 index 0000000000000..61a434bde7c5f --- /dev/null +++ b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-imports/input.js @@ -0,0 +1,12 @@ +import React from 'react' +import { Inter } from '@next/font/google' +import { Fira_Code } from '@next/font/google' + +const inter = Inter({ + variant: '900', +}) + +const fira = Fira_Code({ + variant: '400', + display: 'swap', +}) diff --git a/packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-imports/output.js b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-imports/output.js new file mode 100644 index 0000000000000..2c68623d1119e --- /dev/null +++ b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-imports/output.js @@ -0,0 +1,3 @@ +import inter from '@next/font/google?Inter;{"variant":"900"}'; +import fira from '@next/font/google?Fira_Code;{"display":"swap","variant":"400"}'; +import React from 'react'; diff --git a/packages/next-swc/crates/core/tests/fixture/next-font-loaders/no-args/input.js b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/no-args/input.js new file mode 100644 index 0000000000000..cc7d2326b91a3 --- /dev/null +++ b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/no-args/input.js @@ -0,0 +1,3 @@ +import { Fira_Code } from '@next/font/google' + +const fira = Fira_Code() diff --git a/packages/next-swc/crates/core/tests/fixture/next-font-loaders/no-args/output.js b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/no-args/output.js new file mode 100644 index 0000000000000..f371ef0ea53cf --- /dev/null +++ b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/no-args/output.js @@ -0,0 +1 @@ +import fira from "@next/font/google?Fira_Code"; diff --git a/packages/next-swc/crates/core/tests/full.rs b/packages/next-swc/crates/core/tests/full.rs index 01d081f570177..964eac330067e 100644 --- a/packages/next-swc/crates/core/tests/full.rs +++ b/packages/next-swc/crates/core/tests/full.rs @@ -65,6 +65,7 @@ fn test(input: &Path, minify: bool) { shake_exports: None, emotion: Some(assert_json("{}")), modularize_imports: None, + font_loaders: None, }; let options = options.patch(&fm); From 1264196897e11a0561ff9ca9df10c25fb5ee718e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Born=C3=B6?= Date: Thu, 22 Sep 2022 00:10:24 +0200 Subject: [PATCH 11/76] Add next font package (#40227) For some context: https://vercel.slack.com/archives/CGU8HUTUH/p1662124179102509 Adds `@next/font` package. `scripts/update-google-fonts.js` generates functions and metadata for all available google fonts. The metadata is used in `loader.ts` to validate font options (from #40221). It then fetches the CSS from google fonts, downloads the font files and emits them as static assets. The actual integration with `packages/next` and integration tests depends on #40221, will follow up with new PR. Co-authored-by: JJ Kasper --- package.json | 1 + packages/font/README.md | 3 + packages/font/google/index.d.ts | 1 + packages/font/google/index.js | 1 + packages/font/google/loader.d.ts | 1 + packages/font/google/loader.js | 1 + packages/font/package.json | 19 + packages/font/src/google/font-data.json | 10208 +++++++++++++++++ packages/font/src/google/index.ts | 13243 ++++++++++++++++++++++ packages/font/src/google/loader.ts | 121 + packages/font/src/google/utils.ts | 189 + packages/font/tsconfig.json | 13 + packages/next/server/font-utils.ts | 2 +- pnpm-lock.yaml | 8 +- scripts/update-google-fonts.js | 74 + test/unit/google-font-loader.test.ts | 334 + 16 files changed, 24215 insertions(+), 4 deletions(-) create mode 100644 packages/font/README.md create mode 100644 packages/font/google/index.d.ts create mode 100644 packages/font/google/index.js create mode 100644 packages/font/google/loader.d.ts create mode 100644 packages/font/google/loader.js create mode 100644 packages/font/package.json create mode 100644 packages/font/src/google/font-data.json create mode 100644 packages/font/src/google/index.ts create mode 100644 packages/font/src/google/loader.ts create mode 100644 packages/font/src/google/utils.ts create mode 100644 packages/font/tsconfig.json create mode 100644 scripts/update-google-fonts.js create mode 100644 test/unit/google-font-loader.test.ts diff --git a/package.json b/package.json index 51091d1b20cfa..d1c5ea07a022c 100644 --- a/package.json +++ b/package.json @@ -63,6 +63,7 @@ "@next/bundle-analyzer": "workspace:*", "@next/env": "workspace:*", "@next/eslint-plugin-next": "workspace:*", + "@next/font": "workspace:*", "@next/mdx": "workspace:*", "@next/plugin-storybook": "workspace:*", "@next/polyfill-module": "workspace:*", diff --git a/packages/font/README.md b/packages/font/README.md new file mode 100644 index 0000000000000..39b038d8caed1 --- /dev/null +++ b/packages/font/README.md @@ -0,0 +1,3 @@ +# `@next/font` + +Experimental `@next/font` package diff --git a/packages/font/google/index.d.ts b/packages/font/google/index.d.ts new file mode 100644 index 0000000000000..f637355cefaef --- /dev/null +++ b/packages/font/google/index.d.ts @@ -0,0 +1 @@ +export * from '../dist/google' diff --git a/packages/font/google/index.js b/packages/font/google/index.js new file mode 100644 index 0000000000000..207253086b485 --- /dev/null +++ b/packages/font/google/index.js @@ -0,0 +1 @@ +throw new Error('@next/font/google is not correctly setup') diff --git a/packages/font/google/loader.d.ts b/packages/font/google/loader.d.ts new file mode 100644 index 0000000000000..4de1cb05c57cd --- /dev/null +++ b/packages/font/google/loader.d.ts @@ -0,0 +1 @@ +export { default } from '../dist/google/loader' diff --git a/packages/font/google/loader.js b/packages/font/google/loader.js new file mode 100644 index 0000000000000..87dd8ad728f24 --- /dev/null +++ b/packages/font/google/loader.js @@ -0,0 +1 @@ +module.exports = require('../dist/google/loader') diff --git a/packages/font/package.json b/packages/font/package.json new file mode 100644 index 0000000000000..b09bd11bd47c5 --- /dev/null +++ b/packages/font/package.json @@ -0,0 +1,19 @@ +{ + "name": "@next/font", + "version": "12.3.2-canary.0", + "repository": { + "url": "vercel/next.js", + "directory": "packages/font" + }, + "files": [ + "dist", + "google" + ], + "license": "MIT", + "scripts": { + "build": "rm -rf dist && tsc -d -p tsconfig.json", + "prepublishOnly": "cd ../../ && turbo run build", + "dev": "tsc -d -w -p tsconfig.json", + "typescript": "tsec --noEmit -p tsconfig.json" + } +} diff --git a/packages/font/src/google/font-data.json b/packages/font/src/google/font-data.json new file mode 100644 index 0000000000000..619037601dd1e --- /dev/null +++ b/packages/font/src/google/font-data.json @@ -0,0 +1,10208 @@ +{ + "ABeeZee": { + "variants": ["400", "400-italic"] + }, + "Abel": { + "variants": ["400"] + }, + "Abhaya Libre": { + "variants": ["400", "500", "600", "700", "800"] + }, + "Aboreto": { + "variants": ["400"] + }, + "Abril Fatface": { + "variants": ["400"] + }, + "Aclonica": { + "variants": ["400"] + }, + "Acme": { + "variants": ["400"] + }, + "Actor": { + "variants": ["400"] + }, + "Adamina": { + "variants": ["400"] + }, + "Advent Pro": { + "variants": ["100", "200", "300", "400", "500", "600", "700"] + }, + "Aguafina Script": { + "variants": ["400"] + }, + "Akaya Kanadaka": { + "variants": ["400"] + }, + "Akaya Telivigala": { + "variants": ["400"] + }, + "Akronim": { + "variants": ["400"] + }, + "Akshar": { + "variants": ["300", "400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Aladin": { + "variants": ["400"] + }, + "Alata": { + "variants": ["400"] + }, + "Alatsi": { + "variants": ["400"] + }, + "Albert Sans": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Aldrich": { + "variants": ["400"] + }, + "Alef": { + "variants": ["400", "700"] + }, + "Alegreya": { + "variants": [ + "400", + "500", + "600", + "700", + "800", + "900", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Alegreya SC": { + "variants": [ + "400", + "500", + "700", + "800", + "900", + "400-italic", + "500-italic", + "700-italic", + "800-italic", + "900-italic" + ] + }, + "Alegreya Sans": { + "variants": [ + "100", + "300", + "400", + "500", + "700", + "800", + "900", + "100-italic", + "300-italic", + "400-italic", + "500-italic", + "700-italic", + "800-italic", + "900-italic" + ] + }, + "Alegreya Sans SC": { + "variants": [ + "100", + "300", + "400", + "500", + "700", + "800", + "900", + "100-italic", + "300-italic", + "400-italic", + "500-italic", + "700-italic", + "800-italic", + "900-italic" + ] + }, + "Aleo": { + "variants": ["300", "400", "700", "300-italic", "400-italic", "700-italic"] + }, + "Alex Brush": { + "variants": ["400"] + }, + "Alfa Slab One": { + "variants": ["400"] + }, + "Alice": { + "variants": ["400"] + }, + "Alike": { + "variants": ["400"] + }, + "Alike Angular": { + "variants": ["400"] + }, + "Allan": { + "variants": ["400", "700"] + }, + "Allerta": { + "variants": ["400"] + }, + "Allerta Stencil": { + "variants": ["400"] + }, + "Allison": { + "variants": ["400"] + }, + "Allura": { + "variants": ["400"] + }, + "Almarai": { + "variants": ["300", "400", "700", "800"] + }, + "Almendra": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "Almendra Display": { + "variants": ["400"] + }, + "Almendra SC": { + "variants": ["400"] + }, + "Alumni Sans": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Alumni Sans Collegiate One": { + "variants": ["400", "400-italic"] + }, + "Alumni Sans Inline One": { + "variants": ["400", "400-italic"] + }, + "Alumni Sans Pinstripe": { + "variants": ["400", "400-italic"] + }, + "Amarante": { + "variants": ["400"] + }, + "Amaranth": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "Amatic SC": { + "variants": ["400", "700"] + }, + "Amethysta": { + "variants": ["400"] + }, + "Amiko": { + "variants": ["400", "600", "700"] + }, + "Amiri": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "Amiri Quran": { + "variants": ["400"] + }, + "Amita": { + "variants": ["400", "700"] + }, + "Anaheim": { + "variants": ["400"] + }, + "Andada Pro": { + "variants": [ + "400", + "500", + "600", + "700", + "800", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 840, + "defaultValue": 400 + } + ] + }, + "Andika": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "Anek Bangla": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "axes": [ + { + "tag": "wdth", + "min": 75, + "max": 125, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Anek Devanagari": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "axes": [ + { + "tag": "wdth", + "min": 75, + "max": 125, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Anek Gujarati": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "axes": [ + { + "tag": "wdth", + "min": 75, + "max": 125, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Anek Gurmukhi": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "axes": [ + { + "tag": "wdth", + "min": 75, + "max": 125, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Anek Kannada": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "axes": [ + { + "tag": "wdth", + "min": 75, + "max": 125, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Anek Latin": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "axes": [ + { + "tag": "wdth", + "min": 75, + "max": 125, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Anek Malayalam": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "axes": [ + { + "tag": "wdth", + "min": 75, + "max": 125, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Anek Odia": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "axes": [ + { + "tag": "wdth", + "min": 75, + "max": 125, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Anek Tamil": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "axes": [ + { + "tag": "wdth", + "min": 75, + "max": 125, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Anek Telugu": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "axes": [ + { + "tag": "wdth", + "min": 75, + "max": 125, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Angkor": { + "variants": ["400"] + }, + "Annie Use Your Telescope": { + "variants": ["400"] + }, + "Anonymous Pro": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "Antic": { + "variants": ["400"] + }, + "Antic Didone": { + "variants": ["400"] + }, + "Antic Slab": { + "variants": ["400"] + }, + "Anton": { + "variants": ["400"] + }, + "Antonio": { + "variants": ["100", "200", "300", "400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Anybody": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wdth", + "min": 50, + "max": 150, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Arapey": { + "variants": ["400", "400-italic"] + }, + "Arbutus": { + "variants": ["400"] + }, + "Arbutus Slab": { + "variants": ["400"] + }, + "Architects Daughter": { + "variants": ["400"] + }, + "Archivo": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wdth", + "min": 62, + "max": 125, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Archivo Black": { + "variants": ["400"] + }, + "Archivo Narrow": { + "variants": [ + "400", + "500", + "600", + "700", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Are You Serious": { + "variants": ["400"] + }, + "Aref Ruqaa": { + "variants": ["400", "700"] + }, + "Aref Ruqaa Ink": { + "variants": ["400", "700"] + }, + "Arima": { + "variants": ["100", "200", "300", "400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Arima Madurai": { + "variants": ["100", "200", "300", "400", "500", "700", "800", "900"] + }, + "Arimo": { + "variants": [ + "400", + "500", + "600", + "700", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Arizonia": { + "variants": ["400"] + }, + "Armata": { + "variants": ["400"] + }, + "Arsenal": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "Artifika": { + "variants": ["400"] + }, + "Arvo": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "Arya": { + "variants": ["400", "700"] + }, + "Asap": { + "variants": [ + "400", + "500", + "600", + "700", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Asap Condensed": { + "variants": [ + "400", + "500", + "600", + "700", + "400-italic", + "500-italic", + "600-italic", + "700-italic" + ] + }, + "Asar": { + "variants": ["400"] + }, + "Asset": { + "variants": ["400"] + }, + "Assistant": { + "variants": ["200", "300", "400", "500", "600", "700", "800", "variable"], + "axes": [ + { + "tag": "wght", + "min": 200, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Astloch": { + "variants": ["400", "700"] + }, + "Asul": { + "variants": ["400", "700"] + }, + "Athiti": { + "variants": ["200", "300", "400", "500", "600", "700"] + }, + "Atkinson Hyperlegible": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "Atma": { + "variants": ["300", "400", "500", "600", "700"] + }, + "Atomic Age": { + "variants": ["400"] + }, + "Aubrey": { + "variants": ["400"] + }, + "Audiowide": { + "variants": ["400"] + }, + "Autour One": { + "variants": ["400"] + }, + "Average": { + "variants": ["400"] + }, + "Average Sans": { + "variants": ["400"] + }, + "Averia Gruesa Libre": { + "variants": ["400"] + }, + "Averia Libre": { + "variants": ["300", "400", "700", "300-italic", "400-italic", "700-italic"] + }, + "Averia Sans Libre": { + "variants": ["300", "400", "700", "300-italic", "400-italic", "700-italic"] + }, + "Averia Serif Libre": { + "variants": ["300", "400", "700", "300-italic", "400-italic", "700-italic"] + }, + "Azeret Mono": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "B612": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "B612 Mono": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "BIZ UDGothic": { + "variants": ["400", "700"] + }, + "BIZ UDMincho": { + "variants": ["400"] + }, + "BIZ UDPGothic": { + "variants": ["400", "700"] + }, + "BIZ UDPMincho": { + "variants": ["400"] + }, + "Babylonica": { + "variants": ["400"] + }, + "Bad Script": { + "variants": ["400"] + }, + "Bahiana": { + "variants": ["400"] + }, + "Bahianita": { + "variants": ["400"] + }, + "Bai Jamjuree": { + "variants": [ + "200", + "300", + "400", + "500", + "600", + "700", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic" + ] + }, + "Bakbak One": { + "variants": ["400"] + }, + "Ballet": { + "variants": ["400", "variable"], + "axes": [ + { + "tag": "opsz", + "min": 16, + "max": 72, + "defaultValue": 16 + } + ] + }, + "Baloo 2": { + "variants": ["400", "500", "600", "700", "800", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Baloo Bhai 2": { + "variants": ["400", "500", "600", "700", "800", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Baloo Bhaijaan 2": { + "variants": ["400", "500", "600", "700", "800", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Baloo Bhaina 2": { + "variants": ["400", "500", "600", "700", "800", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Baloo Chettan 2": { + "variants": ["400", "500", "600", "700", "800", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Baloo Da 2": { + "variants": ["400", "500", "600", "700", "800", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Baloo Paaji 2": { + "variants": ["400", "500", "600", "700", "800", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Baloo Tamma 2": { + "variants": ["400", "500", "600", "700", "800", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Baloo Tammudu 2": { + "variants": ["400", "500", "600", "700", "800", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Baloo Thambi 2": { + "variants": ["400", "500", "600", "700", "800", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Balsamiq Sans": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "Balthazar": { + "variants": ["400"] + }, + "Bangers": { + "variants": ["400"] + }, + "Barlow": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic" + ] + }, + "Barlow Condensed": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic" + ] + }, + "Barlow Semi Condensed": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic" + ] + }, + "Barriecito": { + "variants": ["400"] + }, + "Barrio": { + "variants": ["400"] + }, + "Basic": { + "variants": ["400"] + }, + "Baskervville": { + "variants": ["400", "400-italic"] + }, + "Battambang": { + "variants": ["100", "300", "400", "700", "900"] + }, + "Baumans": { + "variants": ["400"] + }, + "Bayon": { + "variants": ["400"] + }, + "Be Vietnam Pro": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic" + ] + }, + "Beau Rivage": { + "variants": ["400"] + }, + "Bebas Neue": { + "variants": ["400"] + }, + "Belgrano": { + "variants": ["400"] + }, + "Bellefair": { + "variants": ["400"] + }, + "Belleza": { + "variants": ["400"] + }, + "Bellota": { + "variants": ["300", "400", "700", "300-italic", "400-italic", "700-italic"] + }, + "Bellota Text": { + "variants": ["300", "400", "700", "300-italic", "400-italic", "700-italic"] + }, + "BenchNine": { + "variants": ["300", "400", "700"] + }, + "Benne": { + "variants": ["400"] + }, + "Bentham": { + "variants": ["400"] + }, + "Berkshire Swash": { + "variants": ["400"] + }, + "Besley": { + "variants": [ + "400", + "500", + "600", + "700", + "800", + "900", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Beth Ellen": { + "variants": ["400"] + }, + "Bevan": { + "variants": ["400", "400-italic"] + }, + "BhuTuka Expanded One": { + "variants": ["400"] + }, + "Big Shoulders Display": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Big Shoulders Inline Display": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Big Shoulders Inline Text": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Big Shoulders Stencil Display": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Big Shoulders Stencil Text": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Big Shoulders Text": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Bigelow Rules": { + "variants": ["400"] + }, + "Bigshot One": { + "variants": ["400"] + }, + "Bilbo": { + "variants": ["400"] + }, + "Bilbo Swash Caps": { + "variants": ["400"] + }, + "BioRhyme": { + "variants": ["200", "300", "400", "700", "800"] + }, + "BioRhyme Expanded": { + "variants": ["200", "300", "400", "700", "800"] + }, + "Birthstone": { + "variants": ["400"] + }, + "Birthstone Bounce": { + "variants": ["400", "500"] + }, + "Biryani": { + "variants": ["200", "300", "400", "600", "700", "800", "900"] + }, + "Bitter": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Black And White Picture": { + "variants": ["400"] + }, + "Black Han Sans": { + "variants": ["400"] + }, + "Black Ops One": { + "variants": ["400"] + }, + "Blaka": { + "variants": ["400"] + }, + "Blaka Hollow": { + "variants": ["400"] + }, + "Blaka Ink": { + "variants": ["400"] + }, + "Blinker": { + "variants": ["100", "200", "300", "400", "600", "700", "800", "900"] + }, + "Bodoni Moda": { + "variants": [ + "400", + "500", + "600", + "700", + "800", + "900", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "opsz", + "min": 6, + "max": 96, + "defaultValue": 11 + }, + { + "tag": "wght", + "min": 400, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Bokor": { + "variants": ["400"] + }, + "Bona Nova": { + "variants": ["400", "700", "400-italic"] + }, + "Bonbon": { + "variants": ["400"] + }, + "Bonheur Royale": { + "variants": ["400"] + }, + "Boogaloo": { + "variants": ["400"] + }, + "Bowlby One": { + "variants": ["400"] + }, + "Bowlby One SC": { + "variants": ["400"] + }, + "Brawler": { + "variants": ["400", "700"] + }, + "Bree Serif": { + "variants": ["400"] + }, + "Brygada 1918": { + "variants": [ + "400", + "500", + "600", + "700", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Bubblegum Sans": { + "variants": ["400"] + }, + "Bubbler One": { + "variants": ["400"] + }, + "Buda": { + "variants": ["300"] + }, + "Buenard": { + "variants": ["400", "700"] + }, + "Bungee": { + "variants": ["400"] + }, + "Bungee Hairline": { + "variants": ["400"] + }, + "Bungee Inline": { + "variants": ["400"] + }, + "Bungee Outline": { + "variants": ["400"] + }, + "Bungee Shade": { + "variants": ["400"] + }, + "Bungee Spice": { + "variants": ["400"] + }, + "Butcherman": { + "variants": ["400"] + }, + "Butterfly Kids": { + "variants": ["400"] + }, + "Cabin": { + "variants": [ + "400", + "500", + "600", + "700", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wdth", + "min": 75, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Cabin Condensed": { + "variants": ["400", "500", "600", "700"] + }, + "Cabin Sketch": { + "variants": ["400", "700"] + }, + "Caesar Dressing": { + "variants": ["400"] + }, + "Cagliostro": { + "variants": ["400"] + }, + "Cairo": { + "variants": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 200, + "max": 1000, + "defaultValue": 400 + } + ] + }, + "Cairo Play": { + "variants": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "slnt", + "min": -11, + "max": 11, + "defaultValue": 0 + }, + { + "tag": "wght", + "min": 200, + "max": 1000, + "defaultValue": 400 + } + ] + }, + "Caladea": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "Calistoga": { + "variants": ["400"] + }, + "Calligraffitti": { + "variants": ["400"] + }, + "Cambay": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "Cambo": { + "variants": ["400"] + }, + "Candal": { + "variants": ["400"] + }, + "Cantarell": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "Cantata One": { + "variants": ["400"] + }, + "Cantora One": { + "variants": ["400"] + }, + "Capriola": { + "variants": ["400"] + }, + "Caramel": { + "variants": ["400"] + }, + "Carattere": { + "variants": ["400"] + }, + "Cardo": { + "variants": ["400", "700", "400-italic"] + }, + "Carme": { + "variants": ["400"] + }, + "Carrois Gothic": { + "variants": ["400"] + }, + "Carrois Gothic SC": { + "variants": ["400"] + }, + "Carter One": { + "variants": ["400"] + }, + "Castoro": { + "variants": ["400", "400-italic"] + }, + "Catamaran": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Caudex": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "Caveat": { + "variants": ["400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Caveat Brush": { + "variants": ["400"] + }, + "Cedarville Cursive": { + "variants": ["400"] + }, + "Ceviche One": { + "variants": ["400"] + }, + "Chakra Petch": { + "variants": [ + "300", + "400", + "500", + "600", + "700", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic" + ] + }, + "Changa": { + "variants": ["200", "300", "400", "500", "600", "700", "800", "variable"], + "axes": [ + { + "tag": "wght", + "min": 200, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Changa One": { + "variants": ["400", "400-italic"] + }, + "Chango": { + "variants": ["400"] + }, + "Charis SIL": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "Charm": { + "variants": ["400", "700"] + }, + "Charmonman": { + "variants": ["400", "700"] + }, + "Chathura": { + "variants": ["100", "300", "400", "700", "800"] + }, + "Chau Philomene One": { + "variants": ["400", "400-italic"] + }, + "Chela One": { + "variants": ["400"] + }, + "Chelsea Market": { + "variants": ["400"] + }, + "Chenla": { + "variants": ["400"] + }, + "Cherish": { + "variants": ["400"] + }, + "Cherry Cream Soda": { + "variants": ["400"] + }, + "Cherry Swash": { + "variants": ["400", "700"] + }, + "Chewy": { + "variants": ["400"] + }, + "Chicle": { + "variants": ["400"] + }, + "Chilanka": { + "variants": ["400"] + }, + "Chivo": { + "variants": [ + "300", + "400", + "700", + "900", + "300-italic", + "400-italic", + "700-italic", + "900-italic" + ] + }, + "Chonburi": { + "variants": ["400"] + }, + "Cinzel": { + "variants": ["400", "500", "600", "700", "800", "900", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Cinzel Decorative": { + "variants": ["400", "700", "900"] + }, + "Clicker Script": { + "variants": ["400"] + }, + "Coda": { + "variants": ["400", "800"] + }, + "Coda Caption": { + "variants": ["800"] + }, + "Codystar": { + "variants": ["300", "400"] + }, + "Coiny": { + "variants": ["400"] + }, + "Combo": { + "variants": ["400"] + }, + "Comfortaa": { + "variants": ["300", "400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Comforter": { + "variants": ["400"] + }, + "Comforter Brush": { + "variants": ["400"] + }, + "Comic Neue": { + "variants": ["300", "400", "700", "300-italic", "400-italic", "700-italic"] + }, + "Coming Soon": { + "variants": ["400"] + }, + "Commissioner": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Concert One": { + "variants": ["400"] + }, + "Condiment": { + "variants": ["400"] + }, + "Content": { + "variants": ["400", "700"] + }, + "Contrail One": { + "variants": ["400"] + }, + "Convergence": { + "variants": ["400"] + }, + "Cookie": { + "variants": ["400"] + }, + "Copse": { + "variants": ["400"] + }, + "Corben": { + "variants": ["400", "700"] + }, + "Corinthia": { + "variants": ["400", "700"] + }, + "Cormorant": { + "variants": [ + "300", + "400", + "500", + "600", + "700", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Cormorant Garamond": { + "variants": [ + "300", + "400", + "500", + "600", + "700", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic" + ] + }, + "Cormorant Infant": { + "variants": [ + "300", + "400", + "500", + "600", + "700", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic" + ] + }, + "Cormorant SC": { + "variants": ["300", "400", "500", "600", "700"] + }, + "Cormorant Unicase": { + "variants": ["300", "400", "500", "600", "700"] + }, + "Cormorant Upright": { + "variants": ["300", "400", "500", "600", "700"] + }, + "Courgette": { + "variants": ["400"] + }, + "Courier Prime": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "Cousine": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "Coustard": { + "variants": ["400", "900"] + }, + "Covered By Your Grace": { + "variants": ["400"] + }, + "Crafty Girls": { + "variants": ["400"] + }, + "Creepster": { + "variants": ["400"] + }, + "Crete Round": { + "variants": ["400", "400-italic"] + }, + "Crimson Pro": { + "variants": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 200, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Crimson Text": { + "variants": ["400", "600", "700", "400-italic", "600-italic", "700-italic"] + }, + "Croissant One": { + "variants": ["400"] + }, + "Crushed": { + "variants": ["400"] + }, + "Cuprum": { + "variants": [ + "400", + "500", + "600", + "700", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Cute Font": { + "variants": ["400"] + }, + "Cutive": { + "variants": ["400"] + }, + "Cutive Mono": { + "variants": ["400"] + }, + "DM Mono": { + "variants": ["300", "400", "500", "300-italic", "400-italic", "500-italic"] + }, + "DM Sans": { + "variants": ["400", "500", "700", "400-italic", "500-italic", "700-italic"] + }, + "DM Serif Display": { + "variants": ["400", "400-italic"] + }, + "DM Serif Text": { + "variants": ["400", "400-italic"] + }, + "Damion": { + "variants": ["400"] + }, + "Dancing Script": { + "variants": ["400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Dangrek": { + "variants": ["400"] + }, + "Darker Grotesque": { + "variants": ["300", "400", "500", "600", "700", "800", "900"] + }, + "David Libre": { + "variants": ["400", "500", "700"] + }, + "Dawning of a New Day": { + "variants": ["400"] + }, + "Days One": { + "variants": ["400"] + }, + "Dekko": { + "variants": ["400"] + }, + "Dela Gothic One": { + "variants": ["400"] + }, + "Delius": { + "variants": ["400"] + }, + "Delius Swash Caps": { + "variants": ["400"] + }, + "Delius Unicase": { + "variants": ["400", "700"] + }, + "Della Respira": { + "variants": ["400"] + }, + "Denk One": { + "variants": ["400"] + }, + "Devonshire": { + "variants": ["400"] + }, + "Dhurjati": { + "variants": ["400"] + }, + "Didact Gothic": { + "variants": ["400"] + }, + "Diplomata": { + "variants": ["400"] + }, + "Diplomata SC": { + "variants": ["400"] + }, + "Do Hyeon": { + "variants": ["400"] + }, + "Dokdo": { + "variants": ["400"] + }, + "Domine": { + "variants": ["400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Donegal One": { + "variants": ["400"] + }, + "Dongle": { + "variants": ["300", "400", "700"] + }, + "Doppio One": { + "variants": ["400"] + }, + "Dorsa": { + "variants": ["400"] + }, + "Dosis": { + "variants": ["200", "300", "400", "500", "600", "700", "800", "variable"], + "axes": [ + { + "tag": "wght", + "min": 200, + "max": 800, + "defaultValue": 400 + } + ] + }, + "DotGothic16": { + "variants": ["400"] + }, + "Dr Sugiyama": { + "variants": ["400"] + }, + "Duru Sans": { + "variants": ["400"] + }, + "DynaPuff": { + "variants": ["400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wdth", + "min": 75, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Dynalight": { + "variants": ["400"] + }, + "EB Garamond": { + "variants": [ + "400", + "500", + "600", + "700", + "800", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Eagle Lake": { + "variants": ["400"] + }, + "East Sea Dokdo": { + "variants": ["400"] + }, + "Eater": { + "variants": ["400"] + }, + "Economica": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "Eczar": { + "variants": ["400", "500", "600", "700", "800", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Edu NSW ACT Foundation": { + "variants": ["400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Edu QLD Beginner": { + "variants": ["400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Edu SA Beginner": { + "variants": ["400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Edu TAS Beginner": { + "variants": ["400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Edu VIC WA NT Beginner": { + "variants": ["400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "El Messiri": { + "variants": ["400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Electrolize": { + "variants": ["400"] + }, + "Elsie": { + "variants": ["400", "900"] + }, + "Elsie Swash Caps": { + "variants": ["400", "900"] + }, + "Emblema One": { + "variants": ["400"] + }, + "Emilys Candy": { + "variants": ["400"] + }, + "Encode Sans": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wdth", + "min": 75, + "max": 125, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Encode Sans Condensed": { + "variants": ["100", "200", "300", "400", "500", "600", "700", "800", "900"] + }, + "Encode Sans Expanded": { + "variants": ["100", "200", "300", "400", "500", "600", "700", "800", "900"] + }, + "Encode Sans SC": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wdth", + "min": 75, + "max": 125, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Encode Sans Semi Condensed": { + "variants": ["100", "200", "300", "400", "500", "600", "700", "800", "900"] + }, + "Encode Sans Semi Expanded": { + "variants": ["100", "200", "300", "400", "500", "600", "700", "800", "900"] + }, + "Engagement": { + "variants": ["400"] + }, + "Englebert": { + "variants": ["400"] + }, + "Enriqueta": { + "variants": ["400", "500", "600", "700"] + }, + "Ephesis": { + "variants": ["400"] + }, + "Epilogue": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Erica One": { + "variants": ["400"] + }, + "Esteban": { + "variants": ["400"] + }, + "Estonia": { + "variants": ["400"] + }, + "Euphoria Script": { + "variants": ["400"] + }, + "Ewert": { + "variants": ["400"] + }, + "Exo": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Exo 2": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Expletus Sans": { + "variants": [ + "400", + "500", + "600", + "700", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Explora": { + "variants": ["400"] + }, + "Fahkwang": { + "variants": [ + "200", + "300", + "400", + "500", + "600", + "700", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic" + ] + }, + "Familjen Grotesk": { + "variants": [ + "400", + "500", + "600", + "700", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Fanwood Text": { + "variants": ["400", "400-italic"] + }, + "Farro": { + "variants": ["300", "400", "500", "700"] + }, + "Farsan": { + "variants": ["400"] + }, + "Fascinate": { + "variants": ["400"] + }, + "Fascinate Inline": { + "variants": ["400"] + }, + "Faster One": { + "variants": ["400"] + }, + "Fasthand": { + "variants": ["400"] + }, + "Fauna One": { + "variants": ["400"] + }, + "Faustina": { + "variants": [ + "300", + "400", + "500", + "600", + "700", + "800", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Federant": { + "variants": ["400"] + }, + "Federo": { + "variants": ["400"] + }, + "Felipa": { + "variants": ["400"] + }, + "Fenix": { + "variants": ["400"] + }, + "Festive": { + "variants": ["400"] + }, + "Figtree": { + "variants": ["300", "400", "500", "600", "700", "800", "900", "variable"], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Finger Paint": { + "variants": ["400"] + }, + "Finlandica": { + "variants": [ + "400", + "500", + "600", + "700", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Fira Code": { + "variants": ["300", "400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Fira Mono": { + "variants": ["400", "500", "700"] + }, + "Fira Sans": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic" + ] + }, + "Fira Sans Condensed": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic" + ] + }, + "Fira Sans Extra Condensed": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic" + ] + }, + "Fjalla One": { + "variants": ["400"] + }, + "Fjord One": { + "variants": ["400"] + }, + "Flamenco": { + "variants": ["300", "400"] + }, + "Flavors": { + "variants": ["400"] + }, + "Fleur De Leah": { + "variants": ["400"] + }, + "Flow Block": { + "variants": ["400"] + }, + "Flow Circular": { + "variants": ["400"] + }, + "Flow Rounded": { + "variants": ["400"] + }, + "Fondamento": { + "variants": ["400", "400-italic"] + }, + "Fontdiner Swanky": { + "variants": ["400"] + }, + "Forum": { + "variants": ["400"] + }, + "Francois One": { + "variants": ["400"] + }, + "Frank Ruhl Libre": { + "variants": ["300", "400", "500", "700", "900"] + }, + "Fraunces": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "SOFT", + "min": 0, + "max": 100, + "defaultValue": 0 + }, + { + "tag": "WONK", + "min": 0, + "max": 1, + "defaultValue": 0 + }, + { + "tag": "opsz", + "min": 9, + "max": 144, + "defaultValue": 14 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Freckle Face": { + "variants": ["400"] + }, + "Fredericka the Great": { + "variants": ["400"] + }, + "Fredoka": { + "variants": ["300", "400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wdth", + "min": 75, + "max": 125, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Fredoka One": { + "variants": ["400"] + }, + "Freehand": { + "variants": ["400"] + }, + "Fresca": { + "variants": ["400"] + }, + "Frijole": { + "variants": ["400"] + }, + "Fruktur": { + "variants": ["400", "400-italic"] + }, + "Fugaz One": { + "variants": ["400"] + }, + "Fuggles": { + "variants": ["400"] + }, + "Fuzzy Bubbles": { + "variants": ["400", "700"] + }, + "GFS Didot": { + "variants": ["400"] + }, + "GFS Neohellenic": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "Gabriela": { + "variants": ["400"] + }, + "Gaegu": { + "variants": ["300", "400", "700"] + }, + "Gafata": { + "variants": ["400"] + }, + "Galada": { + "variants": ["400"] + }, + "Galdeano": { + "variants": ["400"] + }, + "Galindo": { + "variants": ["400"] + }, + "Gamja Flower": { + "variants": ["400"] + }, + "Gantari": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Gayathri": { + "variants": ["100", "400", "700"] + }, + "Gelasio": { + "variants": [ + "400", + "500", + "600", + "700", + "400-italic", + "500-italic", + "600-italic", + "700-italic" + ] + }, + "Gemunu Libre": { + "variants": ["200", "300", "400", "500", "600", "700", "800", "variable"], + "axes": [ + { + "tag": "wght", + "min": 200, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Genos": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Gentium Book Basic": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "Gentium Book Plus": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "Gentium Plus": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "Geo": { + "variants": ["400", "400-italic"] + }, + "Georama": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 150, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Geostar": { + "variants": ["400"] + }, + "Geostar Fill": { + "variants": ["400"] + }, + "Germania One": { + "variants": ["400"] + }, + "Gideon Roman": { + "variants": ["400"] + }, + "Gidugu": { + "variants": ["400"] + }, + "Gilda Display": { + "variants": ["400"] + }, + "Girassol": { + "variants": ["400"] + }, + "Give You Glory": { + "variants": ["400"] + }, + "Glass Antiqua": { + "variants": ["400"] + }, + "Glegoo": { + "variants": ["400", "700"] + }, + "Gloria Hallelujah": { + "variants": ["400"] + }, + "Glory": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Gluten": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "slnt", + "min": -13, + "max": 13, + "defaultValue": 0 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Goblin One": { + "variants": ["400"] + }, + "Gochi Hand": { + "variants": ["400"] + }, + "Goldman": { + "variants": ["400", "700"] + }, + "Gorditas": { + "variants": ["400", "700"] + }, + "Gothic A1": { + "variants": ["100", "200", "300", "400", "500", "600", "700", "800", "900"] + }, + "Gotu": { + "variants": ["400"] + }, + "Goudy Bookletter 1911": { + "variants": ["400"] + }, + "Gowun Batang": { + "variants": ["400", "700"] + }, + "Gowun Dodum": { + "variants": ["400"] + }, + "Graduate": { + "variants": ["400"] + }, + "Grand Hotel": { + "variants": ["400"] + }, + "Grandstander": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Grape Nuts": { + "variants": ["400"] + }, + "Gravitas One": { + "variants": ["400"] + }, + "Great Vibes": { + "variants": ["400"] + }, + "Grechen Fuemen": { + "variants": ["400"] + }, + "Grenze": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic" + ] + }, + "Grenze Gotisch": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Grey Qo": { + "variants": ["400"] + }, + "Griffy": { + "variants": ["400"] + }, + "Gruppo": { + "variants": ["400"] + }, + "Gudea": { + "variants": ["400", "700", "400-italic"] + }, + "Gugi": { + "variants": ["400"] + }, + "Gulzar": { + "variants": ["400"] + }, + "Gupter": { + "variants": ["400", "500", "700"] + }, + "Gurajada": { + "variants": ["400"] + }, + "Gwendolyn": { + "variants": ["400", "700"] + }, + "Habibi": { + "variants": ["400"] + }, + "Hachi Maru Pop": { + "variants": ["400"] + }, + "Hahmlet": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Halant": { + "variants": ["300", "400", "500", "600", "700"] + }, + "Hammersmith One": { + "variants": ["400"] + }, + "Hanalei": { + "variants": ["400"] + }, + "Hanalei Fill": { + "variants": ["400"] + }, + "Handlee": { + "variants": ["400"] + }, + "Hanuman": { + "variants": ["100", "300", "400", "700", "900"] + }, + "Happy Monkey": { + "variants": ["400"] + }, + "Harmattan": { + "variants": ["400", "700"] + }, + "Headland One": { + "variants": ["400"] + }, + "Heebo": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Henny Penny": { + "variants": ["400"] + }, + "Hepta Slab": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 1, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Herr Von Muellerhoff": { + "variants": ["400"] + }, + "Hi Melody": { + "variants": ["400"] + }, + "Hina Mincho": { + "variants": ["400"] + }, + "Hind": { + "variants": ["300", "400", "500", "600", "700"] + }, + "Hind Guntur": { + "variants": ["300", "400", "500", "600", "700"] + }, + "Hind Madurai": { + "variants": ["300", "400", "500", "600", "700"] + }, + "Hind Siliguri": { + "variants": ["300", "400", "500", "600", "700"] + }, + "Hind Vadodara": { + "variants": ["300", "400", "500", "600", "700"] + }, + "Holtwood One SC": { + "variants": ["400"] + }, + "Homemade Apple": { + "variants": ["400"] + }, + "Homenaje": { + "variants": ["400"] + }, + "Hubballi": { + "variants": ["400"] + }, + "Hurricane": { + "variants": ["400"] + }, + "IBM Plex Mono": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic" + ] + }, + "IBM Plex Sans": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic" + ] + }, + "IBM Plex Sans Arabic": { + "variants": ["100", "200", "300", "400", "500", "600", "700"] + }, + "IBM Plex Sans Condensed": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic" + ] + }, + "IBM Plex Sans Devanagari": { + "variants": ["100", "200", "300", "400", "500", "600", "700"] + }, + "IBM Plex Sans Hebrew": { + "variants": ["100", "200", "300", "400", "500", "600", "700"] + }, + "IBM Plex Sans KR": { + "variants": ["100", "200", "300", "400", "500", "600", "700"] + }, + "IBM Plex Sans Thai": { + "variants": ["100", "200", "300", "400", "500", "600", "700"] + }, + "IBM Plex Sans Thai Looped": { + "variants": ["100", "200", "300", "400", "500", "600", "700"] + }, + "IBM Plex Serif": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic" + ] + }, + "IM Fell DW Pica": { + "variants": ["400", "400-italic"] + }, + "IM Fell DW Pica SC": { + "variants": ["400"] + }, + "IM Fell Double Pica": { + "variants": ["400", "400-italic"] + }, + "IM Fell Double Pica SC": { + "variants": ["400"] + }, + "IM Fell English": { + "variants": ["400", "400-italic"] + }, + "IM Fell English SC": { + "variants": ["400"] + }, + "IM Fell French Canon": { + "variants": ["400", "400-italic"] + }, + "IM Fell French Canon SC": { + "variants": ["400"] + }, + "IM Fell Great Primer": { + "variants": ["400", "400-italic"] + }, + "IM Fell Great Primer SC": { + "variants": ["400"] + }, + "Ibarra Real Nova": { + "variants": [ + "400", + "500", + "600", + "700", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Iceberg": { + "variants": ["400"] + }, + "Iceland": { + "variants": ["400"] + }, + "Imbue": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "opsz", + "min": 10, + "max": 100, + "defaultValue": 10 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Imperial Script": { + "variants": ["400"] + }, + "Imprima": { + "variants": ["400"] + }, + "Inconsolata": { + "variants": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wdth", + "min": 50, + "max": 200, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 200, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Inder": { + "variants": ["400"] + }, + "Indie Flower": { + "variants": ["400"] + }, + "Ingrid Darling": { + "variants": ["400"] + }, + "Inika": { + "variants": ["400", "700"] + }, + "Inknut Antiqua": { + "variants": ["300", "400", "500", "600", "700", "800", "900"] + }, + "Inria Sans": { + "variants": ["300", "400", "700", "300-italic", "400-italic", "700-italic"] + }, + "Inria Serif": { + "variants": ["300", "400", "700", "300-italic", "400-italic", "700-italic"] + }, + "Inspiration": { + "variants": ["400"] + }, + "Inter": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "slnt", + "min": -10, + "max": 0, + "defaultValue": 0 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Irish Grover": { + "variants": ["400"] + }, + "Island Moments": { + "variants": ["400"] + }, + "Istok Web": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "Italiana": { + "variants": ["400"] + }, + "Italianno": { + "variants": ["400"] + }, + "Itim": { + "variants": ["400"] + }, + "Jacques Francois": { + "variants": ["400"] + }, + "Jacques Francois Shadow": { + "variants": ["400"] + }, + "Jaldi": { + "variants": ["400", "700"] + }, + "JetBrains Mono": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Jim Nightshade": { + "variants": ["400"] + }, + "Joan": { + "variants": ["400"] + }, + "Jockey One": { + "variants": ["400"] + }, + "Jolly Lodger": { + "variants": ["400"] + }, + "Jomhuria": { + "variants": ["400"] + }, + "Jomolhari": { + "variants": ["400"] + }, + "Josefin Sans": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Josefin Slab": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Jost": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Joti One": { + "variants": ["400"] + }, + "Jua": { + "variants": ["400"] + }, + "Judson": { + "variants": ["400", "700", "400-italic"] + }, + "Julee": { + "variants": ["400"] + }, + "Julius Sans One": { + "variants": ["400"] + }, + "Junge": { + "variants": ["400"] + }, + "Jura": { + "variants": ["300", "400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Just Another Hand": { + "variants": ["400"] + }, + "Just Me Again Down Here": { + "variants": ["400"] + }, + "K2D": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic" + ] + }, + "Kadwa": { + "variants": ["400", "700"] + }, + "Kaisei Decol": { + "variants": ["400", "500", "700"] + }, + "Kaisei HarunoUmi": { + "variants": ["400", "500", "700"] + }, + "Kaisei Opti": { + "variants": ["400", "500", "700"] + }, + "Kaisei Tokumin": { + "variants": ["400", "500", "700", "800"] + }, + "Kalam": { + "variants": ["300", "400", "700"] + }, + "Kameron": { + "variants": ["400", "700"] + }, + "Kanit": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic" + ] + }, + "Kantumruy": { + "variants": ["300", "400", "700"] + }, + "Kantumruy Pro": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Karantina": { + "variants": ["300", "400", "700"] + }, + "Karla": { + "variants": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 200, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Karma": { + "variants": ["300", "400", "500", "600", "700"] + }, + "Katibeh": { + "variants": ["400"] + }, + "Kaushan Script": { + "variants": ["400"] + }, + "Kavivanar": { + "variants": ["400"] + }, + "Kavoon": { + "variants": ["400"] + }, + "Kdam Thmor Pro": { + "variants": ["400"] + }, + "Keania One": { + "variants": ["400"] + }, + "Kelly Slab": { + "variants": ["400"] + }, + "Kenia": { + "variants": ["400"] + }, + "Khand": { + "variants": ["300", "400", "500", "600", "700"] + }, + "Khmer": { + "variants": ["400"] + }, + "Khula": { + "variants": ["300", "400", "600", "700", "800"] + }, + "Kings": { + "variants": ["400"] + }, + "Kirang Haerang": { + "variants": ["400"] + }, + "Kite One": { + "variants": ["400"] + }, + "Kiwi Maru": { + "variants": ["300", "400", "500"] + }, + "Klee One": { + "variants": ["400", "600"] + }, + "Knewave": { + "variants": ["400"] + }, + "KoHo": { + "variants": [ + "200", + "300", + "400", + "500", + "600", + "700", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic" + ] + }, + "Kodchasan": { + "variants": [ + "200", + "300", + "400", + "500", + "600", + "700", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic" + ] + }, + "Koh Santepheap": { + "variants": ["100", "300", "400", "700", "900"] + }, + "Kolker Brush": { + "variants": ["400"] + }, + "Kosugi": { + "variants": ["400"] + }, + "Kosugi Maru": { + "variants": ["400"] + }, + "Kotta One": { + "variants": ["400"] + }, + "Koulen": { + "variants": ["400"] + }, + "Kranky": { + "variants": ["400"] + }, + "Kreon": { + "variants": ["300", "400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Kristi": { + "variants": ["400"] + }, + "Krona One": { + "variants": ["400"] + }, + "Krub": { + "variants": [ + "200", + "300", + "400", + "500", + "600", + "700", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic" + ] + }, + "Kufam": { + "variants": [ + "400", + "500", + "600", + "700", + "800", + "900", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Kulim Park": { + "variants": [ + "200", + "300", + "400", + "600", + "700", + "200-italic", + "300-italic", + "400-italic", + "600-italic", + "700-italic" + ] + }, + "Kumar One": { + "variants": ["400"] + }, + "Kumar One Outline": { + "variants": ["400"] + }, + "Kumbh Sans": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Kurale": { + "variants": ["400"] + }, + "La Belle Aurore": { + "variants": ["400"] + }, + "Lacquer": { + "variants": ["400"] + }, + "Laila": { + "variants": ["300", "400", "500", "600", "700"] + }, + "Lakki Reddy": { + "variants": ["400"] + }, + "Lalezar": { + "variants": ["400"] + }, + "Lancelot": { + "variants": ["400"] + }, + "Langar": { + "variants": ["400"] + }, + "Lateef": { + "variants": ["400"] + }, + "Lato": { + "variants": [ + "100", + "300", + "400", + "700", + "900", + "100-italic", + "300-italic", + "400-italic", + "700-italic", + "900-italic" + ] + }, + "Lavishly Yours": { + "variants": ["400"] + }, + "League Gothic": { + "variants": ["400", "variable"], + "axes": [ + { + "tag": "wdth", + "min": 75, + "max": 100, + "defaultValue": 100 + } + ] + }, + "League Script": { + "variants": ["400"] + }, + "League Spartan": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Leckerli One": { + "variants": ["400"] + }, + "Ledger": { + "variants": ["400"] + }, + "Lekton": { + "variants": ["400", "700", "400-italic"] + }, + "Lemon": { + "variants": ["400"] + }, + "Lemonada": { + "variants": ["300", "400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Lexend": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Lexend Deca": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Lexend Exa": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Lexend Giga": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Lexend Mega": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Lexend Peta": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Lexend Tera": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Lexend Zetta": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Libre Barcode 128": { + "variants": ["400"] + }, + "Libre Barcode 128 Text": { + "variants": ["400"] + }, + "Libre Barcode 39": { + "variants": ["400"] + }, + "Libre Barcode 39 Extended": { + "variants": ["400"] + }, + "Libre Barcode 39 Extended Text": { + "variants": ["400"] + }, + "Libre Barcode 39 Text": { + "variants": ["400"] + }, + "Libre Barcode EAN13 Text": { + "variants": ["400"] + }, + "Libre Baskerville": { + "variants": ["400", "700", "400-italic"] + }, + "Libre Bodoni": { + "variants": [ + "400", + "500", + "600", + "700", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Libre Caslon Display": { + "variants": ["400"] + }, + "Libre Caslon Text": { + "variants": ["400", "700", "400-italic"] + }, + "Libre Franklin": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Licorice": { + "variants": ["400"] + }, + "Life Savers": { + "variants": ["400", "700", "800"] + }, + "Lilita One": { + "variants": ["400"] + }, + "Lily Script One": { + "variants": ["400"] + }, + "Limelight": { + "variants": ["400"] + }, + "Linden Hill": { + "variants": ["400", "400-italic"] + }, + "Literata": { + "variants": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "opsz", + "min": 7, + "max": 72, + "defaultValue": 14 + }, + { + "tag": "wght", + "min": 200, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Liu Jian Mao Cao": { + "variants": ["400"] + }, + "Livvic": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "900-italic" + ] + }, + "Lobster": { + "variants": ["400"] + }, + "Lobster Two": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "Londrina Outline": { + "variants": ["400"] + }, + "Londrina Shadow": { + "variants": ["400"] + }, + "Londrina Sketch": { + "variants": ["400"] + }, + "Londrina Solid": { + "variants": ["100", "300", "400", "900"] + }, + "Long Cang": { + "variants": ["400"] + }, + "Lora": { + "variants": [ + "400", + "500", + "600", + "700", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Love Light": { + "variants": ["400"] + }, + "Love Ya Like A Sister": { + "variants": ["400"] + }, + "Loved by the King": { + "variants": ["400"] + }, + "Lovers Quarrel": { + "variants": ["400"] + }, + "Luckiest Guy": { + "variants": ["400"] + }, + "Lusitana": { + "variants": ["400", "700"] + }, + "Lustria": { + "variants": ["400"] + }, + "Luxurious Roman": { + "variants": ["400"] + }, + "Luxurious Script": { + "variants": ["400"] + }, + "M PLUS 1": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "M PLUS 1 Code": { + "variants": ["100", "200", "300", "400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 700, + "defaultValue": 400 + } + ] + }, + "M PLUS 1p": { + "variants": ["100", "300", "400", "500", "700", "800", "900"] + }, + "M PLUS 2": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "M PLUS Code Latin": { + "variants": ["100", "200", "300", "400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wdth", + "min": 100, + "max": 125, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 700, + "defaultValue": 400 + } + ] + }, + "M PLUS Rounded 1c": { + "variants": ["100", "300", "400", "500", "700", "800", "900"] + }, + "Ma Shan Zheng": { + "variants": ["400"] + }, + "Macondo": { + "variants": ["400"] + }, + "Macondo Swash Caps": { + "variants": ["400"] + }, + "Mada": { + "variants": ["200", "300", "400", "500", "600", "700", "900"] + }, + "Magra": { + "variants": ["400", "700"] + }, + "Maiden Orange": { + "variants": ["400"] + }, + "Maitree": { + "variants": ["200", "300", "400", "500", "600", "700"] + }, + "Major Mono Display": { + "variants": ["400"] + }, + "Mako": { + "variants": ["400"] + }, + "Mali": { + "variants": [ + "200", + "300", + "400", + "500", + "600", + "700", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic" + ] + }, + "Mallanna": { + "variants": ["400"] + }, + "Mandali": { + "variants": ["400"] + }, + "Manjari": { + "variants": ["100", "400", "700"] + }, + "Manrope": { + "variants": ["200", "300", "400", "500", "600", "700", "800", "variable"], + "axes": [ + { + "tag": "wght", + "min": 200, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Mansalva": { + "variants": ["400"] + }, + "Manuale": { + "variants": [ + "300", + "400", + "500", + "600", + "700", + "800", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Marcellus": { + "variants": ["400"] + }, + "Marcellus SC": { + "variants": ["400"] + }, + "Marck Script": { + "variants": ["400"] + }, + "Margarine": { + "variants": ["400"] + }, + "Markazi Text": { + "variants": ["400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Marko One": { + "variants": ["400"] + }, + "Marmelad": { + "variants": ["400"] + }, + "Martel": { + "variants": ["200", "300", "400", "600", "700", "800", "900"] + }, + "Martel Sans": { + "variants": ["200", "300", "400", "600", "700", "800", "900"] + }, + "Marvel": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "Mate": { + "variants": ["400", "400-italic"] + }, + "Mate SC": { + "variants": ["400"] + }, + "Maven Pro": { + "variants": ["400", "500", "600", "700", "800", "900", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 900, + "defaultValue": 400 + } + ] + }, + "McLaren": { + "variants": ["400"] + }, + "Mea Culpa": { + "variants": ["400"] + }, + "Meddon": { + "variants": ["400"] + }, + "MedievalSharp": { + "variants": ["400"] + }, + "Medula One": { + "variants": ["400"] + }, + "Meera Inimai": { + "variants": ["400"] + }, + "Megrim": { + "variants": ["400"] + }, + "Meie Script": { + "variants": ["400"] + }, + "Meow Script": { + "variants": ["400"] + }, + "Merienda": { + "variants": ["400", "700"] + }, + "Merienda One": { + "variants": ["400"] + }, + "Merriweather": { + "variants": [ + "300", + "400", + "700", + "900", + "300-italic", + "400-italic", + "700-italic", + "900-italic" + ] + }, + "Merriweather Sans": { + "variants": [ + "300", + "400", + "500", + "600", + "700", + "800", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Metal": { + "variants": ["400"] + }, + "Metal Mania": { + "variants": ["400"] + }, + "Metamorphous": { + "variants": ["400"] + }, + "Metrophobic": { + "variants": ["400"] + }, + "Michroma": { + "variants": ["400"] + }, + "Milonga": { + "variants": ["400"] + }, + "Miltonian": { + "variants": ["400"] + }, + "Miltonian Tattoo": { + "variants": ["400"] + }, + "Mina": { + "variants": ["400", "700"] + }, + "Mingzat": { + "variants": ["400"] + }, + "Miniver": { + "variants": ["400"] + }, + "Miriam Libre": { + "variants": ["400", "700"] + }, + "Mirza": { + "variants": ["400", "500", "600", "700"] + }, + "Miss Fajardose": { + "variants": ["400"] + }, + "Mitr": { + "variants": ["200", "300", "400", "500", "600", "700"] + }, + "Mochiy Pop One": { + "variants": ["400"] + }, + "Mochiy Pop P One": { + "variants": ["400"] + }, + "Modak": { + "variants": ["400"] + }, + "Modern Antiqua": { + "variants": ["400"] + }, + "Mogra": { + "variants": ["400"] + }, + "Mohave": { + "variants": [ + "300", + "400", + "500", + "600", + "700", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Molengo": { + "variants": ["400"] + }, + "Molle": { + "variants": ["400-italic"] + }, + "Monda": { + "variants": ["400", "700"] + }, + "Monofett": { + "variants": ["400"] + }, + "Monoton": { + "variants": ["400"] + }, + "Monsieur La Doulaise": { + "variants": ["400"] + }, + "Montaga": { + "variants": ["400"] + }, + "Montagu Slab": { + "variants": ["100", "200", "300", "400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "opsz", + "min": 16, + "max": 144, + "defaultValue": 144 + }, + { + "tag": "wght", + "min": 100, + "max": 700, + "defaultValue": 400 + } + ] + }, + "MonteCarlo": { + "variants": ["400"] + }, + "Montez": { + "variants": ["400"] + }, + "Montserrat": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Montserrat Alternates": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic" + ] + }, + "Montserrat Subrayada": { + "variants": ["400", "700"] + }, + "Moo Lah Lah": { + "variants": ["400"] + }, + "Moon Dance": { + "variants": ["400"] + }, + "Moul": { + "variants": ["400"] + }, + "Moulpali": { + "variants": ["400"] + }, + "Mountains of Christmas": { + "variants": ["400", "700"] + }, + "Mouse Memoirs": { + "variants": ["400"] + }, + "Mr Bedfort": { + "variants": ["400"] + }, + "Mr Dafoe": { + "variants": ["400"] + }, + "Mr De Haviland": { + "variants": ["400"] + }, + "Mrs Saint Delafield": { + "variants": ["400"] + }, + "Mrs Sheppards": { + "variants": ["400"] + }, + "Ms Madi": { + "variants": ["400"] + }, + "Mukta": { + "variants": ["200", "300", "400", "500", "600", "700", "800"] + }, + "Mukta Mahee": { + "variants": ["200", "300", "400", "500", "600", "700", "800"] + }, + "Mukta Malar": { + "variants": ["200", "300", "400", "500", "600", "700", "800"] + }, + "Mukta Vaani": { + "variants": ["200", "300", "400", "500", "600", "700", "800"] + }, + "Mulish": { + "variants": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 200, + "max": 1000, + "defaultValue": 400 + } + ] + }, + "Murecho": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "MuseoModerno": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "My Soul": { + "variants": ["400"] + }, + "Mystery Quest": { + "variants": ["400"] + }, + "NTR": { + "variants": ["400"] + }, + "Nabla": { + "variants": ["400", "variable"], + "axes": [ + { + "tag": "EDPT", + "min": 0, + "max": 200, + "defaultValue": 100 + }, + { + "tag": "EHLT", + "min": 0, + "max": 24, + "defaultValue": 12 + } + ] + }, + "Nanum Brush Script": { + "variants": ["400"] + }, + "Nanum Gothic": { + "variants": ["400", "700", "800"] + }, + "Nanum Gothic Coding": { + "variants": ["400", "700"] + }, + "Nanum Myeongjo": { + "variants": ["400", "700", "800"] + }, + "Nanum Pen Script": { + "variants": ["400"] + }, + "Neonderthaw": { + "variants": ["400"] + }, + "Nerko One": { + "variants": ["400"] + }, + "Neucha": { + "variants": ["400"] + }, + "Neuton": { + "variants": ["200", "300", "400", "700", "800", "400-italic"] + }, + "New Rocker": { + "variants": ["400"] + }, + "New Tegomin": { + "variants": ["400"] + }, + "News Cycle": { + "variants": ["400", "700"] + }, + "Newsreader": { + "variants": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "opsz", + "min": 6, + "max": 72, + "defaultValue": 16 + }, + { + "tag": "wght", + "min": 200, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Niconne": { + "variants": ["400"] + }, + "Niramit": { + "variants": [ + "200", + "300", + "400", + "500", + "600", + "700", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic" + ] + }, + "Nixie One": { + "variants": ["400"] + }, + "Nobile": { + "variants": ["400", "500", "700", "400-italic", "500-italic", "700-italic"] + }, + "Nokora": { + "variants": ["100", "300", "400", "700", "900"] + }, + "Norican": { + "variants": ["400"] + }, + "Nosifer": { + "variants": ["400"] + }, + "Notable": { + "variants": ["400"] + }, + "Nothing You Could Do": { + "variants": ["400"] + }, + "Noticia Text": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "Noto Color Emoji": { + "variants": ["400"] + }, + "Noto Emoji": { + "variants": ["300", "400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Noto Kufi Arabic": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Music": { + "variants": ["400"] + }, + "Noto Naskh Arabic": { + "variants": ["400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Noto Nastaliq Urdu": { + "variants": ["400", "700"] + }, + "Noto Rashi Hebrew": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic" + ] + }, + "Noto Sans Adlam": { + "variants": ["400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Noto Sans Adlam Unjoined": { + "variants": ["400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Noto Sans Anatolian Hieroglyphs": { + "variants": ["400"] + }, + "Noto Sans Arabic": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Armenian": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Avestan": { + "variants": ["400"] + }, + "Noto Sans Balinese": { + "variants": ["400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Noto Sans Bamum": { + "variants": ["400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Noto Sans Bassa Vah": { + "variants": ["400"] + }, + "Noto Sans Batak": { + "variants": ["400"] + }, + "Noto Sans Bengali": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Bhaiksuki": { + "variants": ["400"] + }, + "Noto Sans Brahmi": { + "variants": ["400"] + }, + "Noto Sans Buginese": { + "variants": ["400"] + }, + "Noto Sans Buhid": { + "variants": ["400"] + }, + "Noto Sans Canadian Aboriginal": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Carian": { + "variants": ["400"] + }, + "Noto Sans Caucasian Albanian": { + "variants": ["400"] + }, + "Noto Sans Chakma": { + "variants": ["400"] + }, + "Noto Sans Cham": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Cherokee": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Coptic": { + "variants": ["400"] + }, + "Noto Sans Cuneiform": { + "variants": ["400"] + }, + "Noto Sans Cypriot": { + "variants": ["400"] + }, + "Noto Sans Deseret": { + "variants": ["400"] + }, + "Noto Sans Devanagari": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Display": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Duployan": { + "variants": ["400"] + }, + "Noto Sans Egyptian Hieroglyphs": { + "variants": ["400"] + }, + "Noto Sans Elbasan": { + "variants": ["400"] + }, + "Noto Sans Elymaic": { + "variants": ["400"] + }, + "Noto Sans Georgian": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Glagolitic": { + "variants": ["400"] + }, + "Noto Sans Gothic": { + "variants": ["400"] + }, + "Noto Sans Grantha": { + "variants": ["400"] + }, + "Noto Sans Gujarati": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Gunjala Gondi": { + "variants": ["400"] + }, + "Noto Sans Gurmukhi": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans HK": { + "variants": ["100", "300", "400", "500", "700", "900"] + }, + "Noto Sans Hanifi Rohingya": { + "variants": ["400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Noto Sans Hanunoo": { + "variants": ["400"] + }, + "Noto Sans Hatran": { + "variants": ["400"] + }, + "Noto Sans Hebrew": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Imperial Aramaic": { + "variants": ["400"] + }, + "Noto Sans Indic Siyaq Numbers": { + "variants": ["400"] + }, + "Noto Sans Inscriptional Pahlavi": { + "variants": ["400"] + }, + "Noto Sans Inscriptional Parthian": { + "variants": ["400"] + }, + "Noto Sans JP": { + "variants": ["100", "300", "400", "500", "700", "900"] + }, + "Noto Sans Javanese": { + "variants": ["400", "700"] + }, + "Noto Sans KR": { + "variants": ["100", "300", "400", "500", "700", "900"] + }, + "Noto Sans Kaithi": { + "variants": ["400"] + }, + "Noto Sans Kannada": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Kayah Li": { + "variants": ["400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Noto Sans Kharoshthi": { + "variants": ["400"] + }, + "Noto Sans Khmer": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Khojki": { + "variants": ["400"] + }, + "Noto Sans Khudawadi": { + "variants": ["400"] + }, + "Noto Sans Lao": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Lepcha": { + "variants": ["400"] + }, + "Noto Sans Limbu": { + "variants": ["400"] + }, + "Noto Sans Linear A": { + "variants": ["400"] + }, + "Noto Sans Linear B": { + "variants": ["400"] + }, + "Noto Sans Lisu": { + "variants": ["400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Noto Sans Lycian": { + "variants": ["400"] + }, + "Noto Sans Lydian": { + "variants": ["400"] + }, + "Noto Sans Mahajani": { + "variants": ["400"] + }, + "Noto Sans Malayalam": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Mandaic": { + "variants": ["400"] + }, + "Noto Sans Manichaean": { + "variants": ["400"] + }, + "Noto Sans Marchen": { + "variants": ["400"] + }, + "Noto Sans Masaram Gondi": { + "variants": ["400"] + }, + "Noto Sans Math": { + "variants": ["400"] + }, + "Noto Sans Mayan Numerals": { + "variants": ["400"] + }, + "Noto Sans Medefaidrin": { + "variants": ["400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Noto Sans Meetei Mayek": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Meroitic": { + "variants": ["400"] + }, + "Noto Sans Miao": { + "variants": ["400"] + }, + "Noto Sans Modi": { + "variants": ["400"] + }, + "Noto Sans Mongolian": { + "variants": ["400"] + }, + "Noto Sans Mono": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Mro": { + "variants": ["400"] + }, + "Noto Sans Multani": { + "variants": ["400"] + }, + "Noto Sans Myanmar": { + "variants": ["100", "200", "300", "400", "500", "600", "700", "800", "900"] + }, + "Noto Sans N Ko": { + "variants": ["400"] + }, + "Noto Sans Nabataean": { + "variants": ["400"] + }, + "Noto Sans New Tai Lue": { + "variants": ["400"] + }, + "Noto Sans Newa": { + "variants": ["400"] + }, + "Noto Sans Nushu": { + "variants": ["400"] + }, + "Noto Sans Ogham": { + "variants": ["400"] + }, + "Noto Sans Ol Chiki": { + "variants": ["400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Noto Sans Old Hungarian": { + "variants": ["400"] + }, + "Noto Sans Old Italic": { + "variants": ["400"] + }, + "Noto Sans Old North Arabian": { + "variants": ["400"] + }, + "Noto Sans Old Permic": { + "variants": ["400"] + }, + "Noto Sans Old Persian": { + "variants": ["400"] + }, + "Noto Sans Old Sogdian": { + "variants": ["400"] + }, + "Noto Sans Old South Arabian": { + "variants": ["400"] + }, + "Noto Sans Old Turkic": { + "variants": ["400"] + }, + "Noto Sans Oriya": { + "variants": ["100", "400", "700", "900"] + }, + "Noto Sans Osage": { + "variants": ["400"] + }, + "Noto Sans Osmanya": { + "variants": ["400"] + }, + "Noto Sans Pahawh Hmong": { + "variants": ["400"] + }, + "Noto Sans Palmyrene": { + "variants": ["400"] + }, + "Noto Sans Pau Cin Hau": { + "variants": ["400"] + }, + "Noto Sans Phags Pa": { + "variants": ["400"] + }, + "Noto Sans Phoenician": { + "variants": ["400"] + }, + "Noto Sans Psalter Pahlavi": { + "variants": ["400"] + }, + "Noto Sans Rejang": { + "variants": ["400"] + }, + "Noto Sans Runic": { + "variants": ["400"] + }, + "Noto Sans SC": { + "variants": ["100", "300", "400", "500", "700", "900"] + }, + "Noto Sans Samaritan": { + "variants": ["400"] + }, + "Noto Sans Saurashtra": { + "variants": ["400"] + }, + "Noto Sans Sharada": { + "variants": ["400"] + }, + "Noto Sans Shavian": { + "variants": ["400"] + }, + "Noto Sans Siddham": { + "variants": ["400"] + }, + "Noto Sans Sinhala": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Sogdian": { + "variants": ["400"] + }, + "Noto Sans Sora Sompeng": { + "variants": ["400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Noto Sans Soyombo": { + "variants": ["400"] + }, + "Noto Sans Sundanese": { + "variants": ["400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Noto Sans Syloti Nagri": { + "variants": ["400"] + }, + "Noto Sans Symbols": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Symbols 2": { + "variants": ["400"] + }, + "Noto Sans Syriac": { + "variants": ["100", "400", "900"] + }, + "Noto Sans TC": { + "variants": ["100", "300", "400", "500", "700", "900"] + }, + "Noto Sans Tagalog": { + "variants": ["400"] + }, + "Noto Sans Tagbanwa": { + "variants": ["400"] + }, + "Noto Sans Tai Le": { + "variants": ["400"] + }, + "Noto Sans Tai Tham": { + "variants": ["400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Noto Sans Tai Viet": { + "variants": ["400"] + }, + "Noto Sans Takri": { + "variants": ["400"] + }, + "Noto Sans Tamil": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Tamil Supplement": { + "variants": ["400"] + }, + "Noto Sans Telugu": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Thaana": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Thai": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Thai Looped": { + "variants": ["100", "200", "300", "400", "500", "600", "700", "800", "900"] + }, + "Noto Sans Tifinagh": { + "variants": ["400"] + }, + "Noto Sans Tirhuta": { + "variants": ["400"] + }, + "Noto Sans Ugaritic": { + "variants": ["400"] + }, + "Noto Sans Vai": { + "variants": ["400"] + }, + "Noto Sans Wancho": { + "variants": ["400"] + }, + "Noto Sans Warang Citi": { + "variants": ["400"] + }, + "Noto Sans Yi": { + "variants": ["400"] + }, + "Noto Sans Zanabazar Square": { + "variants": ["400"] + }, + "Noto Serif": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "Noto Serif Ahom": { + "variants": ["400"] + }, + "Noto Serif Armenian": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Serif Balinese": { + "variants": ["400"] + }, + "Noto Serif Bengali": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Serif Devanagari": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Serif Display": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Serif Dogra": { + "variants": ["400"] + }, + "Noto Serif Ethiopic": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Serif Georgian": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Serif Grantha": { + "variants": ["400"] + }, + "Noto Serif Gujarati": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Serif Gurmukhi": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Serif HK": { + "variants": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 200, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Serif Hebrew": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Serif JP": { + "variants": ["200", "300", "400", "500", "600", "700", "900"] + }, + "Noto Serif KR": { + "variants": ["200", "300", "400", "500", "600", "700", "900"] + }, + "Noto Serif Kannada": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Serif Khmer": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Serif Lao": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Serif Malayalam": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Serif Myanmar": { + "variants": ["100", "200", "300", "400", "500", "600", "700", "800", "900"] + }, + "Noto Serif Nyiakeng Puachue Hmong": { + "variants": ["400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Noto Serif SC": { + "variants": ["200", "300", "400", "500", "600", "700", "900"] + }, + "Noto Serif Sinhala": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Serif TC": { + "variants": ["200", "300", "400", "500", "600", "700", "900"] + }, + "Noto Serif Tamil": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Serif Tangut": { + "variants": ["400"] + }, + "Noto Serif Telugu": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Serif Thai": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Serif Tibetan": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Serif Yezidi": { + "variants": ["400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Noto Traditional Nushu": { + "variants": ["400"] + }, + "Nova Cut": { + "variants": ["400"] + }, + "Nova Flat": { + "variants": ["400"] + }, + "Nova Mono": { + "variants": ["400"] + }, + "Nova Oval": { + "variants": ["400"] + }, + "Nova Round": { + "variants": ["400"] + }, + "Nova Script": { + "variants": ["400"] + }, + "Nova Slim": { + "variants": ["400"] + }, + "Nova Square": { + "variants": ["400"] + }, + "Numans": { + "variants": ["400"] + }, + "Nunito": { + "variants": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 200, + "max": 1000, + "defaultValue": 400 + } + ] + }, + "Nunito Sans": { + "variants": [ + "200", + "300", + "400", + "600", + "700", + "800", + "900", + "200-italic", + "300-italic", + "400-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic" + ] + }, + "Nuosu SIL": { + "variants": ["400"] + }, + "Odibee Sans": { + "variants": ["400"] + }, + "Odor Mean Chey": { + "variants": ["400"] + }, + "Offside": { + "variants": ["400"] + }, + "Oi": { + "variants": ["400"] + }, + "Old Standard TT": { + "variants": ["400", "700", "400-italic"] + }, + "Oldenburg": { + "variants": ["400"] + }, + "Ole": { + "variants": ["400"] + }, + "Oleo Script": { + "variants": ["400", "700"] + }, + "Oleo Script Swash Caps": { + "variants": ["400", "700"] + }, + "Oooh Baby": { + "variants": ["400"] + }, + "Open Sans": { + "variants": [ + "300", + "400", + "500", + "600", + "700", + "800", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wdth", + "min": 75, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 300, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Oranienbaum": { + "variants": ["400"] + }, + "Orbitron": { + "variants": ["400", "500", "600", "700", "800", "900", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Oregano": { + "variants": ["400", "400-italic"] + }, + "Orelega One": { + "variants": ["400"] + }, + "Orienta": { + "variants": ["400"] + }, + "Original Surfer": { + "variants": ["400"] + }, + "Oswald": { + "variants": ["200", "300", "400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 200, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Outfit": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Over the Rainbow": { + "variants": ["400"] + }, + "Overlock": { + "variants": ["400", "700", "900", "400-italic", "700-italic", "900-italic"] + }, + "Overlock SC": { + "variants": ["400"] + }, + "Overpass": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Overpass Mono": { + "variants": ["300", "400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Ovo": { + "variants": ["400"] + }, + "Oxanium": { + "variants": ["200", "300", "400", "500", "600", "700", "800", "variable"], + "axes": [ + { + "tag": "wght", + "min": 200, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Oxygen": { + "variants": ["300", "400", "700"] + }, + "Oxygen Mono": { + "variants": ["400"] + }, + "PT Mono": { + "variants": ["400"] + }, + "PT Sans": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "PT Sans Caption": { + "variants": ["400", "700"] + }, + "PT Sans Narrow": { + "variants": ["400", "700"] + }, + "PT Serif": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "PT Serif Caption": { + "variants": ["400", "400-italic"] + }, + "Pacifico": { + "variants": ["400"] + }, + "Padauk": { + "variants": ["400", "700"] + }, + "Palanquin": { + "variants": ["100", "200", "300", "400", "500", "600", "700"] + }, + "Palanquin Dark": { + "variants": ["400", "500", "600", "700"] + }, + "Pangolin": { + "variants": ["400"] + }, + "Paprika": { + "variants": ["400"] + }, + "Parisienne": { + "variants": ["400"] + }, + "Passero One": { + "variants": ["400"] + }, + "Passion One": { + "variants": ["400", "700", "900"] + }, + "Passions Conflict": { + "variants": ["400"] + }, + "Pathway Gothic One": { + "variants": ["400"] + }, + "Patrick Hand": { + "variants": ["400"] + }, + "Patrick Hand SC": { + "variants": ["400"] + }, + "Pattaya": { + "variants": ["400"] + }, + "Patua One": { + "variants": ["400"] + }, + "Pavanam": { + "variants": ["400"] + }, + "Paytone One": { + "variants": ["400"] + }, + "Peddana": { + "variants": ["400"] + }, + "Peralta": { + "variants": ["400"] + }, + "Permanent Marker": { + "variants": ["400"] + }, + "Petemoss": { + "variants": ["400"] + }, + "Petit Formal Script": { + "variants": ["400"] + }, + "Petrona": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Philosopher": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "Piazzolla": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "opsz", + "min": 8, + "max": 30, + "defaultValue": 14 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Piedra": { + "variants": ["400"] + }, + "Pinyon Script": { + "variants": ["400"] + }, + "Pirata One": { + "variants": ["400"] + }, + "Plaster": { + "variants": ["400"] + }, + "Play": { + "variants": ["400", "700"] + }, + "Playball": { + "variants": ["400"] + }, + "Playfair Display": { + "variants": [ + "400", + "500", + "600", + "700", + "800", + "900", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Playfair Display SC": { + "variants": ["400", "700", "900", "400-italic", "700-italic", "900-italic"] + }, + "Plus Jakarta Sans": { + "variants": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 200, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Podkova": { + "variants": ["400", "500", "600", "700", "800", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Poiret One": { + "variants": ["400"] + }, + "Poller One": { + "variants": ["400"] + }, + "Poly": { + "variants": ["400", "400-italic"] + }, + "Pompiere": { + "variants": ["400"] + }, + "Pontano Sans": { + "variants": ["400"] + }, + "Poor Story": { + "variants": ["400"] + }, + "Poppins": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic" + ] + }, + "Port Lligat Sans": { + "variants": ["400"] + }, + "Port Lligat Slab": { + "variants": ["400"] + }, + "Potta One": { + "variants": ["400"] + }, + "Pragati Narrow": { + "variants": ["400", "700"] + }, + "Praise": { + "variants": ["400"] + }, + "Prata": { + "variants": ["400"] + }, + "Preahvihear": { + "variants": ["400"] + }, + "Press Start 2P": { + "variants": ["400"] + }, + "Pridi": { + "variants": ["200", "300", "400", "500", "600", "700"] + }, + "Princess Sofia": { + "variants": ["400"] + }, + "Prociono": { + "variants": ["400"] + }, + "Prompt": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic" + ] + }, + "Prosto One": { + "variants": ["400"] + }, + "Proza Libre": { + "variants": [ + "400", + "500", + "600", + "700", + "800", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic" + ] + }, + "Public Sans": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Puppies Play": { + "variants": ["400"] + }, + "Puritan": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "Purple Purse": { + "variants": ["400"] + }, + "Qahiri": { + "variants": ["400"] + }, + "Quando": { + "variants": ["400"] + }, + "Quantico": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "Quattrocento": { + "variants": ["400", "700"] + }, + "Quattrocento Sans": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "Questrial": { + "variants": ["400"] + }, + "Quicksand": { + "variants": ["300", "400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Quintessential": { + "variants": ["400"] + }, + "Qwigley": { + "variants": ["400"] + }, + "Qwitcher Grypen": { + "variants": ["400", "700"] + }, + "Racing Sans One": { + "variants": ["400"] + }, + "Radio Canada": { + "variants": [ + "300", + "400", + "500", + "600", + "700", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wdth", + "min": 75, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Radley": { + "variants": ["400", "400-italic"] + }, + "Rajdhani": { + "variants": ["300", "400", "500", "600", "700"] + }, + "Rakkas": { + "variants": ["400"] + }, + "Raleway": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Raleway Dots": { + "variants": ["400"] + }, + "Ramabhadra": { + "variants": ["400"] + }, + "Ramaraja": { + "variants": ["400"] + }, + "Rambla": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "Rammetto One": { + "variants": ["400"] + }, + "Rampart One": { + "variants": ["400"] + }, + "Ranchers": { + "variants": ["400"] + }, + "Rancho": { + "variants": ["400"] + }, + "Ranga": { + "variants": ["400", "700"] + }, + "Rasa": { + "variants": [ + "300", + "400", + "500", + "600", + "700", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Rationale": { + "variants": ["400"] + }, + "Ravi Prakash": { + "variants": ["400"] + }, + "Readex Pro": { + "variants": ["200", "300", "400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 160, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Recursive": { + "variants": ["300", "400", "500", "600", "700", "800", "900", "variable"], + "axes": [ + { + "tag": "CASL", + "min": 0, + "max": 1, + "defaultValue": 0 + }, + { + "tag": "CRSV", + "min": 0, + "max": 1, + "defaultValue": 0.5 + }, + { + "tag": "MONO", + "min": 0, + "max": 1, + "defaultValue": 0 + }, + { + "tag": "slnt", + "min": -15, + "max": 0, + "defaultValue": 0 + }, + { + "tag": "wght", + "min": 300, + "max": 1000, + "defaultValue": 400 + } + ] + }, + "Red Hat Display": { + "variants": [ + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Red Hat Mono": { + "variants": [ + "300", + "400", + "500", + "600", + "700", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Red Hat Text": { + "variants": [ + "300", + "400", + "500", + "600", + "700", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Red Rose": { + "variants": ["300", "400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Redacted": { + "variants": ["400"] + }, + "Redacted Script": { + "variants": ["300", "400", "700"] + }, + "Redressed": { + "variants": ["400"] + }, + "Reem Kufi": { + "variants": ["400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Reem Kufi Fun": { + "variants": ["400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Reem Kufi Ink": { + "variants": ["400"] + }, + "Reenie Beanie": { + "variants": ["400"] + }, + "Reggae One": { + "variants": ["400"] + }, + "Revalia": { + "variants": ["400"] + }, + "Rhodium Libre": { + "variants": ["400"] + }, + "Ribeye": { + "variants": ["400"] + }, + "Ribeye Marrow": { + "variants": ["400"] + }, + "Righteous": { + "variants": ["400"] + }, + "Risque": { + "variants": ["400"] + }, + "Road Rage": { + "variants": ["400"] + }, + "Roboto": { + "variants": [ + "100", + "300", + "400", + "500", + "700", + "900", + "100-italic", + "300-italic", + "400-italic", + "500-italic", + "700-italic", + "900-italic" + ] + }, + "Roboto Condensed": { + "variants": ["300", "400", "700", "300-italic", "400-italic", "700-italic"] + }, + "Roboto Flex": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "1000", + "variable" + ], + "axes": [ + { + "tag": "GRAD", + "min": -200, + "max": 150, + "defaultValue": 0 + }, + { + "tag": "XTRA", + "min": 323, + "max": 603, + "defaultValue": 468 + }, + { + "tag": "YOPQ", + "min": 25, + "max": 135, + "defaultValue": 79 + }, + { + "tag": "YTAS", + "min": 649, + "max": 854, + "defaultValue": 750 + }, + { + "tag": "YTDE", + "min": -305, + "max": -98, + "defaultValue": -203 + }, + { + "tag": "YTFI", + "min": 560, + "max": 788, + "defaultValue": 738 + }, + { + "tag": "YTLC", + "min": 416, + "max": 570, + "defaultValue": 514 + }, + { + "tag": "YTUC", + "min": 528, + "max": 760, + "defaultValue": 712 + }, + { + "tag": "opsz", + "min": 8, + "max": 144, + "defaultValue": 14 + }, + { + "tag": "slnt", + "min": -10, + "max": 0, + "defaultValue": 0 + }, + { + "tag": "wdth", + "min": 25, + "max": 151, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 1000, + "defaultValue": 400 + } + ] + }, + "Roboto Mono": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Roboto Serif": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "GRAD", + "min": -50, + "max": 100, + "defaultValue": 0 + }, + { + "tag": "opsz", + "min": 8, + "max": 144, + "defaultValue": 14 + }, + { + "tag": "wdth", + "min": 50, + "max": 150, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Roboto Slab": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Rochester": { + "variants": ["400"] + }, + "Rock Salt": { + "variants": ["400"] + }, + "RocknRoll One": { + "variants": ["400"] + }, + "Rokkitt": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Romanesco": { + "variants": ["400"] + }, + "Ropa Sans": { + "variants": ["400", "400-italic"] + }, + "Rosario": { + "variants": [ + "300", + "400", + "500", + "600", + "700", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Rosarivo": { + "variants": ["400", "400-italic"] + }, + "Rouge Script": { + "variants": ["400"] + }, + "Rowdies": { + "variants": ["300", "400", "700"] + }, + "Rozha One": { + "variants": ["400"] + }, + "Rubik": { + "variants": [ + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Rubik Beastly": { + "variants": ["400"] + }, + "Rubik Bubbles": { + "variants": ["400"] + }, + "Rubik Burned": { + "variants": ["400"] + }, + "Rubik Dirt": { + "variants": ["400"] + }, + "Rubik Distressed": { + "variants": ["400"] + }, + "Rubik Glitch": { + "variants": ["400"] + }, + "Rubik Iso": { + "variants": ["400"] + }, + "Rubik Marker Hatch": { + "variants": ["400"] + }, + "Rubik Maze": { + "variants": ["400"] + }, + "Rubik Microbe": { + "variants": ["400"] + }, + "Rubik Mono One": { + "variants": ["400"] + }, + "Rubik Moonrocks": { + "variants": ["400"] + }, + "Rubik Puddles": { + "variants": ["400"] + }, + "Rubik Wet Paint": { + "variants": ["400"] + }, + "Ruda": { + "variants": ["400", "500", "600", "700", "800", "900", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Rufina": { + "variants": ["400", "700"] + }, + "Ruge Boogie": { + "variants": ["400"] + }, + "Ruluko": { + "variants": ["400"] + }, + "Rum Raisin": { + "variants": ["400"] + }, + "Ruslan Display": { + "variants": ["400"] + }, + "Russo One": { + "variants": ["400"] + }, + "Ruthie": { + "variants": ["400"] + }, + "Rye": { + "variants": ["400"] + }, + "STIX Two Text": { + "variants": [ + "400", + "500", + "600", + "700", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Sacramento": { + "variants": ["400"] + }, + "Sahitya": { + "variants": ["400", "700"] + }, + "Sail": { + "variants": ["400"] + }, + "Saira": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wdth", + "min": 50, + "max": 125, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Saira Condensed": { + "variants": ["100", "200", "300", "400", "500", "600", "700", "800", "900"] + }, + "Saira Extra Condensed": { + "variants": ["100", "200", "300", "400", "500", "600", "700", "800", "900"] + }, + "Saira Semi Condensed": { + "variants": ["100", "200", "300", "400", "500", "600", "700", "800", "900"] + }, + "Saira Stencil One": { + "variants": ["400"] + }, + "Salsa": { + "variants": ["400"] + }, + "Sanchez": { + "variants": ["400", "400-italic"] + }, + "Sancreek": { + "variants": ["400"] + }, + "Sansita": { + "variants": [ + "400", + "700", + "800", + "900", + "400-italic", + "700-italic", + "800-italic", + "900-italic" + ] + }, + "Sansita Swashed": { + "variants": ["300", "400", "500", "600", "700", "800", "900", "variable"], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Sarabun": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic" + ] + }, + "Sarala": { + "variants": ["400", "700"] + }, + "Sarina": { + "variants": ["400"] + }, + "Sarpanch": { + "variants": ["400", "500", "600", "700", "800", "900"] + }, + "Sassy Frass": { + "variants": ["400"] + }, + "Satisfy": { + "variants": ["400"] + }, + "Sawarabi Gothic": { + "variants": ["400"] + }, + "Sawarabi Mincho": { + "variants": ["400"] + }, + "Scada": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "Scheherazade New": { + "variants": ["400", "700"] + }, + "Schoolbell": { + "variants": ["400"] + }, + "Scope One": { + "variants": ["400"] + }, + "Seaweed Script": { + "variants": ["400"] + }, + "Secular One": { + "variants": ["400"] + }, + "Sedgwick Ave": { + "variants": ["400"] + }, + "Sedgwick Ave Display": { + "variants": ["400"] + }, + "Sen": { + "variants": ["400", "700", "800"] + }, + "Send Flowers": { + "variants": ["400"] + }, + "Sevillana": { + "variants": ["400"] + }, + "Seymour One": { + "variants": ["400"] + }, + "Shadows Into Light": { + "variants": ["400"] + }, + "Shadows Into Light Two": { + "variants": ["400"] + }, + "Shalimar": { + "variants": ["400"] + }, + "Shanti": { + "variants": ["400"] + }, + "Share": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "Share Tech": { + "variants": ["400"] + }, + "Share Tech Mono": { + "variants": ["400"] + }, + "Shippori Antique": { + "variants": ["400"] + }, + "Shippori Antique B1": { + "variants": ["400"] + }, + "Shippori Mincho": { + "variants": ["400", "500", "600", "700", "800"] + }, + "Shippori Mincho B1": { + "variants": ["400", "500", "600", "700", "800"] + }, + "Shojumaru": { + "variants": ["400"] + }, + "Short Stack": { + "variants": ["400"] + }, + "Shrikhand": { + "variants": ["400"] + }, + "Siemreap": { + "variants": ["400"] + }, + "Sigmar One": { + "variants": ["400"] + }, + "Signika": { + "variants": ["300", "400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Signika Negative": { + "variants": ["300", "400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Silkscreen": { + "variants": ["400", "700"] + }, + "Simonetta": { + "variants": ["400", "900", "400-italic", "900-italic"] + }, + "Single Day": { + "variants": ["400"] + }, + "Sintony": { + "variants": ["400", "700"] + }, + "Sirin Stencil": { + "variants": ["400"] + }, + "Six Caps": { + "variants": ["400"] + }, + "Skranji": { + "variants": ["400", "700"] + }, + "Slabo 13px": { + "variants": ["400"] + }, + "Slabo 27px": { + "variants": ["400"] + }, + "Slackey": { + "variants": ["400"] + }, + "Smokum": { + "variants": ["400"] + }, + "Smooch": { + "variants": ["400"] + }, + "Smooch Sans": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Smythe": { + "variants": ["400"] + }, + "Sniglet": { + "variants": ["400", "800"] + }, + "Snippet": { + "variants": ["400"] + }, + "Snowburst One": { + "variants": ["400"] + }, + "Sofadi One": { + "variants": ["400"] + }, + "Sofia": { + "variants": ["400"] + }, + "Solway": { + "variants": ["300", "400", "500", "700", "800"] + }, + "Song Myung": { + "variants": ["400"] + }, + "Sonsie One": { + "variants": ["400"] + }, + "Sora": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Sorts Mill Goudy": { + "variants": ["400", "400-italic"] + }, + "Source Code Pro": { + "variants": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 200, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Source Sans 3": { + "variants": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 200, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Source Sans Pro": { + "variants": [ + "200", + "300", + "400", + "600", + "700", + "900", + "200-italic", + "300-italic", + "400-italic", + "600-italic", + "700-italic", + "900-italic" + ] + }, + "Source Serif 4": { + "variants": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "opsz", + "min": 8, + "max": 60, + "defaultValue": 14 + }, + { + "tag": "wght", + "min": 200, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Source Serif Pro": { + "variants": [ + "200", + "300", + "400", + "600", + "700", + "900", + "200-italic", + "300-italic", + "400-italic", + "600-italic", + "700-italic", + "900-italic" + ] + }, + "Space Grotesk": { + "variants": ["300", "400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Space Mono": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "Special Elite": { + "variants": ["400"] + }, + "Spectral": { + "variants": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic" + ] + }, + "Spectral SC": { + "variants": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic" + ] + }, + "Spicy Rice": { + "variants": ["400"] + }, + "Spinnaker": { + "variants": ["400"] + }, + "Spirax": { + "variants": ["400"] + }, + "Splash": { + "variants": ["400"] + }, + "Spline Sans": { + "variants": ["300", "400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Spline Sans Mono": { + "variants": [ + "300", + "400", + "500", + "600", + "700", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Squada One": { + "variants": ["400"] + }, + "Square Peg": { + "variants": ["400"] + }, + "Sree Krushnadevaraya": { + "variants": ["400"] + }, + "Sriracha": { + "variants": ["400"] + }, + "Srisakdi": { + "variants": ["400", "700"] + }, + "Staatliches": { + "variants": ["400"] + }, + "Stalemate": { + "variants": ["400"] + }, + "Stalinist One": { + "variants": ["400"] + }, + "Stardos Stencil": { + "variants": ["400", "700"] + }, + "Stick": { + "variants": ["400"] + }, + "Stick No Bills": { + "variants": ["200", "300", "400", "500", "600", "700", "800", "variable"], + "axes": [ + { + "tag": "wght", + "min": 200, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Stint Ultra Condensed": { + "variants": ["400"] + }, + "Stint Ultra Expanded": { + "variants": ["400"] + }, + "Stoke": { + "variants": ["300", "400"] + }, + "Strait": { + "variants": ["400"] + }, + "Style Script": { + "variants": ["400"] + }, + "Stylish": { + "variants": ["400"] + }, + "Sue Ellen Francisco": { + "variants": ["400"] + }, + "Suez One": { + "variants": ["400"] + }, + "Sulphur Point": { + "variants": ["300", "400", "700"] + }, + "Sumana": { + "variants": ["400", "700"] + }, + "Sunflower": { + "variants": ["300", "500", "700"] + }, + "Sunshiney": { + "variants": ["400"] + }, + "Supermercado One": { + "variants": ["400"] + }, + "Sura": { + "variants": ["400", "700"] + }, + "Suranna": { + "variants": ["400"] + }, + "Suravaram": { + "variants": ["400"] + }, + "Suwannaphum": { + "variants": ["100", "300", "400", "700", "900"] + }, + "Swanky and Moo Moo": { + "variants": ["400"] + }, + "Syncopate": { + "variants": ["400", "700"] + }, + "Syne": { + "variants": ["400", "500", "600", "700", "800", "variable"], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Syne Mono": { + "variants": ["400"] + }, + "Syne Tactile": { + "variants": ["400"] + }, + "Tai Heritage Pro": { + "variants": ["400", "700"] + }, + "Tajawal": { + "variants": ["200", "300", "400", "500", "700", "800", "900"] + }, + "Tangerine": { + "variants": ["400", "700"] + }, + "Tapestry": { + "variants": ["400"] + }, + "Taprom": { + "variants": ["400"] + }, + "Tauri": { + "variants": ["400"] + }, + "Taviraj": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic" + ] + }, + "Teko": { + "variants": ["300", "400", "500", "600", "700"] + }, + "Telex": { + "variants": ["400"] + }, + "Tenali Ramakrishna": { + "variants": ["400"] + }, + "Tenor Sans": { + "variants": ["400"] + }, + "Text Me One": { + "variants": ["400"] + }, + "Texturina": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "opsz", + "min": 12, + "max": 72, + "defaultValue": 12 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Thasadith": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "The Girl Next Door": { + "variants": ["400"] + }, + "The Nautigal": { + "variants": ["400", "700"] + }, + "Tienne": { + "variants": ["400", "700", "900"] + }, + "Tillana": { + "variants": ["400", "500", "600", "700", "800"] + }, + "Timmana": { + "variants": ["400"] + }, + "Tinos": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "Tiro Bangla": { + "variants": ["400", "400-italic"] + }, + "Tiro Devanagari Hindi": { + "variants": ["400", "400-italic"] + }, + "Tiro Devanagari Marathi": { + "variants": ["400", "400-italic"] + }, + "Tiro Devanagari Sanskrit": { + "variants": ["400", "400-italic"] + }, + "Tiro Gurmukhi": { + "variants": ["400", "400-italic"] + }, + "Tiro Kannada": { + "variants": ["400", "400-italic"] + }, + "Tiro Tamil": { + "variants": ["400", "400-italic"] + }, + "Tiro Telugu": { + "variants": ["400", "400-italic"] + }, + "Titan One": { + "variants": ["400"] + }, + "Titillium Web": { + "variants": [ + "200", + "300", + "400", + "600", + "700", + "900", + "200-italic", + "300-italic", + "400-italic", + "600-italic", + "700-italic" + ] + }, + "Tomorrow": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic" + ] + }, + "Tourney": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wdth", + "min": 75, + "max": 125, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Trade Winds": { + "variants": ["400"] + }, + "Train One": { + "variants": ["400"] + }, + "Trirong": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic" + ] + }, + "Trispace": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "axes": [ + { + "tag": "wdth", + "min": 75, + "max": 125, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Trocchi": { + "variants": ["400"] + }, + "Trochut": { + "variants": ["400", "700", "400-italic"] + }, + "Truculenta": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "opsz", + "min": 12, + "max": 72, + "defaultValue": 14 + }, + { + "tag": "wdth", + "min": 75, + "max": 125, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Trykker": { + "variants": ["400"] + }, + "Tulpen One": { + "variants": ["400"] + }, + "Turret Road": { + "variants": ["200", "300", "400", "500", "700", "800"] + }, + "Twinkle Star": { + "variants": ["400"] + }, + "Ubuntu": { + "variants": [ + "300", + "400", + "500", + "700", + "300-italic", + "400-italic", + "500-italic", + "700-italic" + ] + }, + "Ubuntu Condensed": { + "variants": ["400"] + }, + "Ubuntu Mono": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "Uchen": { + "variants": ["400"] + }, + "Ultra": { + "variants": ["400"] + }, + "Uncial Antiqua": { + "variants": ["400"] + }, + "Underdog": { + "variants": ["400"] + }, + "Unica One": { + "variants": ["400"] + }, + "UnifrakturCook": { + "variants": ["700"] + }, + "UnifrakturMaguntia": { + "variants": ["400"] + }, + "Unkempt": { + "variants": ["400", "700"] + }, + "Unlock": { + "variants": ["400"] + }, + "Unna": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "Updock": { + "variants": ["400"] + }, + "Urbanist": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "VT323": { + "variants": ["400"] + }, + "Vampiro One": { + "variants": ["400"] + }, + "Varela": { + "variants": ["400"] + }, + "Varela Round": { + "variants": ["400"] + }, + "Varta": { + "variants": ["300", "400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Vast Shadow": { + "variants": ["400"] + }, + "Vazirmatn": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Vesper Libre": { + "variants": ["400", "500", "700", "900"] + }, + "Viaoda Libre": { + "variants": ["400"] + }, + "Vibes": { + "variants": ["400"] + }, + "Vibur": { + "variants": ["400"] + }, + "Vidaloka": { + "variants": ["400"] + }, + "Viga": { + "variants": ["400"] + }, + "Voces": { + "variants": ["400"] + }, + "Volkhov": { + "variants": ["400", "700", "400-italic", "700-italic"] + }, + "Vollkorn": { + "variants": [ + "400", + "500", + "600", + "700", + "800", + "900", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Vollkorn SC": { + "variants": ["400", "600", "700", "900"] + }, + "Voltaire": { + "variants": ["400"] + }, + "Vujahday Script": { + "variants": ["400"] + }, + "Waiting for the Sunrise": { + "variants": ["400"] + }, + "Wallpoet": { + "variants": ["400"] + }, + "Walter Turncoat": { + "variants": ["400"] + }, + "Warnes": { + "variants": ["400"] + }, + "Water Brush": { + "variants": ["400"] + }, + "Waterfall": { + "variants": ["400"] + }, + "Wellfleet": { + "variants": ["400"] + }, + "Wendy One": { + "variants": ["400"] + }, + "Whisper": { + "variants": ["400"] + }, + "WindSong": { + "variants": ["400", "500"] + }, + "Wire One": { + "variants": ["400"] + }, + "Work Sans": { + "variants": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "100-italic", + "200-italic", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "800-italic", + "900-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Xanh Mono": { + "variants": ["400", "400-italic"] + }, + "Yaldevi": { + "variants": ["200", "300", "400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 200, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Yanone Kaffeesatz": { + "variants": ["200", "300", "400", "500", "600", "700", "variable"], + "axes": [ + { + "tag": "wght", + "min": 200, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Yantramanav": { + "variants": ["100", "300", "400", "500", "700", "900"] + }, + "Yatra One": { + "variants": ["400"] + }, + "Yellowtail": { + "variants": ["400"] + }, + "Yeon Sung": { + "variants": ["400"] + }, + "Yeseva One": { + "variants": ["400"] + }, + "Yesteryear": { + "variants": ["400"] + }, + "Yomogi": { + "variants": ["400"] + }, + "Yrsa": { + "variants": [ + "300", + "400", + "500", + "600", + "700", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic", + "variable", + "variable-italic" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Yuji Boku": { + "variants": ["400"] + }, + "Yuji Mai": { + "variants": ["400"] + }, + "Yuji Syuku": { + "variants": ["400"] + }, + "Yusei Magic": { + "variants": ["400"] + }, + "ZCOOL KuaiLe": { + "variants": ["400"] + }, + "ZCOOL QingKe HuangYou": { + "variants": ["400"] + }, + "ZCOOL XiaoWei": { + "variants": ["400"] + }, + "Zen Antique": { + "variants": ["400"] + }, + "Zen Antique Soft": { + "variants": ["400"] + }, + "Zen Dots": { + "variants": ["400"] + }, + "Zen Kaku Gothic Antique": { + "variants": ["300", "400", "500", "700", "900"] + }, + "Zen Kaku Gothic New": { + "variants": ["300", "400", "500", "700", "900"] + }, + "Zen Kurenaido": { + "variants": ["400"] + }, + "Zen Loop": { + "variants": ["400", "400-italic"] + }, + "Zen Maru Gothic": { + "variants": ["300", "400", "500", "700", "900"] + }, + "Zen Old Mincho": { + "variants": ["400", "700", "900"] + }, + "Zen Tokyo Zoo": { + "variants": ["400"] + }, + "Zeyada": { + "variants": ["400"] + }, + "Zhi Mang Xing": { + "variants": ["400"] + }, + "Zilla Slab": { + "variants": [ + "300", + "400", + "500", + "600", + "700", + "300-italic", + "400-italic", + "500-italic", + "600-italic", + "700-italic" + ] + }, + "Zilla Slab Highlight": { + "variants": ["400", "700"] + } +} diff --git a/packages/font/src/google/index.ts b/packages/font/src/google/index.ts new file mode 100644 index 0000000000000..83921541286c8 --- /dev/null +++ b/packages/font/src/google/index.ts @@ -0,0 +1,13243 @@ +type Display = 'auto' | 'block' | 'swap' | 'fallback' | 'optional' +type FontModule = { + className: string + variable: string + style: { fontFamily: string; fontWeight?: number; fontStyle?: string } +} +export declare function ABeeZee(options: { + variant: '400' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Abel(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Abhaya_Libre(options: { + variant: '400' | '500' | '600' | '700' | '800' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Aboreto(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Abril_Fatface(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Aclonica(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Acme(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Actor(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Adamina(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Advent_Pro(options: { + variant: '100' | '200' | '300' | '400' | '500' | '600' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Aguafina_Script(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Akaya_Kanadaka(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Akaya_Telivigala(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Akronim(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Akshar(options?: { + variant?: '300' | '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Aladin(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Alata(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Alatsi(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Albert_Sans(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Aldrich(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Alef(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Alegreya(options?: { + variant?: + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Alegreya_SC(options: { + variant: + | '400' + | '500' + | '700' + | '800' + | '900' + | '400-italic' + | '500-italic' + | '700-italic' + | '800-italic' + | '900-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Alegreya_Sans(options: { + variant: + | '100' + | '300' + | '400' + | '500' + | '700' + | '800' + | '900' + | '100-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '700-italic' + | '800-italic' + | '900-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Alegreya_Sans_SC(options: { + variant: + | '100' + | '300' + | '400' + | '500' + | '700' + | '800' + | '900' + | '100-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '700-italic' + | '800-italic' + | '900-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Aleo(options: { + variant: '300' | '400' | '700' | '300-italic' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Alex_Brush(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Alfa_Slab_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Alice(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Alike(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Alike_Angular(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Allan(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Allerta(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Allerta_Stencil(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Allison(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Allura(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Almarai(options: { + variant: '300' | '400' | '700' | '800' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Almendra(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Almendra_Display(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Almendra_SC(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Alumni_Sans(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Alumni_Sans_Collegiate_One(options: { + variant: '400' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Alumni_Sans_Inline_One(options: { + variant: '400' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Alumni_Sans_Pinstripe(options: { + variant: '400' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Amarante(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Amaranth(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Amatic_SC(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Amethysta(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Amiko(options: { + variant: '400' | '600' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Amiri(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Amiri_Quran(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Amita(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Anaheim(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Andada_Pro(options?: { + variant?: + | '400' + | '500' + | '600' + | '700' + | '800' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Andika(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Anek_Bangla(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Anek_Devanagari(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Anek_Gujarati(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Anek_Gurmukhi(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Anek_Kannada(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Anek_Latin(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Anek_Malayalam(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Anek_Odia(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Anek_Tamil(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Anek_Telugu(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Angkor(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Annie_Use_Your_Telescope(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Anonymous_Pro(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Antic(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Antic_Didone(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Antic_Slab(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Anton(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Antonio(options?: { + variant?: '100' | '200' | '300' | '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Anybody(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Arapey(options: { + variant: '400' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Arbutus(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Arbutus_Slab(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Architects_Daughter(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Archivo(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Archivo_Black(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Archivo_Narrow(options?: { + variant?: + | '400' + | '500' + | '600' + | '700' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Are_You_Serious(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Aref_Ruqaa(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Aref_Ruqaa_Ink(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Arima(options?: { + variant?: '100' | '200' | '300' | '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Arima_Madurai(options: { + variant: '100' | '200' | '300' | '400' | '500' | '700' | '800' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Arimo(options?: { + variant?: + | '400' + | '500' + | '600' + | '700' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Arizonia(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Armata(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Arsenal(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Artifika(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Arvo(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Arya(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Asap(options?: { + variant?: + | '400' + | '500' + | '600' + | '700' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Asap_Condensed(options: { + variant: + | '400' + | '500' + | '600' + | '700' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Asar(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Asset(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Assistant(options?: { + variant?: '200' | '300' | '400' | '500' | '600' | '700' | '800' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Astloch(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Asul(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Athiti(options: { + variant: '200' | '300' | '400' | '500' | '600' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Atkinson_Hyperlegible(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Atma(options: { + variant: '300' | '400' | '500' | '600' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Atomic_Age(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Aubrey(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Audiowide(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Autour_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Average(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Average_Sans(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Averia_Gruesa_Libre(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Averia_Libre(options: { + variant: '300' | '400' | '700' | '300-italic' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Averia_Sans_Libre(options: { + variant: '300' | '400' | '700' | '300-italic' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Averia_Serif_Libre(options: { + variant: '300' | '400' | '700' | '300-italic' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Azeret_Mono(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function B612(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function B612_Mono(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function BIZ_UDGothic(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function BIZ_UDMincho(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function BIZ_UDPGothic(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function BIZ_UDPMincho(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Babylonica(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Bad_Script(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Bahiana(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Bahianita(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Bai_Jamjuree(options: { + variant: + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Bakbak_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Ballet(options?: { + variant?: '400' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'opsz'[] +}): FontModule +export declare function Baloo_2(options?: { + variant?: '400' | '500' | '600' | '700' | '800' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Baloo_Bhai_2(options?: { + variant?: '400' | '500' | '600' | '700' | '800' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Baloo_Bhaijaan_2(options?: { + variant?: '400' | '500' | '600' | '700' | '800' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Baloo_Bhaina_2(options?: { + variant?: '400' | '500' | '600' | '700' | '800' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Baloo_Chettan_2(options?: { + variant?: '400' | '500' | '600' | '700' | '800' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Baloo_Da_2(options?: { + variant?: '400' | '500' | '600' | '700' | '800' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Baloo_Paaji_2(options?: { + variant?: '400' | '500' | '600' | '700' | '800' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Baloo_Tamma_2(options?: { + variant?: '400' | '500' | '600' | '700' | '800' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Baloo_Tammudu_2(options?: { + variant?: '400' | '500' | '600' | '700' | '800' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Baloo_Thambi_2(options?: { + variant?: '400' | '500' | '600' | '700' | '800' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Balsamiq_Sans(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Balthazar(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Bangers(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Barlow(options: { + variant: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Barlow_Condensed(options: { + variant: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Barlow_Semi_Condensed(options: { + variant: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Barriecito(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Barrio(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Basic(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Baskervville(options: { + variant: '400' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Battambang(options: { + variant: '100' | '300' | '400' | '700' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Baumans(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Bayon(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Be_Vietnam_Pro(options: { + variant: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Beau_Rivage(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Bebas_Neue(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Belgrano(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Bellefair(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Belleza(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Bellota(options: { + variant: '300' | '400' | '700' | '300-italic' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Bellota_Text(options: { + variant: '300' | '400' | '700' | '300-italic' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function BenchNine(options: { + variant: '300' | '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Benne(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Bentham(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Berkshire_Swash(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Besley(options?: { + variant?: + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Beth_Ellen(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Bevan(options: { + variant: '400' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function BhuTuka_Expanded_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Big_Shoulders_Display(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Big_Shoulders_Inline_Display(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Big_Shoulders_Inline_Text(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Big_Shoulders_Stencil_Display(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Big_Shoulders_Stencil_Text(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Big_Shoulders_Text(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Bigelow_Rules(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Bigshot_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Bilbo(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Bilbo_Swash_Caps(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function BioRhyme(options: { + variant: '200' | '300' | '400' | '700' | '800' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function BioRhyme_Expanded(options: { + variant: '200' | '300' | '400' | '700' | '800' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Birthstone(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Birthstone_Bounce(options: { + variant: '400' | '500' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Biryani(options: { + variant: '200' | '300' | '400' | '600' | '700' | '800' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Bitter(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Black_And_White_Picture(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Black_Han_Sans(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Black_Ops_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Blaka(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Blaka_Hollow(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Blaka_Ink(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Blinker(options: { + variant: '100' | '200' | '300' | '400' | '600' | '700' | '800' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Bodoni_Moda(options?: { + variant?: + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'opsz'[] +}): FontModule +export declare function Bokor(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Bona_Nova(options: { + variant: '400' | '700' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Bonbon(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Bonheur_Royale(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Boogaloo(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Bowlby_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Bowlby_One_SC(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Brawler(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Bree_Serif(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Brygada_1918(options?: { + variant?: + | '400' + | '500' + | '600' + | '700' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Bubblegum_Sans(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Bubbler_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Buda(options: { + variant: '300' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Buenard(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Bungee(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Bungee_Hairline(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Bungee_Inline(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Bungee_Outline(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Bungee_Shade(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Bungee_Spice(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Butcherman(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Butterfly_Kids(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Cabin(options?: { + variant?: + | '400' + | '500' + | '600' + | '700' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Cabin_Condensed(options: { + variant: '400' | '500' | '600' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Cabin_Sketch(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Caesar_Dressing(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Cagliostro(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Cairo(options?: { + variant?: + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Cairo_Play(options?: { + variant?: + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'slnt'[] +}): FontModule +export declare function Caladea(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Calistoga(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Calligraffitti(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Cambay(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Cambo(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Candal(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Cantarell(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Cantata_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Cantora_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Capriola(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Caramel(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Carattere(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Cardo(options: { + variant: '400' | '700' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Carme(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Carrois_Gothic(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Carrois_Gothic_SC(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Carter_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Castoro(options: { + variant: '400' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Catamaran(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Caudex(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Caveat(options?: { + variant?: '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Caveat_Brush(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Cedarville_Cursive(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Ceviche_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Chakra_Petch(options: { + variant: + | '300' + | '400' + | '500' + | '600' + | '700' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Changa(options?: { + variant?: '200' | '300' | '400' | '500' | '600' | '700' | '800' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Changa_One(options: { + variant: '400' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Chango(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Charis_SIL(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Charm(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Charmonman(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Chathura(options: { + variant: '100' | '300' | '400' | '700' | '800' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Chau_Philomene_One(options: { + variant: '400' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Chela_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Chelsea_Market(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Chenla(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Cherish(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Cherry_Cream_Soda(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Cherry_Swash(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Chewy(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Chicle(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Chilanka(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Chivo(options: { + variant: + | '300' + | '400' + | '700' + | '900' + | '300-italic' + | '400-italic' + | '700-italic' + | '900-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Chonburi(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Cinzel(options?: { + variant?: '400' | '500' | '600' | '700' | '800' | '900' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Cinzel_Decorative(options: { + variant: '400' | '700' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Clicker_Script(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Coda(options: { + variant: '400' | '800' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Coda_Caption(options: { + variant: '800' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Codystar(options: { + variant: '300' | '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Coiny(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Combo(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Comfortaa(options?: { + variant?: '300' | '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Comforter(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Comforter_Brush(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Comic_Neue(options: { + variant: '300' | '400' | '700' | '300-italic' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Coming_Soon(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Commissioner(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Concert_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Condiment(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Content(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Contrail_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Convergence(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Cookie(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Copse(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Corben(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Corinthia(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Cormorant(options?: { + variant?: + | '300' + | '400' + | '500' + | '600' + | '700' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Cormorant_Garamond(options: { + variant: + | '300' + | '400' + | '500' + | '600' + | '700' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Cormorant_Infant(options: { + variant: + | '300' + | '400' + | '500' + | '600' + | '700' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Cormorant_SC(options: { + variant: '300' | '400' | '500' | '600' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Cormorant_Unicase(options: { + variant: '300' | '400' | '500' | '600' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Cormorant_Upright(options: { + variant: '300' | '400' | '500' | '600' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Courgette(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Courier_Prime(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Cousine(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Coustard(options: { + variant: '400' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Covered_By_Your_Grace(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Crafty_Girls(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Creepster(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Crete_Round(options: { + variant: '400' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Crimson_Pro(options?: { + variant?: + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Crimson_Text(options: { + variant: '400' | '600' | '700' | '400-italic' | '600-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Croissant_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Crushed(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Cuprum(options?: { + variant?: + | '400' + | '500' + | '600' + | '700' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Cute_Font(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Cutive(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Cutive_Mono(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function DM_Mono(options: { + variant: '300' | '400' | '500' | '300-italic' | '400-italic' | '500-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function DM_Sans(options: { + variant: '400' | '500' | '700' | '400-italic' | '500-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function DM_Serif_Display(options: { + variant: '400' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function DM_Serif_Text(options: { + variant: '400' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Damion(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Dancing_Script(options?: { + variant?: '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Dangrek(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Darker_Grotesque(options: { + variant: '300' | '400' | '500' | '600' | '700' | '800' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function David_Libre(options: { + variant: '400' | '500' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Dawning_of_a_New_Day(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Days_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Dekko(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Dela_Gothic_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Delius(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Delius_Swash_Caps(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Delius_Unicase(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Della_Respira(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Denk_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Devonshire(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Dhurjati(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Didact_Gothic(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Diplomata(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Diplomata_SC(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Do_Hyeon(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Dokdo(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Domine(options?: { + variant?: '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Donegal_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Dongle(options: { + variant: '300' | '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Doppio_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Dorsa(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Dosis(options?: { + variant?: '200' | '300' | '400' | '500' | '600' | '700' | '800' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function DotGothic16(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Dr_Sugiyama(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Duru_Sans(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function DynaPuff(options?: { + variant?: '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Dynalight(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function EB_Garamond(options?: { + variant?: + | '400' + | '500' + | '600' + | '700' + | '800' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Eagle_Lake(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function East_Sea_Dokdo(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Eater(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Economica(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Eczar(options?: { + variant?: '400' | '500' | '600' | '700' | '800' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Edu_NSW_ACT_Foundation(options?: { + variant?: '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Edu_QLD_Beginner(options?: { + variant?: '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Edu_SA_Beginner(options?: { + variant?: '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Edu_TAS_Beginner(options?: { + variant?: '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Edu_VIC_WA_NT_Beginner(options?: { + variant?: '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function El_Messiri(options?: { + variant?: '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Electrolize(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Elsie(options: { + variant: '400' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Elsie_Swash_Caps(options: { + variant: '400' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Emblema_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Emilys_Candy(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Encode_Sans(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Encode_Sans_Condensed(options: { + variant: '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Encode_Sans_Expanded(options: { + variant: '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Encode_Sans_SC(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Encode_Sans_Semi_Condensed(options: { + variant: '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Encode_Sans_Semi_Expanded(options: { + variant: '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Engagement(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Englebert(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Enriqueta(options: { + variant: '400' | '500' | '600' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Ephesis(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Epilogue(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Erica_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Esteban(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Estonia(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Euphoria_Script(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Ewert(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Exo(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Exo_2(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Expletus_Sans(options?: { + variant?: + | '400' + | '500' + | '600' + | '700' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Explora(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Fahkwang(options: { + variant: + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Familjen_Grotesk(options?: { + variant?: + | '400' + | '500' + | '600' + | '700' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Fanwood_Text(options: { + variant: '400' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Farro(options: { + variant: '300' | '400' | '500' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Farsan(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Fascinate(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Fascinate_Inline(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Faster_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Fasthand(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Fauna_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Faustina(options?: { + variant?: + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Federant(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Federo(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Felipa(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Fenix(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Festive(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Figtree(options?: { + variant?: '300' | '400' | '500' | '600' | '700' | '800' | '900' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Finger_Paint(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Finlandica(options?: { + variant?: + | '400' + | '500' + | '600' + | '700' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Fira_Code(options?: { + variant?: '300' | '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Fira_Mono(options: { + variant: '400' | '500' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Fira_Sans(options: { + variant: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Fira_Sans_Condensed(options: { + variant: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Fira_Sans_Extra_Condensed(options: { + variant: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Fjalla_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Fjord_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Flamenco(options: { + variant: '300' | '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Flavors(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Fleur_De_Leah(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Flow_Block(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Flow_Circular(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Flow_Rounded(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Fondamento(options: { + variant: '400' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Fontdiner_Swanky(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Forum(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Francois_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Frank_Ruhl_Libre(options: { + variant: '300' | '400' | '500' | '700' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Fraunces(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: ('SOFT' | 'WONK' | 'opsz')[] +}): FontModule +export declare function Freckle_Face(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Fredericka_the_Great(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Fredoka(options?: { + variant?: '300' | '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Fredoka_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Freehand(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Fresca(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Frijole(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Fruktur(options: { + variant: '400' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Fugaz_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Fuggles(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Fuzzy_Bubbles(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function GFS_Didot(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function GFS_Neohellenic(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Gabriela(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Gaegu(options: { + variant: '300' | '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Gafata(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Galada(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Galdeano(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Galindo(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Gamja_Flower(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Gantari(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Gayathri(options: { + variant: '100' | '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Gelasio(options: { + variant: + | '400' + | '500' + | '600' + | '700' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Gemunu_Libre(options?: { + variant?: '200' | '300' | '400' | '500' | '600' | '700' | '800' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Genos(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Gentium_Book_Basic(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Gentium_Book_Plus(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Gentium_Plus(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Geo(options: { + variant: '400' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Georama(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Geostar(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Geostar_Fill(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Germania_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Gideon_Roman(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Gidugu(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Gilda_Display(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Girassol(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Give_You_Glory(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Glass_Antiqua(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Glegoo(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Gloria_Hallelujah(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Glory(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Gluten(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'slnt'[] +}): FontModule +export declare function Goblin_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Gochi_Hand(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Goldman(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Gorditas(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Gothic_A1(options: { + variant: '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Gotu(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Goudy_Bookletter_1911(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Gowun_Batang(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Gowun_Dodum(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Graduate(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Grand_Hotel(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Grandstander(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Grape_Nuts(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Gravitas_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Great_Vibes(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Grechen_Fuemen(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Grenze(options: { + variant: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Grenze_Gotisch(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Grey_Qo(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Griffy(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Gruppo(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Gudea(options: { + variant: '400' | '700' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Gugi(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Gulzar(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Gupter(options: { + variant: '400' | '500' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Gurajada(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Gwendolyn(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Habibi(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Hachi_Maru_Pop(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Hahmlet(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Halant(options: { + variant: '300' | '400' | '500' | '600' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Hammersmith_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Hanalei(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Hanalei_Fill(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Handlee(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Hanuman(options: { + variant: '100' | '300' | '400' | '700' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Happy_Monkey(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Harmattan(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Headland_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Heebo(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Henny_Penny(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Hepta_Slab(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Herr_Von_Muellerhoff(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Hi_Melody(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Hina_Mincho(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Hind(options: { + variant: '300' | '400' | '500' | '600' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Hind_Guntur(options: { + variant: '300' | '400' | '500' | '600' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Hind_Madurai(options: { + variant: '300' | '400' | '500' | '600' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Hind_Siliguri(options: { + variant: '300' | '400' | '500' | '600' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Hind_Vadodara(options: { + variant: '300' | '400' | '500' | '600' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Holtwood_One_SC(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Homemade_Apple(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Homenaje(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Hubballi(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Hurricane(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function IBM_Plex_Mono(options: { + variant: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function IBM_Plex_Sans(options: { + variant: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function IBM_Plex_Sans_Arabic(options: { + variant: '100' | '200' | '300' | '400' | '500' | '600' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function IBM_Plex_Sans_Condensed(options: { + variant: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function IBM_Plex_Sans_Devanagari(options: { + variant: '100' | '200' | '300' | '400' | '500' | '600' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function IBM_Plex_Sans_Hebrew(options: { + variant: '100' | '200' | '300' | '400' | '500' | '600' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function IBM_Plex_Sans_KR(options: { + variant: '100' | '200' | '300' | '400' | '500' | '600' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function IBM_Plex_Sans_Thai(options: { + variant: '100' | '200' | '300' | '400' | '500' | '600' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function IBM_Plex_Sans_Thai_Looped(options: { + variant: '100' | '200' | '300' | '400' | '500' | '600' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function IBM_Plex_Serif(options: { + variant: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function IM_Fell_DW_Pica(options: { + variant: '400' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function IM_Fell_DW_Pica_SC(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function IM_Fell_Double_Pica(options: { + variant: '400' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function IM_Fell_Double_Pica_SC(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function IM_Fell_English(options: { + variant: '400' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function IM_Fell_English_SC(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function IM_Fell_French_Canon(options: { + variant: '400' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function IM_Fell_French_Canon_SC(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function IM_Fell_Great_Primer(options: { + variant: '400' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function IM_Fell_Great_Primer_SC(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Ibarra_Real_Nova(options?: { + variant?: + | '400' + | '500' + | '600' + | '700' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Iceberg(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Iceland(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Imbue(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'opsz'[] +}): FontModule +export declare function Imperial_Script(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Imprima(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Inconsolata(options?: { + variant?: + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Inder(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Indie_Flower(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Ingrid_Darling(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Inika(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Inknut_Antiqua(options: { + variant: '300' | '400' | '500' | '600' | '700' | '800' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Inria_Sans(options: { + variant: '300' | '400' | '700' | '300-italic' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Inria_Serif(options: { + variant: '300' | '400' | '700' | '300-italic' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Inspiration(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Inter(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'slnt'[] +}): FontModule +export declare function Irish_Grover(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Island_Moments(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Istok_Web(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Italiana(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Italianno(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Itim(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Jacques_Francois(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Jacques_Francois_Shadow(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Jaldi(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function JetBrains_Mono(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Jim_Nightshade(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Joan(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Jockey_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Jolly_Lodger(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Jomhuria(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Jomolhari(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Josefin_Sans(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Josefin_Slab(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Jost(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Joti_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Jua(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Judson(options: { + variant: '400' | '700' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Julee(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Julius_Sans_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Junge(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Jura(options?: { + variant?: '300' | '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Just_Another_Hand(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Just_Me_Again_Down_Here(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function K2D(options: { + variant: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Kadwa(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Kaisei_Decol(options: { + variant: '400' | '500' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Kaisei_HarunoUmi(options: { + variant: '400' | '500' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Kaisei_Opti(options: { + variant: '400' | '500' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Kaisei_Tokumin(options: { + variant: '400' | '500' | '700' | '800' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Kalam(options: { + variant: '300' | '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Kameron(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Kanit(options: { + variant: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Kantumruy(options: { + variant: '300' | '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Kantumruy_Pro(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Karantina(options: { + variant: '300' | '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Karla(options?: { + variant?: + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Karma(options: { + variant: '300' | '400' | '500' | '600' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Katibeh(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Kaushan_Script(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Kavivanar(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Kavoon(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Kdam_Thmor_Pro(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Keania_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Kelly_Slab(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Kenia(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Khand(options: { + variant: '300' | '400' | '500' | '600' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Khmer(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Khula(options: { + variant: '300' | '400' | '600' | '700' | '800' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Kings(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Kirang_Haerang(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Kite_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Kiwi_Maru(options: { + variant: '300' | '400' | '500' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Klee_One(options: { + variant: '400' | '600' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Knewave(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function KoHo(options: { + variant: + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Kodchasan(options: { + variant: + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Koh_Santepheap(options: { + variant: '100' | '300' | '400' | '700' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Kolker_Brush(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Kosugi(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Kosugi_Maru(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Kotta_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Koulen(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Kranky(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Kreon(options?: { + variant?: '300' | '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Kristi(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Krona_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Krub(options: { + variant: + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Kufam(options?: { + variant?: + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Kulim_Park(options: { + variant: + | '200' + | '300' + | '400' + | '600' + | '700' + | '200-italic' + | '300-italic' + | '400-italic' + | '600-italic' + | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Kumar_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Kumar_One_Outline(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Kumbh_Sans(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Kurale(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function La_Belle_Aurore(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Lacquer(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Laila(options: { + variant: '300' | '400' | '500' | '600' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Lakki_Reddy(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Lalezar(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Lancelot(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Langar(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Lateef(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Lato(options: { + variant: + | '100' + | '300' + | '400' + | '700' + | '900' + | '100-italic' + | '300-italic' + | '400-italic' + | '700-italic' + | '900-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Lavishly_Yours(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function League_Gothic(options?: { + variant?: '400' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function League_Script(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function League_Spartan(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Leckerli_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Ledger(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Lekton(options: { + variant: '400' | '700' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Lemon(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Lemonada(options?: { + variant?: '300' | '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Lexend(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Lexend_Deca(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Lexend_Exa(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Lexend_Giga(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Lexend_Mega(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Lexend_Peta(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Lexend_Tera(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Lexend_Zetta(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Libre_Barcode_128(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Libre_Barcode_128_Text(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Libre_Barcode_39(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Libre_Barcode_39_Extended(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Libre_Barcode_39_Extended_Text(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Libre_Barcode_39_Text(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Libre_Barcode_EAN13_Text(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Libre_Baskerville(options: { + variant: '400' | '700' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Libre_Bodoni(options?: { + variant?: + | '400' + | '500' + | '600' + | '700' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Libre_Caslon_Display(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Libre_Caslon_Text(options: { + variant: '400' | '700' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Libre_Franklin(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Licorice(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Life_Savers(options: { + variant: '400' | '700' | '800' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Lilita_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Lily_Script_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Limelight(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Linden_Hill(options: { + variant: '400' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Literata(options?: { + variant?: + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'opsz'[] +}): FontModule +export declare function Liu_Jian_Mao_Cao(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Livvic(options: { + variant: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '900-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Lobster(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Lobster_Two(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Londrina_Outline(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Londrina_Shadow(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Londrina_Sketch(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Londrina_Solid(options: { + variant: '100' | '300' | '400' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Long_Cang(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Lora(options?: { + variant?: + | '400' + | '500' + | '600' + | '700' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Love_Light(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Love_Ya_Like_A_Sister(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Loved_by_the_King(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Lovers_Quarrel(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Luckiest_Guy(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Lusitana(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Lustria(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Luxurious_Roman(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Luxurious_Script(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function M_PLUS_1(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function M_PLUS_1_Code(options?: { + variant?: '100' | '200' | '300' | '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function M_PLUS_1p(options: { + variant: '100' | '300' | '400' | '500' | '700' | '800' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function M_PLUS_2(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function M_PLUS_Code_Latin(options?: { + variant?: '100' | '200' | '300' | '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function M_PLUS_Rounded_1c(options: { + variant: '100' | '300' | '400' | '500' | '700' | '800' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Ma_Shan_Zheng(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Macondo(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Macondo_Swash_Caps(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Mada(options: { + variant: '200' | '300' | '400' | '500' | '600' | '700' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Magra(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Maiden_Orange(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Maitree(options: { + variant: '200' | '300' | '400' | '500' | '600' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Major_Mono_Display(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Mako(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Mali(options: { + variant: + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Mallanna(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Mandali(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Manjari(options: { + variant: '100' | '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Manrope(options?: { + variant?: '200' | '300' | '400' | '500' | '600' | '700' | '800' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Mansalva(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Manuale(options?: { + variant?: + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Marcellus(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Marcellus_SC(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Marck_Script(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Margarine(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Markazi_Text(options?: { + variant?: '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Marko_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Marmelad(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Martel(options: { + variant: '200' | '300' | '400' | '600' | '700' | '800' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Martel_Sans(options: { + variant: '200' | '300' | '400' | '600' | '700' | '800' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Marvel(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Mate(options: { + variant: '400' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Mate_SC(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Maven_Pro(options?: { + variant?: '400' | '500' | '600' | '700' | '800' | '900' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function McLaren(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Mea_Culpa(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Meddon(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function MedievalSharp(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Medula_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Meera_Inimai(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Megrim(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Meie_Script(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Meow_Script(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Merienda(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Merienda_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Merriweather(options: { + variant: + | '300' + | '400' + | '700' + | '900' + | '300-italic' + | '400-italic' + | '700-italic' + | '900-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Merriweather_Sans(options?: { + variant?: + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Metal(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Metal_Mania(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Metamorphous(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Metrophobic(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Michroma(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Milonga(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Miltonian(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Miltonian_Tattoo(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Mina(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Mingzat(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Miniver(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Miriam_Libre(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Mirza(options: { + variant: '400' | '500' | '600' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Miss_Fajardose(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Mitr(options: { + variant: '200' | '300' | '400' | '500' | '600' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Mochiy_Pop_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Mochiy_Pop_P_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Modak(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Modern_Antiqua(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Mogra(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Mohave(options?: { + variant?: + | '300' + | '400' + | '500' + | '600' + | '700' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Molengo(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Molle(options: { + variant: '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Monda(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Monofett(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Monoton(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Monsieur_La_Doulaise(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Montaga(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Montagu_Slab(options?: { + variant?: '100' | '200' | '300' | '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'opsz'[] +}): FontModule +export declare function MonteCarlo(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Montez(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Montserrat(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Montserrat_Alternates(options: { + variant: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Montserrat_Subrayada(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Moo_Lah_Lah(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Moon_Dance(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Moul(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Moulpali(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Mountains_of_Christmas(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Mouse_Memoirs(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Mr_Bedfort(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Mr_Dafoe(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Mr_De_Haviland(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Mrs_Saint_Delafield(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Mrs_Sheppards(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Ms_Madi(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Mukta(options: { + variant: '200' | '300' | '400' | '500' | '600' | '700' | '800' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Mukta_Mahee(options: { + variant: '200' | '300' | '400' | '500' | '600' | '700' | '800' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Mukta_Malar(options: { + variant: '200' | '300' | '400' | '500' | '600' | '700' | '800' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Mukta_Vaani(options: { + variant: '200' | '300' | '400' | '500' | '600' | '700' | '800' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Mulish(options?: { + variant?: + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Murecho(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function MuseoModerno(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function My_Soul(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Mystery_Quest(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function NTR(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Nabla(options?: { + variant?: '400' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: ('EDPT' | 'EHLT')[] +}): FontModule +export declare function Nanum_Brush_Script(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Nanum_Gothic(options: { + variant: '400' | '700' | '800' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Nanum_Gothic_Coding(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Nanum_Myeongjo(options: { + variant: '400' | '700' | '800' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Nanum_Pen_Script(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Neonderthaw(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Nerko_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Neucha(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Neuton(options: { + variant: '200' | '300' | '400' | '700' | '800' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function New_Rocker(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function New_Tegomin(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function News_Cycle(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Newsreader(options?: { + variant?: + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'opsz'[] +}): FontModule +export declare function Niconne(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Niramit(options: { + variant: + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Nixie_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Nobile(options: { + variant: '400' | '500' | '700' | '400-italic' | '500-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Nokora(options: { + variant: '100' | '300' | '400' | '700' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Norican(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Nosifer(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Notable(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Nothing_You_Could_Do(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noticia_Text(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Color_Emoji(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Emoji(options?: { + variant?: '300' | '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Kufi_Arabic(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Music(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Naskh_Arabic(options?: { + variant?: '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Nastaliq_Urdu(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Rashi_Hebrew(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans(options: { + variant: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Adlam(options?: { + variant?: '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Adlam_Unjoined(options?: { + variant?: '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Anatolian_Hieroglyphs(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Arabic(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Noto_Sans_Armenian(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Noto_Sans_Avestan(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Balinese(options?: { + variant?: '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Bamum(options?: { + variant?: '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Bassa_Vah(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Batak(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Bengali(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Noto_Sans_Bhaiksuki(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Brahmi(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Buginese(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Buhid(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Canadian_Aboriginal(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Carian(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Caucasian_Albanian(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Chakma(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Cham(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Cherokee(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Coptic(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Cuneiform(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Cypriot(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Deseret(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Devanagari(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Noto_Sans_Display(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Noto_Sans_Duployan(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Egyptian_Hieroglyphs(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Elbasan(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Elymaic(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Georgian(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Noto_Sans_Glagolitic(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Gothic(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Grantha(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Gujarati(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Noto_Sans_Gunjala_Gondi(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Gurmukhi(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Noto_Sans_HK(options: { + variant: '100' | '300' | '400' | '500' | '700' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Hanifi_Rohingya(options?: { + variant?: '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Hanunoo(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Hatran(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Hebrew(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Noto_Sans_Imperial_Aramaic(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Indic_Siyaq_Numbers(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Inscriptional_Pahlavi(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Inscriptional_Parthian(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_JP(options: { + variant: '100' | '300' | '400' | '500' | '700' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Javanese(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_KR(options: { + variant: '100' | '300' | '400' | '500' | '700' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Kaithi(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Kannada(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Noto_Sans_Kayah_Li(options?: { + variant?: '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Kharoshthi(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Khmer(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Noto_Sans_Khojki(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Khudawadi(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Lao(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Noto_Sans_Lepcha(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Limbu(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Linear_A(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Linear_B(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Lisu(options?: { + variant?: '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Lycian(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Lydian(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Mahajani(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Malayalam(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Noto_Sans_Mandaic(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Manichaean(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Marchen(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Masaram_Gondi(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Math(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Mayan_Numerals(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Medefaidrin(options?: { + variant?: '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Meetei_Mayek(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Meroitic(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Miao(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Modi(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Mongolian(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Mono(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Noto_Sans_Mro(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Multani(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Myanmar(options: { + variant: '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_N_Ko(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Nabataean(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_New_Tai_Lue(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Newa(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Nushu(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Ogham(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Ol_Chiki(options?: { + variant?: '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Old_Hungarian(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Old_Italic(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Old_North_Arabian(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Old_Permic(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Old_Persian(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Old_Sogdian(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Old_South_Arabian(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Old_Turkic(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Oriya(options: { + variant: '100' | '400' | '700' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Osage(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Osmanya(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Pahawh_Hmong(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Palmyrene(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Pau_Cin_Hau(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Phags_Pa(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Phoenician(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Psalter_Pahlavi(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Rejang(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Runic(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_SC(options: { + variant: '100' | '300' | '400' | '500' | '700' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Samaritan(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Saurashtra(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Sharada(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Shavian(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Siddham(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Sinhala(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Noto_Sans_Sogdian(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Sora_Sompeng(options?: { + variant?: '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Soyombo(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Sundanese(options?: { + variant?: '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Syloti_Nagri(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Symbols(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Symbols_2(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Syriac(options: { + variant: '100' | '400' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_TC(options: { + variant: '100' | '300' | '400' | '500' | '700' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Tagalog(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Tagbanwa(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Tai_Le(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Tai_Tham(options?: { + variant?: '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Tai_Viet(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Takri(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Tamil(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Noto_Sans_Tamil_Supplement(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Telugu(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Noto_Sans_Thaana(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Thai(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Noto_Sans_Thai_Looped(options: { + variant: '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Tifinagh(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Tirhuta(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Ugaritic(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Vai(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Wancho(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Warang_Citi(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Yi(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Sans_Zanabazar_Square(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Serif(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Serif_Ahom(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Serif_Armenian(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Noto_Serif_Balinese(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Serif_Bengali(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Noto_Serif_Devanagari(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Noto_Serif_Display(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Noto_Serif_Dogra(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Serif_Ethiopic(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Noto_Serif_Georgian(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Noto_Serif_Grantha(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Serif_Gujarati(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Serif_Gurmukhi(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Serif_HK(options?: { + variant?: + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Serif_Hebrew(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Noto_Serif_JP(options: { + variant: '200' | '300' | '400' | '500' | '600' | '700' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Serif_KR(options: { + variant: '200' | '300' | '400' | '500' | '600' | '700' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Serif_Kannada(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Serif_Khmer(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Noto_Serif_Lao(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Noto_Serif_Malayalam(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Serif_Myanmar(options: { + variant: '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Serif_Nyiakeng_Puachue_Hmong(options?: { + variant?: '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Serif_SC(options: { + variant: '200' | '300' | '400' | '500' | '600' | '700' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Serif_Sinhala(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Noto_Serif_TC(options: { + variant: '200' | '300' | '400' | '500' | '600' | '700' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Serif_Tamil(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Noto_Serif_Tangut(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Serif_Telugu(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Serif_Thai(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Noto_Serif_Tibetan(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Serif_Yezidi(options?: { + variant?: '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Noto_Traditional_Nushu(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Nova_Cut(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Nova_Flat(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Nova_Mono(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Nova_Oval(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Nova_Round(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Nova_Script(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Nova_Slim(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Nova_Square(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Numans(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Nunito(options?: { + variant?: + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Nunito_Sans(options: { + variant: + | '200' + | '300' + | '400' + | '600' + | '700' + | '800' + | '900' + | '200-italic' + | '300-italic' + | '400-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Nuosu_SIL(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Odibee_Sans(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Odor_Mean_Chey(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Offside(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Oi(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Old_Standard_TT(options: { + variant: '400' | '700' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Oldenburg(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Ole(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Oleo_Script(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Oleo_Script_Swash_Caps(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Oooh_Baby(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Open_Sans(options?: { + variant?: + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Oranienbaum(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Orbitron(options?: { + variant?: '400' | '500' | '600' | '700' | '800' | '900' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Oregano(options: { + variant: '400' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Orelega_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Orienta(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Original_Surfer(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Oswald(options?: { + variant?: '200' | '300' | '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Outfit(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Over_the_Rainbow(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Overlock(options: { + variant: '400' | '700' | '900' | '400-italic' | '700-italic' | '900-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Overlock_SC(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Overpass(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Overpass_Mono(options?: { + variant?: '300' | '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Ovo(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Oxanium(options?: { + variant?: '200' | '300' | '400' | '500' | '600' | '700' | '800' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Oxygen(options: { + variant: '300' | '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Oxygen_Mono(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function PT_Mono(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function PT_Sans(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function PT_Sans_Caption(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function PT_Sans_Narrow(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function PT_Serif(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function PT_Serif_Caption(options: { + variant: '400' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Pacifico(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Padauk(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Palanquin(options: { + variant: '100' | '200' | '300' | '400' | '500' | '600' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Palanquin_Dark(options: { + variant: '400' | '500' | '600' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Pangolin(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Paprika(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Parisienne(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Passero_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Passion_One(options: { + variant: '400' | '700' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Passions_Conflict(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Pathway_Gothic_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Patrick_Hand(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Patrick_Hand_SC(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Pattaya(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Patua_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Pavanam(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Paytone_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Peddana(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Peralta(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Permanent_Marker(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Petemoss(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Petit_Formal_Script(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Petrona(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Philosopher(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Piazzolla(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'opsz'[] +}): FontModule +export declare function Piedra(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Pinyon_Script(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Pirata_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Plaster(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Play(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Playball(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Playfair_Display(options?: { + variant?: + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Playfair_Display_SC(options: { + variant: '400' | '700' | '900' | '400-italic' | '700-italic' | '900-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Plus_Jakarta_Sans(options?: { + variant?: + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Podkova(options?: { + variant?: '400' | '500' | '600' | '700' | '800' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Poiret_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Poller_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Poly(options: { + variant: '400' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Pompiere(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Pontano_Sans(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Poor_Story(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Poppins(options: { + variant: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Port_Lligat_Sans(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Port_Lligat_Slab(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Potta_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Pragati_Narrow(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Praise(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Prata(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Preahvihear(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Press_Start_2P(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Pridi(options: { + variant: '200' | '300' | '400' | '500' | '600' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Princess_Sofia(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Prociono(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Prompt(options: { + variant: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Prosto_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Proza_Libre(options: { + variant: + | '400' + | '500' + | '600' + | '700' + | '800' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Public_Sans(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Puppies_Play(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Puritan(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Purple_Purse(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Qahiri(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Quando(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Quantico(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Quattrocento(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Quattrocento_Sans(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Questrial(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Quicksand(options?: { + variant?: '300' | '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Quintessential(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Qwigley(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Qwitcher_Grypen(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Racing_Sans_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Radio_Canada(options?: { + variant?: + | '300' + | '400' + | '500' + | '600' + | '700' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Radley(options: { + variant: '400' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Rajdhani(options: { + variant: '300' | '400' | '500' | '600' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Rakkas(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Raleway(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Raleway_Dots(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Ramabhadra(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Ramaraja(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Rambla(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Rammetto_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Rampart_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Ranchers(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Rancho(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Ranga(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Rasa(options?: { + variant?: + | '300' + | '400' + | '500' + | '600' + | '700' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Rationale(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Ravi_Prakash(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Readex_Pro(options?: { + variant?: '200' | '300' | '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Recursive(options?: { + variant?: '300' | '400' | '500' | '600' | '700' | '800' | '900' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: ('CASL' | 'CRSV' | 'MONO' | 'slnt')[] +}): FontModule +export declare function Red_Hat_Display(options?: { + variant?: + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Red_Hat_Mono(options?: { + variant?: + | '300' + | '400' + | '500' + | '600' + | '700' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Red_Hat_Text(options?: { + variant?: + | '300' + | '400' + | '500' + | '600' + | '700' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Red_Rose(options?: { + variant?: '300' | '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Redacted(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Redacted_Script(options: { + variant: '300' | '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Redressed(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Reem_Kufi(options?: { + variant?: '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Reem_Kufi_Fun(options?: { + variant?: '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Reem_Kufi_Ink(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Reenie_Beanie(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Reggae_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Revalia(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Rhodium_Libre(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Ribeye(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Ribeye_Marrow(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Righteous(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Risque(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Road_Rage(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Roboto(options: { + variant: + | '100' + | '300' + | '400' + | '500' + | '700' + | '900' + | '100-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '700-italic' + | '900-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Roboto_Condensed(options: { + variant: '300' | '400' | '700' | '300-italic' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Roboto_Flex(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '1000' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: ( + | 'GRAD' + | 'XTRA' + | 'YOPQ' + | 'YTAS' + | 'YTDE' + | 'YTFI' + | 'YTLC' + | 'YTUC' + | 'opsz' + | 'slnt' + | 'wdth' + )[] +}): FontModule +export declare function Roboto_Mono(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Roboto_Serif(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: ('GRAD' | 'opsz' | 'wdth')[] +}): FontModule +export declare function Roboto_Slab(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Rochester(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Rock_Salt(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function RocknRoll_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Rokkitt(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Romanesco(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Ropa_Sans(options: { + variant: '400' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Rosario(options?: { + variant?: + | '300' + | '400' + | '500' + | '600' + | '700' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Rosarivo(options: { + variant: '400' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Rouge_Script(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Rowdies(options: { + variant: '300' | '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Rozha_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Rubik(options?: { + variant?: + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Rubik_Beastly(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Rubik_Bubbles(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Rubik_Burned(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Rubik_Dirt(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Rubik_Distressed(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Rubik_Glitch(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Rubik_Iso(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Rubik_Marker_Hatch(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Rubik_Maze(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Rubik_Microbe(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Rubik_Mono_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Rubik_Moonrocks(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Rubik_Puddles(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Rubik_Wet_Paint(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Ruda(options?: { + variant?: '400' | '500' | '600' | '700' | '800' | '900' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Rufina(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Ruge_Boogie(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Ruluko(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Rum_Raisin(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Ruslan_Display(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Russo_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Ruthie(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Rye(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function STIX_Two_Text(options?: { + variant?: + | '400' + | '500' + | '600' + | '700' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Sacramento(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Sahitya(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Sail(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Saira(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Saira_Condensed(options: { + variant: '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Saira_Extra_Condensed(options: { + variant: '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Saira_Semi_Condensed(options: { + variant: '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Saira_Stencil_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Salsa(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Sanchez(options: { + variant: '400' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Sancreek(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Sansita(options: { + variant: + | '400' + | '700' + | '800' + | '900' + | '400-italic' + | '700-italic' + | '800-italic' + | '900-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Sansita_Swashed(options?: { + variant?: '300' | '400' | '500' | '600' | '700' | '800' | '900' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Sarabun(options: { + variant: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Sarala(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Sarina(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Sarpanch(options: { + variant: '400' | '500' | '600' | '700' | '800' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Sassy_Frass(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Satisfy(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Sawarabi_Gothic(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Sawarabi_Mincho(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Scada(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Scheherazade_New(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Schoolbell(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Scope_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Seaweed_Script(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Secular_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Sedgwick_Ave(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Sedgwick_Ave_Display(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Sen(options: { + variant: '400' | '700' | '800' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Send_Flowers(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Sevillana(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Seymour_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Shadows_Into_Light(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Shadows_Into_Light_Two(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Shalimar(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Shanti(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Share(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Share_Tech(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Share_Tech_Mono(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Shippori_Antique(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Shippori_Antique_B1(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Shippori_Mincho(options: { + variant: '400' | '500' | '600' | '700' | '800' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Shippori_Mincho_B1(options: { + variant: '400' | '500' | '600' | '700' | '800' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Shojumaru(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Short_Stack(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Shrikhand(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Siemreap(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Sigmar_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Signika(options?: { + variant?: '300' | '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Signika_Negative(options?: { + variant?: '300' | '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Silkscreen(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Simonetta(options: { + variant: '400' | '900' | '400-italic' | '900-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Single_Day(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Sintony(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Sirin_Stencil(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Six_Caps(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Skranji(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Slabo_13px(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Slabo_27px(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Slackey(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Smokum(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Smooch(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Smooch_Sans(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Smythe(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Sniglet(options: { + variant: '400' | '800' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Snippet(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Snowburst_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Sofadi_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Sofia(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Solway(options: { + variant: '300' | '400' | '500' | '700' | '800' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Song_Myung(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Sonsie_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Sora(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Sorts_Mill_Goudy(options: { + variant: '400' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Source_Code_Pro(options?: { + variant?: + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Source_Sans_3(options?: { + variant?: + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Source_Sans_Pro(options: { + variant: + | '200' + | '300' + | '400' + | '600' + | '700' + | '900' + | '200-italic' + | '300-italic' + | '400-italic' + | '600-italic' + | '700-italic' + | '900-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Source_Serif_4(options?: { + variant?: + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'opsz'[] +}): FontModule +export declare function Source_Serif_Pro(options: { + variant: + | '200' + | '300' + | '400' + | '600' + | '700' + | '900' + | '200-italic' + | '300-italic' + | '400-italic' + | '600-italic' + | '700-italic' + | '900-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Space_Grotesk(options?: { + variant?: '300' | '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Space_Mono(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Special_Elite(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Spectral(options: { + variant: + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Spectral_SC(options: { + variant: + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Spicy_Rice(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Spinnaker(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Spirax(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Splash(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Spline_Sans(options?: { + variant?: '300' | '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Spline_Sans_Mono(options?: { + variant?: + | '300' + | '400' + | '500' + | '600' + | '700' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Squada_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Square_Peg(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Sree_Krushnadevaraya(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Sriracha(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Srisakdi(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Staatliches(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Stalemate(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Stalinist_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Stardos_Stencil(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Stick(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Stick_No_Bills(options?: { + variant?: '200' | '300' | '400' | '500' | '600' | '700' | '800' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Stint_Ultra_Condensed(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Stint_Ultra_Expanded(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Stoke(options: { + variant: '300' | '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Strait(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Style_Script(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Stylish(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Sue_Ellen_Francisco(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Suez_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Sulphur_Point(options: { + variant: '300' | '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Sumana(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Sunflower(options: { + variant: '300' | '500' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Sunshiney(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Supermercado_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Sura(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Suranna(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Suravaram(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Suwannaphum(options: { + variant: '100' | '300' | '400' | '700' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Swanky_and_Moo_Moo(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Syncopate(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Syne(options?: { + variant?: '400' | '500' | '600' | '700' | '800' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Syne_Mono(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Syne_Tactile(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Tai_Heritage_Pro(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Tajawal(options: { + variant: '200' | '300' | '400' | '500' | '700' | '800' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Tangerine(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Tapestry(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Taprom(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Tauri(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Taviraj(options: { + variant: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Teko(options: { + variant: '300' | '400' | '500' | '600' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Telex(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Tenali_Ramakrishna(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Tenor_Sans(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Text_Me_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Texturina(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'opsz'[] +}): FontModule +export declare function Thasadith(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function The_Girl_Next_Door(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function The_Nautigal(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Tienne(options: { + variant: '400' | '700' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Tillana(options: { + variant: '400' | '500' | '600' | '700' | '800' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Timmana(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Tinos(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Tiro_Bangla(options: { + variant: '400' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Tiro_Devanagari_Hindi(options: { + variant: '400' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Tiro_Devanagari_Marathi(options: { + variant: '400' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Tiro_Devanagari_Sanskrit(options: { + variant: '400' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Tiro_Gurmukhi(options: { + variant: '400' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Tiro_Kannada(options: { + variant: '400' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Tiro_Tamil(options: { + variant: '400' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Tiro_Telugu(options: { + variant: '400' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Titan_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Titillium_Web(options: { + variant: + | '200' + | '300' + | '400' + | '600' + | '700' + | '900' + | '200-italic' + | '300-italic' + | '400-italic' + | '600-italic' + | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Tomorrow(options: { + variant: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Tourney(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Trade_Winds(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Train_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Trirong(options: { + variant: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Trispace(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: 'wdth'[] +}): FontModule +export declare function Trocchi(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Trochut(options: { + variant: '400' | '700' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Truculenta(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + axes?: ('opsz' | 'wdth')[] +}): FontModule +export declare function Trykker(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Tulpen_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Turret_Road(options: { + variant: '200' | '300' | '400' | '500' | '700' | '800' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Twinkle_Star(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Ubuntu(options: { + variant: + | '300' + | '400' + | '500' + | '700' + | '300-italic' + | '400-italic' + | '500-italic' + | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Ubuntu_Condensed(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Ubuntu_Mono(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Uchen(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Ultra(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Uncial_Antiqua(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Underdog(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Unica_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function UnifrakturCook(options: { + variant: '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function UnifrakturMaguntia(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Unkempt(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Unlock(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Unna(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Updock(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Urbanist(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function VT323(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Vampiro_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Varela(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Varela_Round(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Varta(options?: { + variant?: '300' | '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Vast_Shadow(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Vazirmatn(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Vesper_Libre(options: { + variant: '400' | '500' | '700' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Viaoda_Libre(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Vibes(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Vibur(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Vidaloka(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Viga(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Voces(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Volkhov(options: { + variant: '400' | '700' | '400-italic' | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Vollkorn(options?: { + variant?: + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Vollkorn_SC(options: { + variant: '400' | '600' | '700' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Voltaire(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Vujahday_Script(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Waiting_for_the_Sunrise(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Wallpoet(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Walter_Turncoat(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Warnes(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Water_Brush(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Waterfall(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Wellfleet(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Wendy_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Whisper(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function WindSong(options: { + variant: '400' | '500' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Wire_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Work_Sans(options?: { + variant?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | '100-italic' + | '200-italic' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | '800-italic' + | '900-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Xanh_Mono(options: { + variant: '400' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Yaldevi(options?: { + variant?: '200' | '300' | '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Yanone_Kaffeesatz(options?: { + variant?: '200' | '300' | '400' | '500' | '600' | '700' | 'variable' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Yantramanav(options: { + variant: '100' | '300' | '400' | '500' | '700' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Yatra_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Yellowtail(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Yeon_Sung(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Yeseva_One(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Yesteryear(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Yomogi(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Yrsa(options?: { + variant?: + | '300' + | '400' + | '500' + | '600' + | '700' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + | 'variable' + | 'variable-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Yuji_Boku(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Yuji_Mai(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Yuji_Syuku(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Yusei_Magic(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function ZCOOL_KuaiLe(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function ZCOOL_QingKe_HuangYou(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function ZCOOL_XiaoWei(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Zen_Antique(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Zen_Antique_Soft(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Zen_Dots(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Zen_Kaku_Gothic_Antique(options: { + variant: '300' | '400' | '500' | '700' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Zen_Kaku_Gothic_New(options: { + variant: '300' | '400' | '500' | '700' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Zen_Kurenaido(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Zen_Loop(options: { + variant: '400' | '400-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Zen_Maru_Gothic(options: { + variant: '300' | '400' | '500' | '700' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Zen_Old_Mincho(options: { + variant: '400' | '700' | '900' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Zen_Tokyo_Zoo(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Zeyada(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Zhi_Mang_Xing(options: { + variant: '400' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Zilla_Slab(options: { + variant: + | '300' + | '400' + | '500' + | '600' + | '700' + | '300-italic' + | '400-italic' + | '500-italic' + | '600-italic' + | '700-italic' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule +export declare function Zilla_Slab_Highlight(options: { + variant: '400' | '700' + display?: Display + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean +}): FontModule diff --git a/packages/font/src/google/loader.ts b/packages/font/src/google/loader.ts new file mode 100644 index 0000000000000..1985e6111d551 --- /dev/null +++ b/packages/font/src/google/loader.ts @@ -0,0 +1,121 @@ +// @ts-ignore +import fetch from 'next/dist/compiled/node-fetch' +// @ts-ignore +import { calculateOverrideCSS } from 'next/dist/server/font-utils' +import { + fetchCSSFromGoogleFonts, + getFontAxes, + getUrl, + validateData, +} from './utils' + +type FontLoaderOptions = { + functionName: string + data: any[] + config: any + emitFontFile: (content: Buffer, ext: string, preload: boolean) => string +} + +export default async function downloadGoogleFonts({ + functionName, + data, + config, + emitFontFile, +}: FontLoaderOptions) { + if (!config?.subsets) { + throw new Error( + 'Please specify subsets for `@next/font/google` in your `next.config.js`' + ) + } + + const { + fontFamily, + weight, + style, + display, + preload, + selectedVariableAxes, + fallback, + adjustFontFallback, + } = validateData(functionName, data) + const fontAxes = getFontAxes(fontFamily, weight, style, selectedVariableAxes) + const url = getUrl(fontFamily, fontAxes, display) + + const fontFaceDeclarations = await fetchCSSFromGoogleFonts(url, fontFamily) + + // Find font files to download + const fontFiles: Array<{ + googleFontFileUrl: string + preloadFontFile: boolean + }> = [] + let currentSubset = '' + for (const line of fontFaceDeclarations.split('\n')) { + // Each @font-face has the subset above it in a comment + const newSubset = /\/\* (.+?) \*\//.exec(line)?.[1] + if (newSubset) { + currentSubset = newSubset + } else { + const googleFontFileUrl = /src: url\((.+?)\)/.exec(line)?.[1] + if (googleFontFileUrl) { + fontFiles.push({ + googleFontFileUrl, + preloadFontFile: !!preload && config.subsets.includes(currentSubset), + }) + } + } + } + + // Download font files + const downloadedFiles = await Promise.all( + fontFiles.map(async ({ googleFontFileUrl, preloadFontFile }) => { + let fontFileBuffer: Buffer + if (process.env.NEXT_FONT_GOOGLE_MOCKED_RESPONSES) { + fontFileBuffer = Buffer.from(googleFontFileUrl) + } else { + const arrayBuffer = await fetch(googleFontFileUrl).then((r: any) => + r.arrayBuffer() + ) + fontFileBuffer = Buffer.from(arrayBuffer) + } + + const ext = /\.(woff|woff2|eot|ttf|otf)$/.exec(googleFontFileUrl)![1] + // Emit font file to .next/static/fonts + 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( + googleFontFileUrl, + selfHostedFileUrl + ) + } + + // Add fallback font + if (adjustFontFallback) { + try { + updatedCssResponse += calculateOverrideCSS( + fontFamily, + require('next/dist/server/google-font-metrics.json') + ) + } catch (e) { + console.log('Error getting font override values - ', e) + } + } + + return { + css: updatedCssResponse, + fallbackFonts: fallback, + } +} diff --git a/packages/font/src/google/utils.ts b/packages/font/src/google/utils.ts new file mode 100644 index 0000000000000..af525a7a493b0 --- /dev/null +++ b/packages/font/src/google/utils.ts @@ -0,0 +1,189 @@ +// @ts-ignore +import fetch from 'next/dist/compiled/node-fetch' +import fontData from './font-data.json' +const allowedDisplayValues = ['auto', 'block', 'swap', 'fallback', 'optional'] + +const formatValues = (values: string[]) => + values.map((val) => `\`${val}\``).join(', ') + +type FontOptions = { + fontFamily: string + weight: string + style: string + display: string + preload: boolean + selectedVariableAxes?: string[] + fallback?: string[] + adjustFontFallback: boolean +} +export function validateData(functionName: string, data: any): FontOptions { + let { + variant, + display = 'optional', + preload = true, + axes, + fallback, + adjustFontFallback = true, + } = data[0] || ({} as any) + if (functionName === '') { + throw new Error(`@next/font/google has no default export`) + } + + const fontFamily = functionName.replace(/_/g, ' ') + + const fontVariants = (fontData as any)[fontFamily]?.variants + if (!fontVariants) { + throw new Error(`Unknown font \`${fontFamily}\``) + } + + // Set variable as default, throw if not available + if (!variant) { + if (fontVariants.includes('variable')) { + variant = 'variable' + } else { + throw new Error( + `Missing variant for font \`${fontFamily}\`.\nAvailable variants: ${formatValues( + fontVariants + )}` + ) + } + } + + if (!fontVariants.includes(variant)) { + throw new Error( + `Unknown variant \`${variant}\` for font \`${fontFamily}\`.\nAvailable variants: ${formatValues( + fontVariants + )}` + ) + } + + if (!allowedDisplayValues.includes(display)) { + throw new Error( + `Invalid display value \`${display}\` for font \`${fontFamily}\`.\nAvailable display values: ${formatValues( + allowedDisplayValues + )}` + ) + } + + const [weight, style] = variant.split('-') + + if (weight !== 'variable' && axes) { + throw new Error('Axes can only be defined for variable fonts') + } + + return { + fontFamily, + weight, + style, + display, + preload, + selectedVariableAxes: axes, + fallback, + adjustFontFallback, + } +} + +export function getUrl( + fontFamily: string, + axes: [string, string][], + display: string +) { + // Google api requires the axes to be sorted, starting with lowercase words + axes.sort(([a], [b]) => { + const aIsLowercase = a.charCodeAt(0) > 96 + const bIsLowercase = b.charCodeAt(0) > 96 + if (aIsLowercase && !bIsLowercase) return -1 + if (bIsLowercase && !aIsLowercase) return 1 + + return a > b ? 1 : -1 + }) + + return `https://fonts.googleapis.com/css2?family=${fontFamily.replace( + / /g, + '+' + )}:${axes.map(([key]) => key).join(',')}@${axes + .map(([, val]) => val) + .join(',')}&display=${display}` +} + +export async function fetchCSSFromGoogleFonts(url: string, fontFamily: string) { + let mockedResponse: string | undefined + if (process.env.NEXT_FONT_GOOGLE_MOCKED_RESPONSES) { + const mockFile = require(process.env.NEXT_FONT_GOOGLE_MOCKED_RESPONSES) + mockedResponse = mockFile[url] + if (!mockedResponse) { + throw new Error('Missing mocked response for URL: ' + url) + } + } + + let cssResponse + if (mockedResponse) { + cssResponse = mockedResponse + } else { + const res = await fetch(url, { + headers: { + // The file format is based off of the user agent, make sure woff2 files are fetched + 'user-agent': + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36', + }, + }) + + if (!res.ok) { + throw new Error(`Failed to fetch font \`${fontFamily}\`.\nURL: ${url}`) + } + + cssResponse = await res.text() + } + + return cssResponse +} + +export function getFontAxes( + fontFamily: string, + weight: string, + style: string, + selectedVariableAxes?: string[] +): [string, string][] { + const allAxes: Array<{ tag: string; min: number; max: number }> = ( + fontData as any + )[fontFamily].axes + const italicAxis: [string, string][] = + style === 'italic' ? [['ital', '1']] : [] + + if (weight === 'variable') { + if (selectedVariableAxes) { + const defineAbleAxes: string[] = allAxes + .map(({ tag }) => tag) + .filter((tag) => tag !== 'wght') + if (defineAbleAxes.length === 0) { + throw new Error(`Font \`${fontFamily}\` has no definable \`axes\``) + } + if (!Array.isArray(selectedVariableAxes)) { + throw new Error( + `Invalid axes value for font \`${fontFamily}\`, expected an array of axes.\nAvailable axes: ${formatValues( + defineAbleAxes + )}` + ) + } + selectedVariableAxes.forEach((key) => { + if (!defineAbleAxes.some((tag) => tag === key)) { + throw new Error( + `Invalid axes value \`${key}\` for font \`${fontFamily}\`.\nAvailable axes: ${formatValues( + defineAbleAxes + )}` + ) + } + }) + } + + const variableAxes: [string, string][] = allAxes + .filter( + ({ tag }) => tag === 'wght' || selectedVariableAxes?.includes(tag) + ) + .map(({ tag, min, max }) => [tag, `${min}..${max}`]) + + return [...italicAxis, ...variableAxes] + } else { + return [...italicAxis, ['wght', weight]] + } +} diff --git a/packages/font/tsconfig.json b/packages/font/tsconfig.json new file mode 100644 index 0000000000000..7834550630a18 --- /dev/null +++ b/packages/font/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "strict": true, + "resolveJsonModule": true, + "module": "commonjs", + "esModuleInterop": true, + "target": "es2019", + "outDir": "dist", + "rootDir": "src" + }, + "include": ["src/**/*.ts"], + "exclude": ["node_modules"] +} diff --git a/packages/next/server/font-utils.ts b/packages/next/server/font-utils.ts index c505bbbb55028..557d47b17612a 100644 --- a/packages/next/server/font-utils.ts +++ b/packages/next/server/font-utils.ts @@ -98,7 +98,7 @@ function parseGoogleFontName(css: string): Array { return [...fontNames] } -function calculateOverrideCSS(font: string, fontMetrics: any) { +export function calculateOverrideCSS(font: string, fontMetrics: any) { const fontName = font.toLowerCase().trim().replace(/ /g, '-') const fontKey = font.toLowerCase().trim().replace(/ /g, '') const { category, ascentOverride, descentOverride, lineGapOverride } = diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index aee0111858f5a..a1a6a25b2847a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -24,6 +24,7 @@ importers: '@next/bundle-analyzer': workspace:* '@next/env': workspace:* '@next/eslint-plugin-next': workspace:* + '@next/font': workspace:* '@next/mdx': workspace:* '@next/plugin-storybook': workspace:* '@next/polyfill-module': workspace:* @@ -180,6 +181,7 @@ importers: '@next/bundle-analyzer': link:packages/next-bundle-analyzer '@next/env': link:packages/next-env '@next/eslint-plugin-next': link:packages/eslint-plugin-next + '@next/font': link:packages/font '@next/mdx': link:packages/next-mdx '@next/plugin-storybook': link:packages/next-plugin-storybook '@next/polyfill-module': link:packages/next-polyfill-module @@ -561,8 +563,8 @@ importers: source-map: 0.6.1 stream-browserify: 3.0.0 stream-http: 3.1.1 - string_decoder: 1.3.0 string-hash: 1.1.3 + string_decoder: 1.3.0 strip-ansi: 6.0.0 styled-jsx: 5.0.7 tar: 6.1.11 @@ -750,8 +752,8 @@ importers: source-map: 0.6.1 stream-browserify: 3.0.0 stream-http: 3.1.1 - string_decoder: 1.3.0 string-hash: 1.1.3 + string_decoder: 1.3.0 strip-ansi: 6.0.0 tar: 6.1.11 taskr: 1.1.0 @@ -11224,8 +11226,8 @@ packages: engines: { node: '>=10' } hasBin: true dependencies: - is-text-path: 1.0.1 JSONStream: 1.3.5 + is-text-path: 1.0.1 lodash: 4.17.21 meow: 8.1.2 split2: 2.2.0 diff --git a/scripts/update-google-fonts.js b/scripts/update-google-fonts.js new file mode 100644 index 0000000000000..c8d808dc8b768 --- /dev/null +++ b/scripts/update-google-fonts.js @@ -0,0 +1,74 @@ +const fs = require('fs/promises') +const path = require('path') +const fetch = require('node-fetch') + +;(async () => { + const { familyMetadataList } = await fetch( + 'https://fonts.google.com/metadata/fonts' + ).then((r) => r.json()) + + let fontFunctions = `type Display = 'auto'|'block'|'swap'|'fallback'|'optional' +type FontModule = { className: string, variable: string, style: { fontFamily: string, fontWeight?: number, fontStyle?: string } } + ` + const fontData = {} + for (let { family, fonts, axes } of familyMetadataList) { + let hasItalic = false + const variants = Object.keys(fonts).map((variant) => { + if (variant.endsWith('i')) { + hasItalic = true + return `${variant.slice(0, 3)}-italic` + } + return variant + }) + + const hasVariableFont = axes.length > 0 + + let optionalAxes + if (hasVariableFont) { + variants.push('variable') + if (hasItalic) { + variants.push('variable-italic') + } + + const nonWeightAxes = axes.filter(({ tag }) => tag !== 'wght') + if (nonWeightAxes.length > 0) { + optionalAxes = nonWeightAxes + } + } + + fontData[family] = { + variants, + axes: hasVariableFont ? axes : undefined, + } + const optionalIfVariableFont = hasVariableFont ? '?' : '' + fontFunctions += `export declare function ${family.replaceAll( + ' ', + '_' + )}(options${optionalIfVariableFont}: { + variant${optionalIfVariableFont}:${variants + .map((variant) => `"${variant}"`) + .join('|')} + display?:Display, + preload?:boolean, + fallback?: string[] + adjustFontFallback?: boolean + ${ + optionalAxes + ? `axes?:(${optionalAxes.map(({ tag }) => `'${tag}'`).join('|')})[]` + : '' + } + }):FontModule + ` + } + + await Promise.all([ + fs.writeFile( + path.join(__dirname, '../packages/font/src/google/index.ts'), + fontFunctions + ), + fs.writeFile( + path.join(__dirname, '../packages/font/src/google/font-data.json'), + JSON.stringify(fontData, null, 2) + ), + ]) +})() diff --git a/test/unit/google-font-loader.test.ts b/test/unit/google-font-loader.test.ts new file mode 100644 index 0000000000000..8c73f84a49d25 --- /dev/null +++ b/test/unit/google-font-loader.test.ts @@ -0,0 +1,334 @@ +import loader from '@next/font/google/loader' +import fetch from 'next/dist/compiled/node-fetch' + +jest.mock('next/dist/compiled/node-fetch') + +describe('@next/font/google loader', () => { + afterEach(() => { + jest.resetAllMocks() + }) + + describe('URL from options', () => { + test.each([ + [ + 'Inter', + {}, + 'https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=optional', + ], + [ + 'Inter', + { variant: '400' }, + 'https://fonts.googleapis.com/css2?family=Inter:wght@400&display=optional', + ], + [ + 'Inter', + { variant: '900', display: 'block' }, + 'https://fonts.googleapis.com/css2?family=Inter:wght@900&display=block', + ], + [ + 'Source_Sans_Pro', + { variant: '900', display: 'auto' }, + 'https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@900&display=auto', + ], + [ + 'Source_Sans_Pro', + { variant: '200-italic' }, + 'https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@1,200&display=optional', + ], + [ + 'Roboto_Flex', + { display: 'swap' }, + 'https://fonts.googleapis.com/css2?family=Roboto+Flex:wght@100..1000&display=swap', + ], + [ + 'Roboto_Flex', + { display: 'fallback', variant: 'variable', axes: ['opsz'] }, + 'https://fonts.googleapis.com/css2?family=Roboto+Flex:opsz,wght@8..144,100..1000&display=fallback', + ], + [ + 'Roboto_Flex', + { + display: 'optional', + axes: ['YTUC', 'slnt', 'wdth', 'opsz', 'XTRA', 'YTAS'], + }, + 'https://fonts.googleapis.com/css2?family=Roboto+Flex:opsz,slnt,wdth,wght,XTRA,YTAS,YTUC@8..144,-10..0,25..151,100..1000,323..603,649..854,528..760&display=optional', + ], + [ + 'Oooh_Baby', + { variant: '400' }, + 'https://fonts.googleapis.com/css2?family=Oooh+Baby:wght@400&display=optional', + ], + [ + 'Albert_Sans', + { variant: 'variable-italic' }, + 'https://fonts.googleapis.com/css2?family=Albert+Sans:ital,wght@1,100..900&display=optional', + ], + [ + 'Fraunces', + { variant: 'variable-italic', axes: ['WONK', 'opsz', 'SOFT'] }, + 'https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght,SOFT,WONK@1,9..144,100..900,0..100,0..1&display=optional', + ], + ])('%s', async (functionName: string, data: any, url: string) => { + fetch.mockResolvedValue({ + ok: true, + text: async () => 'OK', + }) + const { css } = await loader({ + functionName, + data: [{ adjustFontFallback: false, ...data }], + config: { subsets: [] }, + emitFontFile: jest.fn(), + }) + expect(css).toBe('OK') + expect(fetch).toHaveBeenCalledTimes(1) + expect(fetch).toHaveBeenCalledWith(url, expect.any(Object)) + }) + }) + + describe('Fallback fonts', () => { + test('Inter', async () => { + fetch.mockResolvedValue({ + ok: true, + text: async () => '', + }) + const { css, fallbackFonts } = await loader({ + functionName: 'Inter', + data: [], + config: { subsets: [] }, + emitFontFile: jest.fn(), + }) + expect(css).toMatchInlineSnapshot(` +" + @font-face { + font-family: \\"inter-fallback\\"; + ascent-override: 96.88%; + descent-override: 24.15%; + line-gap-override: 0.00%; + src: local(\\"Arial\\"); + } + " +`) + expect(fallbackFonts).toBeUndefined() + }) + + test('Source Code Pro', async () => { + fetch.mockResolvedValue({ + ok: true, + text: async () => '', + }) + const { css, fallbackFonts } = await loader({ + functionName: 'Source_Code_Pro', + data: [], + config: { subsets: [] }, + emitFontFile: jest.fn(), + }) + expect(css).toMatchInlineSnapshot(` +" + @font-face { + font-family: \\"source-code-pro-fallback\\"; + ascent-override: 98.40%; + descent-override: 27.30%; + line-gap-override: 0.00%; + src: local(\\"Arial\\"); + } + " +`) + expect(fallbackFonts).toBeUndefined() + }) + + test('Fraunces', async () => { + fetch.mockResolvedValue({ + ok: true, + text: async () => '', + }) + const { css, fallbackFonts } = await loader({ + functionName: 'Fraunces', + data: [{ fallback: ['Abc', 'Def'] }], + config: { subsets: [] }, + emitFontFile: jest.fn(), + }) + expect(css).toMatchInlineSnapshot(` +" + @font-face { + font-family: \\"fraunces-fallback\\"; + ascent-override: 97.80%; + descent-override: 25.50%; + line-gap-override: 0.00%; + src: local(\\"Times New Roman\\"); + } + " +`) + expect(fallbackFonts).toEqual(['Abc', 'Def']) + }) + + test('adjustFontFallback disabled', async () => { + fetch.mockResolvedValue({ + ok: true, + text: async () => '', + }) + const { css, fallbackFonts } = await loader({ + functionName: 'Inter', + data: [{ adjustFontFallback: false, fallback: ['system-ui', 'Arial'] }], + config: { subsets: [] }, + emitFontFile: jest.fn(), + }) + expect(css).toBe('') + expect(fallbackFonts).toEqual(['system-ui', 'Arial']) + }) + }) + + describe('Errors', () => { + test('Failed to fetch', async () => { + fetch.mockResolvedValue({ + ok: false, + }) + + await expect( + loader({ + functionName: 'Inter', + data: [], + config: { subsets: [] }, + emitFontFile: jest.fn(), + }) + ).rejects.toThrowErrorMatchingInlineSnapshot(` + "Failed to fetch font \`Inter\`. + URL: https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=optional" + `) + }) + + test('Missing config with subsets', async () => { + await expect( + loader({ + functionName: 'Inter', + data: [], + config: undefined, + emitFontFile: jest.fn(), + }) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Please specify subsets for \`@next/font/google\` in your \`next.config.js\`"` + ) + }) + + test('Missing function name', async () => { + await expect( + loader({ + functionName: '', // default import + data: [], + config: { subsets: [] }, + emitFontFile: jest.fn(), + }) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"@next/font/google has no default export"` + ) + }) + + test('Unknown font', async () => { + await expect( + loader({ + functionName: 'Unknown_Font', + data: [], + config: { subsets: [] }, + emitFontFile: jest.fn(), + }) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Unknown font \`Unknown Font\`"` + ) + }) + + test('Unknown variant', async () => { + await expect( + loader({ + functionName: 'Inter', + data: [{ variant: '123' }], + config: { subsets: [] }, + emitFontFile: jest.fn(), + }) + ).rejects.toThrowErrorMatchingInlineSnapshot(` + "Unknown variant \`123\` for font \`Inter\`. + Available variants: \`100\`, \`200\`, \`300\`, \`400\`, \`500\`, \`600\`, \`700\`, \`800\`, \`900\`, \`variable\`" + `) + }) + + test('Missing variant for non variable font', async () => { + await expect( + loader({ + functionName: 'Abel', + data: [], + config: { subsets: [] }, + emitFontFile: jest.fn(), + }) + ).rejects.toThrowErrorMatchingInlineSnapshot(` + "Missing variant for font \`Abel\`. + Available variants: \`400\`" + `) + }) + + test('Invalid display value', async () => { + await expect( + loader({ + functionName: 'Inter', + data: [{ display: 'invalid' }], + config: { subsets: [] }, + emitFontFile: jest.fn(), + }) + ).rejects.toThrowErrorMatchingInlineSnapshot(` + "Invalid display value \`invalid\` for font \`Inter\`. + Available display values: \`auto\`, \`block\`, \`swap\`, \`fallback\`, \`optional\`" + `) + }) + + test('Setting axes on non variable font', async () => { + await expect( + loader({ + functionName: 'Abel', + data: [{ variant: '400', axes: [] }], + config: { subsets: [] }, + emitFontFile: jest.fn(), + }) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Axes can only be defined for variable fonts"` + ) + }) + + test('Setting axes on font without definable axes', async () => { + await expect( + loader({ + functionName: 'Lora', + data: [{ axes: [] }], + config: { subsets: [] }, + emitFontFile: jest.fn(), + }) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Font \`Lora\` has no definable \`axes\`"` + ) + }) + + test('Invalid axes value', async () => { + await expect( + loader({ + functionName: 'Inter', + data: [{ axes: true }], + config: { subsets: [] }, + emitFontFile: jest.fn(), + }) + ).rejects.toThrowErrorMatchingInlineSnapshot(` + "Invalid axes value for font \`Inter\`, expected an array of axes. + Available axes: \`slnt\`" + `) + }) + + test('Invalid value in axes array', async () => { + await expect( + loader({ + functionName: 'Roboto_Flex', + data: [{ axes: ['INVALID'] }], + config: { subsets: [] }, + emitFontFile: jest.fn(), + }) + ).rejects.toThrowErrorMatchingInlineSnapshot(` + "Invalid axes value \`INVALID\` for font \`Roboto Flex\`. + Available axes: \`GRAD\`, \`XTRA\`, \`YOPQ\`, \`YTAS\`, \`YTDE\`, \`YTFI\`, \`YTLC\`, \`YTUC\`, \`opsz\`, \`slnt\`, \`wdth\`" + `) + }) + }) +}) From 4607140a7f1922190a0be8b3017e4fd8c39f69ed Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Wed, 21 Sep 2022 15:20:12 -0700 Subject: [PATCH 12/76] v12.3.2-canary.1 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-config-next/package.json | 4 ++-- packages/eslint-plugin-next/package.json | 2 +- packages/font/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next-swc/package.json | 2 +- packages/next/package.json | 14 ++++++------ packages/react-dev-overlay/package.json | 2 +- packages/react-refresh-utils/package.json | 2 +- pnpm-lock.yaml | 23 +++++++++++--------- 17 files changed, 36 insertions(+), 33 deletions(-) diff --git a/lerna.json b/lerna.json index 258e54c72d1ac..e85ed9347ba07 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "12.3.2-canary.0" + "version": "12.3.2-canary.1" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index a7ab39f0a1820..a4ce59156450f 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "12.3.2-canary.0", + "version": "12.3.2-canary.1", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index 532fc3a72ca14..dbeb3f58ff241 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "12.3.2-canary.0", + "version": "12.3.2-canary.1", "description": "ESLint configuration used by NextJS.", "main": "index.js", "license": "MIT", @@ -9,7 +9,7 @@ "directory": "packages/eslint-config-next" }, "dependencies": { - "@next/eslint-plugin-next": "12.3.2-canary.0", + "@next/eslint-plugin-next": "12.3.2-canary.1", "@rushstack/eslint-patch": "^1.1.3", "@typescript-eslint/parser": "^5.21.0", "eslint-import-resolver-node": "^0.3.6", diff --git a/packages/eslint-plugin-next/package.json b/packages/eslint-plugin-next/package.json index 801d903f99073..82de495885b86 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "12.3.2-canary.0", + "version": "12.3.2-canary.1", "description": "ESLint plugin for NextJS.", "main": "lib/index.js", "license": "MIT", diff --git a/packages/font/package.json b/packages/font/package.json index b09bd11bd47c5..51a16d74ab410 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,6 +1,6 @@ { "name": "@next/font", - "version": "12.3.2-canary.0", + "version": "12.3.2-canary.1", "repository": { "url": "vercel/next.js", "directory": "packages/font" diff --git a/packages/next-bundle-analyzer/package.json b/packages/next-bundle-analyzer/package.json index 72318cd3d97e2..bc389afd56148 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "12.3.2-canary.0", + "version": "12.3.2-canary.1", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index b0c701219b952..8b265d23f62e2 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "12.3.2-canary.0", + "version": "12.3.2-canary.1", "license": "MIT", "dependencies": { "chalk": "4.1.0", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index e38620f1710ce..d9ed337b47286 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "12.3.2-canary.0", + "version": "12.3.2-canary.1", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index c0ea228acc6a3..e0038a2927207 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "12.3.2-canary.0", + "version": "12.3.2-canary.1", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index 6009f7375f19b..e6474ecdbb9b3 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "12.3.2-canary.0", + "version": "12.3.2-canary.1", "repository": { "url": "vercel/next.js", "directory": "packages/next-plugin-storybook" diff --git a/packages/next-polyfill-module/package.json b/packages/next-polyfill-module/package.json index b065aee308e64..184c18efa0f90 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "12.3.2-canary.0", + "version": "12.3.2-canary.1", "description": "A standard library polyfill for ES Modules supporting browsers (Edge 16+, Firefox 60+, Chrome 61+, Safari 10.1+)", "main": "dist/polyfill-module.js", "license": "MIT", diff --git a/packages/next-polyfill-nomodule/package.json b/packages/next-polyfill-nomodule/package.json index d1a32f050530e..6cc946bb523fd 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "12.3.2-canary.0", + "version": "12.3.2-canary.1", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index cad052d086abe..f5e7f78b29f62 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "12.3.2-canary.0", + "version": "12.3.2-canary.1", "private": true, "scripts": { "build-native": "napi build --platform -p next-swc-napi --cargo-name next_swc_napi native --features plugin", diff --git a/packages/next/package.json b/packages/next/package.json index 543cb1ac2aed2..183e90e5096b1 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "12.3.2-canary.0", + "version": "12.3.2-canary.1", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -68,7 +68,7 @@ ] }, "dependencies": { - "@next/env": "12.3.2-canary.0", + "@next/env": "12.3.2-canary.1", "@swc/helpers": "0.4.11", "caniuse-lite": "^1.0.30001406", "postcss": "8.4.14", @@ -119,11 +119,11 @@ "@hapi/accept": "5.0.2", "@napi-rs/cli": "2.7.0", "@napi-rs/triples": "1.1.0", - "@next/polyfill-module": "12.3.2-canary.0", - "@next/polyfill-nomodule": "12.3.2-canary.0", - "@next/react-dev-overlay": "12.3.2-canary.0", - "@next/react-refresh-utils": "12.3.2-canary.0", - "@next/swc": "12.3.2-canary.0", + "@next/polyfill-module": "12.3.2-canary.1", + "@next/polyfill-nomodule": "12.3.2-canary.1", + "@next/react-dev-overlay": "12.3.2-canary.1", + "@next/react-refresh-utils": "12.3.2-canary.1", + "@next/swc": "12.3.2-canary.1", "@segment/ajv-human-errors": "2.1.2", "@taskr/clear": "1.1.0", "@taskr/esnext": "1.1.0", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index 50fe5926156a2..a149a4c1a5064 100644 --- a/packages/react-dev-overlay/package.json +++ b/packages/react-dev-overlay/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-dev-overlay", - "version": "12.3.2-canary.0", + "version": "12.3.2-canary.1", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index 907be4826daff..522ec35941379 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "12.3.2-canary.0", + "version": "12.3.2-canary.1", "description": "An experimental package providing utilities for React Refresh.", "repository": { "url": "vercel/next.js", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a1a6a25b2847a..a730420754097 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -369,7 +369,7 @@ importers: packages/eslint-config-next: specifiers: - '@next/eslint-plugin-next': 12.3.2-canary.0 + '@next/eslint-plugin-next': 12.3.2-canary.1 '@rushstack/eslint-patch': ^1.1.3 '@typescript-eslint/parser': ^5.21.0 eslint-import-resolver-node: ^0.3.6 @@ -398,6 +398,9 @@ importers: devDependencies: '@types/eslint': 7.28.0 + packages/font: + specifiers: {} + packages/next: specifiers: '@ampproject/toolbox-optimizer': 2.8.3 @@ -425,12 +428,12 @@ importers: '@hapi/accept': 5.0.2 '@napi-rs/cli': 2.7.0 '@napi-rs/triples': 1.1.0 - '@next/env': 12.3.2-canary.0 - '@next/polyfill-module': 12.3.2-canary.0 - '@next/polyfill-nomodule': 12.3.2-canary.0 - '@next/react-dev-overlay': 12.3.2-canary.0 - '@next/react-refresh-utils': 12.3.2-canary.0 - '@next/swc': 12.3.2-canary.0 + '@next/env': 12.3.2-canary.1 + '@next/polyfill-module': 12.3.2-canary.1 + '@next/polyfill-nomodule': 12.3.2-canary.1 + '@next/react-dev-overlay': 12.3.2-canary.1 + '@next/react-refresh-utils': 12.3.2-canary.1 + '@next/swc': 12.3.2-canary.1 '@segment/ajv-human-errors': 2.1.2 '@swc/helpers': 0.4.11 '@taskr/clear': 1.1.0 @@ -563,8 +566,8 @@ importers: source-map: 0.6.1 stream-browserify: 3.0.0 stream-http: 3.1.1 - string-hash: 1.1.3 string_decoder: 1.3.0 + string-hash: 1.1.3 strip-ansi: 6.0.0 styled-jsx: 5.0.7 tar: 6.1.11 @@ -752,8 +755,8 @@ importers: source-map: 0.6.1 stream-browserify: 3.0.0 stream-http: 3.1.1 - string-hash: 1.1.3 string_decoder: 1.3.0 + string-hash: 1.1.3 strip-ansi: 6.0.0 tar: 6.1.11 taskr: 1.1.0 @@ -11226,8 +11229,8 @@ packages: engines: { node: '>=10' } hasBin: true dependencies: - JSONStream: 1.3.5 is-text-path: 1.0.1 + JSONStream: 1.3.5 lodash: 4.17.21 meow: 8.1.2 split2: 2.2.0 From 1d7ce56a703f93f80e22cd61842b898587ea7aa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Orb=C3=A1n?= Date: Thu, 22 Sep 2022 00:06:29 +0100 Subject: [PATCH 13/76] chore(examples): lock `msw` version in `with-msw` example (#40777) Closes #40775 ## 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) --- examples/with-msw/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/with-msw/package.json b/examples/with-msw/package.json index f29175130e65c..5b9b20b7b4b46 100644 --- a/examples/with-msw/package.json +++ b/examples/with-msw/package.json @@ -6,7 +6,7 @@ "start": "next start" }, "dependencies": { - "msw": "^0.44.2", + "msw": "0.47.3", "next": "latest", "react": "^18.2.0", "react-dom": "^18.2.0" From 48264c263ac7cd2c3d183540fa04637ffd52d207 Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Wed, 21 Sep 2022 16:32:49 -0700 Subject: [PATCH 14/76] Update publish to scope as public for initializing (#40778) New scoped packages need to be initialized as public so this adds the `publishConfig` for this. Fixes: https://github.com/vercel/next.js/actions/runs/3101494786/jobs/5023375720 --- packages/font/package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/font/package.json b/packages/font/package.json index 51a16d74ab410..51739845395ab 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -15,5 +15,8 @@ "prepublishOnly": "cd ../../ && turbo run build", "dev": "tsc -d -w -p tsconfig.json", "typescript": "tsec --noEmit -p tsconfig.json" + }, + "publishConfig": { + "access": "public" } } From 69595adc3202eb92afaf340ec704ae50e1fdaa68 Mon Sep 17 00:00:00 2001 From: Henrik Wenz Date: Thu, 22 Sep 2022 01:37:57 +0200 Subject: [PATCH 15/76] chore: refactor using-router example (#40774) ## Changes - Updated dependencies - Migrated to Typescript - Added additional router use cases ## Documentation / Examples - [x] Make sure the linting passes by running `pnpm lint` - [x] The "examples guidelines" are followed from [our contributing doc](https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md) --- .../using-router/components/CustomLink.tsx | 47 +++++++++++++++++++ examples/using-router/components/Header.js | 33 ------------- examples/using-router/components/Header.tsx | 14 ++++++ examples/using-router/package.json | 4 +- .../pages/{about.js => about.tsx} | 6 +-- .../pages/{index.js => index.tsx} | 6 +-- examples/using-router/tsconfig.json | 20 ++++++++ 7 files changed, 89 insertions(+), 41 deletions(-) create mode 100644 examples/using-router/components/CustomLink.tsx delete mode 100644 examples/using-router/components/Header.js create mode 100644 examples/using-router/components/Header.tsx rename examples/using-router/pages/{about.js => about.tsx} (67%) rename examples/using-router/pages/{index.js => index.tsx} (66%) create mode 100644 examples/using-router/tsconfig.json diff --git a/examples/using-router/components/CustomLink.tsx b/examples/using-router/components/CustomLink.tsx new file mode 100644 index 0000000000000..6964c15ab58ba --- /dev/null +++ b/examples/using-router/components/CustomLink.tsx @@ -0,0 +1,47 @@ +import { useRouter } from 'next/router' +import { useEffect, ReactNode, HTMLAttributes } from 'react' + +type CustomLinkProps = { + children: ReactNode + href: string + prefetch?: boolean + replace?: boolean + shallow?: boolean +} & HTMLAttributes + +// typically you want to use `next/link` for this usecase +// but this example shows how you can also access the router +// and use it manually +export default function CustomLink({ + children, + href, + prefetch = false, + replace = false, + shallow = false, + ...props +}: CustomLinkProps) { + const router = useRouter() + + useEffect(() => { + if (prefetch) { + router.prefetch(href) + } + }, [router, href, prefetch]) + + return ( + { + event.preventDefault() + if (replace) { + router.replace(href, undefined, { shallow }) + } else { + router.push(href, undefined, { shallow }) + } + }} + > + {children} + + ) +} diff --git a/examples/using-router/components/Header.js b/examples/using-router/components/Header.js deleted file mode 100644 index 22090caa181e8..0000000000000 --- a/examples/using-router/components/Header.js +++ /dev/null @@ -1,33 +0,0 @@ -import { useRouter } from 'next/router' - -export default function Header() { - return ( -
- Home - About -
- ) -} - -const Link = ({ children, href }) => { - const router = useRouter() - return ( - { - e.preventDefault() - // typically you want to use `next/link` for this usecase - // but this example shows how you can also access the router - // and use it manually - router.push(href) - }} - > - {children} - - - ) -} diff --git a/examples/using-router/components/Header.tsx b/examples/using-router/components/Header.tsx new file mode 100644 index 0000000000000..7525d7bb739b1 --- /dev/null +++ b/examples/using-router/components/Header.tsx @@ -0,0 +1,14 @@ +import CustomLink from './CustomLink' + +export default function Header() { + return ( +
+ +
+ ) +} diff --git a/examples/using-router/package.json b/examples/using-router/package.json index 349de02f4d84b..bf29745bfe271 100644 --- a/examples/using-router/package.json +++ b/examples/using-router/package.json @@ -7,7 +7,7 @@ }, "dependencies": { "next": "latest", - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": "^18.2.0", + "react-dom": "^18.2.0" } } diff --git a/examples/using-router/pages/about.js b/examples/using-router/pages/about.tsx similarity index 67% rename from examples/using-router/pages/about.js rename to examples/using-router/pages/about.tsx index 086dde4a32665..0f43605f1b198 100644 --- a/examples/using-router/pages/about.js +++ b/examples/using-router/pages/about.tsx @@ -1,10 +1,10 @@ import Header from '../components/Header' -export default function About() { +export default function AboutPage() { return ( -
+ <>

This is the about page.

-
+ ) } diff --git a/examples/using-router/pages/index.js b/examples/using-router/pages/index.tsx similarity index 66% rename from examples/using-router/pages/index.js rename to examples/using-router/pages/index.tsx index 36583518a84cd..a1ac37ffab93c 100644 --- a/examples/using-router/pages/index.js +++ b/examples/using-router/pages/index.tsx @@ -1,10 +1,10 @@ import Header from '../components/Header' -export default function Home() { +export default function IndexPage() { return ( -
+ <>

HOME PAGE is here!

-
+ ) } diff --git a/examples/using-router/tsconfig.json b/examples/using-router/tsconfig.json new file mode 100644 index 0000000000000..50bcb22f653d7 --- /dev/null +++ b/examples/using-router/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "incremental": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve" + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], + "exclude": ["node_modules"] +} From cbfab2a3b732a5be789f0a3a9e4c2e1177adf80e Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Thu, 22 Sep 2022 02:18:18 +0200 Subject: [PATCH 16/76] Strip internal pages for pagesDir in app edge ssr (#40776) For app edge SSR, we don't need any internal pages for it since it's handled by app-renderer. This results around reducing 20KB from app edge SSR # Changes * Strip those internal pages modules when it's in app edge SSR * Minimize edge SSR chunk to see the tree-shake result * Add bundle analyzer with switcher in stats-app for testing. Using `TEST_ANAYLYSE=1` to build stats-app for testing --- .../next-stats-action/src/run/index.js | 10 ++++++--- packages/next/build/webpack-config.ts | 2 +- .../loaders/next-edge-ssr-loader/index.ts | 19 ++++++++++------- .../loaders/next-edge-ssr-loader/render.ts | 6 +++++- test/.stats-app/app/app-edge-ssr/page.js | 7 +++++++ test/.stats-app/next.config.js | 9 ++++++++ test/.stats-app/package.json | 4 ++-- test/.stats-app/pages/edge-ssr.js | 6 ------ test/.stats-app/stats-config.js | 21 ++++++++++++++++--- 9 files changed, 61 insertions(+), 23 deletions(-) create mode 100644 test/.stats-app/app/app-edge-ssr/page.js create mode 100644 test/.stats-app/next.config.js diff --git a/.github/actions/next-stats-action/src/run/index.js b/.github/actions/next-stats-action/src/run/index.js index 09e5b3761a17d..5e332d4c9f6b2 100644 --- a/.github/actions/next-stats-action/src/run/index.js +++ b/.github/actions/next-stats-action/src/run/index.js @@ -253,9 +253,13 @@ async function linkPkgs(pkgDir = '', pkgPaths) { await fs.writeFile(pkgJsonPath, JSON.stringify(pkgData, null, 2), 'utf8') await fs.remove(yarnEnvValues.YARN_CACHE_FOLDER) - await exec(`cd ${pkgDir} && pnpm install`, false, { - env: yarnEnvValues, - }) + await exec( + `cd ${pkgDir} && pnpm install --strict-peer-dependencies=false`, + false, + { + env: yarnEnvValues, + } + ) } module.exports = runConfigs diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts index 07cc82f4b4ab1..db71cbc61ea5c 100644 --- a/packages/next/build/webpack-config.ts +++ b/packages/next/build/webpack-config.ts @@ -1401,7 +1401,7 @@ export default async function getBaseWebpackConfig( runtimeChunk: isClient ? { name: CLIENT_STATIC_FILES_RUNTIME_WEBPACK } : undefined, - minimize: !dev && isClient, + minimize: !dev && (isClient || isEdgeServer), minimizer: [ // Minify JavaScript (compiler: webpack.Compiler) => { diff --git a/packages/next/build/webpack/loaders/next-edge-ssr-loader/index.ts b/packages/next/build/webpack/loaders/next-edge-ssr-loader/index.ts index 1a1dc07d23106..889a9ebe8bdff 100644 --- a/packages/next/build/webpack/loaders/next-edge-ssr-loader/index.ts +++ b/packages/next/build/webpack/loaders/next-edge-ssr-loader/index.ts @@ -68,29 +68,33 @@ export default async function edgeSSRLoader(this: any) { import { adapter, enhanceGlobals } from 'next/dist/server/web/adapter' import { getRender } from 'next/dist/build/webpack/loaders/next-edge-ssr-loader/render' - import Document from ${stringifiedDocumentPath} - enhanceGlobals() + const pageType = ${JSON.stringify(pagesType)} ${ isAppDir ? ` + const Document = null const appRenderToHTML = require('next/dist/server/app-render').renderToHTMLOrFlight const pagesRenderToHTML = null const pageMod = require(${JSON.stringify(pageModPath)}) + const appMod = null + const errorMod = null + const error500Mod = null ` : ` + const Document = require(${stringifiedDocumentPath}).default const appRenderToHTML = null const pagesRenderToHTML = require('next/dist/server/render').renderToHTML const pageMod = require(${stringifiedPagePath}) + const appMod = require(${stringifiedAppPath}) + const errorMod = require(${stringifiedErrorPath}) + const error500Mod = ${ + stringified500Path ? `require(${stringified500Path})` : 'null' + } ` } - const appMod = require(${stringifiedAppPath}) - const errorMod = require(${stringifiedErrorPath}) - const error500Mod = ${ - stringified500Path ? `require(${stringified500Path})` : 'null' - } const buildManifest = self.__BUILD_MANIFEST const reactLoadableManifest = self.__REACT_LOADABLE_MANIFEST @@ -101,6 +105,7 @@ export default async function edgeSSRLoader(this: any) { } const render = getRender({ + pageType, dev: ${dev}, page: ${JSON.stringify(page)}, appMod, diff --git a/packages/next/build/webpack/loaders/next-edge-ssr-loader/render.ts b/packages/next/build/webpack/loaders/next-edge-ssr-loader/render.ts index 30ac4851283d9..128ccbe478250 100644 --- a/packages/next/build/webpack/loaders/next-edge-ssr-loader/render.ts +++ b/packages/next/build/webpack/loaders/next-edge-ssr-loader/render.ts @@ -17,6 +17,7 @@ export function getRender({ pageMod, errorMod, error500Mod, + pagesType, Document, buildManifest, reactLoadableManifest, @@ -28,6 +29,7 @@ export function getRender({ config, buildId, }: { + pagesType?: 'app' | 'pages' | 'root' dev: boolean page: string appMod: any @@ -46,13 +48,14 @@ export function getRender({ config: NextConfig buildId: string }) { + const isAppPath = pagesType === 'app' const baseLoadComponentResult = { dev, buildManifest, reactLoadableManifest, subresourceIntegrityManifest, Document, - App: appMod.default as AppType, + App: appMod?.default as AppType, } const server = new WebServer({ @@ -72,6 +75,7 @@ export function getRender({ appRenderToHTML, pagesRenderToHTML, loadComponent: async (pathname) => { + if (isAppPath) return null if (pathname === page) { return { ...baseLoadComponentResult, diff --git a/test/.stats-app/app/app-edge-ssr/page.js b/test/.stats-app/app/app-edge-ssr/page.js new file mode 100644 index 0000000000000..20e49c40a12cc --- /dev/null +++ b/test/.stats-app/app/app-edge-ssr/page.js @@ -0,0 +1,7 @@ +export default function page() { + return 'edge-ssr' +} + +export const config = { + runtime: 'experimental-edge', +} diff --git a/test/.stats-app/next.config.js b/test/.stats-app/next.config.js new file mode 100644 index 0000000000000..3b9bfdac02772 --- /dev/null +++ b/test/.stats-app/next.config.js @@ -0,0 +1,9 @@ +const withBundleAnalyzer = require('@next/bundle-analyzer')({ + enabled: !!process.env.TEST_ANALYZE, +}) + +module.exports = withBundleAnalyzer({ + experimental: { + appDir: true, + }, +}) diff --git a/test/.stats-app/package.json b/test/.stats-app/package.json index 5ed2c313a0cc1..374d524426a5d 100644 --- a/test/.stats-app/package.json +++ b/test/.stats-app/package.json @@ -4,7 +4,7 @@ "license": "MIT", "dependencies": { "next": "latest", - "react": "18.2.0", - "react-dom": "18.2.0" + "react": "experimental", + "react-dom": "experimental" } } diff --git a/test/.stats-app/pages/edge-ssr.js b/test/.stats-app/pages/edge-ssr.js index f92742cc52817..20e49c40a12cc 100644 --- a/test/.stats-app/pages/edge-ssr.js +++ b/test/.stats-app/pages/edge-ssr.js @@ -2,12 +2,6 @@ export default function page() { return 'edge-ssr' } -export async function getServerSideProps() { - return { - props: {}, - } -} - export const config = { runtime: 'experimental-edge', } diff --git a/test/.stats-app/stats-config.js b/test/.stats-app/stats-config.js index c6e87308db9d8..58316e4a8ee6d 100644 --- a/test/.stats-app/stats-config.js +++ b/test/.stats-app/stats-config.js @@ -32,8 +32,11 @@ const clientGlobs = [ globs: ['fetched-pages/**/*.html'], }, { - name: 'Edge SSR Page bundle Size', - globs: ['.next/server/pages/edge-ssr.js'], + name: 'Edge SSR bundle Size', + globs: [ + '.next/server/pages/edge-ssr.js', + '.next/server/app/app-edge-ssr/page.js', + ], }, { name: 'Middleware size', @@ -89,6 +92,9 @@ module.exports = { path: 'next.config.js', content: ` module.exports = { + experimental: { + appDir: true, + }, generateBuildId: () => 'BUILD_ID', webpack(config) { config.optimization.minimize = false @@ -109,7 +115,10 @@ module.exports = { { path: 'next.config.js', content: ` - module.exports = { + module.exports = { + experimental: { + appDir: true, + }, generateBuildId: () => 'BUILD_ID' } `, @@ -144,6 +153,9 @@ module.exports = { path: 'next.config.js', content: ` module.exports = { + experimental: { + appDir: true, + }, generateBuildId: () => 'BUILD_ID', swcMinify: true, webpack(config) { @@ -166,6 +178,9 @@ module.exports = { path: 'next.config.js', content: ` module.exports = { + experimental: { + appDir: true, + }, swcMinify: true, generateBuildId: () => 'BUILD_ID' } From c2487ce2629a9d061a600c6ecb3b7d28492bead0 Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Wed, 21 Sep 2022 17:21:58 -0700 Subject: [PATCH 17/76] v12.3.2-canary.2 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-config-next/package.json | 4 ++-- packages/eslint-plugin-next/package.json | 2 +- packages/font/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next-swc/package.json | 2 +- packages/next/package.json | 14 +++++++------- packages/react-dev-overlay/package.json | 2 +- packages/react-refresh-utils/package.json | 2 +- pnpm-lock.yaml | 14 +++++++------- 17 files changed, 30 insertions(+), 30 deletions(-) diff --git a/lerna.json b/lerna.json index e85ed9347ba07..d48fc2f60979d 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "12.3.2-canary.1" + "version": "12.3.2-canary.2" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index a4ce59156450f..b338ed7b2d03a 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "12.3.2-canary.1", + "version": "12.3.2-canary.2", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index dbeb3f58ff241..c64193426b808 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "12.3.2-canary.1", + "version": "12.3.2-canary.2", "description": "ESLint configuration used by NextJS.", "main": "index.js", "license": "MIT", @@ -9,7 +9,7 @@ "directory": "packages/eslint-config-next" }, "dependencies": { - "@next/eslint-plugin-next": "12.3.2-canary.1", + "@next/eslint-plugin-next": "12.3.2-canary.2", "@rushstack/eslint-patch": "^1.1.3", "@typescript-eslint/parser": "^5.21.0", "eslint-import-resolver-node": "^0.3.6", diff --git a/packages/eslint-plugin-next/package.json b/packages/eslint-plugin-next/package.json index 82de495885b86..1ea785a15ce90 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "12.3.2-canary.1", + "version": "12.3.2-canary.2", "description": "ESLint plugin for NextJS.", "main": "lib/index.js", "license": "MIT", diff --git a/packages/font/package.json b/packages/font/package.json index 51739845395ab..4782cf19834a4 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,6 +1,6 @@ { "name": "@next/font", - "version": "12.3.2-canary.1", + "version": "12.3.2-canary.2", "repository": { "url": "vercel/next.js", "directory": "packages/font" diff --git a/packages/next-bundle-analyzer/package.json b/packages/next-bundle-analyzer/package.json index bc389afd56148..ac1e0f9c7f49c 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "12.3.2-canary.1", + "version": "12.3.2-canary.2", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index 8b265d23f62e2..1ef039e41e75d 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "12.3.2-canary.1", + "version": "12.3.2-canary.2", "license": "MIT", "dependencies": { "chalk": "4.1.0", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index d9ed337b47286..95419f0fdbfa6 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "12.3.2-canary.1", + "version": "12.3.2-canary.2", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index e0038a2927207..3a5a75d4ecbc9 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "12.3.2-canary.1", + "version": "12.3.2-canary.2", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index e6474ecdbb9b3..32f07122eedec 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "12.3.2-canary.1", + "version": "12.3.2-canary.2", "repository": { "url": "vercel/next.js", "directory": "packages/next-plugin-storybook" diff --git a/packages/next-polyfill-module/package.json b/packages/next-polyfill-module/package.json index 184c18efa0f90..3c1b0854f7e46 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "12.3.2-canary.1", + "version": "12.3.2-canary.2", "description": "A standard library polyfill for ES Modules supporting browsers (Edge 16+, Firefox 60+, Chrome 61+, Safari 10.1+)", "main": "dist/polyfill-module.js", "license": "MIT", diff --git a/packages/next-polyfill-nomodule/package.json b/packages/next-polyfill-nomodule/package.json index 6cc946bb523fd..c3a934aa98d8d 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "12.3.2-canary.1", + "version": "12.3.2-canary.2", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index f5e7f78b29f62..e436d99297f13 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "12.3.2-canary.1", + "version": "12.3.2-canary.2", "private": true, "scripts": { "build-native": "napi build --platform -p next-swc-napi --cargo-name next_swc_napi native --features plugin", diff --git a/packages/next/package.json b/packages/next/package.json index 183e90e5096b1..7463ebd7edce0 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "12.3.2-canary.1", + "version": "12.3.2-canary.2", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -68,7 +68,7 @@ ] }, "dependencies": { - "@next/env": "12.3.2-canary.1", + "@next/env": "12.3.2-canary.2", "@swc/helpers": "0.4.11", "caniuse-lite": "^1.0.30001406", "postcss": "8.4.14", @@ -119,11 +119,11 @@ "@hapi/accept": "5.0.2", "@napi-rs/cli": "2.7.0", "@napi-rs/triples": "1.1.0", - "@next/polyfill-module": "12.3.2-canary.1", - "@next/polyfill-nomodule": "12.3.2-canary.1", - "@next/react-dev-overlay": "12.3.2-canary.1", - "@next/react-refresh-utils": "12.3.2-canary.1", - "@next/swc": "12.3.2-canary.1", + "@next/polyfill-module": "12.3.2-canary.2", + "@next/polyfill-nomodule": "12.3.2-canary.2", + "@next/react-dev-overlay": "12.3.2-canary.2", + "@next/react-refresh-utils": "12.3.2-canary.2", + "@next/swc": "12.3.2-canary.2", "@segment/ajv-human-errors": "2.1.2", "@taskr/clear": "1.1.0", "@taskr/esnext": "1.1.0", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index a149a4c1a5064..4266772112e7d 100644 --- a/packages/react-dev-overlay/package.json +++ b/packages/react-dev-overlay/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-dev-overlay", - "version": "12.3.2-canary.1", + "version": "12.3.2-canary.2", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index 522ec35941379..5e2de08706320 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "12.3.2-canary.1", + "version": "12.3.2-canary.2", "description": "An experimental package providing utilities for React Refresh.", "repository": { "url": "vercel/next.js", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a730420754097..872106b1d4460 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -369,7 +369,7 @@ importers: packages/eslint-config-next: specifiers: - '@next/eslint-plugin-next': 12.3.2-canary.1 + '@next/eslint-plugin-next': 12.3.2-canary.2 '@rushstack/eslint-patch': ^1.1.3 '@typescript-eslint/parser': ^5.21.0 eslint-import-resolver-node: ^0.3.6 @@ -428,12 +428,12 @@ importers: '@hapi/accept': 5.0.2 '@napi-rs/cli': 2.7.0 '@napi-rs/triples': 1.1.0 - '@next/env': 12.3.2-canary.1 - '@next/polyfill-module': 12.3.2-canary.1 - '@next/polyfill-nomodule': 12.3.2-canary.1 - '@next/react-dev-overlay': 12.3.2-canary.1 - '@next/react-refresh-utils': 12.3.2-canary.1 - '@next/swc': 12.3.2-canary.1 + '@next/env': 12.3.2-canary.2 + '@next/polyfill-module': 12.3.2-canary.2 + '@next/polyfill-nomodule': 12.3.2-canary.2 + '@next/react-dev-overlay': 12.3.2-canary.2 + '@next/react-refresh-utils': 12.3.2-canary.2 + '@next/swc': 12.3.2-canary.2 '@segment/ajv-human-errors': 2.1.2 '@swc/helpers': 0.4.11 '@taskr/clear': 1.1.0 From ef9ba4509a0dfc7b43df3f0f5bbedf78d6de8327 Mon Sep 17 00:00:00 2001 From: Anthony Shew Date: Wed, 21 Sep 2022 18:13:54 -0700 Subject: [PATCH 18/76] Fix: Contentful webhook body parse. (#40732) ## 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) --- examples/cms-contentful/pages/api/revalidate.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cms-contentful/pages/api/revalidate.js b/examples/cms-contentful/pages/api/revalidate.js index 8b3b73924f1ec..a4cf828e518fa 100644 --- a/examples/cms-contentful/pages/api/revalidate.js +++ b/examples/cms-contentful/pages/api/revalidate.js @@ -14,7 +14,7 @@ export default async function handler(req, res) { } try { - let postSlug = req.body.fields.slug['en-US'] + let postSlug = JSON.parse(req.body).fields.slug['en-US'] // revalidate the individual post and the home page await res.revalidate(`/posts/${postSlug}`) From bf8ee1edb4f6b134ada58e2ea65e33670c0c08ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Born=C3=B6?= Date: Thu, 22 Sep 2022 07:12:59 +0200 Subject: [PATCH 19/76] Add support for font loaders (#40746) For some context: [https://vercel.slack.com/archives/CGU8HUTUH/p1662124179102509](https://vercel.slack.com/archives/CGU8HUTUH/p1662124179102509) Continuation of #40221 and #40227 Adds `experimental.fontLoaders`. SWC next-font-loaders (#40221) transforms font loader (e.g. #40227) call expressions into an import with the function call arguments as a query. The imports will be matched by `next-font-loader`. It runs the configured font loaders - emits font files and returns CSS. Exports are added, and the font-family is made locally scoped. The returned CSS is turned into a CSS module with `css-loader` which lets you consume the font-family. `FontLoaderManifestPlugin` creates a manifest of the preloaded font files for each entrypoint. Preload/preconnect are then added in `_document.tsx` if any font files were found for that path. Co-authored-by: JJ Kasper --- packages/next/build/entries.ts | 1 + packages/next/build/index.ts | 4 + packages/next/build/swc/options.js | 3 + packages/next/build/webpack-config.ts | 6 + .../build/webpack/config/blocks/css/index.ts | 55 ++ .../config/blocks/css/loaders/font-loader.ts | 70 +++ .../webpack/config/blocks/css/messages.ts | 6 + .../webpack/loaders/css-loader/src/index.js | 7 +- .../webpack/loaders/css-loader/src/utils.js | 18 +- .../loaders/next-edge-ssr-loader/index.ts | 6 + .../loaders/next-edge-ssr-loader/render.ts | 4 + .../webpack/loaders/next-font-loader/index.ts | 83 +++ .../next-font-loader/postcss-font-loader.ts | 135 +++++ .../plugins/font-loader-manifest-plugin.ts | 62 +++ .../webpack/plugins/middleware-plugin.ts | 28 +- packages/next/export/index.ts | 4 + packages/next/pages/_document.tsx | 60 +++ packages/next/server/base-server.ts | 7 + packages/next/server/config-schema.ts | 3 + packages/next/server/config-shared.ts | 1 + packages/next/server/dev/next-dev-server.ts | 5 + packages/next/server/next-server.ts | 10 +- packages/next/server/render.tsx | 3 + packages/next/server/web-server.ts | 5 + packages/next/shared/lib/constants.ts | 1 + packages/next/shared/lib/html-context.ts | 2 + .../font-loader-in-document-error.test.ts | 32 ++ .../font-loader-in-document/next.config.js | 9 + .../pages/_document.js | 17 + .../font-loader-in-document/pages/index.js | 3 + .../next-font/app/components/CompWithFonts.js | 20 + test/e2e/next-font/app/next.config.js | 9 + test/e2e/next-font/app/pages/_app.js | 16 + test/e2e/next-font/app/pages/variables.js | 78 +++ test/e2e/next-font/app/pages/with-fallback.js | 22 + test/e2e/next-font/app/pages/with-fonts.js | 14 + test/e2e/next-font/app/pages/without-fonts.js | 3 + test/e2e/next-font/basepath.test.ts | 54 ++ test/e2e/next-font/basepath/next.config.js | 10 + test/e2e/next-font/basepath/pages/index.js | 6 + .../next-font/google-font-mocked-responses.js | 496 ++++++++++++++++++ test/e2e/next-font/index.test.ts | 294 +++++++++++ .../with-font-declarations-file.test.ts | 110 ++++ .../components/roboto-comp.js | 10 + .../with-font-declarations-file/fonts.js | 16 + .../next.config.js | 9 + .../with-font-declarations-file/pages/_app.js | 15 + .../pages/inter.js | 10 + .../pages/roboto.js | 5 + .../next-font/without-preloaded-fonts.test.ts | 132 +++++ .../without-preloaded-fonts/next.config.js | 9 + .../without-preloaded-fonts/pages/_app.js | 12 + .../pages/no-preload.js | 6 + .../pages/without-fonts.js | 3 + 54 files changed, 1994 insertions(+), 15 deletions(-) create mode 100644 packages/next/build/webpack/config/blocks/css/loaders/font-loader.ts create mode 100644 packages/next/build/webpack/loaders/next-font-loader/index.ts create mode 100644 packages/next/build/webpack/loaders/next-font-loader/postcss-font-loader.ts create mode 100644 packages/next/build/webpack/plugins/font-loader-manifest-plugin.ts create mode 100644 test/development/next-font/font-loader-in-document-error.test.ts create mode 100644 test/development/next-font/font-loader-in-document/next.config.js create mode 100644 test/development/next-font/font-loader-in-document/pages/_document.js create mode 100644 test/development/next-font/font-loader-in-document/pages/index.js create mode 100644 test/e2e/next-font/app/components/CompWithFonts.js create mode 100644 test/e2e/next-font/app/next.config.js create mode 100644 test/e2e/next-font/app/pages/_app.js create mode 100644 test/e2e/next-font/app/pages/variables.js create mode 100644 test/e2e/next-font/app/pages/with-fallback.js create mode 100644 test/e2e/next-font/app/pages/with-fonts.js create mode 100644 test/e2e/next-font/app/pages/without-fonts.js create mode 100644 test/e2e/next-font/basepath.test.ts create mode 100644 test/e2e/next-font/basepath/next.config.js create mode 100644 test/e2e/next-font/basepath/pages/index.js create mode 100644 test/e2e/next-font/google-font-mocked-responses.js create mode 100644 test/e2e/next-font/index.test.ts create mode 100644 test/e2e/next-font/with-font-declarations-file.test.ts create mode 100644 test/e2e/next-font/with-font-declarations-file/components/roboto-comp.js create mode 100644 test/e2e/next-font/with-font-declarations-file/fonts.js create mode 100644 test/e2e/next-font/with-font-declarations-file/next.config.js create mode 100644 test/e2e/next-font/with-font-declarations-file/pages/_app.js create mode 100644 test/e2e/next-font/with-font-declarations-file/pages/inter.js create mode 100644 test/e2e/next-font/with-font-declarations-file/pages/roboto.js create mode 100644 test/e2e/next-font/without-preloaded-fonts.test.ts create mode 100644 test/e2e/next-font/without-preloaded-fonts/next.config.js create mode 100644 test/e2e/next-font/without-preloaded-fonts/pages/_app.js create mode 100644 test/e2e/next-font/without-preloaded-fonts/pages/no-preload.js create mode 100644 test/e2e/next-font/without-preloaded-fonts/pages/without-fonts.js diff --git a/packages/next/build/entries.ts b/packages/next/build/entries.ts index 2fc0253ba59a6..6b0a6e0a39025 100644 --- a/packages/next/build/entries.ts +++ b/packages/next/build/entries.ts @@ -204,6 +204,7 @@ export function getEdgeServerEntry(opts: { pagesType: opts.pagesType, appDirLoader: Buffer.from(opts.appDirLoader || '').toString('base64'), sriEnabled: !opts.isDev && !!opts.config.experimental.sri?.algorithm, + hasFontLoaders: !!opts.config.experimental.fontLoaders, } return { diff --git a/packages/next/build/index.ts b/packages/next/build/index.ts index 29f82ca095d84..775d726bec4c4 100644 --- a/packages/next/build/index.ts +++ b/packages/next/build/index.ts @@ -59,6 +59,7 @@ import { APP_BUILD_MANIFEST, FLIGHT_SERVER_CSS_MANIFEST, RSC_MODULE_TYPES, + FONT_LOADER_MANIFEST, } from '../shared/lib/constants' import { getSortedRoutes, isDynamicRoute } from '../shared/lib/router/utils' import { __ApiPreviewProps } from '../server/api-utils' @@ -828,6 +829,9 @@ export default async function build( config.optimizeFonts ? path.join(serverDir, FONT_MANIFEST) : null, BUILD_ID_FILE, appDir ? path.join(serverDir, APP_PATHS_MANIFEST) : null, + config.experimental.fontLoaders + ? path.join(serverDir, FONT_LOADER_MANIFEST) + : null, ] .filter(nonNullable) .map((file) => path.join(config.distDir, file)), diff --git a/packages/next/build/swc/options.js b/packages/next/build/swc/options.js index 9cfc10bd9bfc5..bb8208b6dd6b4 100644 --- a/packages/next/build/swc/options.js +++ b/packages/next/build/swc/options.js @@ -123,6 +123,9 @@ function getBaseSWCOptions({ isServer: !!isServerLayer, } : false, + fontLoaders: + nextConfig?.experimental?.fontLoaders && + Object.keys(nextConfig.experimental.fontLoaders), } } diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts index db71cbc61ea5c..b4260973ab2fa 100644 --- a/packages/next/build/webpack-config.ts +++ b/packages/next/build/webpack-config.ts @@ -61,6 +61,7 @@ import loadJsConfig from './load-jsconfig' import { loadBindings } from './swc' import { AppBuildManifestPlugin } from './webpack/plugins/app-build-manifest-plugin' import { SubresourceIntegrityPlugin } from './webpack/plugins/subresource-integrity-plugin' +import { FontLoaderManifestPlugin } from './webpack/plugins/font-loader-manifest-plugin' const NEXT_PROJECT_ROOT = pathJoin(__dirname, '..', '..') const NEXT_PROJECT_ROOT_DIST = pathJoin(NEXT_PROJECT_ROOT, 'dist') @@ -1508,6 +1509,7 @@ export default async function getBaseWebpackConfig( 'next-middleware-asset-loader', 'next-middleware-wasm-loader', 'next-app-loader', + 'next-font-loader', ].reduce((alias, loader) => { // using multiple aliases to replace `resolveLoader.modules` alias[loader] = path.join(__dirname, 'webpack', 'loaders', loader) @@ -1838,6 +1840,7 @@ export default async function getBaseWebpackConfig( new MiddlewarePlugin({ dev, sriEnabled: !dev && !!config.experimental.sri?.algorithm, + hasFontLoaders: !!config.experimental.fontLoaders, }), isClient && new BuildManifestPlugin({ @@ -1890,6 +1893,9 @@ export default async function getBaseWebpackConfig( isClient && !!config.experimental.sri?.algorithm && new SubresourceIntegrityPlugin(config.experimental.sri.algorithm), + isClient && + config.experimental.fontLoaders && + new FontLoaderManifestPlugin(), !dev && isClient && new (require('./webpack/plugins/telemetry-plugin').TelemetryPlugin)( diff --git a/packages/next/build/webpack/config/blocks/css/index.ts b/packages/next/build/webpack/config/blocks/css/index.ts index 5b81ffc7da103..3ebc34d9e74bd 100644 --- a/packages/next/build/webpack/config/blocks/css/index.ts +++ b/packages/next/build/webpack/config/blocks/css/index.ts @@ -3,11 +3,13 @@ import { webpack } from 'next/dist/compiled/webpack/webpack' import { loader, plugin } from '../../helpers' import { ConfigurationContext, ConfigurationFn, pipe } from '../../utils' import { getCssModuleLoader, getGlobalCssLoader } from './loaders' +import { getFontLoader } from './loaders/font-loader' import { getCustomDocumentError, getGlobalImportError, getGlobalModuleImportError, getLocalModuleImportError, + getFontLoaderDocumentImportError, } from './messages' import { getPostCssPlugins } from './plugins' @@ -199,6 +201,59 @@ export const css = curry(async function css( }) ) + // Resolve the configured font loaders, the resolved files are noop files that next-font-loader will match + let fontLoaders: [string, string][] | undefined = ctx.experimental.fontLoaders + ? Object.entries(ctx.experimental.fontLoaders).map( + ([fontLoader, fontLoaderOptions]: any) => [ + require.resolve(fontLoader), + fontLoaderOptions, + ] + ) + : undefined + + // Font loaders cannot be imported in _document. + fontLoaders?.forEach(([fontLoaderPath, fontLoaderOptions]) => { + fns.push( + loader({ + oneOf: [ + markRemovable({ + test: fontLoaderPath, + // Use a loose regex so we don't have to crawl the file system to + // find the real file name (if present). + issuer: /pages[\\/]_document\./, + use: { + loader: 'error-loader', + options: { + reason: getFontLoaderDocumentImportError(), + }, + }, + }), + ], + }) + ) + + // Matches the resolved font loaders noop files to run next-font-loader + fns.push( + loader({ + oneOf: [ + markRemovable({ + sideEffects: false, + test: fontLoaderPath, + issuer: { + and: [ + { + or: [ctx.rootDirectory, regexClientEntry], + }, + ], + not: [/node_modules/], + }, + use: getFontLoader(ctx, lazyPostCSSInitializer, fontLoaderOptions), + }), + ], + }) + ) + }) + // CSS Modules support must be enabled on the server and client so the class // names are available for SSR or Prerendering. if (ctx.experimental.appDir && !ctx.isProduction) { diff --git a/packages/next/build/webpack/config/blocks/css/loaders/font-loader.ts b/packages/next/build/webpack/config/blocks/css/loaders/font-loader.ts new file mode 100644 index 0000000000000..c48efd1d75916 --- /dev/null +++ b/packages/next/build/webpack/config/blocks/css/loaders/font-loader.ts @@ -0,0 +1,70 @@ +import { webpack } from 'next/dist/compiled/webpack/webpack' +import { ConfigurationContext } from '../../../utils' +import { getClientStyleLoader } from './client' +import { cssFileResolve } from './file-resolve' + +export function getFontLoader( + ctx: ConfigurationContext, + postcss: any, + fontLoaderOptions: any +): webpack.RuleSetUseItem[] { + const loaders: webpack.RuleSetUseItem[] = [] + + if (ctx.isClient) { + // Add appropriate development mode or production mode style + // loader + loaders.push( + getClientStyleLoader({ + isAppDir: !!ctx.experimental.appDir, + isDevelopment: ctx.isDevelopment, + assetPrefix: ctx.assetPrefix, + }) + ) + } + + loaders.push({ + loader: require.resolve('../../../../loaders/css-loader/src'), + options: { + postcss, + importLoaders: 1, + // Use CJS mode for backwards compatibility: + esModule: false, + url: (url: string, resourcePath: string) => + cssFileResolve(url, resourcePath, ctx.experimental.urlImports), + import: (url: string, _: any, resourcePath: string) => + cssFileResolve(url, resourcePath, ctx.experimental.urlImports), + modules: { + // Do not transform class names (CJS mode backwards compatibility): + exportLocalsConvention: 'asIs', + // Server-side (Node.js) rendering support: + exportOnlyLocals: ctx.isServer, + // Disallow global style exports so we can code-split CSS and + // not worry about loading order. + mode: 'pure', + getLocalIdent: ( + _context: any, + _localIdentName: any, + exportName: string, + _options: any, + meta: any + ) => { + // hash from next-font-loader + return `__${exportName}_${meta.fontFamilyHash}` + }, + }, + fontLoader: true, + }, + }) + + loaders.push({ + loader: 'next-font-loader', + options: { + isServer: ctx.isServer, + assetPrefix: ctx.assetPrefix, + fontLoaderOptions, + postcss, + }, + }) + + return loaders +} diff --git a/packages/next/build/webpack/config/blocks/css/messages.ts b/packages/next/build/webpack/config/blocks/css/messages.ts index 61c62c994fc34..42b5c720e54ba 100644 --- a/packages/next/build/webpack/config/blocks/css/messages.ts +++ b/packages/next/build/webpack/config/blocks/css/messages.ts @@ -31,3 +31,9 @@ export function getCustomDocumentError() { 'pages/_document.js' )}. Please move global styles to ${chalk.cyan('pages/_app.js')}.` } + +export function getFontLoaderDocumentImportError() { + return `Font loaders ${chalk.bold('cannot')} be used within ${chalk.cyan( + 'pages/_document.js' + )}.` +} diff --git a/packages/next/build/webpack/loaders/css-loader/src/index.js b/packages/next/build/webpack/loaders/css-loader/src/index.js index eae004f556ea7..bc259cdfefee3 100644 --- a/packages/next/build/webpack/loaders/css-loader/src/index.js +++ b/packages/next/build/webpack/loaders/css-loader/src/index.js @@ -4,7 +4,6 @@ */ import CssSyntaxError from './CssSyntaxError' import Warning from '../../postcss-loader/src/Warning' -// import { icssParser, importParser, urlParser } from './plugins' import { stringifyRequest } from '../../../stringify-request' const moduleRegExp = /\.module\.\w+$/i @@ -128,6 +127,7 @@ function normalizeOptions(rawOptions, loaderContext) { : rawOptions.importLoaders, esModule: typeof rawOptions.esModule === 'undefined' ? true : rawOptions.esModule, + fontLoader: rawOptions.fontLoader, } } @@ -169,10 +169,11 @@ export default async function loader(content, map, meta) { const { icssParser, importParser, urlParser } = require('./plugins') const replacements = [] - const exports = [] + // if it's a font loader next-font-loader will have exports that should be exported as is + const exports = options.fontLoader ? meta.exports : [] if (shouldUseModulesPlugins(options)) { - plugins.push(...getModulesPlugins(options, this)) + plugins.push(...getModulesPlugins(options, this, meta)) } const importPluginImports = [] diff --git a/packages/next/build/webpack/loaders/css-loader/src/utils.js b/packages/next/build/webpack/loaders/css-loader/src/utils.js index 0ab83b2fd9ec6..328800a9317c8 100644 --- a/packages/next/build/webpack/loaders/css-loader/src/utils.js +++ b/packages/next/build/webpack/loaders/css-loader/src/utils.js @@ -135,7 +135,7 @@ function shouldUseIcssPlugin(options) { return options.icss === true || Boolean(options.modules) } -function getModulesPlugins(options, loaderContext) { +function getModulesPlugins(options, loaderContext, meta) { const { mode, getLocalIdent, @@ -154,11 +154,17 @@ function getModulesPlugins(options, loaderContext) { extractImports(), modulesScope({ generateScopedName(exportName) { - return getLocalIdent(loaderContext, localIdentName, exportName, { - context: localIdentContext, - hashPrefix: localIdentHashPrefix, - regExp: localIdentRegExp, - }) + return getLocalIdent( + loaderContext, + localIdentName, + exportName, + { + context: localIdentContext, + hashPrefix: localIdentHashPrefix, + regExp: localIdentRegExp, + }, + meta + ) }, exportGlobals: options.modules.exportGlobals, }), diff --git a/packages/next/build/webpack/loaders/next-edge-ssr-loader/index.ts b/packages/next/build/webpack/loaders/next-edge-ssr-loader/index.ts index 889a9ebe8bdff..a04f5c9979b9c 100644 --- a/packages/next/build/webpack/loaders/next-edge-ssr-loader/index.ts +++ b/packages/next/build/webpack/loaders/next-edge-ssr-loader/index.ts @@ -15,6 +15,7 @@ export type EdgeSSRLoaderQuery = { appDirLoader?: string pagesType?: 'app' | 'pages' | 'root' sriEnabled: boolean + hasFontLoaders: boolean } export default async function edgeSSRLoader(this: any) { @@ -32,6 +33,7 @@ export default async function edgeSSRLoader(this: any) { appDirLoader: appDirLoaderBase64, pagesType, sriEnabled, + hasFontLoaders, } = this.getOptions() const appDirLoader = Buffer.from( @@ -103,6 +105,9 @@ export default async function edgeSSRLoader(this: any) { const subresourceIntegrityManifest = ${ sriEnabled ? 'self.__SUBRESOURCE_INTEGRITY_MANIFEST' : 'undefined' } + const fontLoaderManifest = ${ + hasFontLoaders ? 'self.__FONT_LOADER_MANIFEST' : 'undefined' + } const render = getRender({ pageType, @@ -122,6 +127,7 @@ export default async function edgeSSRLoader(this: any) { subresourceIntegrityManifest, config: ${stringifiedConfig}, buildId: ${JSON.stringify(buildId)}, + fontLoaderManifest, }) export const ComponentMod = pageMod diff --git a/packages/next/build/webpack/loaders/next-edge-ssr-loader/render.ts b/packages/next/build/webpack/loaders/next-edge-ssr-loader/render.ts index 128ccbe478250..23c175a5a77cd 100644 --- a/packages/next/build/webpack/loaders/next-edge-ssr-loader/render.ts +++ b/packages/next/build/webpack/loaders/next-edge-ssr-loader/render.ts @@ -2,6 +2,7 @@ import type { NextConfig } from '../../../../server/config-shared' import type { DocumentType, AppType } from '../../../../shared/lib/utils' import type { BuildManifest } from '../../../../server/get-page-files' import type { ReactLoadableManifest } from '../../../../server/load-components' +import type { FontLoaderManifest } from '../../plugins/font-loader-manifest-plugin' import WebServer from '../../../../server/web-server' import { @@ -28,6 +29,7 @@ export function getRender({ serverCSSManifest, config, buildId, + fontLoaderManifest, }: { pagesType?: 'app' | 'pages' | 'root' dev: boolean @@ -47,6 +49,7 @@ export function getRender({ appServerMod: any config: NextConfig buildId: string + fontLoaderManifest: FontLoaderManifest }) { const isAppPath = pagesType === 'app' const baseLoadComponentResult = { @@ -54,6 +57,7 @@ export function getRender({ buildManifest, reactLoadableManifest, subresourceIntegrityManifest, + fontLoaderManifest, Document, App: appMod?.default as AppType, } diff --git a/packages/next/build/webpack/loaders/next-font-loader/index.ts b/packages/next/build/webpack/loaders/next-font-loader/index.ts new file mode 100644 index 0000000000000..196ac837ceb11 --- /dev/null +++ b/packages/next/build/webpack/loaders/next-font-loader/index.ts @@ -0,0 +1,83 @@ +import path from 'path' +import loaderUtils from 'next/dist/compiled/loader-utils3' +import postcssFontLoaderPlugn from './postcss-font-loader' + +type FontLoader = (options: { + functionName: string + data: any[] + config: any + emitFontFile: (content: Buffer, ext: string, preload: boolean) => string +}) => Promise<{ css: string; fallbackFonts: string[] }> + +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/fonts/[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 [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 } = await fontLoader({ + functionName, + data, + config: fontLoaderOptions, + emitFontFile, + }) + + 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) + ).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 + callback(err) + } + }) +} diff --git a/packages/next/build/webpack/loaders/next-font-loader/postcss-font-loader.ts b/packages/next/build/webpack/loaders/next-font-loader/postcss-font-loader.ts new file mode 100644 index 0000000000000..08313dd565df3 --- /dev/null +++ b/packages/next/build/webpack/loaders/next-font-loader/postcss-font-loader.ts @@ -0,0 +1,135 @@ +import postcss, { Declaration } from 'postcss' + +const postcssFontLoaderPlugn = ( + exports: { name: any; value: any }[], + fontFamilyHash: string, + fallbackFonts: string[] = [] +) => { + return { + postcssPlugin: 'postcss-font-loader', + Once(root: any) { + const fontFamilies: string[] = [] + let rawFamily: string | undefined + let fontWeight: string | undefined + let fontStyle: string | undefined + + const formatFamily = (family: string) => { + if (family[0] === "'" || family[0] === '"') { + family = family.slice(1, family.length - 1) + } + // Turn the font family unguessable to make it localy scoped + return `'__${family.replace(/ /g, '_')}_${fontFamilyHash}'` + } + + for (const node of root.nodes) { + if (node.type === 'atrule' && node.name === 'font-face') { + const familyNode = node.nodes.find( + (decl: Declaration) => decl.prop === 'font-family' + ) + if (!familyNode) { + continue + } + + if (!rawFamily) { + let family: string = familyNode.value + if (family[0] === "'" || family[0] === '"') { + family = family.slice(1, family.length - 1) + } + rawFamily = family + } + const formattedFamily = formatFamily(familyNode.value) + familyNode.value = formattedFamily + + if (fontFamilies.includes(formattedFamily)) { + continue + } + fontFamilies.push(formattedFamily) + + // Only extract weight and style from first encountered family, the rest will treated as fallbacks + if (fontFamilies.length > 1) { + continue + } + + // Extract weight and style from first encountered @font-face + const weight = node.nodes.find( + (decl: Declaration) => decl.prop === 'font-weight' + ) + + // Skip if the value includes ' ', then it's a range of possible values + if (weight && !weight.value.includes(' ')) { + fontWeight = weight.value + } + + const style = node.nodes.find( + (decl: Declaration) => decl.prop === 'font-style' + ) + // Skip if the value includes ' ', then it's a range of possible values + if (style && !style.value.includes(' ')) { + fontStyle = style.value + } + } + } + + const [mainFontFamily, ...adjustFontFallbacks] = fontFamilies + // If fallback fonts were provided from the font loader, they should be used before the adjustFontFallbacks + const formattedFontFamilies = [ + mainFontFamily, + ...fallbackFonts, + ...adjustFontFallbacks, + ].join(', ') + // Add class with family, weight and style + const classRule = new postcss.Rule({ selector: '.className' }) + classRule.nodes = [ + new postcss.Declaration({ + prop: 'font-family', + value: formattedFontFamilies, + }), + ...(fontWeight + ? [ + new postcss.Declaration({ + prop: 'font-weight', + value: fontWeight, + }), + ] + : []), + ...(fontStyle + ? [ + new postcss.Declaration({ + prop: 'font-style', + value: fontStyle, + }), + ] + : []), + ] + root.nodes.push(classRule) + + // Add class that defines a variable with the font family + const varialbeRule = new postcss.Rule({ selector: '.variable' }) + varialbeRule.nodes = [ + new postcss.Declaration({ + prop: rawFamily + ? `--next-font-${rawFamily.toLowerCase().replace(/ /g, '-')}${ + fontWeight ? `-${fontWeight}` : '' + }${fontStyle === 'italic' ? `-${fontStyle}` : ''}` + : '', + value: formattedFontFamilies, + }), + ] + root.nodes.push(varialbeRule) + + // Export @font-face values as is + exports.push({ + name: 'style', + value: { + fontFamily: formattedFontFamilies, + fontWeight: fontWeight && Number(fontWeight), + fontStyle, + }, + }) + }, + } +} + +postcssFontLoaderPlugn.postcss = true + +export default postcssFontLoaderPlugn diff --git a/packages/next/build/webpack/plugins/font-loader-manifest-plugin.ts b/packages/next/build/webpack/plugins/font-loader-manifest-plugin.ts new file mode 100644 index 0000000000000..c68992af80e14 --- /dev/null +++ b/packages/next/build/webpack/plugins/font-loader-manifest-plugin.ts @@ -0,0 +1,62 @@ +import { webpack, sources } from 'next/dist/compiled/webpack/webpack' +import getRouteFromEntrypoint from '../../../server/get-route-from-entrypoint' +import { FONT_LOADER_MANIFEST } from '../../../shared/lib/constants' + +export type FontLoaderManifest = { + pages: { + [path: string]: string[] + } +} +const PLUGIN_NAME = 'FontLoaderManifestPlugin' + +// Creates a manifest of all fonts that should be preloaded given a route +export class FontLoaderManifestPlugin { + apply(compiler: webpack.Compiler) { + compiler.hooks.make.tap(PLUGIN_NAME, (compilation) => { + compilation.hooks.processAssets.tap( + { + name: PLUGIN_NAME, + stage: webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONS, + }, + (assets: any) => { + const fontLoaderManifest: FontLoaderManifest = { + pages: {}, + } + + for (const entrypoint of compilation.entrypoints.values()) { + const pagePath = getRouteFromEntrypoint(entrypoint.name!) + + if (!pagePath) { + continue + } + + const fontFiles: string[] = entrypoint.chunks + .flatMap((chunk: any) => [...chunk.auxiliaryFiles]) + .filter((file: string) => + /\.(woff|woff2|eot|ttf|otf)$/.test(file) + ) + + // Font files ending with .p.(woff|woff2|eot|ttf|otf) are preloaded + const preloadedFontFiles: string[] = fontFiles.filter( + (file: string) => /\.p.(woff|woff2|eot|ttf|otf)$/.test(file) + ) + + // Create an entry for the path even if no files should preload. If that's the case a preconnect tag is added. + if (fontFiles.length > 0) { + fontLoaderManifest.pages[pagePath] = preloadedFontFiles + } + } + + const manifest = JSON.stringify(fontLoaderManifest, null, 2) + assets[`server/${FONT_LOADER_MANIFEST}.js`] = new sources.RawSource( + `self.__FONT_LOADER_MANIFEST=${manifest}` + ) + assets[`server/${FONT_LOADER_MANIFEST}.json`] = new sources.RawSource( + manifest + ) + } + ) + }) + return + } +} diff --git a/packages/next/build/webpack/plugins/middleware-plugin.ts b/packages/next/build/webpack/plugins/middleware-plugin.ts index cee3db5e520e0..d87d9301b586a 100644 --- a/packages/next/build/webpack/plugins/middleware-plugin.ts +++ b/packages/next/build/webpack/plugins/middleware-plugin.ts @@ -19,6 +19,7 @@ import { NEXT_CLIENT_SSR_ENTRY_SUFFIX, FLIGHT_SERVER_CSS_MANIFEST, SUBRESOURCE_INTEGRITY_MANIFEST, + FONT_LOADER_MANIFEST, } from '../../../shared/lib/constants' import { getPageStaticInfo, @@ -85,7 +86,7 @@ function isUsingIndirectEvalAndUsedByExports(args: { function getEntryFiles( entryFiles: string[], meta: EntryMetadata, - opts: { sriEnabled: boolean } + opts: { sriEnabled: boolean; hasFontLoaders: boolean } ) { const files: string[] = [] if (meta.edgeSSR) { @@ -114,6 +115,10 @@ function getEntryFiles( `server/${MIDDLEWARE_BUILD_MANIFEST}.js`, `server/${MIDDLEWARE_REACT_LOADABLE_MANIFEST}.js` ) + + if (opts.hasFontLoaders) { + files.push(`server/${FONT_LOADER_MANIFEST}.js`) + } } files.push( @@ -127,7 +132,7 @@ function getEntryFiles( function getCreateAssets(params: { compilation: webpack.Compilation metadataByEntry: Map - opts: { sriEnabled: boolean } + opts: { sriEnabled: boolean; hasFontLoaders: boolean } }) { const { compilation, metadataByEntry, opts } = params return (assets: any) => { @@ -790,10 +795,20 @@ function getExtractMetadata(params: { export default class MiddlewarePlugin { private readonly dev: boolean private readonly sriEnabled: boolean - - constructor({ dev, sriEnabled }: { dev: boolean; sriEnabled: boolean }) { + private readonly hasFontLoaders: boolean + + constructor({ + dev, + sriEnabled, + hasFontLoaders, + }: { + dev: boolean + sriEnabled: boolean + hasFontLoaders: boolean + }) { this.dev = dev this.sriEnabled = sriEnabled + this.hasFontLoaders = hasFontLoaders } public apply(compiler: webpack.Compiler) { @@ -836,7 +851,10 @@ export default class MiddlewarePlugin { getCreateAssets({ compilation, metadataByEntry, - opts: { sriEnabled: this.sriEnabled }, + opts: { + sriEnabled: this.sriEnabled, + hasFontLoaders: this.hasFontLoaders, + }, }) ) }) diff --git a/packages/next/export/index.ts b/packages/next/export/index.ts index 8a5d48ab17a69..0106566a967cf 100644 --- a/packages/next/export/index.ts +++ b/packages/next/export/index.ts @@ -24,6 +24,7 @@ import { EXPORT_MARKER, FLIGHT_MANIFEST, FLIGHT_SERVER_CSS_MANIFEST, + FONT_LOADER_MANIFEST, PAGES_MANIFEST, PHASE_EXPORT, PRERENDER_MANIFEST, @@ -389,6 +390,9 @@ export default async function exportApp( optimizeFonts: nextConfig.optimizeFonts as FontConfig, largePageDataBytes: nextConfig.experimental.largePageDataBytes, serverComponents: !!nextConfig.experimental.appDir, + fontLoaderManifest: nextConfig.experimental.fontLoaders + ? require(join(distDir, 'server', `${FONT_LOADER_MANIFEST}.json`)) + : undefined, } const { serverRuntimeConfig, publicRuntimeConfig } = nextConfig diff --git a/packages/next/pages/_document.tsx b/packages/next/pages/_document.tsx index 26564e04cc50b..0733e5e077a17 100644 --- a/packages/next/pages/_document.tsx +++ b/packages/next/pages/_document.tsx @@ -11,6 +11,7 @@ import type { NEXT_DATA, } from '../shared/lib/utils' import type { ScriptProps } from '../client/script' +import type { FontLoaderManifest } from '../build/webpack/plugins/font-loader-manifest-plugin' import { BuildManifest, getPageFiles } from '../server/get-page-files' import { htmlEscapeJsonString } from '../server/htmlescape' @@ -353,6 +354,54 @@ function getAmpPath(ampPath: string, asPath: string): string { return ampPath || `${asPath}${asPath.includes('?') ? '&' : '?'}amp=1` } +function getFontLoaderLinks( + fontLoaderManifest: FontLoaderManifest | undefined, + dangerousAsPath: string, + assetPrefix: string = '' +) { + if (!fontLoaderManifest) { + return { + preconnect: null, + preload: null, + } + } + + const appFontsEntry = fontLoaderManifest.pages['/_app'] + const pageFontsEntry = fontLoaderManifest.pages[dangerousAsPath] + + const preloadedFontFiles = [ + ...(appFontsEntry ?? []), + ...(pageFontsEntry ?? []), + ] + + // If no font files should preload but there's an entry for the path, add a preconnect tag. + const preconnectToSelf = !!( + preloadedFontFiles.length === 0 && + (appFontsEntry || pageFontsEntry) + ) + + return { + preconnect: preconnectToSelf ? ( + + ) : null, + preload: preloadedFontFiles + ? preloadedFontFiles.map((fontFile) => { + const ext = /\.(woff|woff2|eot|ttf|otf)$/.exec(fontFile)![1] + return ( + + ) + }) + : null, + } +} + // Use `React.Component` to avoid errors from the RSC checks because // it can't be imported directly in Server Components: // @@ -608,6 +657,8 @@ export class Head extends React.Component { disableOptimizedLoading, optimizeCss, optimizeFonts, + assetPrefix, + fontLoaderManifest, } = this.context const disableRuntimeJS = unstable_runtimeJS === false @@ -722,6 +773,12 @@ export class Head extends React.Component { process.env.NEXT_RUNTIME !== 'edge' && inAmpMode ) + const fontLoaderLinks = getFontLoaderLinks( + fontLoaderManifest, + dangerousAsPath, + assetPrefix + ) + return ( {this.context.isDevelopment && ( @@ -762,6 +819,9 @@ export class Head extends React.Component { {children} {optimizeFonts && } + {fontLoaderLinks.preconnect} + {fontLoaderLinks.preload} + {process.env.NEXT_RUNTIME !== 'edge' && inAmpMode && ( <> { supportsDynamicHTML?: boolean serverComponentManifest?: any serverCSSManifest?: any + fontLoaderManifest?: FontLoaderManifest renderServerComponentData?: boolean serverComponentProps?: any largePageDataBytes?: number @@ -230,6 +232,7 @@ export default abstract class Server { protected customRoutes: CustomRoutes protected serverComponentManifest?: any protected serverCSSManifest?: any + protected fontLoaderManifest?: FontLoaderManifest public readonly hostname?: string public readonly port?: number @@ -252,6 +255,7 @@ export default abstract class Server { protected abstract getPrerenderManifest(): PrerenderManifest protected abstract getServerComponentManifest(): any protected abstract getServerCSSManifest(): any + protected abstract getFontLoaderManifest(): FontLoaderManifest | undefined protected abstract attachRequestMeta( req: BaseNextRequest, parsedUrl: NextUrlWithParsedQuery @@ -370,6 +374,9 @@ export default abstract class Server { this.serverCSSManifest = serverComponents ? this.getServerCSSManifest() : undefined + this.fontLoaderManifest = this.nextConfig.experimental.fontLoaders + ? this.getFontLoaderManifest() + : undefined this.renderOpts = { poweredByHeader: this.nextConfig.poweredByHeader, diff --git a/packages/next/server/config-schema.ts b/packages/next/server/config-schema.ts index 1592d0624e8a8..f330036276f68 100644 --- a/packages/next/server/config-schema.ts +++ b/packages/next/server/config-schema.ts @@ -387,6 +387,9 @@ const configSchema = { workerThreads: { type: 'boolean', }, + fontLoaders: { + type: 'object', + }, }, type: 'object', }, diff --git a/packages/next/server/config-shared.ts b/packages/next/server/config-shared.ts index d0612a7d4fb35..0ae07ad1ecdcf 100644 --- a/packages/next/server/config-shared.ts +++ b/packages/next/server/config-shared.ts @@ -150,6 +150,7 @@ export interface ExperimentalConfig { algorithm?: SubresourceIntegrityAlgorithm } adjustFontFallbacks?: boolean + fontLoaders?: { [fontLoader: string]: any } } export type ExportPathMap = { diff --git a/packages/next/server/dev/next-dev-server.ts b/packages/next/server/dev/next-dev-server.ts index 9128481ca70b2..cea2e139c78ba 100644 --- a/packages/next/server/dev/next-dev-server.ts +++ b/packages/next/server/dev/next-dev-server.ts @@ -1126,6 +1126,10 @@ export default class DevServer extends Server { return undefined } + protected getFontLoaderManifest() { + return undefined + } + protected async hasMiddleware(): Promise { return this.hasPage(this.actualMiddlewareFile!) } @@ -1353,6 +1357,7 @@ export default class DevServer extends Server { this.serverComponentManifest = super.getServerComponentManifest() this.serverCSSManifest = super.getServerCSSManifest() } + this.fontLoaderManifest = super.getFontLoaderManifest() return super.findPageComponents({ pathname, query, params, isAppPath }) } catch (err) { diff --git a/packages/next/server/next-server.ts b/packages/next/server/next-server.ts index 3a077b90aa16e..e04669a71dab9 100644 --- a/packages/next/server/next-server.ts +++ b/packages/next/server/next-server.ts @@ -45,6 +45,7 @@ import { FLIGHT_SERVER_CSS_MANIFEST, SERVERLESS_DIRECTORY, SERVER_DIRECTORY, + FONT_LOADER_MANIFEST, } from '../shared/lib/constants' import { recursiveReadDirSync } from './lib/recursive-readdir-sync' import { format as formatUrl, UrlWithParsedQuery } from 'url' @@ -524,7 +525,8 @@ export default class NextNodeServer extends BaseServer { params.path[0] === 'media' || params.path[0] === this.buildId || params.path[0] === 'pages' || - params.path[1] === 'pages' + params.path[1] === 'pages' || + params.path[0] === 'fonts' ) { this.setImmutableAssetCacheControl(res) } @@ -822,6 +824,7 @@ export default class NextNodeServer extends BaseServer { // https://github.com/vercel/next.js/blob/df7cbd904c3bd85f399d1ce90680c0ecf92d2752/packages/next/server/render.tsx#L947-L952 renderOpts.serverComponentManifest = this.serverComponentManifest renderOpts.serverCSSManifest = this.serverCSSManifest + renderOpts.fontLoaderManifest = this.fontLoaderManifest if ( this.nextConfig.experimental.appDir && @@ -1016,6 +1019,11 @@ export default class NextNodeServer extends BaseServer { )) } + protected getFontLoaderManifest() { + if (!this.nextConfig.experimental.fontLoaders) return undefined + return require(join(this.distDir, 'server', `${FONT_LOADER_MANIFEST}.json`)) + } + protected getFallback(page: string): Promise { page = normalizePagePath(page) const cacheFs = this.getCacheFilesystem() diff --git a/packages/next/server/render.tsx b/packages/next/server/render.tsx index 304167ef843d8..5e5a0a8aed862 100644 --- a/packages/next/server/render.tsx +++ b/packages/next/server/render.tsx @@ -26,6 +26,7 @@ import type { } from 'next/types' import type { UnwrapPromise } from '../lib/coalesced-function' import type { ReactReadableStream } from './node-web-streams-helper' +import type { FontLoaderManifest } from '../build/webpack/plugins/font-loader-manifest-plugin' import React from 'react' import { StyleRegistry, createStyleRegistry } from 'styled-jsx' @@ -232,6 +233,7 @@ export type RenderOptsPartial = { resolvedAsPath?: string serverComponentManifest?: any serverCSSManifest?: any + fontLoaderManifest?: FontLoaderManifest distDir?: string locale?: string locales?: string[] @@ -1446,6 +1448,7 @@ export async function renderToHTML( nextScriptWorkers: renderOpts.nextScriptWorkers, runtime: globalRuntime, largePageDataBytes: renderOpts.largePageDataBytes, + fontLoaderManifest: renderOpts.fontLoaderManifest, } const document = ( diff --git a/packages/next/server/web-server.ts b/packages/next/server/web-server.ts index 2326ec5bf8136..77fe205d393d0 100644 --- a/packages/next/server/web-server.ts +++ b/packages/next/server/web-server.ts @@ -131,6 +131,11 @@ export default class NextWebServer extends BaseServer { return this.serverOptions.webServerConfig.extendRenderOpts.serverCSSManifest } + protected getFontLoaderManifest() { + return this.serverOptions.webServerConfig.extendRenderOpts + .fontLoaderManifest + } + protected generateRoutes(): { headers: Route[] rewrites: { diff --git a/packages/next/shared/lib/constants.ts b/packages/next/shared/lib/constants.ts index fe527c83685e7..e9c43bdd4cf36 100644 --- a/packages/next/shared/lib/constants.ts +++ b/packages/next/shared/lib/constants.ts @@ -27,6 +27,7 @@ export const APP_PATH_ROUTES_MANIFEST = 'app-path-routes-manifest.json' export const BUILD_MANIFEST = 'build-manifest.json' export const APP_BUILD_MANIFEST = 'app-build-manifest.json' export const SUBRESOURCE_INTEGRITY_MANIFEST = 'subresource-integrity-manifest' +export const FONT_LOADER_MANIFEST = 'font-loader-manifest' export const EXPORT_MARKER = 'export-marker.json' export const EXPORT_DETAIL = 'export-detail.json' export const PRERENDER_MANIFEST = 'prerender-manifest.json' diff --git a/packages/next/shared/lib/html-context.ts b/packages/next/shared/lib/html-context.ts index 57b08a6972533..254db0636cf4b 100644 --- a/packages/next/shared/lib/html-context.ts +++ b/packages/next/shared/lib/html-context.ts @@ -2,6 +2,7 @@ import type { BuildManifest } from '../../server/get-page-files' import type { ServerRuntime } from 'next/types' import type { NEXT_DATA } from './utils' import type { FontConfig } from '../../server/font-utils' +import type { FontLoaderManifest } from '../../build/webpack/plugins/font-loader-manifest-plugin' import { createContext } from 'react' @@ -42,6 +43,7 @@ export type HtmlProps = { runtime?: ServerRuntime hasConcurrentFeatures?: boolean largePageDataBytes?: number + fontLoaderManifest?: FontLoaderManifest } export const HtmlContext = createContext(null as any) diff --git a/test/development/next-font/font-loader-in-document-error.test.ts b/test/development/next-font/font-loader-in-document-error.test.ts new file mode 100644 index 0000000000000..403da95bd1d58 --- /dev/null +++ b/test/development/next-font/font-loader-in-document-error.test.ts @@ -0,0 +1,32 @@ +import { createNext, FileRef } from 'e2e-utils' +import { NextInstance } from 'test/lib/next-modes/base' +import { check, getRedboxSource } from 'next-test-utils' +import webdriver from 'next-webdriver' +import { join } from 'path' + +describe('font-loader-in-document-error', () => { + let next: NextInstance + + beforeAll(async () => { + next = await createNext({ + files: { + pages: new FileRef(join(__dirname, 'font-loader-in-document/pages')), + 'next.config.js': new FileRef( + join(__dirname, 'font-loader-in-document/next.config.js') + ), + }, + dependencies: { + '@next/font': 'canary', + }, + }) + }) + afterAll(() => next.destroy()) + + test('font loader inside _document', async () => { + const browser = await webdriver(next.appPort, '/') + await check(() => getRedboxSource(browser), /Font loaders/) + expect(await getRedboxSource(browser)).toInclude( + 'Font loaders cannot be used within pages/_document.js' + ) + }) +}) diff --git a/test/development/next-font/font-loader-in-document/next.config.js b/test/development/next-font/font-loader-in-document/next.config.js new file mode 100644 index 0000000000000..6cd855478a746 --- /dev/null +++ b/test/development/next-font/font-loader-in-document/next.config.js @@ -0,0 +1,9 @@ +module.exports = { + experimental: { + fontLoaders: { + '@next/font/google': { + subsets: ['latin'], + }, + }, + }, +} diff --git a/test/development/next-font/font-loader-in-document/pages/_document.js b/test/development/next-font/font-loader-in-document/pages/_document.js new file mode 100644 index 0000000000000..4e50cbee8c11e --- /dev/null +++ b/test/development/next-font/font-loader-in-document/pages/_document.js @@ -0,0 +1,17 @@ +import { Html, Head, Main, NextScript } from 'next/document' +import { Abel } from '@next/font/google' + +// eslint-disable-next-line no-unused-vars +const abel = Abel({ variant: '400' }) + +export default function Document() { + return ( + + + +
+ + + + ) +} diff --git a/test/development/next-font/font-loader-in-document/pages/index.js b/test/development/next-font/font-loader-in-document/pages/index.js new file mode 100644 index 0000000000000..71c4bddbe5455 --- /dev/null +++ b/test/development/next-font/font-loader-in-document/pages/index.js @@ -0,0 +1,3 @@ +export default function Index() { + return

Hello world

+} diff --git a/test/e2e/next-font/app/components/CompWithFonts.js b/test/e2e/next-font/app/components/CompWithFonts.js new file mode 100644 index 0000000000000..f82d59672c9a2 --- /dev/null +++ b/test/e2e/next-font/app/components/CompWithFonts.js @@ -0,0 +1,20 @@ +import { Inter, Roboto } from '@next/font/google' +const inter = Inter({ variant: '900', display: 'swap', preload: false }) +const roboto = Roboto({ + variant: '100-italic', + display: 'swap', + preload: true, +}) + +export default function Component() { + return ( + <> +
+ {JSON.stringify(inter)} +
+
+ {JSON.stringify(roboto)} +
+ + ) +} diff --git a/test/e2e/next-font/app/next.config.js b/test/e2e/next-font/app/next.config.js new file mode 100644 index 0000000000000..6cd855478a746 --- /dev/null +++ b/test/e2e/next-font/app/next.config.js @@ -0,0 +1,9 @@ +module.exports = { + experimental: { + fontLoaders: { + '@next/font/google': { + subsets: ['latin'], + }, + }, + }, +} diff --git a/test/e2e/next-font/app/pages/_app.js b/test/e2e/next-font/app/pages/_app.js new file mode 100644 index 0000000000000..1deef62049a1c --- /dev/null +++ b/test/e2e/next-font/app/pages/_app.js @@ -0,0 +1,16 @@ +import { Open_Sans } from '@next/font/google' +const openSans = Open_Sans() + +function MyApp({ Component, pageProps }) { + return ( + <> +
+ {JSON.stringify(openSans)} +
+ + + ) +} + +export { openSans } +export default MyApp diff --git a/test/e2e/next-font/app/pages/variables.js b/test/e2e/next-font/app/pages/variables.js new file mode 100644 index 0000000000000..ce3649496d1e3 --- /dev/null +++ b/test/e2e/next-font/app/pages/variables.js @@ -0,0 +1,78 @@ +import { Fira_Code, Albert_Sans, Inter, Roboto } from '@next/font/google' +const firaCode = Fira_Code() +const albertSans = Albert_Sans({ + variant: 'variable-italic', + adjustFontFallback: false, +}) +const inter = Inter({ variant: '900', display: 'swap' }) // Don't preload by default when swap +const roboto = Roboto({ + variant: '100-italic', + display: 'swap', + preload: true, +}) + +export default function WithFonts() { + return ( + <> + {/* Fira Code Variable */} +
+ With variables +
+
+ Without variables +
+ + {/* Albert Sant Variable Italic */} +
+ With variables +
+
+ Without variables +
+ + {/* Inter 900 */} +
+ With variables +
+
+ Without variables +
+ + {/* Roboto 100 Italic */} +
+ With variables +
+
+ Without variables +
+ + ) +} diff --git a/test/e2e/next-font/app/pages/with-fallback.js b/test/e2e/next-font/app/pages/with-fallback.js new file mode 100644 index 0000000000000..587452fb45fd8 --- /dev/null +++ b/test/e2e/next-font/app/pages/with-fallback.js @@ -0,0 +1,22 @@ +import { Open_Sans } from '@next/font/google' +const openSans = Open_Sans({ fallback: ['system-ui', 'Arial'] }) + +export default function WithFonts() { + return ( + <> +
+ {JSON.stringify(openSans)} +
+
+ {JSON.stringify(openSans)} +
+
+ {JSON.stringify(openSans)} +
+ + ) +} diff --git a/test/e2e/next-font/app/pages/with-fonts.js b/test/e2e/next-font/app/pages/with-fonts.js new file mode 100644 index 0000000000000..13dbe3e46bf9f --- /dev/null +++ b/test/e2e/next-font/app/pages/with-fonts.js @@ -0,0 +1,14 @@ +import CompWithFonts from '../components/CompWithFonts' +import { openSans } from './_app' + +export default function WithFonts() { + return ( + <> + +
+ {JSON.stringify(openSans)} +
+
+ + ) +} diff --git a/test/e2e/next-font/app/pages/without-fonts.js b/test/e2e/next-font/app/pages/without-fonts.js new file mode 100644 index 0000000000000..0f649722e671d --- /dev/null +++ b/test/e2e/next-font/app/pages/without-fonts.js @@ -0,0 +1,3 @@ +export default function WithoutFonts() { + return

Hello world

+} diff --git a/test/e2e/next-font/basepath.test.ts b/test/e2e/next-font/basepath.test.ts new file mode 100644 index 0000000000000..0b6d242fc138a --- /dev/null +++ b/test/e2e/next-font/basepath.test.ts @@ -0,0 +1,54 @@ +import cheerio from 'cheerio' +import { createNext, FileRef } from 'e2e-utils' +import { NextInstance } from 'test/lib/next-modes/base' +import { renderViaHTTP } from 'next-test-utils' +import { join } from 'path' + +const mockedGoogleFontResponses = require.resolve( + './google-font-mocked-responses.js' +) + +describe('@next/font/google basepath', () => { + let next: NextInstance + + if ((global as any).isNextDeploy) { + it('should skip next deploy for now', () => {}) + return + } + + beforeAll(async () => { + next = await createNext({ + files: { + pages: new FileRef(join(__dirname, 'basepath/pages')), + 'next.config.js': new FileRef( + join(__dirname, 'basepath/next.config.js') + ), + }, + dependencies: { + '@next/font': 'canary', + }, + env: { + NEXT_FONT_GOOGLE_MOCKED_RESPONSES: mockedGoogleFontResponses, + }, + }) + }) + afterAll(() => next.destroy()) + + test('preload correct files', async () => { + const html = await renderViaHTTP(next.url, '/dashboard') + const $ = cheerio.load(html) + + // Preconnect + expect($('link[rel="preconnect"]').length).toBe(0) + + // Preload + expect($('link[as="font"]').length).toBe(1) + expect($('link[as="font"]').get(0).attribs).toEqual({ + as: 'font', + crossorigin: 'anonymous', + href: '/dashboard/_next/static/fonts/0812efcfaefec5ea.p.woff2', + rel: 'preload', + type: 'font/woff2', + }) + }) +}) diff --git a/test/e2e/next-font/basepath/next.config.js b/test/e2e/next-font/basepath/next.config.js new file mode 100644 index 0000000000000..8509832e4b888 --- /dev/null +++ b/test/e2e/next-font/basepath/next.config.js @@ -0,0 +1,10 @@ +module.exports = { + basePath: '/dashboard', + experimental: { + fontLoaders: { + '@next/font/google': { + subsets: ['latin'], + }, + }, + }, +} diff --git a/test/e2e/next-font/basepath/pages/index.js b/test/e2e/next-font/basepath/pages/index.js new file mode 100644 index 0000000000000..02056b6f303d3 --- /dev/null +++ b/test/e2e/next-font/basepath/pages/index.js @@ -0,0 +1,6 @@ +import { Open_Sans } from '@next/font/google' +const openSans = Open_Sans() + +export default function Inter() { + return

Hello world

+} diff --git a/test/e2e/next-font/google-font-mocked-responses.js b/test/e2e/next-font/google-font-mocked-responses.js new file mode 100644 index 0000000000000..732813f2401c2 --- /dev/null +++ b/test/e2e/next-font/google-font-mocked-responses.js @@ -0,0 +1,496 @@ +module.exports = { + 'https://fonts.googleapis.com/css2?family=Open+Sans:wght@300..800&display=optional': ` +/* cyrillic-ext */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 300 800; + font-stretch: 100%; + font-display: optional; + src: url(https://fonts.gstatic.com/s/opensans/v34/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSKmu0SC55K5gw.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 300 800; + font-stretch: 100%; + font-display: optional; + src: url(https://fonts.gstatic.com/s/opensans/v34/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSumu0SC55K5gw.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 300 800; + font-stretch: 100%; + font-display: optional; + src: url(https://fonts.gstatic.com/s/opensans/v34/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSOmu0SC55K5gw.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 300 800; + font-stretch: 100%; + font-display: optional; + src: url(https://fonts.gstatic.com/s/opensans/v34/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSymu0SC55K5gw.woff2) format('woff2'); + unicode-range: U+0370-03FF; +} +/* hebrew */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 300 800; + font-stretch: 100%; + font-display: optional; + src: url(https://fonts.gstatic.com/s/opensans/v34/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTS2mu0SC55K5gw.woff2) format('woff2'); + unicode-range: U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F; +} +/* vietnamese */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 300 800; + font-stretch: 100%; + font-display: optional; + src: url(https://fonts.gstatic.com/s/opensans/v34/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSCmu0SC55K5gw.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 300 800; + font-stretch: 100%; + font-display: optional; + src: url(https://fonts.gstatic.com/s/opensans/v34/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSGmu0SC55K5gw.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 300 800; + font-stretch: 100%; + font-display: optional; + src: url(https://fonts.gstatic.com/s/opensans/v34/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTS-mu0SC55I.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} + `, + 'https://fonts.googleapis.com/css2?family=Inter:wght@900&display=swap': ` + /* cyrillic-ext */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 900; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v12/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuBWYAZJhiJ-Ek-_EeAmM.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 900; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v12/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuBWYAZthiJ-Ek-_EeAmM.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 900; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v12/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuBWYAZNhiJ-Ek-_EeAmM.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 900; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v12/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuBWYAZxhiJ-Ek-_EeAmM.woff2) format('woff2'); + unicode-range: U+0370-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 900; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v12/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuBWYAZBhiJ-Ek-_EeAmM.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 900; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v12/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuBWYAZFhiJ-Ek-_EeAmM.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 900; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v12/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuBWYAZ9hiJ-Ek-_EeA.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} + `, + 'https://fonts.googleapis.com/css2?family=Roboto:ital,wght@1,100&display=swap': ` + /* cyrillic-ext */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 100; + font-display: swap; + src: url(https://fonts.gstatic.com/s/roboto/v30/KFOiCnqEu92Fr1Mu51QrEz0dL-vwnYh2eg.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 100; + font-display: swap; + src: url(https://fonts.gstatic.com/s/roboto/v30/KFOiCnqEu92Fr1Mu51QrEzQdL-vwnYh2eg.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 100; + font-display: swap; + src: url(https://fonts.gstatic.com/s/roboto/v30/KFOiCnqEu92Fr1Mu51QrEzwdL-vwnYh2eg.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 100; + font-display: swap; + src: url(https://fonts.gstatic.com/s/roboto/v30/KFOiCnqEu92Fr1Mu51QrEzMdL-vwnYh2eg.woff2) format('woff2'); + unicode-range: U+0370-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 100; + font-display: swap; + src: url(https://fonts.gstatic.com/s/roboto/v30/KFOiCnqEu92Fr1Mu51QrEz8dL-vwnYh2eg.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 100; + font-display: swap; + src: url(https://fonts.gstatic.com/s/roboto/v30/KFOiCnqEu92Fr1Mu51QrEz4dL-vwnYh2eg.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 100; + font-display: swap; + src: url(https://fonts.gstatic.com/s/roboto/v30/KFOiCnqEu92Fr1Mu51QrEzAdL-vwnYg.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} + `, + 'https://fonts.googleapis.com/css2?family=Roboto:wght@400&display=optional': ` + /* cyrillic-ext */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + font-display: optional; + src: url(https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu72xKKTU1Kvnz.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + font-display: optional; + src: url(https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu5mxKKTU1Kvnz.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + font-display: optional; + src: url(https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu7mxKKTU1Kvnz.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + font-display: optional; + src: url(https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu4WxKKTU1Kvnz.woff2) format('woff2'); + unicode-range: U+0370-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + font-display: optional; + src: url(https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu7WxKKTU1Kvnz.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + font-display: optional; + src: url(https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu7GxKKTU1Kvnz.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + font-display: optional; + src: url(https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu4mxKKTU1Kg.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} + `, + 'https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=block': ` + /* cyrillic-ext */ + @font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 100 900; + font-display: block; + src: url(https://fonts.gstatic.com/s/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2JL7W0Q5n-wU.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; + } + /* cyrillic */ + @font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 100 900; + font-display: block; + src: url(https://fonts.gstatic.com/s/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa0ZL7W0Q5n-wU.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; + } + /* greek-ext */ + @font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 100 900; + font-display: block; + src: url(https://fonts.gstatic.com/s/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2ZL7W0Q5n-wU.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; + } + /* greek */ + @font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 100 900; + font-display: block; + src: url(https://fonts.gstatic.com/s/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1pL7W0Q5n-wU.woff2) format('woff2'); + unicode-range: U+0370-03FF; + } + /* vietnamese */ + @font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 100 900; + font-display: block; + src: url(https://fonts.gstatic.com/s/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2pL7W0Q5n-wU.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; + } + /* latin-ext */ + @font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 100 900; + font-display: block; + src: url(https://fonts.gstatic.com/s/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa25L7W0Q5n-wU.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; + } + /* latin */ + @font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 100 900; + font-display: block; + src: url(https://fonts.gstatic.com/s/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1ZL7W0Q5nw.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; + } + `, + 'https://fonts.googleapis.com/css2?family=Source+Code+Pro:wght@200..900&display=swap': ` + /* cyrillic-ext */ +@font-face { + font-family: 'Source Code Pro'; + font-style: normal; + font-weight: 200 900; + font-display: swap; + src: url(https://fonts.gstatic.com/s/sourcecodepro/v22/HI_SiYsKILxRpg3hIP6sJ7fM7PqlMOvWnsUnxlC9.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Source Code Pro'; + font-style: normal; + font-weight: 200 900; + font-display: swap; + src: url(https://fonts.gstatic.com/s/sourcecodepro/v22/HI_SiYsKILxRpg3hIP6sJ7fM7PqlOevWnsUnxlC9.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Source Code Pro'; + font-style: normal; + font-weight: 200 900; + font-display: swap; + src: url(https://fonts.gstatic.com/s/sourcecodepro/v22/HI_SiYsKILxRpg3hIP6sJ7fM7PqlMevWnsUnxlC9.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Source Code Pro'; + font-style: normal; + font-weight: 200 900; + font-display: swap; + src: url(https://fonts.gstatic.com/s/sourcecodepro/v22/HI_SiYsKILxRpg3hIP6sJ7fM7PqlPuvWnsUnxlC9.woff2) format('woff2'); + unicode-range: U+0370-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Source Code Pro'; + font-style: normal; + font-weight: 200 900; + font-display: swap; + src: url(https://fonts.gstatic.com/s/sourcecodepro/v22/HI_SiYsKILxRpg3hIP6sJ7fM7PqlMuvWnsUnxlC9.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Source Code Pro'; + font-style: normal; + font-weight: 200 900; + font-display: swap; + src: url(https://fonts.gstatic.com/s/sourcecodepro/v22/HI_SiYsKILxRpg3hIP6sJ7fM7PqlM-vWnsUnxlC9.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Source Code Pro'; + font-style: normal; + font-weight: 200 900; + font-display: swap; + src: url(https://fonts.gstatic.com/s/sourcecodepro/v22/HI_SiYsKILxRpg3hIP6sJ7fM7PqlPevWnsUnxg.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} + `, + 'https://fonts.googleapis.com/css2?family=Abel:wght@400&display=optional': ` + /* latin */ +@font-face { + font-family: 'Abel'; + font-style: normal; + font-weight: 400; + font-display: optional; + src: url(https://fonts.gstatic.com/s/abel/v18/MwQ5bhbm2POE2V9BPbh5uGM.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} + `, + 'https://fonts.googleapis.com/css2?family=Fira+Code:wght@300..700&display=optional': ` + /* cyrillic-ext */ +@font-face { + font-family: 'Fira Code'; + font-style: normal; + font-weight: 300 700; + font-display: optional; + src: url(https://fonts.gstatic.com/s/firacode/v21/uU9NCBsR6Z2vfE9aq3bh0NSDqFGedCMX.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Fira Code'; + font-style: normal; + font-weight: 300 700; + font-display: optional; + src: url(https://fonts.gstatic.com/s/firacode/v21/uU9NCBsR6Z2vfE9aq3bh2dSDqFGedCMX.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Fira Code'; + font-style: normal; + font-weight: 300 700; + font-display: optional; + src: url(https://fonts.gstatic.com/s/firacode/v21/uU9NCBsR6Z2vfE9aq3bh0dSDqFGedCMX.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Fira Code'; + font-style: normal; + font-weight: 300 700; + font-display: optional; + src: url(https://fonts.gstatic.com/s/firacode/v21/uU9NCBsR6Z2vfE9aq3bh3tSDqFGedCMX.woff2) format('woff2'); + unicode-range: U+0370-03FF; +} +/* latin-ext */ +@font-face { + font-family: 'Fira Code'; + font-style: normal; + font-weight: 300 700; + font-display: optional; + src: url(https://fonts.gstatic.com/s/firacode/v21/uU9NCBsR6Z2vfE9aq3bh09SDqFGedCMX.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Fira Code'; + font-style: normal; + font-weight: 300 700; + font-display: optional; + src: url(https://fonts.gstatic.com/s/firacode/v21/uU9NCBsR6Z2vfE9aq3bh3dSDqFGedA.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} + `, + 'https://fonts.googleapis.com/css2?family=Albert+Sans:ital,wght@1,100..900&display=optional': ` + /* latin-ext */ +@font-face { + font-family: 'Albert Sans'; + font-style: italic; + font-weight: 100 900; + font-display: optional; + src: url(https://fonts.gstatic.com/s/albertsans/v1/i7dMIFdwYjGaAMFtZd_QA1ZeUFuaHi6WZ3S_Yg.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Albert Sans'; + font-style: italic; + font-weight: 100 900; + font-display: optional; + src: url(https://fonts.gstatic.com/s/albertsans/v1/i7dMIFdwYjGaAMFtZd_QA1ZeUFWaHi6WZ3Q.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} + `, +} diff --git a/test/e2e/next-font/index.test.ts b/test/e2e/next-font/index.test.ts new file mode 100644 index 0000000000000..aed14be9eb00e --- /dev/null +++ b/test/e2e/next-font/index.test.ts @@ -0,0 +1,294 @@ +import cheerio from 'cheerio' +import { createNext, FileRef } from 'e2e-utils' +import { NextInstance } from 'test/lib/next-modes/base' +import { renderViaHTTP } from 'next-test-utils' +import { join } from 'path' +import webdriver from 'next-webdriver' + +const mockedGoogleFontResponses = require.resolve( + './google-font-mocked-responses.js' +) + +describe('@next/font/google', () => { + let next: NextInstance + + if ((global as any).isNextDeploy) { + it('should skip next deploy for now', () => {}) + return + } + + beforeAll(async () => { + next = await createNext({ + files: { + pages: new FileRef(join(__dirname, 'app/pages')), + components: new FileRef(join(__dirname, 'app/components')), + 'next.config.js': new FileRef(join(__dirname, 'app/next.config.js')), + }, + dependencies: { + '@next/font': 'canary', + }, + env: { + NEXT_FONT_GOOGLE_MOCKED_RESPONSES: mockedGoogleFontResponses, + }, + }) + }) + afterAll(() => next.destroy()) + + describe('import values', () => { + test('page with font', async () => { + const html = await renderViaHTTP(next.url, '/with-fonts') + const $ = cheerio.load(html) + + // _app.js + expect(JSON.parse($('#app-open-sans').text())).toEqual({ + className: '__className_bbc724', + variable: '__variable_bbc724', + style: { + fontFamily: "'__Open_Sans_bbc724', '__open-sans-fallback_bbc724'", + fontStyle: 'normal', + }, + }) + + // with-fonts.js + expect(JSON.parse($('#with-fonts-open-sans').text())).toEqual({ + className: '__className_bbc724', + variable: '__variable_bbc724', + style: { + fontFamily: "'__Open_Sans_bbc724', '__open-sans-fallback_bbc724'", + fontStyle: 'normal', + }, + }) + + // CompWithFonts.js + expect(JSON.parse($('#comp-with-fonts-inter').text())).toEqual({ + className: '__className_17e98a', + variable: '__variable_17e98a', + style: { + fontFamily: "'__Inter_17e98a', '__inter-fallback_17e98a'", + fontStyle: 'normal', + fontWeight: 900, + }, + }) + expect(JSON.parse($('#comp-with-fonts-roboto').text())).toEqual({ + className: '__className_72084b', + variable: '__variable_72084b', + style: { + fontFamily: "'__Roboto_72084b', '__roboto-fallback_72084b'", + fontStyle: 'italic', + fontWeight: 100, + }, + }) + }) + }) + + describe('computed styles', () => { + test('page with fonts', async () => { + const browser = await webdriver(next.url, '/with-fonts') + + // _app.js + expect( + await browser.eval( + 'getComputedStyle(document.querySelector("#app-open-sans")).fontFamily' + ) + ).toBe('__Open_Sans_bbc724, __open-sans-fallback_bbc724') + expect( + await browser.eval( + 'getComputedStyle(document.querySelector("#app-open-sans")).fontWeight' + ) + ).toBe('400') + expect( + await browser.eval( + 'getComputedStyle(document.querySelector("#app-open-sans")).fontStyle' + ) + ).toBe('normal') + + // with-fonts.js + expect( + await browser.eval( + 'getComputedStyle(document.querySelector("#with-fonts-open-sans")).fontFamily' + ) + ).toBe('__Open_Sans_bbc724, __open-sans-fallback_bbc724') + expect( + await browser.eval( + 'getComputedStyle(document.querySelector("#with-fonts-open-sans")).fontWeight' + ) + ).toBe('400') + expect( + await browser.eval( + 'getComputedStyle(document.querySelector("#with-fonts-open-sans")).fontStyle' + ) + ).toBe('normal') + expect( + await browser.eval( + 'getComputedStyle(document.querySelector("#with-fonts-open-sans-style")).fontWeight' + ) + ).toBe('400') + expect( + await browser.eval( + 'getComputedStyle(document.querySelector("#with-fonts-open-sans-style")).fontStyle' + ) + ).toBe('normal') + + // CompWithFonts.js + expect( + await browser.eval( + 'getComputedStyle(document.querySelector("#comp-with-fonts-inter")).fontFamily' + ) + ).toBe('__Inter_17e98a, __inter-fallback_17e98a') + expect( + await browser.eval( + 'getComputedStyle(document.querySelector("#comp-with-fonts-inter")).fontWeight' + ) + ).toBe('900') + expect( + await browser.eval( + 'getComputedStyle(document.querySelector("#comp-with-fonts-inter")).fontStyle' + ) + ).toBe('normal') + + expect( + await browser.eval( + 'getComputedStyle(document.querySelector("#comp-with-fonts-roboto")).fontFamily' + ) + ).toBe('__Roboto_72084b, __roboto-fallback_72084b') + expect( + await browser.eval( + 'getComputedStyle(document.querySelector("#comp-with-fonts-roboto")).fontWeight' + ) + ).toBe('100') + expect( + await browser.eval( + 'getComputedStyle(document.querySelector("#comp-with-fonts-roboto")).fontStyle' + ) + ).toBe('italic') + }) + + test('page using variables', async () => { + const browser = await webdriver(next.url, '/variables') + + // Fira Code Variable + expect( + await browser.eval( + 'getComputedStyle(document.querySelector("#variables-fira-code")).fontFamily' + ) + ).toBe('__Fira_Code_a1dc08, __fira-code-fallback_a1dc08') + expect( + await browser.eval( + 'getComputedStyle(document.querySelector("#without-variables-fira-code")).fontFamily' + ) + ).not.toBe('__Fira_Code_a1dc08, __fira-code-fallback_a1dc08') + + // Albert Sant Variable Italic + expect( + await browser.eval( + 'getComputedStyle(document.querySelector("#variables-albert-sans-italic")).fontFamily' + ) + ).toBe('__Albert_Sans_2b85d2') + expect( + await browser.eval( + 'getComputedStyle(document.querySelector("#without-variables-albert-sans-italic")).fontFamily' + ) + ).not.toBe('__Albert_Sans_2b85d2') + + // Inter 900 + expect( + await browser.eval( + 'getComputedStyle(document.querySelector("#variables-inter-900")).fontFamily' + ) + ).toBe('__Inter_ea3712, __inter-fallback_ea3712') + expect( + await browser.eval( + 'getComputedStyle(document.querySelector("#without-variables-inter-900")).fontFamily' + ) + ).not.toBe('__Inter_ea3712, __inter-fallback_ea3712') + + // Roboto 100 Italic + expect( + await browser.eval( + 'getComputedStyle(document.querySelector("#variables-roboto-100-italic")).fontFamily' + ) + ).toBe('__Roboto_72084b, __roboto-fallback_72084b') + expect( + await browser.eval( + 'getComputedStyle(document.querySelector("#without-variables-roboto-100-italic")).fontFamily' + ) + ).not.toBe('__Roboto_72084b') + }) + + test('page using fallback fonts', async () => { + const browser = await webdriver(next.url, '/with-fallback') + + // .className + expect( + await browser.eval( + 'getComputedStyle(document.querySelector("#with-fallback-fonts-classname")).fontFamily' + ) + ).toBe( + '__Open_Sans_bbc724, system-ui, Arial, __open-sans-fallback_bbc724' + ) + + // .style + expect( + await browser.eval( + 'getComputedStyle(document.querySelector("#with-fallback-fonts-style")).fontFamily' + ) + ).toBe( + '__Open_Sans_bbc724, system-ui, Arial, __open-sans-fallback_bbc724' + ) + + // .variable + expect( + await browser.eval( + 'getComputedStyle(document.querySelector("#with-fallback-fonts-variable")).fontFamily' + ) + ).toBe( + '__Open_Sans_bbc724, system-ui, Arial, __open-sans-fallback_bbc724' + ) + }) + }) + + describe('preload', () => { + test('page with fonts', async () => { + const html = await renderViaHTTP(next.url, '/with-fonts') + const $ = cheerio.load(html) + + // Preconnect + expect($('link[rel="preconnect"]').length).toBe(0) + + expect($('link[as="font"]').length).toBe(2) + // From /_app + expect($('link[as="font"]').get(0).attribs).toEqual({ + as: 'font', + crossorigin: 'anonymous', + href: '/_next/static/fonts/0812efcfaefec5ea.p.woff2', + rel: 'preload', + type: 'font/woff2', + }) + expect($('link[as="font"]').get(1).attribs).toEqual({ + as: 'font', + crossorigin: 'anonymous', + href: '/_next/static/fonts/4f3dcdf40b3ca86d.p.woff2', + rel: 'preload', + type: 'font/woff2', + }) + }) + + test('page without fonts', async () => { + const html = await renderViaHTTP(next.url, '/without-fonts') + const $ = cheerio.load(html) + + // Preconnect + expect($('link[rel="preconnect"]').length).toBe(0) + + // From _app + expect($('link[as="font"]').length).toBe(1) + expect($('link[as="font"]').get(0).attribs).toEqual({ + as: 'font', + crossorigin: 'anonymous', + href: '/_next/static/fonts/0812efcfaefec5ea.p.woff2', + rel: 'preload', + type: 'font/woff2', + }) + }) + }) +}) diff --git a/test/e2e/next-font/with-font-declarations-file.test.ts b/test/e2e/next-font/with-font-declarations-file.test.ts new file mode 100644 index 0000000000000..c6d5bca36edc5 --- /dev/null +++ b/test/e2e/next-font/with-font-declarations-file.test.ts @@ -0,0 +1,110 @@ +import cheerio from 'cheerio' +import { createNext, FileRef } from 'e2e-utils' +import { NextInstance } from 'test/lib/next-modes/base' +import { renderViaHTTP } from 'next-test-utils' +import { join } from 'path' + +const mockedGoogleFontResponses = require.resolve( + './google-font-mocked-responses.js' +) + +const isDev = (global as any).isNextDev + +describe('@next/font/google with-font-declarations-file', () => { + let next: NextInstance + + if ((global as any).isNextDeploy) { + it('should skip next deploy for now', () => {}) + return + } + + beforeAll(async () => { + next = await createNext({ + files: { + pages: new FileRef( + join(__dirname, 'with-font-declarations-file/pages') + ), + components: new FileRef( + join(__dirname, 'with-font-declarations-file/components') + ), + 'fonts.js': new FileRef( + join(__dirname, 'with-font-declarations-file/fonts.js') + ), + 'next.config.js': new FileRef( + join(__dirname, 'with-font-declarations-file/next.config.js') + ), + }, + dependencies: { + '@next/font': 'canary', + }, + env: { + NEXT_FONT_GOOGLE_MOCKED_RESPONSES: mockedGoogleFontResponses, + }, + }) + }) + afterAll(() => next.destroy()) + + test('preload correct files at /inter', async () => { + const html = await renderViaHTTP(next.url, '/inter') + const $ = cheerio.load(html) + + // Preconnect + expect($('link[rel="preconnect"]').length).toBe(0) + + if (isDev) { + // In dev all fonts will be preloaded since it's before DCE + expect($('link[as="font"]').length).toBe(3) + } else { + // Preload + expect($('link[as="font"]').length).toBe(2) + // From /_app + expect($('link[as="font"]').get(0).attribs).toEqual({ + as: 'font', + crossorigin: 'anonymous', + href: '/_next/static/fonts/0812efcfaefec5ea.p.woff2', + rel: 'preload', + type: 'font/woff2', + }) + // From /inter + expect($('link[as="font"]').get(1).attribs).toEqual({ + as: 'font', + crossorigin: 'anonymous', + href: '/_next/static/fonts/4a7f86e553ee7e51.p.woff2', + rel: 'preload', + type: 'font/woff2', + }) + } + }) + + test('preload correct files at /roboto', async () => { + const html = await renderViaHTTP(next.url, '/roboto') + const $ = cheerio.load(html) + + // Preconnect + expect($('link[rel="preconnect"]').length).toBe(0) + + if (isDev) { + // In dev all fonts will be preloaded since it's before DCE + expect($('link[as="font"]').length).toBe(3) + } else { + // Preload + expect($('link[as="font"]').length).toBe(2) + // From /_app + expect($('link[as="font"]').get(0).attribs).toEqual({ + as: 'font', + crossorigin: 'anonymous', + href: '/_next/static/fonts/0812efcfaefec5ea.p.woff2', + rel: 'preload', + type: 'font/woff2', + }) + // From /roboto + expect($('link[as="font"]').get(1).attribs).toEqual({ + as: 'font', + crossorigin: 'anonymous', + href: '/_next/static/fonts/9a7e84b4dd095b33.p.woff2', + rel: 'preload', + type: 'font/woff2', + }) + } + }) +}) diff --git a/test/e2e/next-font/with-font-declarations-file/components/roboto-comp.js b/test/e2e/next-font/with-font-declarations-file/components/roboto-comp.js new file mode 100644 index 0000000000000..4c58fcd0c139d --- /dev/null +++ b/test/e2e/next-font/with-font-declarations-file/components/roboto-comp.js @@ -0,0 +1,10 @@ +import Link from 'next/link' +import { roboto } from '../fonts' + +export default function Roboto() { + return ( + + To inter + + ) +} diff --git a/test/e2e/next-font/with-font-declarations-file/fonts.js b/test/e2e/next-font/with-font-declarations-file/fonts.js new file mode 100644 index 0000000000000..9e82f26c76719 --- /dev/null +++ b/test/e2e/next-font/with-font-declarations-file/fonts.js @@ -0,0 +1,16 @@ +import { + Open_Sans, + Source_Code_Pro, + Abel, + Inter, + Roboto, +} from '@next/font/google' + +const openSans = Open_Sans() +const sourceCodePro = Source_Code_Pro({ display: 'swap', preload: false }) +const abel = Abel({ variant: '400', display: 'optional', preload: false }) + +const inter = Inter({ display: 'block', preload: true }) +const roboto = Roboto({ variant: '400' }) + +export { openSans, sourceCodePro, abel, inter, roboto } diff --git a/test/e2e/next-font/with-font-declarations-file/next.config.js b/test/e2e/next-font/with-font-declarations-file/next.config.js new file mode 100644 index 0000000000000..6cd855478a746 --- /dev/null +++ b/test/e2e/next-font/with-font-declarations-file/next.config.js @@ -0,0 +1,9 @@ +module.exports = { + experimental: { + fontLoaders: { + '@next/font/google': { + subsets: ['latin'], + }, + }, + }, +} diff --git a/test/e2e/next-font/with-font-declarations-file/pages/_app.js b/test/e2e/next-font/with-font-declarations-file/pages/_app.js new file mode 100644 index 0000000000000..8aa19db97f4dd --- /dev/null +++ b/test/e2e/next-font/with-font-declarations-file/pages/_app.js @@ -0,0 +1,15 @@ +import { openSans, sourceCodePro, abel } from '../fonts' + +function MyApp({ Component, pageProps }) { + return ( +
+
+
+ +
+
+
+ ) +} + +export default MyApp diff --git a/test/e2e/next-font/with-font-declarations-file/pages/inter.js b/test/e2e/next-font/with-font-declarations-file/pages/inter.js new file mode 100644 index 0000000000000..7eafc740bd028 --- /dev/null +++ b/test/e2e/next-font/with-font-declarations-file/pages/inter.js @@ -0,0 +1,10 @@ +import Link from 'next/link' +import { inter } from '../fonts' + +export default function Inter() { + return ( + + To roboto + + ) +} diff --git a/test/e2e/next-font/with-font-declarations-file/pages/roboto.js b/test/e2e/next-font/with-font-declarations-file/pages/roboto.js new file mode 100644 index 0000000000000..85b22d621b1b2 --- /dev/null +++ b/test/e2e/next-font/with-font-declarations-file/pages/roboto.js @@ -0,0 +1,5 @@ +import RobotoComp from '../components/roboto-comp' + +export default function Roboto() { + return +} diff --git a/test/e2e/next-font/without-preloaded-fonts.test.ts b/test/e2e/next-font/without-preloaded-fonts.test.ts new file mode 100644 index 0000000000000..2c7cf366c5a2b --- /dev/null +++ b/test/e2e/next-font/without-preloaded-fonts.test.ts @@ -0,0 +1,132 @@ +import cheerio from 'cheerio' +import { createNext, FileRef } from 'e2e-utils' +import { NextInstance } from 'test/lib/next-modes/base' +import { renderViaHTTP } from 'next-test-utils' +import { join } from 'path' + +const mockedGoogleFontResponses = require.resolve( + './google-font-mocked-responses.js' +) + +describe('@next/font/google without-preloaded-fonts without _app', () => { + let next: NextInstance + + if ((global as any).isNextDeploy) { + it('should skip next deploy for now', () => {}) + return + } + + beforeAll(async () => { + next = await createNext({ + files: { + 'pages/no-preload.js': new FileRef( + join(__dirname, 'without-preloaded-fonts/pages/no-preload.js') + ), + 'pages/without-fonts.js': new FileRef( + join(__dirname, 'without-preloaded-fonts/pages/without-fonts.js') + ), + 'next.config.js': new FileRef( + join(__dirname, 'without-preloaded-fonts/next.config.js') + ), + }, + dependencies: { + '@next/font': 'canary', + }, + env: { + NEXT_FONT_GOOGLE_MOCKED_RESPONSES: mockedGoogleFontResponses, + }, + }) + }) + afterAll(() => next.destroy()) + + test('without preload', async () => { + const html = await renderViaHTTP(next.url, '/no-preload') + const $ = cheerio.load(html) + + // Preconnect + expect($('link[rel="preconnect"]').length).toBe(1) + expect($('link[rel="preconnect"]').get(0).attribs).toEqual({ + crossorigin: 'anonymous', + href: '/', + rel: 'preconnect', + }) + + // Preload + expect($('link[as="font"]').length).toBe(0) + }) + + test('without fonts', async () => { + const html = await renderViaHTTP(next.url, '/without-fonts') + const $ = cheerio.load(html) + + expect($('link[rel="preconnect"]').length).toBe(0) + expect($('link[as="font"]').length).toBe(0) + }) +}) + +describe('@next/font/google no preloads with _app', () => { + let next: NextInstance + + if ((global as any).isNextDeploy) { + it('should skip next deploy for now', () => {}) + return + } + + beforeAll(async () => { + next = await createNext({ + files: { + 'pages/_app.js': new FileRef( + join(__dirname, 'without-preloaded-fonts/pages/_app.js') + ), + 'pages/no-preload.js': new FileRef( + join(__dirname, 'without-preloaded-fonts/pages/no-preload.js') + ), + 'pages/without-fonts.js': new FileRef( + join(__dirname, 'without-preloaded-fonts/pages/without-fonts.js') + ), + 'next.config.js': new FileRef( + join(__dirname, 'without-preloaded-fonts/next.config.js') + ), + }, + dependencies: { + '@next/font': 'canary', + }, + env: { + NEXT_FONT_GOOGLE_MOCKED_RESPONSES: mockedGoogleFontResponses, + }, + }) + }) + afterAll(() => next.destroy()) + + test('without preload', async () => { + const html = await renderViaHTTP(next.url, '/no-preload') + const $ = cheerio.load(html) + + // Preconnect + expect($('link[rel="preconnect"]').length).toBe(1) + expect($('link[rel="preconnect"]').get(0).attribs).toEqual({ + crossorigin: 'anonymous', + href: '/', + rel: 'preconnect', + }) + + // Preload + expect($('link[as="font"]').length).toBe(0) + }) + + test('without fonts', async () => { + const html = await renderViaHTTP(next.url, '/without-fonts') + const $ = cheerio.load(html) + + // Preconnect + expect($('link[rel="preconnect"]').length).toBe(1) + expect($('link[rel="preconnect"]').get(0).attribs).toEqual({ + crossorigin: 'anonymous', + href: '/', + rel: 'preconnect', + }) + + // Preload + expect($('link[as="font"]').length).toBe(0) + }) +}) diff --git a/test/e2e/next-font/without-preloaded-fonts/next.config.js b/test/e2e/next-font/without-preloaded-fonts/next.config.js new file mode 100644 index 0000000000000..6cd855478a746 --- /dev/null +++ b/test/e2e/next-font/without-preloaded-fonts/next.config.js @@ -0,0 +1,9 @@ +module.exports = { + experimental: { + fontLoaders: { + '@next/font/google': { + subsets: ['latin'], + }, + }, + }, +} diff --git a/test/e2e/next-font/without-preloaded-fonts/pages/_app.js b/test/e2e/next-font/without-preloaded-fonts/pages/_app.js new file mode 100644 index 0000000000000..86f596bdb327c --- /dev/null +++ b/test/e2e/next-font/without-preloaded-fonts/pages/_app.js @@ -0,0 +1,12 @@ +import { Abel } from '@next/font/google' +const abel = Abel({ variant: '400', display: 'optional', preload: false }) + +function MyApp({ Component, pageProps }) { + return ( +
+ +
+ ) +} + +export default MyApp diff --git a/test/e2e/next-font/without-preloaded-fonts/pages/no-preload.js b/test/e2e/next-font/without-preloaded-fonts/pages/no-preload.js new file mode 100644 index 0000000000000..accacef22204c --- /dev/null +++ b/test/e2e/next-font/without-preloaded-fonts/pages/no-preload.js @@ -0,0 +1,6 @@ +import { Abel } from '@next/font/google' +const abel = Abel({ variant: '400', display: 'optional', preload: false }) + +export default function NoPreload() { + return

Hello world

+} diff --git a/test/e2e/next-font/without-preloaded-fonts/pages/without-fonts.js b/test/e2e/next-font/without-preloaded-fonts/pages/without-fonts.js new file mode 100644 index 0000000000000..4e9a1aaafe12c --- /dev/null +++ b/test/e2e/next-font/without-preloaded-fonts/pages/without-fonts.js @@ -0,0 +1,3 @@ +export default function WithoutFonts() { + return

Hello world

+} From 4970d7a0e84dfa4101f09a4476cb123759712bb0 Mon Sep 17 00:00:00 2001 From: Tomer Aberbach Date: Thu, 22 Sep 2022 01:36:59 -0400 Subject: [PATCH 20/76] Set `__NEXT_NEW_LINK_BEHAVIOR` in Jest tests when `newNextLinkBehavior` is true (#40702) Fixes #40463 Could use some help figuring out where to add a test! I looked around and found [`jest-next-swc.test.ts`](https://github.com/vercel/next.js/blob/canary/test/unit/jest-next-swc.test.ts), but I don't think I can use that to test this fix. Anyways, from my local testing this PR seems to fix the issue. Co-authored-by: JJ Kasper --- packages/next/build/jest/jest.ts | 13 ++- .../production/jest/new-link-behavior.test.ts | 86 +++++++++++++++++++ 2 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 test/production/jest/new-link-behavior.test.ts diff --git a/packages/next/build/jest/jest.ts b/packages/next/build/jest/jest.ts index 844afc8e22308..1dbd27da10374 100644 --- a/packages/next/build/jest/jest.ts +++ b/packages/next/build/jest/jest.ts @@ -1,6 +1,7 @@ import { loadEnvConfig } from '@next/env' import { resolve, join } from 'path' import loadConfig from '../../server/config' +import { NextConfigComplete } from '../../server/config-shared' import { PHASE_TEST } from '../../shared/lib/constants' import loadJsConfig from '../load-jsconfig' import * as Log from '../output/log' @@ -27,6 +28,16 @@ function loadClosestPackageJson(dir: string, attempts = 1): any { } } +/** Loads dotenv files and sets environment variables based on next config. */ +function setUpEnv(dir: string, nextConfig: NextConfigComplete) { + const dev = false + loadEnvConfig(dir, dev, Log) + + if (nextConfig.experimental.newNextLinkBehavior) { + process.env.__NEXT_NEW_LINK_BEHAVIOR = 'true' + } +} + /* // Usage in jest.config.js const nextJest = require('next/jest'); @@ -61,7 +72,7 @@ export default function nextJest(options: { dir?: string } = {}) { isEsmProject = packageConfig.type === 'module' nextConfig = await getConfig(resolvedDir) - loadEnvConfig(resolvedDir, false, Log) + setUpEnv(resolvedDir, nextConfig) // TODO: revisit when bug in SWC is fixed that strips `.css` const result = await loadJsConfig(resolvedDir, nextConfig) jsConfig = result.jsConfig diff --git a/test/production/jest/new-link-behavior.test.ts b/test/production/jest/new-link-behavior.test.ts new file mode 100644 index 0000000000000..f088713a443a8 --- /dev/null +++ b/test/production/jest/new-link-behavior.test.ts @@ -0,0 +1,86 @@ +import { createNext } from 'e2e-utils' +import { NextInstance } from 'test/lib/next-modes/base' + +describe('next/jest', () => { + let next: NextInstance + + if (process.env.NEXT_TEST_REACT_VERSION === '^17') { + // react testing library is specific to react version + it('should bail on react v17', () => {}) + return + } + + beforeAll(async () => { + next = await createNext({ + files: { + 'pages/index.jsx': ` + import Link from 'next/link' + + export default function Page() { + return Hello World! + } + `, + 'test/index.test.jsx': ` + import { render, screen, act } from '@testing-library/react' + import Page from '../pages/index' + + it('Link', () => { + act(() => { + render() + + const link = screen.getByRole('link', { name: 'Hello World!' }) + expect(link.getAttribute('href')).toBe('https://example.com') + }) + }) + `, + 'jest.config.js': ` + const nextJest = require('next/jest') + const createJestConfig = nextJest({ dir: './' }) + module.exports = createJestConfig({ + testEnvironment: 'jest-environment-jsdom', + }) + `, + }, + dependencies: { + jest: '27.4.7', + '@testing-library/react': '12.1.2', + }, + packageJson: { + scripts: { + build: 'next build && yarn jest --forceExit test/index.test.jsx', + }, + }, + skipStart: true, + buildCommand: `yarn build`, + }) + }) + + afterAll(() => next.destroy()) + + it(`should use normal Link behavior when newNextLinkBehavior is unset`, async () => { + await next.start() + }) + + it(`should use new link behavior when newNextLinkBehavior is true`, async () => { + await next.stop() + + await next.patchFile( + 'pages/index.jsx', + ` + import Link from 'next/link' + + export default function Page() { + return
Hello World!
+ } + ` + ) + await next.patchFile( + 'next.config.js', + ` + module.exports = { experimental: { newNextLinkBehavior: true } } + ` + ) + + await next.start() + }) +}) From f51e49f8d54a4f3aa417c540338f1240ea41b9ea Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Wed, 21 Sep 2022 22:50:08 -0700 Subject: [PATCH 21/76] Update stats config for release stats (#40780) This keeps the necessary config for release stats for app dir x-ref: https://github.com/vercel/next.js/pull/40776 Fixes: https://github.com/vercel/next.js/actions/runs/3102008544/jobs/5025346767 --- test/.stats-app/next.config.js | 9 --------- test/.stats-app/stats-config.js | 2 ++ 2 files changed, 2 insertions(+), 9 deletions(-) delete mode 100644 test/.stats-app/next.config.js diff --git a/test/.stats-app/next.config.js b/test/.stats-app/next.config.js deleted file mode 100644 index 3b9bfdac02772..0000000000000 --- a/test/.stats-app/next.config.js +++ /dev/null @@ -1,9 +0,0 @@ -const withBundleAnalyzer = require('@next/bundle-analyzer')({ - enabled: !!process.env.TEST_ANALYZE, -}) - -module.exports = withBundleAnalyzer({ - experimental: { - appDir: true, - }, -}) diff --git a/test/.stats-app/stats-config.js b/test/.stats-app/stats-config.js index 58316e4a8ee6d..163dd8b234b06 100644 --- a/test/.stats-app/stats-config.js +++ b/test/.stats-app/stats-config.js @@ -94,6 +94,7 @@ module.exports = { module.exports = { experimental: { appDir: true, + serverComponents: true, }, generateBuildId: () => 'BUILD_ID', webpack(config) { @@ -118,6 +119,7 @@ module.exports = { module.exports = { experimental: { appDir: true, + serverComponents: true, }, generateBuildId: () => 'BUILD_ID' } From cc1e35d821e72e191a01635cd7e97c48d36afbc3 Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Wed, 21 Sep 2022 22:51:10 -0700 Subject: [PATCH 22/76] v12.3.2-canary.3 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-config-next/package.json | 4 ++-- packages/eslint-plugin-next/package.json | 2 +- packages/font/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next-swc/package.json | 2 +- packages/next/package.json | 14 +++++++------- packages/react-dev-overlay/package.json | 2 +- packages/react-refresh-utils/package.json | 2 +- pnpm-lock.yaml | 14 +++++++------- 17 files changed, 30 insertions(+), 30 deletions(-) diff --git a/lerna.json b/lerna.json index d48fc2f60979d..dba490cae4889 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "12.3.2-canary.2" + "version": "12.3.2-canary.3" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index b338ed7b2d03a..c56dd62e4b76e 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "12.3.2-canary.2", + "version": "12.3.2-canary.3", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index c64193426b808..cbcb88ae9dc75 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "12.3.2-canary.2", + "version": "12.3.2-canary.3", "description": "ESLint configuration used by NextJS.", "main": "index.js", "license": "MIT", @@ -9,7 +9,7 @@ "directory": "packages/eslint-config-next" }, "dependencies": { - "@next/eslint-plugin-next": "12.3.2-canary.2", + "@next/eslint-plugin-next": "12.3.2-canary.3", "@rushstack/eslint-patch": "^1.1.3", "@typescript-eslint/parser": "^5.21.0", "eslint-import-resolver-node": "^0.3.6", diff --git a/packages/eslint-plugin-next/package.json b/packages/eslint-plugin-next/package.json index 1ea785a15ce90..2e09ac99f2f30 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "12.3.2-canary.2", + "version": "12.3.2-canary.3", "description": "ESLint plugin for NextJS.", "main": "lib/index.js", "license": "MIT", diff --git a/packages/font/package.json b/packages/font/package.json index 4782cf19834a4..f7febc708ac90 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,6 +1,6 @@ { "name": "@next/font", - "version": "12.3.2-canary.2", + "version": "12.3.2-canary.3", "repository": { "url": "vercel/next.js", "directory": "packages/font" diff --git a/packages/next-bundle-analyzer/package.json b/packages/next-bundle-analyzer/package.json index ac1e0f9c7f49c..1c5486a250616 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "12.3.2-canary.2", + "version": "12.3.2-canary.3", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index 1ef039e41e75d..8666907c3c7b1 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "12.3.2-canary.2", + "version": "12.3.2-canary.3", "license": "MIT", "dependencies": { "chalk": "4.1.0", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index 95419f0fdbfa6..245b60c66e4ac 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "12.3.2-canary.2", + "version": "12.3.2-canary.3", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index 3a5a75d4ecbc9..b2dc30c024f70 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "12.3.2-canary.2", + "version": "12.3.2-canary.3", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index 32f07122eedec..944d76a4a4a7e 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "12.3.2-canary.2", + "version": "12.3.2-canary.3", "repository": { "url": "vercel/next.js", "directory": "packages/next-plugin-storybook" diff --git a/packages/next-polyfill-module/package.json b/packages/next-polyfill-module/package.json index 3c1b0854f7e46..6f5c12c19a4c7 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "12.3.2-canary.2", + "version": "12.3.2-canary.3", "description": "A standard library polyfill for ES Modules supporting browsers (Edge 16+, Firefox 60+, Chrome 61+, Safari 10.1+)", "main": "dist/polyfill-module.js", "license": "MIT", diff --git a/packages/next-polyfill-nomodule/package.json b/packages/next-polyfill-nomodule/package.json index c3a934aa98d8d..96e3380e70c4a 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "12.3.2-canary.2", + "version": "12.3.2-canary.3", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index e436d99297f13..83beff8b84d23 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "12.3.2-canary.2", + "version": "12.3.2-canary.3", "private": true, "scripts": { "build-native": "napi build --platform -p next-swc-napi --cargo-name next_swc_napi native --features plugin", diff --git a/packages/next/package.json b/packages/next/package.json index 7463ebd7edce0..9c5e9cb3071a1 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "12.3.2-canary.2", + "version": "12.3.2-canary.3", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -68,7 +68,7 @@ ] }, "dependencies": { - "@next/env": "12.3.2-canary.2", + "@next/env": "12.3.2-canary.3", "@swc/helpers": "0.4.11", "caniuse-lite": "^1.0.30001406", "postcss": "8.4.14", @@ -119,11 +119,11 @@ "@hapi/accept": "5.0.2", "@napi-rs/cli": "2.7.0", "@napi-rs/triples": "1.1.0", - "@next/polyfill-module": "12.3.2-canary.2", - "@next/polyfill-nomodule": "12.3.2-canary.2", - "@next/react-dev-overlay": "12.3.2-canary.2", - "@next/react-refresh-utils": "12.3.2-canary.2", - "@next/swc": "12.3.2-canary.2", + "@next/polyfill-module": "12.3.2-canary.3", + "@next/polyfill-nomodule": "12.3.2-canary.3", + "@next/react-dev-overlay": "12.3.2-canary.3", + "@next/react-refresh-utils": "12.3.2-canary.3", + "@next/swc": "12.3.2-canary.3", "@segment/ajv-human-errors": "2.1.2", "@taskr/clear": "1.1.0", "@taskr/esnext": "1.1.0", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index 4266772112e7d..acafb9daea8ce 100644 --- a/packages/react-dev-overlay/package.json +++ b/packages/react-dev-overlay/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-dev-overlay", - "version": "12.3.2-canary.2", + "version": "12.3.2-canary.3", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index 5e2de08706320..7fe9d35cd45f2 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "12.3.2-canary.2", + "version": "12.3.2-canary.3", "description": "An experimental package providing utilities for React Refresh.", "repository": { "url": "vercel/next.js", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 872106b1d4460..a7539b9c06e12 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -369,7 +369,7 @@ importers: packages/eslint-config-next: specifiers: - '@next/eslint-plugin-next': 12.3.2-canary.2 + '@next/eslint-plugin-next': 12.3.2-canary.3 '@rushstack/eslint-patch': ^1.1.3 '@typescript-eslint/parser': ^5.21.0 eslint-import-resolver-node: ^0.3.6 @@ -428,12 +428,12 @@ importers: '@hapi/accept': 5.0.2 '@napi-rs/cli': 2.7.0 '@napi-rs/triples': 1.1.0 - '@next/env': 12.3.2-canary.2 - '@next/polyfill-module': 12.3.2-canary.2 - '@next/polyfill-nomodule': 12.3.2-canary.2 - '@next/react-dev-overlay': 12.3.2-canary.2 - '@next/react-refresh-utils': 12.3.2-canary.2 - '@next/swc': 12.3.2-canary.2 + '@next/env': 12.3.2-canary.3 + '@next/polyfill-module': 12.3.2-canary.3 + '@next/polyfill-nomodule': 12.3.2-canary.3 + '@next/react-dev-overlay': 12.3.2-canary.3 + '@next/react-refresh-utils': 12.3.2-canary.3 + '@next/swc': 12.3.2-canary.3 '@segment/ajv-human-errors': 2.1.2 '@swc/helpers': 0.4.11 '@taskr/clear': 1.1.0 From c4647bb6300b9d016f0f196db28057913b3b9a82 Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Thu, 22 Sep 2022 13:08:45 +0200 Subject: [PATCH 23/76] Add handling for 404 in new router (#40787) --- .../build/webpack/loaders/next-app-loader.ts | 1 + .../components/layout-router.client.tsx | 75 +++++++++++++++---- packages/next/client/components/not-found.ts | 8 ++ packages/next/server/app-render.tsx | 13 +++- .../client-component.js | 5 ++ .../error/ssr-error-client-component/page.js | 7 +- test/e2e/app-dir/app/app/not-found/404.js | 3 + .../app/app/not-found/client-side/page.js | 17 +++++ .../app/app/not-found/clientcomponent/a.js | 9 +++ .../clientcomponent/client-component.js | 7 ++ .../app/app/not-found/servercomponent/a.js | 7 ++ test/e2e/app-dir/index.test.ts | 28 +++++++ 12 files changed, 162 insertions(+), 18 deletions(-) create mode 100644 packages/next/client/components/not-found.ts create mode 100644 test/e2e/app-dir/app/app/error/ssr-error-client-component/client-component.js create mode 100644 test/e2e/app-dir/app/app/not-found/404.js create mode 100644 test/e2e/app-dir/app/app/not-found/client-side/page.js create mode 100644 test/e2e/app-dir/app/app/not-found/clientcomponent/a.js create mode 100644 test/e2e/app-dir/app/app/not-found/clientcomponent/client-component.js create mode 100644 test/e2e/app-dir/app/app/not-found/servercomponent/a.js diff --git a/packages/next/build/webpack/loaders/next-app-loader.ts b/packages/next/build/webpack/loaders/next-app-loader.ts index c3adb305a4e5f..10534259ded03 100644 --- a/packages/next/build/webpack/loaders/next-app-loader.ts +++ b/packages/next/build/webpack/loaders/next-app-loader.ts @@ -8,6 +8,7 @@ export const FILE_TYPES = { template: 'template', error: 'error', loading: 'loading', + '404': '404', } as const // TODO-APP: check if this can be narrowed. diff --git a/packages/next/client/components/layout-router.client.tsx b/packages/next/client/components/layout-router.client.tsx index cf8f25bbb7df8..c526a66e62f09 100644 --- a/packages/next/client/components/layout-router.client.tsx +++ b/packages/next/client/components/layout-router.client.tsx @@ -285,6 +285,47 @@ function LoadingBoundary({ return <>{children} } +interface NotFoundBoundaryProps { + notFound?: React.ReactNode + children: React.ReactNode +} + +class NotFoundErrorBoundary extends React.Component< + NotFoundBoundaryProps, + { notFoundTriggered: boolean } +> { + constructor(props: NotFoundBoundaryProps) { + super(props) + this.state = { notFoundTriggered: false } + } + + static getDerivedStateFromError(error: any) { + if (error.code === 'NEXT_NOT_FOUND') { + return { notFoundTriggered: true } + } + // Re-throw if error is not for 404 + throw error + } + + render() { + if (this.state.notFoundTriggered) { + return this.props.notFound + } + + return this.props.children + } +} + +function NotFoundBoundary({ notFound, children }: NotFoundBoundaryProps) { + return notFound ? ( + + {children} + + ) : ( + <>{children} + ) +} + type ErrorComponent = React.ComponentType<{ error: Error; reset: () => void }> interface ErrorBoundaryProps { errorComponent: ErrorComponent @@ -355,6 +396,7 @@ export default function OuterLayoutRouter({ error, loading, template, + notFound, rootLayoutIncluded, }: { parallelRouterKey: string @@ -363,6 +405,7 @@ export default function OuterLayoutRouter({ error: ErrorComponent template: React.ReactNode loading: React.ReactNode | undefined + notFound: React.ReactNode | undefined rootLayoutIncluded: boolean }) { const { childNodes, tree, url } = useContext(LayoutRouterContext) @@ -412,21 +455,23 @@ export default function OuterLayoutRouter({ key={preservedSegment} value={ - - - + + + + + } > diff --git a/packages/next/client/components/not-found.ts b/packages/next/client/components/not-found.ts new file mode 100644 index 0000000000000..a343c5a81ab89 --- /dev/null +++ b/packages/next/client/components/not-found.ts @@ -0,0 +1,8 @@ +export const NOT_FOUND_ERROR_CODE = 'NEXT_NOT_FOUND' + +export function notFound() { + // eslint-disable-next-line no-throw-literal + throw { + code: NOT_FOUND_ERROR_CODE, + } +} diff --git a/packages/next/server/app-render.tsx b/packages/next/server/app-render.tsx index 98f26356a741e..661f7d564998b 100644 --- a/packages/next/server/app-render.tsx +++ b/packages/next/server/app-render.tsx @@ -727,7 +727,15 @@ export async function renderToHTMLOrFlight( loaderTree: [ segment, parallelRoutes, - { layoutOrPagePath, layout, template, error, loading, page }, + { + layoutOrPagePath, + layout, + template, + error, + loading, + page, + '404': notFound, + }, ], parentParams, firstItem, @@ -750,6 +758,7 @@ export async function renderToHTMLOrFlight( const Template = template ? await interopDefault(template()) : React.Fragment + const NotFound = notFound ? await interopDefault(notFound()) : undefined const ErrorComponent = error ? await interopDefault(error()) : undefined const Loading = loading ? await interopDefault(loading()) : undefined const isLayout = typeof layout !== 'undefined' @@ -844,6 +853,7 @@ export async function renderToHTMLOrFlight( } + notFound={NotFound ? : undefined} childProp={childProp} rootLayoutIncluded={rootLayoutIncludedAtThisLevelOrAbove} />, @@ -882,6 +892,7 @@ export async function renderToHTMLOrFlight( } + notFound={NotFound ? : undefined} childProp={childProp} rootLayoutIncluded={rootLayoutIncludedAtThisLevelOrAbove} />, diff --git a/test/e2e/app-dir/app/app/error/ssr-error-client-component/client-component.js b/test/e2e/app-dir/app/app/error/ssr-error-client-component/client-component.js new file mode 100644 index 0000000000000..7743a313b4754 --- /dev/null +++ b/test/e2e/app-dir/app/app/error/ssr-error-client-component/client-component.js @@ -0,0 +1,5 @@ +'client' + +export default function Page() { + throw new Error('Error during SSR') +} diff --git a/test/e2e/app-dir/app/app/error/ssr-error-client-component/page.js b/test/e2e/app-dir/app/app/error/ssr-error-client-component/page.js index 7743a313b4754..39d5495fd3fc6 100644 --- a/test/e2e/app-dir/app/app/error/ssr-error-client-component/page.js +++ b/test/e2e/app-dir/app/app/error/ssr-error-client-component/page.js @@ -1,5 +1,8 @@ -'client' +import ClientComp from './client-component' +import { useHeaders } from 'next/dist/client/components/hooks-server' export default function Page() { - throw new Error('Error during SSR') + // Opt-in to SSR. + useHeaders() + return } diff --git a/test/e2e/app-dir/app/app/not-found/404.js b/test/e2e/app-dir/app/app/not-found/404.js new file mode 100644 index 0000000000000..42acdf4c589be --- /dev/null +++ b/test/e2e/app-dir/app/app/not-found/404.js @@ -0,0 +1,3 @@ +export default function NotFound() { + return

404!

+} diff --git a/test/e2e/app-dir/app/app/not-found/client-side/page.js b/test/e2e/app-dir/app/app/not-found/client-side/page.js new file mode 100644 index 0000000000000..faca8e33aaf63 --- /dev/null +++ b/test/e2e/app-dir/app/app/not-found/client-side/page.js @@ -0,0 +1,17 @@ +'client' + +import { notFound } from 'next/dist/client/components/not-found' +import React from 'react' + +export default function Page() { + const [notFoundEnabled, enableNotFound] = React.useState(false) + + if (notFoundEnabled) { + notFound() + } + return ( + + ) +} diff --git a/test/e2e/app-dir/app/app/not-found/clientcomponent/a.js b/test/e2e/app-dir/app/app/not-found/clientcomponent/a.js new file mode 100644 index 0000000000000..c86055f6b02a3 --- /dev/null +++ b/test/e2e/app-dir/app/app/not-found/clientcomponent/a.js @@ -0,0 +1,9 @@ +// TODO-APP: enable when flight error serialization is implemented +import ClientComp from './client-component' +import { useHeaders } from 'next/dist/client/components/hooks-server' + +export default function Page() { + // Opt-in to SSR. + useHeaders() + return +} diff --git a/test/e2e/app-dir/app/app/not-found/clientcomponent/client-component.js b/test/e2e/app-dir/app/app/not-found/clientcomponent/client-component.js new file mode 100644 index 0000000000000..7469f1ca68690 --- /dev/null +++ b/test/e2e/app-dir/app/app/not-found/clientcomponent/client-component.js @@ -0,0 +1,7 @@ +'client' +import { notFound } from 'next/dist/client/components/not-found' + +export default function ClientComp() { + notFound() + return <> +} diff --git a/test/e2e/app-dir/app/app/not-found/servercomponent/a.js b/test/e2e/app-dir/app/app/not-found/servercomponent/a.js new file mode 100644 index 0000000000000..5704c31c2f4ae --- /dev/null +++ b/test/e2e/app-dir/app/app/not-found/servercomponent/a.js @@ -0,0 +1,7 @@ +// TODO-APP: enable when flight error serialization is implemented +import { notFound } from 'next/dist/client/components/not-found' + +export default function Page() { + notFound() + return <> +} diff --git a/test/e2e/app-dir/index.test.ts b/test/e2e/app-dir/index.test.ts index b73d3942772c4..05accb59abb65 100644 --- a/test/e2e/app-dir/index.test.ts +++ b/test/e2e/app-dir/index.test.ts @@ -1475,6 +1475,34 @@ describe('app dir', () => { }) }) + describe('404', () => { + it.skip('should trigger 404 in a server component', async () => { + const browser = await webdriver(next.url, '/not-found/servercomponent') + + expect( + await browser.waitForElementByCss('#not-found-component').text() + ).toBe('404!') + }) + + it.skip('should trigger 404 in a client component', async () => { + const browser = await webdriver(next.url, '/not-found/clientcomponent') + expect( + await browser.waitForElementByCss('#not-found-component').text() + ).toBe('404!') + }) + + it('should trigger 404 client-side', async () => { + const browser = await webdriver(next.url, '/not-found/client-side') + await browser + .elementByCss('button') + .click() + .waitForElementByCss('#not-found-component') + expect(await browser.elementByCss('#not-found-component').text()).toBe( + '404!' + ) + }) + }) + describe('redirect', () => { describe('components', () => { it.skip('should redirect in a server component', async () => { From 06682d27bb480fcacdc8072d620dd1e37f33040a Mon Sep 17 00:00:00 2001 From: Shu Ding Date: Thu, 22 Sep 2022 16:39:19 +0200 Subject: [PATCH 24/76] Fix alias paths for bundling (#40800) In the server layer, we used to alias `react` to the resolved path e.g. `/next.js/node_modules/.pnpm/react@0.0.0-experimental-e6a062bd2-20220913/node_modules/react`, but it turns out that webpack's enhanced resolver can't handle it correctly together with conditions, and the final resolved path is `/next.js/node_modules/.pnpm/react@0.0.0-experimental-e6a062bd2-20220913/node_modules/react/index.js`. If we change the alias to `react: 'react-exp'` then it correctly resolves to `/next.js/node_modules/.pnpm/react@0.0.0-experimental-e6a062bd2-20220913/node_modules/react/react.shared-subset.js`. ## 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) --- packages/next/build/webpack-config.ts | 28 +++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts index b4260973ab2fa..bc0ba8c2faea5 100644 --- a/packages/next/build/webpack-config.ts +++ b/packages/next/build/webpack-config.ts @@ -826,14 +826,6 @@ export default async function getBaseWebpackConfig( [COMPILER_NAMES.edgeServer]: ['browser', 'module', 'main'], } - const reactAliases = { - react: reactDir, - 'react-dom$': reactDomDir, - 'react-dom/server$': `${reactDomDir}/server`, - 'react-dom/server.browser$': `${reactDomDir}/server.browser`, - 'react-dom/client$': `${reactDomDir}/client`, - } - const resolveConfig = { // Disable .mjs for node_modules bundling extensions: isNodeServer @@ -846,7 +838,11 @@ export default async function getBaseWebpackConfig( alias: { next: NEXT_PROJECT_ROOT, - ...reactAliases, + react: reactDir, + 'react-dom$': reactDomDir, + 'react-dom/server$': `${reactDomDir}/server`, + 'react-dom/server.browser$': `${reactDomDir}/server.browser`, + 'react-dom/client$': `${reactDomDir}/client`, 'styled-jsx/style$': require.resolve(`styled-jsx/style`), 'styled-jsx$': require.resolve(`styled-jsx`), @@ -1009,11 +1005,15 @@ export default async function getBaseWebpackConfig( // we need to provide that alias to webpack's resolver. alias: process.env.__NEXT_REACT_CHANNEL ? { - ...reactAliases, - 'react/package.json': `${reactDir}/package.json`, - 'react/jsx-runtime': `${reactDir}/jsx-runtime`, - 'react/jsx-dev-runtime': `${reactDir}/jsx-dev-runtime`, - 'react-dom/package.json': `${reactDomDir}/package.json`, + react: `react-${process.env.__NEXT_REACT_CHANNEL}`, + 'react/package.json': `react-${process.env.__NEXT_REACT_CHANNEL}/package.json`, + 'react/jsx-runtime': `react-${process.env.__NEXT_REACT_CHANNEL}/jsx-runtime`, + 'react/jsx-dev-runtime': `react-${process.env.__NEXT_REACT_CHANNEL}/jsx-dev-runtime`, + 'react-dom': `react-dom-${process.env.__NEXT_REACT_CHANNEL}`, + 'react-dom/package.json': `react-dom-${process.env.__NEXT_REACT_CHANNEL}/package.json`, + 'react-dom/server': `react-dom-${process.env.__NEXT_REACT_CHANNEL}/server`, + 'react-dom/server.browser': `react-dom-${process.env.__NEXT_REACT_CHANNEL}/server.browser`, + 'react-dom/client': `react-dom-${process.env.__NEXT_REACT_CHANNEL}/client`, } : false, conditionNames: ['react-server'], From f662f1815939aaa39840196a0e23cd1c6c7ced94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Born=C3=B6?= Date: Thu, 22 Sep 2022 17:56:42 +0200 Subject: [PATCH 25/76] Fix flaky full reload hmr tests (#40786) The issue seems to be that ` await check(() => browser.elementByCss('p').text(), 'hello world!!!')` sometimes tries to get `.text()` from the DOM before the full reload and it times out. ## 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) --- test/development/basic/hmr.test.ts | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/test/development/basic/hmr.test.ts b/test/development/basic/hmr.test.ts index 1b852b8df2ab3..75fea4552e34a 100644 --- a/test/development/basic/hmr.test.ts +++ b/test/development/basic/hmr.test.ts @@ -793,13 +793,16 @@ describe('basic HMR', () => { ) const newFileContent = currentFileContent.replace( '

hello world

', - '

hello world!!!

' + '

hello world!!!

' ) await next.patchFile( './pages/hmr/anonymous-page-function.js', newFileContent ) - await check(() => browser.elementByCss('p').text(), 'hello world!!!') + + expect(await browser.waitForElementByCss('#updated').text()).toBe( + 'hello world!!!' + ) // CLI warning and stacktrace expect(next.cliOutput.slice(start)).toContain( @@ -834,9 +837,15 @@ describe('basic HMR', () => { const currentFileContent = await next.readFile( './pages/hmr/runtime-error.js' ) - const newFileContent = currentFileContent.replace('whoops', '"whoops"') + const newFileContent = currentFileContent.replace( + 'whoops', + '

whoops

' + ) await next.patchFile('./pages/hmr/runtime-error.js', newFileContent) - await check(() => browser.elementByCss('body').text(), 'whoops') + + expect(await browser.waitForElementByCss('#updated').text()).toBe( + 'whoops' + ) // CLI warning and stacktrace expect(next.cliOutput.slice(start)).toContain( From f16992a1560313fe992a765a094ba8a40a2cfda0 Mon Sep 17 00:00:00 2001 From: Philipp Bosch Date: Thu, 22 Sep 2022 18:04:44 +0200 Subject: [PATCH 26/76] docs: Remove extraneous FallbackComponent prop from error boundary docs (#40785) It looks like the code snippet was copied over from https://github.com/bvaughn/react-error-boundary but the `ErrorBoundary` component on this docs page does not have a `FallbackComponent` prop but renders the error message content itself. ## Documentation / Examples - [X] Make sure the linting passes by running `pnpm lint` - [X] The "examples guidelines" are followed from [our contributing doc](https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md) --- docs/advanced-features/error-handling.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/advanced-features/error-handling.md b/docs/advanced-features/error-handling.md index a164c58e48392..f4b8d258e5f07 100644 --- a/docs/advanced-features/error-handling.md +++ b/docs/advanced-features/error-handling.md @@ -88,7 +88,7 @@ import ErrorBoundary from '../components/ErrorBoundary' function MyApp({ Component, pageProps }) { return ( // Wrap the Component prop with ErrorBoundary component - + ) From 48292ba7b7d2099086fb5e9648178c91b39f6e8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Born=C3=B6?= Date: Thu, 22 Sep 2022 18:10:36 +0200 Subject: [PATCH 27/76] Fix required server files for font loader manifest (#40784) The manifest currently gets added without file extensions. --- packages/next/build/index.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/next/build/index.ts b/packages/next/build/index.ts index 775d726bec4c4..f2f494a735188 100644 --- a/packages/next/build/index.ts +++ b/packages/next/build/index.ts @@ -829,9 +829,12 @@ export default async function build( config.optimizeFonts ? path.join(serverDir, FONT_MANIFEST) : null, BUILD_ID_FILE, appDir ? path.join(serverDir, APP_PATHS_MANIFEST) : null, - config.experimental.fontLoaders - ? path.join(serverDir, FONT_LOADER_MANIFEST) - : null, + ...(config.experimental.fontLoaders + ? [ + path.join(SERVER_DIRECTORY, FONT_LOADER_MANIFEST + '.js'), + path.join(SERVER_DIRECTORY, FONT_LOADER_MANIFEST + '.json'), + ] + : []), ] .filter(nonNullable) .map((file) => path.join(config.distDir, file)), From be904d79ac47b70df6eab16c578d240c39cdb0fe Mon Sep 17 00:00:00 2001 From: Steven Date: Thu, 22 Sep 2022 12:33:36 -0400 Subject: [PATCH 28/76] Open deploy link in new window for examples (#40804) Let's open the deploy link in a new window so the link isn't blocked when running an an iframe, such as Stackblitz. Previously, this would print the following error: > Refused to display 'https://vercel.com/' in a frame because it set 'X-Frame-Options' to 'deny' --- examples/progressive-web-app/pages/index.tsx | 2 ++ examples/with-cypress/pages/index.tsx | 2 ++ examples/with-docker-compose/next-app/src/pages/index.tsx | 2 ++ examples/with-docker-multi-env/pages/index.js | 2 ++ examples/with-docker/pages/index.js | 2 ++ examples/with-elasticsearch/pages/index.js | 2 ++ examples/with-graphql-gateway/pages/index.tsx | 2 ++ examples/with-knex/pages/index.js | 2 ++ examples/with-mongodb/pages/index.tsx | 2 ++ examples/with-particles/pages/index.tsx | 2 ++ examples/with-playwright/pages/index.js | 2 ++ examples/with-sitemap/pages/index.js | 2 ++ examples/with-vitest/pages/index.tsx | 2 ++ packages/create-next-app/templates/default/pages/index.js | 2 ++ packages/create-next-app/templates/typescript/pages/index.tsx | 2 ++ 15 files changed, 30 insertions(+) diff --git a/examples/progressive-web-app/pages/index.tsx b/examples/progressive-web-app/pages/index.tsx index c7aef703d4d6b..4ee04e47cee7c 100644 --- a/examples/progressive-web-app/pages/index.tsx +++ b/examples/progressive-web-app/pages/index.tsx @@ -34,6 +34,8 @@ export default function Home() {

Deploy →

diff --git a/examples/with-cypress/pages/index.tsx b/examples/with-cypress/pages/index.tsx index 36b3381bad611..40761ba6e80f4 100644 --- a/examples/with-cypress/pages/index.tsx +++ b/examples/with-cypress/pages/index.tsx @@ -50,6 +50,8 @@ export default function Home() {

Deploy →

diff --git a/examples/with-docker-compose/next-app/src/pages/index.tsx b/examples/with-docker-compose/next-app/src/pages/index.tsx index c1d66369a0651..e6a00dac07b78 100644 --- a/examples/with-docker-compose/next-app/src/pages/index.tsx +++ b/examples/with-docker-compose/next-app/src/pages/index.tsx @@ -41,6 +41,8 @@ export default function Home() {

Deploy →

diff --git a/examples/with-docker-multi-env/pages/index.js b/examples/with-docker-multi-env/pages/index.js index 51e835d5e8720..8e57d8b0338c8 100644 --- a/examples/with-docker-multi-env/pages/index.js +++ b/examples/with-docker-multi-env/pages/index.js @@ -41,6 +41,8 @@ export default function Home() {

Deploy →

diff --git a/examples/with-docker/pages/index.js b/examples/with-docker/pages/index.js index 0a6884b38582b..55ad6fe7735bd 100644 --- a/examples/with-docker/pages/index.js +++ b/examples/with-docker/pages/index.js @@ -40,6 +40,8 @@ export default function Home() {

Deploy →

diff --git a/examples/with-elasticsearch/pages/index.js b/examples/with-elasticsearch/pages/index.js index 0d2c6e3563e1b..5cc227f6ea5f2 100644 --- a/examples/with-elasticsearch/pages/index.js +++ b/examples/with-elasticsearch/pages/index.js @@ -52,6 +52,8 @@ export default function Home({ isConnected }) {

Deploy →

diff --git a/examples/with-graphql-gateway/pages/index.tsx b/examples/with-graphql-gateway/pages/index.tsx index 86b5b3b5bf3fd..ff4dd21141cf2 100644 --- a/examples/with-graphql-gateway/pages/index.tsx +++ b/examples/with-graphql-gateway/pages/index.tsx @@ -43,6 +43,8 @@ const Home: NextPage = () => {

Deploy →

diff --git a/examples/with-knex/pages/index.js b/examples/with-knex/pages/index.js index 15b08938f116d..a7cbf37c32a2d 100644 --- a/examples/with-knex/pages/index.js +++ b/examples/with-knex/pages/index.js @@ -60,6 +60,8 @@ export default function Home() {

Deploy →

diff --git a/examples/with-mongodb/pages/index.tsx b/examples/with-mongodb/pages/index.tsx index 5d4050150298e..1a452c94fddf2 100644 --- a/examples/with-mongodb/pages/index.tsx +++ b/examples/with-mongodb/pages/index.tsx @@ -74,6 +74,8 @@ export default function Home({

Deploy →

diff --git a/examples/with-particles/pages/index.tsx b/examples/with-particles/pages/index.tsx index 08fe284baaf4f..602ef23288dd0 100644 --- a/examples/with-particles/pages/index.tsx +++ b/examples/with-particles/pages/index.tsx @@ -45,6 +45,8 @@ const Home: NextPage = () => {

Deploy →

diff --git a/examples/with-playwright/pages/index.js b/examples/with-playwright/pages/index.js index 07b0717dcf936..64bfcddf4700b 100644 --- a/examples/with-playwright/pages/index.js +++ b/examples/with-playwright/pages/index.js @@ -50,6 +50,8 @@ export default function Home() {

Deploy →

diff --git a/examples/with-sitemap/pages/index.js b/examples/with-sitemap/pages/index.js index 801b309119227..b597fd02bbff3 100644 --- a/examples/with-sitemap/pages/index.js +++ b/examples/with-sitemap/pages/index.js @@ -38,6 +38,8 @@ export default function Home() {

Deploy →

diff --git a/examples/with-vitest/pages/index.tsx b/examples/with-vitest/pages/index.tsx index 86b5b3b5bf3fd..ff4dd21141cf2 100644 --- a/examples/with-vitest/pages/index.tsx +++ b/examples/with-vitest/pages/index.tsx @@ -43,6 +43,8 @@ const Home: NextPage = () => {

Deploy →

diff --git a/packages/create-next-app/templates/default/pages/index.js b/packages/create-next-app/templates/default/pages/index.js index dc4b64035213f..5bf5574341670 100644 --- a/packages/create-next-app/templates/default/pages/index.js +++ b/packages/create-next-app/templates/default/pages/index.js @@ -42,6 +42,8 @@ export default function Home() {

Deploy →

diff --git a/packages/create-next-app/templates/typescript/pages/index.tsx b/packages/create-next-app/templates/typescript/pages/index.tsx index 86b5b3b5bf3fd..ff4dd21141cf2 100644 --- a/packages/create-next-app/templates/typescript/pages/index.tsx +++ b/packages/create-next-app/templates/typescript/pages/index.tsx @@ -43,6 +43,8 @@ const Home: NextPage = () => {

Deploy →

From 77c8a2c4dde9baf17abcc648ffea3ac883558e6f Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Thu, 22 Sep 2022 09:37:00 -0700 Subject: [PATCH 29/76] Add missing release stats config for app (#40805) Follow-up to https://github.com/vercel/next.js/pull/40780 adds the extra config that is still needed for release stats. x-ref: https://github.com/vercel/next.js/actions/runs/3103134847/jobs/5026594626 --- test/.stats-app/stats-config.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/.stats-app/stats-config.js b/test/.stats-app/stats-config.js index 163dd8b234b06..fb95fd578e620 100644 --- a/test/.stats-app/stats-config.js +++ b/test/.stats-app/stats-config.js @@ -94,6 +94,7 @@ module.exports = { module.exports = { experimental: { appDir: true, + // remove after next stable relase (current v12.3.1) serverComponents: true, }, generateBuildId: () => 'BUILD_ID', @@ -119,6 +120,7 @@ module.exports = { module.exports = { experimental: { appDir: true, + // remove after next stable relase (current v12.3.1) serverComponents: true, }, generateBuildId: () => 'BUILD_ID' @@ -157,6 +159,8 @@ module.exports = { module.exports = { experimental: { appDir: true, + // remove after next stable relase (current v12.3.1) + serverComponents: true }, generateBuildId: () => 'BUILD_ID', swcMinify: true, @@ -182,6 +186,8 @@ module.exports = { module.exports = { experimental: { appDir: true, + // remove after next stable relase (current v12.3.1) + serverComponents: true }, swcMinify: true, generateBuildId: () => 'BUILD_ID' From 75bbf00a8fd9f7b377132986cfc5dc85aba90b1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Born=C3=B6?= Date: Thu, 22 Sep 2022 21:49:02 +0200 Subject: [PATCH 30/76] Add local font loader (#40801) Moves font related types to `next/font` so they can be reused in font loaders. Adds an argument to font loaders, the relative path from the app root to the module consuming the loader. Needed for resolving local files relative to the module calling it. Also used to improve error message. Adds `@next/font/local` font loader. Similar to `@next/font/google` but used to host locally downloaded font files. --- packages/font/local/index.d.ts | 1 + packages/font/local/index.js | 1 + packages/font/local/loader.d.ts | 1 + packages/font/local/loader.js | 1 + packages/font/package.json | 3 +- packages/font/src/google/index.ts | 6 +- packages/font/src/google/loader.ts | 14 +- packages/font/src/local/index.ts | 24 ++ packages/font/src/local/loader.ts | 67 ++++ packages/font/src/local/utils.ts | 112 +++++++ packages/next-swc/crates/core/src/lib.rs | 8 +- .../font_imports_generator.rs | 3 +- .../crates/core/src/next_font_loaders/mod.rs | 17 +- packages/next-swc/crates/core/tests/errors.rs | 13 +- .../next-font-loaders/not-const/output.js | 4 +- .../options-object/output.js | 8 +- .../next-font-loaders/spread-arg/output.js | 2 +- .../next-swc/crates/core/tests/fixture.rs | 9 +- .../default-import/output.js | 2 +- .../next-font-loaders/exports/output.js | 4 +- .../next-font-loaders/font-options/output.js | 2 +- .../next-font-loaders/import-as/output.js | 2 +- .../next-font-loaders/many-args/output.js | 2 +- .../multiple-calls/output.js | 4 +- .../multiple-font-downloaders/output.js | 4 +- .../multiple-fonts/output.js | 4 +- .../multiple-imports/output.js | 4 +- .../next-font-loaders/no-args/output.js | 2 +- packages/next/build/swc/options.js | 11 +- packages/next/build/webpack-config.ts | 1 + .../webpack/loaders/next-font-loader/index.ts | 24 +- .../build/webpack/loaders/next-swc-loader.js | 5 +- packages/next/font/index.d.ts | 14 + scripts/update-google-fonts.js | 4 +- test/e2e/next-font/app/fonts/my-font.woff2 | 1 + .../next-font/app/fonts/my-other-font.woff | 1 + test/e2e/next-font/app/next.config.js | 1 + .../next-font/app/pages/with-local-fonts.js | 24 ++ test/e2e/next-font/index.test.ts | 61 ++++ .../with-font-declarations-file.test.ts | 39 ++- .../with-font-declarations-file/fonts.js | 7 +- .../with-font-declarations-file/my-font.woff2 | 1 + .../next.config.js | 1 + .../pages/local-font.js | 5 + test/unit/google-font-loader.test.ts | 32 ++ test/unit/local-font-loader.test.ts | 315 ++++++++++++++++++ 46 files changed, 803 insertions(+), 68 deletions(-) create mode 100644 packages/font/local/index.d.ts create mode 100644 packages/font/local/index.js create mode 100644 packages/font/local/loader.d.ts create mode 100644 packages/font/local/loader.js create mode 100644 packages/font/src/local/index.ts create mode 100644 packages/font/src/local/loader.ts create mode 100644 packages/font/src/local/utils.ts create mode 100644 packages/next/font/index.d.ts create mode 100644 test/e2e/next-font/app/fonts/my-font.woff2 create mode 100644 test/e2e/next-font/app/fonts/my-other-font.woff create mode 100644 test/e2e/next-font/app/pages/with-local-fonts.js create mode 100644 test/e2e/next-font/with-font-declarations-file/my-font.woff2 create mode 100644 test/e2e/next-font/with-font-declarations-file/pages/local-font.js create mode 100644 test/unit/local-font-loader.test.ts diff --git a/packages/font/local/index.d.ts b/packages/font/local/index.d.ts new file mode 100644 index 0000000000000..daa1a73acf5f9 --- /dev/null +++ b/packages/font/local/index.d.ts @@ -0,0 +1 @@ +export { default } from '../dist/local/index' diff --git a/packages/font/local/index.js b/packages/font/local/index.js new file mode 100644 index 0000000000000..8b9773a4a1b66 --- /dev/null +++ b/packages/font/local/index.js @@ -0,0 +1 @@ +throw new Error('@next/font/local is not correctly setup') diff --git a/packages/font/local/loader.d.ts b/packages/font/local/loader.d.ts new file mode 100644 index 0000000000000..e48dd5b357805 --- /dev/null +++ b/packages/font/local/loader.d.ts @@ -0,0 +1 @@ +export { default } from '../dist/local/loader' diff --git a/packages/font/local/loader.js b/packages/font/local/loader.js new file mode 100644 index 0000000000000..e1567fbc2e3bf --- /dev/null +++ b/packages/font/local/loader.js @@ -0,0 +1 @@ +module.exports = require('../dist/local/loader') diff --git a/packages/font/package.json b/packages/font/package.json index f7febc708ac90..6bdbc91ab325a 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -7,7 +7,8 @@ }, "files": [ "dist", - "google" + "google", + "local" ], "license": "MIT", "scripts": { diff --git a/packages/font/src/google/index.ts b/packages/font/src/google/index.ts index 83921541286c8..7d87c0e229eb6 100644 --- a/packages/font/src/google/index.ts +++ b/packages/font/src/google/index.ts @@ -1,9 +1,5 @@ +import type { FontModule } from 'next/font' type Display = 'auto' | 'block' | 'swap' | 'fallback' | 'optional' -type FontModule = { - className: string - variable: string - style: { fontFamily: string; fontWeight?: number; fontStyle?: string } -} export declare function ABeeZee(options: { variant: '400' | '400-italic' display?: Display diff --git a/packages/font/src/google/loader.ts b/packages/font/src/google/loader.ts index 1985e6111d551..96e35c06067b9 100644 --- a/packages/font/src/google/loader.ts +++ b/packages/font/src/google/loader.ts @@ -1,3 +1,4 @@ +import type { FontLoader } from 'next/font' // @ts-ignore import fetch from 'next/dist/compiled/node-fetch' // @ts-ignore @@ -9,19 +10,12 @@ import { validateData, } from './utils' -type FontLoaderOptions = { - functionName: string - data: any[] - config: any - emitFontFile: (content: Buffer, ext: string, preload: boolean) => string -} - -export default async function downloadGoogleFonts({ +const downloadGoogleFonts: FontLoader = async ({ functionName, data, config, emitFontFile, -}: FontLoaderOptions) { +}) => { if (!config?.subsets) { throw new Error( 'Please specify subsets for `@next/font/google` in your `next.config.js`' @@ -119,3 +113,5 @@ export default async function downloadGoogleFonts({ fallbackFonts: fallback, } } + +export default downloadGoogleFonts diff --git a/packages/font/src/local/index.ts b/packages/font/src/local/index.ts new file mode 100644 index 0000000000000..20f22a17986ca --- /dev/null +++ b/packages/font/src/local/index.ts @@ -0,0 +1,24 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import type { FontModule } from 'next/font' +type Display = 'auto' | 'block' | 'swap' | 'fallback' | 'optional' +type LocalFont = { + src: string | Array<{ file: string; unicodeRange: string }> + display?: Display + weight?: string + style?: string + fallback?: string[] + preload?: boolean + + ascentOverride?: string + descentOverride?: string + fontStretch?: string + fontVariant?: string + fontFeatureSettings?: string + fontVariationSettings?: string + lineGapOverride?: string + sizeAdjust?: string +} + +export default function localFont(options: LocalFont): FontModule { + throw new Error() +} diff --git a/packages/font/src/local/loader.ts b/packages/font/src/local/loader.ts new file mode 100644 index 0000000000000..168660e94f57b --- /dev/null +++ b/packages/font/src/local/loader.ts @@ -0,0 +1,67 @@ +import type { FontLoader } from 'next/font' + +import { promisify } from 'util' +import { validateData } from './utils' + +const fetchFonts: FontLoader = async ({ + functionName, + data, + emitFontFile, + resolve, + fs, +}) => { + const { + family, + files, + display, + weight, + style, + fallback, + preload, + ascentOverride, + descentOverride, + lineGapOverride, + fontStretch, + fontFeatureSettings, + sizeAdjust, + } = validateData(functionName, data) + + const fontFaces = await Promise.all( + files.map(async ({ file, ext, format, unicodeRange }) => { + const resolved = await resolve(file) + const fileBuffer = await promisify(fs.readFile)(resolved) + + const fontUrl = emitFontFile(fileBuffer, ext, preload) + + const fontFaceProperties = [ + ['font-family', `'${family}'`], + ['src', `url(${fontUrl}) format('${format}')`], + ['font-display', display], + ...(weight ? [['font-weight', weight]] : []), + ...(style ? [['font-style', style]] : []), + ...(ascentOverride ? [['ascent-override', ascentOverride]] : []), + ...(descentOverride ? [['descent-override', descentOverride]] : []), + ...(lineGapOverride ? [['line-gap-override', lineGapOverride]] : []), + ...(fontStretch ? [['font-stretch', fontStretch]] : []), + ...(fontFeatureSettings + ? [['font-feature-settings', fontFeatureSettings]] + : []), + ...(sizeAdjust ? [['size-adjust', sizeAdjust]] : []), + ...(unicodeRange ? [['unicode-range', unicodeRange]] : ''), + ] + + return `@font-face { +${fontFaceProperties + .map(([property, value]) => `${property}: ${value};`) + .join('\n')} +}` + }) + ) + + return { + css: fontFaces.join('\n'), + fallbackFonts: fallback, + } +} + +export default fetchFonts diff --git a/packages/font/src/local/utils.ts b/packages/font/src/local/utils.ts new file mode 100644 index 0000000000000..c21fc5ace26c7 --- /dev/null +++ b/packages/font/src/local/utils.ts @@ -0,0 +1,112 @@ +const allowedDisplayValues = ['auto', 'block', 'swap', 'fallback', 'optional'] + +const formatValues = (values: string[]) => + values.map((val) => `\`${val}\``).join(', ') + +const extToFormat = { + woff: 'woff', + woff2: 'woff2', + ttf: 'truetype', + otf: 'opentype', + eot: 'embedded-opentype', +} + +type FontOptions = { + family: string + files: Array<{ + file: string + ext: string + format: string + unicodeRange?: string + }> + display: string + weight?: string + style?: string + fallback?: string[] + preload: boolean + ascentOverride?: string + descentOverride?: string + fontStretch?: string + fontVariant?: string + fontFeatureSettings?: string + fontVariationSettings?: string + lineGapOverride?: string + sizeAdjust?: string +} +export function validateData(functionName: string, data: any): FontOptions { + if (functionName) { + throw new Error(`@next/font/local has no named exports`) + } + let { + src, + display = 'optional', + weight, + style, + fallback, + preload = true, + ascentOverride, + descentOverride, + fontStretch, + fontVariant, + fontFeatureSettings, + fontVariationSettings, + lineGapOverride, + sizeAdjust, + } = data[0] || ({} as any) + + if (!allowedDisplayValues.includes(display)) { + throw new Error( + `Invalid display value \`${display}\`.\nAvailable display values: ${formatValues( + allowedDisplayValues + )}` + ) + } + + const srcArray = Array.isArray(src) ? src : [{ file: src }] + + if (srcArray.length === 0) { + throw new Error('Src must contain one or more files') + } + + const files = srcArray.map(({ file, unicodeRange }) => { + if (!file) { + throw new Error('Src array objects must have a `file` property') + } + if (srcArray.length > 1 && !unicodeRange) { + throw new Error( + "Files must have a unicode-range if there's more than one" + ) + } + + const ext = /\.(woff|woff2|eot|ttf|otf)$/.exec(file)?.[1] + if (!ext) { + throw new Error(`Unexpected file \`${file}\``) + } + return { + file, + unicodeRange, + ext, + format: extToFormat[ext as 'woff' | 'woff2' | 'eot' | 'ttf' | 'otf'], + } + }) + + const family = /.+\/(.+?)\./.exec(files[0].file)![1] + + return { + family, + files, + display, + weight, + style, + fallback, + preload, + ascentOverride, + descentOverride, + fontStretch, + fontVariant, + fontFeatureSettings, + fontVariationSettings, + lineGapOverride, + sizeAdjust, + } +} diff --git a/packages/next-swc/crates/core/src/lib.rs b/packages/next-swc/crates/core/src/lib.rs index 3d3bca8aca192..286cb3cdaf7ab 100644 --- a/packages/next-swc/crates/core/src/lib.rs +++ b/packages/next-swc/crates/core/src/lib.rs @@ -36,7 +36,6 @@ use serde::Deserialize; use std::cell::RefCell; use std::rc::Rc; use std::{path::PathBuf, sync::Arc}; -use swc_core::ecma::atoms::JsWord; use swc_core::{ base::config::ModuleConfig, @@ -113,7 +112,7 @@ pub struct TransformOptions { pub modularize_imports: Option, #[serde(default)] - pub font_loaders: Option>, + pub font_loaders: Option, } pub fn custom_before_pass<'a, C: Comments + 'a>( @@ -218,10 +217,9 @@ where None => Either::Right(noop()), }, match &opts.font_loaders { - Some(font_loaders) => - Either::Left(next_font_loaders::next_font_loaders(font_loaders.clone())), + Some(config) => Either::Left(next_font_loaders::next_font_loaders(config.clone())), None => Either::Right(noop()), - } + }, ) } diff --git a/packages/next-swc/crates/core/src/next_font_loaders/font_imports_generator.rs b/packages/next-swc/crates/core/src/next_font_loaders/font_imports_generator.rs index 6f8e3bb340712..e8f8e35030f83 100644 --- a/packages/next-swc/crates/core/src/next_font_loaders/font_imports_generator.rs +++ b/packages/next-swc/crates/core/src/next_font_loaders/font_imports_generator.rs @@ -7,6 +7,7 @@ use swc_core::ecma::visit::{noop_visit_type, Visit}; pub struct FontImportsGenerator<'a> { pub state: &'a mut super::State, + pub relative_path: &'a str, } impl<'a> FontImportsGenerator<'a> { @@ -41,7 +42,7 @@ impl<'a> FontImportsGenerator<'a> { Some(function) => String::from(&**function), None => String::new(), }; - let mut values = vec![function_name]; + let mut values = vec![self.relative_path.to_string(), function_name]; values.append(&mut json_values); return Some(ImportDecl { diff --git a/packages/next-swc/crates/core/src/next_font_loaders/mod.rs b/packages/next-swc/crates/core/src/next_font_loaders/mod.rs index 4acf0c9ab2a44..05457fdd38935 100644 --- a/packages/next-swc/crates/core/src/next_font_loaders/mod.rs +++ b/packages/next-swc/crates/core/src/next_font_loaders/mod.rs @@ -1,4 +1,5 @@ use fxhash::FxHashSet; +use serde::Deserialize; use swc_core::{ common::{collections::AHashMap, BytePos, Spanned}, ecma::{ @@ -12,9 +13,16 @@ mod find_functions_outside_module_scope; mod font_functions_collector; mod font_imports_generator; -pub fn next_font_loaders(font_loaders: Vec) -> impl Fold + VisitMut { +#[derive(Clone, Debug, Deserialize)] +#[serde(deny_unknown_fields, rename_all = "camelCase")] +pub struct Config { + pub font_loaders: Vec, + pub relative_file_path_from_root: JsWord, +} + +pub fn next_font_loaders(config: Config) -> impl Fold + VisitMut { as_folder(NextFontLoaders { - font_loaders, + config, state: State { ..Default::default() }, @@ -35,7 +43,7 @@ pub struct State { } struct NextFontLoaders { - font_loaders: Vec, + config: Config, state: State, } @@ -45,7 +53,7 @@ impl VisitMut for NextFontLoaders { fn visit_mut_module_items(&mut self, items: &mut Vec) { // Find imported functions from font loaders let mut functions_collector = font_functions_collector::FontFunctionsCollector { - font_loaders: &self.font_loaders, + font_loaders: &self.config.font_loaders, state: &mut self.state, }; items.visit_with(&mut functions_collector); @@ -54,6 +62,7 @@ impl VisitMut for NextFontLoaders { // Generate imports from font function calls let mut import_generator = font_imports_generator::FontImportsGenerator { state: &mut self.state, + relative_path: &self.config.relative_file_path_from_root, }; items.visit_with(&mut import_generator); diff --git a/packages/next-swc/crates/core/tests/errors.rs b/packages/next-swc/crates/core/tests/errors.rs index 83df8f2851280..73010669cd7ce 100644 --- a/packages/next-swc/crates/core/tests/errors.rs +++ b/packages/next-swc/crates/core/tests/errors.rs @@ -1,6 +1,8 @@ use next_swc::{ - disallow_re_export_all_in_page::disallow_re_export_all_in_page, next_dynamic::next_dynamic, - next_font_loaders::next_font_loaders, next_ssg::next_ssg, + disallow_re_export_all_in_page::disallow_re_export_all_in_page, + next_dynamic::next_dynamic, + next_font_loaders::{next_font_loaders, Config as FontLoaderConfig}, + next_ssg::next_ssg, react_server_components::server_components, }; use std::path::PathBuf; @@ -101,7 +103,12 @@ fn next_font_loaders_errors(input: PathBuf) { let output = input.parent().unwrap().join("output.js"); test_fixture_allowing_error( syntax(), - &|_tr| next_font_loaders(vec!["@next/font/google".into(), "cool-fonts".into()]), + &|_tr| { + next_font_loaders(FontLoaderConfig { + relative_file_path_from_root: "pages/test.tsx".into(), + font_loaders: vec!["@next/font/google".into(), "cool-fonts".into()], + }) + }, &input, &output, ); diff --git a/packages/next-swc/crates/core/tests/errors/next-font-loaders/not-const/output.js b/packages/next-swc/crates/core/tests/errors/next-font-loaders/not-const/output.js index 7048782e0b9d9..9d873b5670521 100644 --- a/packages/next-swc/crates/core/tests/errors/next-font-loaders/not-const/output.js +++ b/packages/next-swc/crates/core/tests/errors/next-font-loaders/not-const/output.js @@ -1,4 +1,4 @@ -import inter1 from '@next/font/google?Inter;{"variant":"400"}'; -import inter2 from '@next/font/google?Inter;{"variant":"400"}'; +import inter1 from '@next/font/google?pages/test.tsx;Inter;{"variant":"400"}'; +import inter2 from '@next/font/google?pages/test.tsx;Inter;{"variant":"400"}'; var i = 10; var i2 = 20; diff --git a/packages/next-swc/crates/core/tests/errors/next-font-loaders/options-object/output.js b/packages/next-swc/crates/core/tests/errors/next-font-loaders/options-object/output.js index 073b736199d28..4042e227df674 100644 --- a/packages/next-swc/crates/core/tests/errors/next-font-loaders/options-object/output.js +++ b/packages/next-swc/crates/core/tests/errors/next-font-loaders/options-object/output.js @@ -1,7 +1,7 @@ -import a from "@next/font/google?ABeeZee;{}"; -import a from "@next/font/google?ABeeZee;{}"; -import a from "@next/font/google?ABeeZee;{}"; -import a from "@next/font/google?ABeeZee;{}"; +import a from "@next/font/google?pages/test.tsx;ABeeZee;{}"; +import a from "@next/font/google?pages/test.tsx;ABeeZee;{}"; +import a from "@next/font/google?pages/test.tsx;ABeeZee;{}"; +import a from "@next/font/google?pages/test.tsx;ABeeZee;{}"; const a = fn({ 10: 'hello' }); diff --git a/packages/next-swc/crates/core/tests/errors/next-font-loaders/spread-arg/output.js b/packages/next-swc/crates/core/tests/errors/next-font-loaders/spread-arg/output.js index 786e60366018d..e04a84742131d 100644 --- a/packages/next-swc/crates/core/tests/errors/next-font-loaders/spread-arg/output.js +++ b/packages/next-swc/crates/core/tests/errors/next-font-loaders/spread-arg/output.js @@ -1,2 +1,2 @@ -import inter from "@next/font/google?Inter;{};[]"; +import inter from "@next/font/google?pages/test.tsx;Inter;{};[]"; const a = fn(...{}, ...[]); diff --git a/packages/next-swc/crates/core/tests/fixture.rs b/packages/next-swc/crates/core/tests/fixture.rs index 2df79b9a0002e..104e8d26fb3e9 100644 --- a/packages/next-swc/crates/core/tests/fixture.rs +++ b/packages/next-swc/crates/core/tests/fixture.rs @@ -1,7 +1,7 @@ use next_swc::{ amp_attributes::amp_attributes, next_dynamic::next_dynamic, - next_font_loaders::next_font_loaders, + next_font_loaders::{next_font_loaders, Config as FontLoaderConfig}, next_ssg::next_ssg, page_config::page_config_test, react_remove_properties::remove_properties, @@ -255,7 +255,12 @@ fn next_font_loaders_fixture(input: PathBuf) { let output = input.parent().unwrap().join("output.js"); test_fixture( syntax(), - &|_tr| next_font_loaders(vec!["@next/font/google".into(), "cool-fonts".into()]), + &|_tr| { + next_font_loaders(FontLoaderConfig { + relative_file_path_from_root: "pages/test.tsx".into(), + font_loaders: vec!["@next/font/google".into(), "cool-fonts".into()], + }) + }, &input, &output, ); diff --git a/packages/next-swc/crates/core/tests/fixture/next-font-loaders/default-import/output.js b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/default-import/output.js index dddf305e87bc5..1e068272cd537 100644 --- a/packages/next-swc/crates/core/tests/fixture/next-font-loaders/default-import/output.js +++ b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/default-import/output.js @@ -1 +1 @@ -import font from 'cool-fonts?;{"prop":true}'; +import font from 'cool-fonts?pages/test.tsx;;{"prop":true}'; diff --git a/packages/next-swc/crates/core/tests/fixture/next-font-loaders/exports/output.js b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/exports/output.js index c852f5621a5cb..908f66c1a50da 100644 --- a/packages/next-swc/crates/core/tests/fixture/next-font-loaders/exports/output.js +++ b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/exports/output.js @@ -1,5 +1,5 @@ -import firaCode from "@next/font/google?Abel"; -import inter from "@next/font/google?Inter"; +import firaCode from "@next/font/google?pages/test.tsx;Abel"; +import inter from "@next/font/google?pages/test.tsx;Inter"; import React from 'react'; export { firaCode }; export default inter; diff --git a/packages/next-swc/crates/core/tests/fixture/next-font-loaders/font-options/output.js b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/font-options/output.js index 3e921aeb54bf0..43d79fb55a64a 100644 --- a/packages/next-swc/crates/core/tests/fixture/next-font-loaders/font-options/output.js +++ b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/font-options/output.js @@ -1,3 +1,3 @@ -import firaCode from '@next/font/google?Fira_Code;{"fallback":["system-ui",{"key":false},[]],"key":{"key2":{}},"preload":true,"variant":"400"}'; +import firaCode from '@next/font/google?pages/test.tsx;Fira_Code;{"fallback":["system-ui",{"key":false},[]],"key":{"key2":{}},"preload":true,"variant":"400"}'; import React from 'react'; console.log(firaCode); diff --git a/packages/next-swc/crates/core/tests/fixture/next-font-loaders/import-as/output.js b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/import-as/output.js index a1e93892abaa6..d14f41fc010ab 100644 --- a/packages/next-swc/crates/core/tests/fixture/next-font-loaders/import-as/output.js +++ b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/import-as/output.js @@ -1,2 +1,2 @@ -import acme1 from 'cool-fonts?Acme;{"variant":"400"}'; +import acme1 from 'cool-fonts?pages/test.tsx;Acme;{"variant":"400"}'; import React from 'react'; diff --git a/packages/next-swc/crates/core/tests/fixture/next-font-loaders/many-args/output.js b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/many-args/output.js index fb4b3804ff6eb..9896e087ff717 100644 --- a/packages/next-swc/crates/core/tests/fixture/next-font-loaders/many-args/output.js +++ b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/many-args/output.js @@ -1 +1 @@ -import geo from '@next/font/google?Geo;"test";[1.0];{"a":2.0};3.0'; +import geo from '@next/font/google?pages/test.tsx;Geo;"test";[1.0];{"a":2.0};3.0'; diff --git a/packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-calls/output.js b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-calls/output.js index 32af21eb3d17d..4b669d860af02 100644 --- a/packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-calls/output.js +++ b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-calls/output.js @@ -1,3 +1,3 @@ -import inter from '@next/font/google?Inter;{"display":"swap","variant":"900"}'; -import inter from '@next/font/google?Inter;{"display":"swap","variant":"900"}'; +import inter from '@next/font/google?pages/test.tsx;Inter;{"display":"swap","variant":"900"}'; +import inter from '@next/font/google?pages/test.tsx;Inter;{"display":"swap","variant":"900"}'; import React from 'react'; diff --git a/packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-font-downloaders/output.js b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-font-downloaders/output.js index b85bbd333f678..dbf06563fd43c 100644 --- a/packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-font-downloaders/output.js +++ b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-font-downloaders/output.js @@ -1,3 +1,3 @@ -import inter from '@next/font/google?Inter;{"variant":"900"}'; -import fira from 'cool-fonts?Fira_Code;{"display":"swap","variant":"400"}'; +import inter from '@next/font/google?pages/test.tsx;Inter;{"variant":"900"}'; +import fira from 'cool-fonts?pages/test.tsx;Fira_Code;{"display":"swap","variant":"400"}'; import React from 'react'; diff --git a/packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-fonts/output.js b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-fonts/output.js index 88a0f1bb6b416..16a5d171af7ce 100644 --- a/packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-fonts/output.js +++ b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-fonts/output.js @@ -1,3 +1,3 @@ -import firaCode from '@next/font/google?Fira_Code;{"fallback":["system-ui"],"variant":"400"}'; -import inter from '@next/font/google?Inter;{"display":"swap","variant":"900"}'; +import firaCode from '@next/font/google?pages/test.tsx;Fira_Code;{"fallback":["system-ui"],"variant":"400"}'; +import inter from '@next/font/google?pages/test.tsx;Inter;{"display":"swap","variant":"900"}'; import React from 'react'; diff --git a/packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-imports/output.js b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-imports/output.js index 2c68623d1119e..d81ae9087787a 100644 --- a/packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-imports/output.js +++ b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/multiple-imports/output.js @@ -1,3 +1,3 @@ -import inter from '@next/font/google?Inter;{"variant":"900"}'; -import fira from '@next/font/google?Fira_Code;{"display":"swap","variant":"400"}'; +import inter from '@next/font/google?pages/test.tsx;Inter;{"variant":"900"}'; +import fira from '@next/font/google?pages/test.tsx;Fira_Code;{"display":"swap","variant":"400"}'; import React from 'react'; diff --git a/packages/next-swc/crates/core/tests/fixture/next-font-loaders/no-args/output.js b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/no-args/output.js index f371ef0ea53cf..2145b65163ff1 100644 --- a/packages/next-swc/crates/core/tests/fixture/next-font-loaders/no-args/output.js +++ b/packages/next-swc/crates/core/tests/fixture/next-font-loaders/no-args/output.js @@ -1 +1 @@ -import fira from "@next/font/google?Fira_Code"; +import fira from "@next/font/google?pages/test.tsx;Fira_Code"; diff --git a/packages/next/build/swc/options.js b/packages/next/build/swc/options.js index bb8208b6dd6b4..71043d3bd003c 100644 --- a/packages/next/build/swc/options.js +++ b/packages/next/build/swc/options.js @@ -33,6 +33,7 @@ function getBaseSWCOptions({ jsConfig, swcCacheDir, isServerLayer, + relativeFilePathFromRoot, }) { const parserConfig = getParserOptions({ filename, jsConfig }) const paths = jsConfig?.compilerOptions?.paths @@ -124,8 +125,12 @@ function getBaseSWCOptions({ } : false, fontLoaders: - nextConfig?.experimental?.fontLoaders && - Object.keys(nextConfig.experimental.fontLoaders), + nextConfig?.experimental?.fontLoaders && relativeFilePathFromRoot + ? { + fontLoaders: Object.keys(nextConfig.experimental.fontLoaders), + relativeFilePathFromRoot, + } + : null, } } @@ -220,6 +225,7 @@ export function getLoaderSWCOptions({ jsConfig, supportedBrowsers, swcCacheDir, + relativeFilePathFromRoot, // This is not passed yet as "paths" resolving is handled by webpack currently. // resolvedBaseUrl, }) { @@ -233,6 +239,7 @@ export function getLoaderSWCOptions({ // resolvedBaseUrl, swcCacheDir, isServerLayer, + relativeFilePathFromRoot, }) const isNextDist = nextDistPath.test(filename) diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts index bc0ba8c2faea5..35bb4c7b75182 100644 --- a/packages/next/build/webpack-config.ts +++ b/packages/next/build/webpack-config.ts @@ -646,6 +646,7 @@ export default async function getBaseWebpackConfig( loader: 'next-swc-loader', options: { isServer: isNodeServer || isEdgeServer, + rootDir: dir, pagesDir, hasReactRefresh: dev && isClient, fileReading: config.experimental.swcFileReading, diff --git a/packages/next/build/webpack/loaders/next-font-loader/index.ts b/packages/next/build/webpack/loaders/next-font-loader/index.ts index 196ac837ceb11..7ca2455227b68 100644 --- a/packages/next/build/webpack/loaders/next-font-loader/index.ts +++ b/packages/next/build/webpack/loaders/next-font-loader/index.ts @@ -1,13 +1,10 @@ +import type { FontLoader } from '../../../../font' + import path from 'path' import loaderUtils from 'next/dist/compiled/loader-utils3' import postcssFontLoaderPlugn from './postcss-font-loader' - -type FontLoader = (options: { - functionName: string - data: any[] - config: any - emitFontFile: (content: Buffer, ext: string, preload: boolean) => string -}) => Promise<{ css: string; fallbackFonts: string[] }> +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') @@ -36,7 +33,9 @@ export default async function nextFontLoader(this: any) { } // next-swc next_font_loaders turns each function call argument into JSON seperated by semicolons - let [functionName, ...data] = this.resourceQuery.slice(1).split(';') + let [relativeFilePathFromRoot, functionName, ...data] = this.resourceQuery + .slice(1) + .split(';') data = data.map((value: string) => JSON.parse(value)) try { @@ -49,6 +48,12 @@ export default async function nextFontLoader(this: any) { 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() @@ -77,6 +82,9 @@ export default async function nextFontLoader(this: any) { callback(null, result.css, null, { exports, ast, fontFamilyHash }) } catch (err: any) { err.stack = false + err.message += ` + +${chalk.cyan(`Location: ${relativeFilePathFromRoot}`)}` callback(err) } }) diff --git a/packages/next/build/webpack/loaders/next-swc-loader.js b/packages/next/build/webpack/loaders/next-swc-loader.js index 2012ddbce264c..4826ab9156c00 100644 --- a/packages/next/build/webpack/loaders/next-swc-loader.js +++ b/packages/next/build/webpack/loaders/next-swc-loader.js @@ -28,7 +28,7 @@ DEALINGS IN THE SOFTWARE. import { isWasm, transform } from '../../swc' import { getLoaderSWCOptions } from '../../swc/options' -import { isAbsolute } from 'path' +import path, { isAbsolute } from 'path' async function loaderTransform(parentTrace, source, inputSourceMap) { // Make the loader async @@ -39,6 +39,7 @@ async function loaderTransform(parentTrace, source, inputSourceMap) { const { isServer, isServerLayer, + rootDir, pagesDir, hasReactRefresh, nextConfig, @@ -47,6 +48,7 @@ async function loaderTransform(parentTrace, source, inputSourceMap) { swcCacheDir, } = loaderOptions const isPageFile = filename.startsWith(pagesDir) + const relativeFilePathFromRoot = path.relative(rootDir, filename) const swcOptions = getLoaderSWCOptions({ pagesDir, @@ -60,6 +62,7 @@ async function loaderTransform(parentTrace, source, inputSourceMap) { jsConfig, supportedBrowsers, swcCacheDir, + relativeFilePathFromRoot, }) const programmaticOptions = { diff --git a/packages/next/font/index.d.ts b/packages/next/font/index.d.ts new file mode 100644 index 0000000000000..23c9295d02c31 --- /dev/null +++ b/packages/next/font/index.d.ts @@ -0,0 +1,14 @@ +export type FontModule = { + className: string + variable: string + style: { fontFamily: string; fontWeight?: number; fontStyle?: string } +} + +export type FontLoader = (options: { + functionName: string + data: any[] + config: any + emitFontFile: (content: Buffer, ext: string, preload: boolean) => string + resolve: (src: string) => string + fs: any +}) => Promise<{ css: string; fallbackFonts?: string[] }> diff --git a/scripts/update-google-fonts.js b/scripts/update-google-fonts.js index c8d808dc8b768..cc323efc3a246 100644 --- a/scripts/update-google-fonts.js +++ b/scripts/update-google-fonts.js @@ -7,8 +7,8 @@ const fetch = require('node-fetch') 'https://fonts.google.com/metadata/fonts' ).then((r) => r.json()) - let fontFunctions = `type Display = 'auto'|'block'|'swap'|'fallback'|'optional' -type FontModule = { className: string, variable: string, style: { fontFamily: string, fontWeight?: number, fontStyle?: string } } + let fontFunctions = `import type { FontModule } from 'next/font' + type Display = 'auto'|'block'|'swap'|'fallback'|'optional' ` const fontData = {} for (let { family, fonts, axes } of familyMetadataList) { diff --git a/test/e2e/next-font/app/fonts/my-font.woff2 b/test/e2e/next-font/app/fonts/my-font.woff2 new file mode 100644 index 0000000000000..7f7c21b8917a6 --- /dev/null +++ b/test/e2e/next-font/app/fonts/my-font.woff2 @@ -0,0 +1 @@ +fake font \ No newline at end of file diff --git a/test/e2e/next-font/app/fonts/my-other-font.woff b/test/e2e/next-font/app/fonts/my-other-font.woff new file mode 100644 index 0000000000000..bf8c513058c62 --- /dev/null +++ b/test/e2e/next-font/app/fonts/my-other-font.woff @@ -0,0 +1 @@ +my other fake font \ No newline at end of file diff --git a/test/e2e/next-font/app/next.config.js b/test/e2e/next-font/app/next.config.js index 6cd855478a746..ebfb4a7678a58 100644 --- a/test/e2e/next-font/app/next.config.js +++ b/test/e2e/next-font/app/next.config.js @@ -4,6 +4,7 @@ module.exports = { '@next/font/google': { subsets: ['latin'], }, + '@next/font/local': {}, }, }, } diff --git a/test/e2e/next-font/app/pages/with-local-fonts.js b/test/e2e/next-font/app/pages/with-local-fonts.js new file mode 100644 index 0000000000000..7294d821e407a --- /dev/null +++ b/test/e2e/next-font/app/pages/with-local-fonts.js @@ -0,0 +1,24 @@ +import localFont from '@next/font/local' + +const myFont1 = localFont({ + src: '../fonts/my-font.woff2', + style: 'italic', + weight: '100', +}) +const myFont2 = localFont({ + src: '../fonts/my-other-font.woff', + preload: false, +}) + +export default function WithFonts() { + return ( + <> +
+ {JSON.stringify(myFont1)} +
+
+ {JSON.stringify(myFont2)} +
+ + ) +} diff --git a/test/e2e/next-font/index.test.ts b/test/e2e/next-font/index.test.ts index aed14be9eb00e..8795d7ead1e19 100644 --- a/test/e2e/next-font/index.test.ts +++ b/test/e2e/next-font/index.test.ts @@ -22,6 +22,7 @@ describe('@next/font/google', () => { files: { pages: new FileRef(join(__dirname, 'app/pages')), components: new FileRef(join(__dirname, 'app/components')), + fonts: new FileRef(join(__dirname, 'app/fonts')), 'next.config.js': new FileRef(join(__dirname, 'app/next.config.js')), }, dependencies: { @@ -79,6 +80,39 @@ describe('@next/font/google', () => { }, }) }) + + test('page with local fonts', async () => { + const html = await renderViaHTTP(next.url, '/with-local-fonts') + const $ = cheerio.load(html) + + // _app.js + expect(JSON.parse($('#app-open-sans').text())).toEqual({ + className: expect.any(String), + variable: expect.any(String), + style: { + fontFamily: "'__Open_Sans_bbc724', '__open-sans-fallback_bbc724'", + fontStyle: 'normal', + }, + }) + + // with-local-fonts.js + expect(JSON.parse($('#first-local-font').text())).toEqual({ + className: expect.any(String), + variable: expect.any(String), + style: { + fontFamily: "'__my-font_2cddd5'", + fontStyle: 'italic', + fontWeight: 100, + }, + }) + expect(JSON.parse($('#second-local-font').text())).toEqual({ + className: expect.any(String), + variable: expect.any(String), + style: { + fontFamily: "'__my-other-font_0a2813'", + }, + }) + }) }) describe('computed styles', () => { @@ -290,5 +324,32 @@ describe('@next/font/google', () => { type: 'font/woff2', }) }) + + test('page with local fonts', async () => { + const html = await renderViaHTTP(next.url, '/with-local-fonts') + const $ = cheerio.load(html) + + // Preconnect + expect($('link[rel="preconnect"]').length).toBe(0) + + // Preload + expect($('link[as="font"]').length).toBe(2) + // _app + expect($('link[as="font"]').get(0).attribs).toEqual({ + as: 'font', + crossorigin: 'anonymous', + href: '/_next/static/fonts/0812efcfaefec5ea.p.woff2', + rel: 'preload', + type: 'font/woff2', + }) + // with-local-fonts + expect($('link[as="font"]').get(1).attribs).toEqual({ + as: 'font', + crossorigin: 'anonymous', + href: '/_next/static/fonts/7be88d77534e80fd.p.woff2', + rel: 'preload', + type: 'font/woff2', + }) + }) }) }) diff --git a/test/e2e/next-font/with-font-declarations-file.test.ts b/test/e2e/next-font/with-font-declarations-file.test.ts index c6d5bca36edc5..ef62aad0fb9b9 100644 --- a/test/e2e/next-font/with-font-declarations-file.test.ts +++ b/test/e2e/next-font/with-font-declarations-file.test.ts @@ -30,6 +30,9 @@ describe('@next/font/google with-font-declarations-file', () => { 'fonts.js': new FileRef( join(__dirname, 'with-font-declarations-file/fonts.js') ), + 'my-font.woff2': new FileRef( + join(__dirname, 'with-font-declarations-file/my-font.woff2') + ), 'next.config.js': new FileRef( join(__dirname, 'with-font-declarations-file/next.config.js') ), @@ -53,7 +56,7 @@ describe('@next/font/google with-font-declarations-file', () => { if (isDev) { // In dev all fonts will be preloaded since it's before DCE - expect($('link[as="font"]').length).toBe(3) + expect($('link[as="font"]').length).toBe(4) } else { // Preload expect($('link[as="font"]').length).toBe(2) @@ -85,7 +88,7 @@ describe('@next/font/google with-font-declarations-file', () => { if (isDev) { // In dev all fonts will be preloaded since it's before DCE - expect($('link[as="font"]').length).toBe(3) + expect($('link[as="font"]').length).toBe(4) } else { // Preload expect($('link[as="font"]').length).toBe(2) @@ -107,4 +110,36 @@ describe('@next/font/google with-font-declarations-file', () => { }) } }) + + test('preload correct files at /local-font', async () => { + const html = await renderViaHTTP(next.url, '/local-font') + const $ = cheerio.load(html) + + // Preconnect + expect($('link[rel="preconnect"]').length).toBe(0) + + if (isDev) { + // In dev all fonts will be preloaded since it's before DCE + expect($('link[as="font"]').length).toBe(4) + } else { + // Preload + expect($('link[as="font"]').length).toBe(2) + // From /_app + expect($('link[as="font"]').get(0).attribs).toEqual({ + as: 'font', + crossorigin: 'anonymous', + href: '/_next/static/fonts/0812efcfaefec5ea.p.woff2', + rel: 'preload', + type: 'font/woff2', + }) + // From /local-font + expect($('link[as="font"]').get(1).attribs).toEqual({ + as: 'font', + crossorigin: 'anonymous', + href: '/_next/static/fonts/2a931eed088772c9.p.woff2', + rel: 'preload', + type: 'font/woff2', + }) + } + }) }) diff --git a/test/e2e/next-font/with-font-declarations-file/fonts.js b/test/e2e/next-font/with-font-declarations-file/fonts.js index 9e82f26c76719..d4785f5c39316 100644 --- a/test/e2e/next-font/with-font-declarations-file/fonts.js +++ b/test/e2e/next-font/with-font-declarations-file/fonts.js @@ -1,3 +1,4 @@ +import localFont from '@next/font/local' import { Open_Sans, Source_Code_Pro, @@ -13,4 +14,8 @@ const abel = Abel({ variant: '400', display: 'optional', preload: false }) const inter = Inter({ display: 'block', preload: true }) const roboto = Roboto({ variant: '400' }) -export { openSans, sourceCodePro, abel, inter, roboto } +const myLocalFont = localFont({ + src: './my-font.woff2', +}) + +export { openSans, sourceCodePro, abel, inter, roboto, myLocalFont } diff --git a/test/e2e/next-font/with-font-declarations-file/my-font.woff2 b/test/e2e/next-font/with-font-declarations-file/my-font.woff2 new file mode 100644 index 0000000000000..ce41b5e6ef948 --- /dev/null +++ b/test/e2e/next-font/with-font-declarations-file/my-font.woff2 @@ -0,0 +1 @@ +fake font data \ No newline at end of file diff --git a/test/e2e/next-font/with-font-declarations-file/next.config.js b/test/e2e/next-font/with-font-declarations-file/next.config.js index 6cd855478a746..ebfb4a7678a58 100644 --- a/test/e2e/next-font/with-font-declarations-file/next.config.js +++ b/test/e2e/next-font/with-font-declarations-file/next.config.js @@ -4,6 +4,7 @@ module.exports = { '@next/font/google': { subsets: ['latin'], }, + '@next/font/local': {}, }, }, } diff --git a/test/e2e/next-font/with-font-declarations-file/pages/local-font.js b/test/e2e/next-font/with-font-declarations-file/pages/local-font.js new file mode 100644 index 0000000000000..1f1f3be35601d --- /dev/null +++ b/test/e2e/next-font/with-font-declarations-file/pages/local-font.js @@ -0,0 +1,5 @@ +import { myLocalFont } from '../fonts' + +export default function LocalFont() { + return

Hello world!

+} diff --git a/test/unit/google-font-loader.test.ts b/test/unit/google-font-loader.test.ts index 8c73f84a49d25..85ce628b035c0 100644 --- a/test/unit/google-font-loader.test.ts +++ b/test/unit/google-font-loader.test.ts @@ -78,6 +78,8 @@ describe('@next/font/google loader', () => { data: [{ adjustFontFallback: false, ...data }], config: { subsets: [] }, emitFontFile: jest.fn(), + resolve: jest.fn(), + fs: {} as any, }) expect(css).toBe('OK') expect(fetch).toHaveBeenCalledTimes(1) @@ -96,6 +98,8 @@ describe('@next/font/google loader', () => { data: [], config: { subsets: [] }, emitFontFile: jest.fn(), + resolve: jest.fn(), + fs: {} as any, }) expect(css).toMatchInlineSnapshot(` " @@ -121,6 +125,8 @@ describe('@next/font/google loader', () => { data: [], config: { subsets: [] }, emitFontFile: jest.fn(), + resolve: jest.fn(), + fs: {} as any, }) expect(css).toMatchInlineSnapshot(` " @@ -146,6 +152,8 @@ describe('@next/font/google loader', () => { data: [{ fallback: ['Abc', 'Def'] }], config: { subsets: [] }, emitFontFile: jest.fn(), + resolve: jest.fn(), + fs: {} as any, }) expect(css).toMatchInlineSnapshot(` " @@ -171,6 +179,8 @@ describe('@next/font/google loader', () => { data: [{ adjustFontFallback: false, fallback: ['system-ui', 'Arial'] }], config: { subsets: [] }, emitFontFile: jest.fn(), + resolve: jest.fn(), + fs: {} as any, }) expect(css).toBe('') expect(fallbackFonts).toEqual(['system-ui', 'Arial']) @@ -189,6 +199,8 @@ describe('@next/font/google loader', () => { data: [], config: { subsets: [] }, emitFontFile: jest.fn(), + resolve: jest.fn(), + fs: {} as any, }) ).rejects.toThrowErrorMatchingInlineSnapshot(` "Failed to fetch font \`Inter\`. @@ -203,6 +215,8 @@ describe('@next/font/google loader', () => { data: [], config: undefined, emitFontFile: jest.fn(), + resolve: jest.fn(), + fs: {} as any, }) ).rejects.toThrowErrorMatchingInlineSnapshot( `"Please specify subsets for \`@next/font/google\` in your \`next.config.js\`"` @@ -216,6 +230,8 @@ describe('@next/font/google loader', () => { data: [], config: { subsets: [] }, emitFontFile: jest.fn(), + resolve: jest.fn(), + fs: {} as any, }) ).rejects.toThrowErrorMatchingInlineSnapshot( `"@next/font/google has no default export"` @@ -229,6 +245,8 @@ describe('@next/font/google loader', () => { data: [], config: { subsets: [] }, emitFontFile: jest.fn(), + resolve: jest.fn(), + fs: {} as any, }) ).rejects.toThrowErrorMatchingInlineSnapshot( `"Unknown font \`Unknown Font\`"` @@ -242,6 +260,8 @@ describe('@next/font/google loader', () => { data: [{ variant: '123' }], config: { subsets: [] }, emitFontFile: jest.fn(), + resolve: jest.fn(), + fs: {} as any, }) ).rejects.toThrowErrorMatchingInlineSnapshot(` "Unknown variant \`123\` for font \`Inter\`. @@ -256,6 +276,8 @@ describe('@next/font/google loader', () => { data: [], config: { subsets: [] }, emitFontFile: jest.fn(), + resolve: jest.fn(), + fs: {} as any, }) ).rejects.toThrowErrorMatchingInlineSnapshot(` "Missing variant for font \`Abel\`. @@ -270,6 +292,8 @@ describe('@next/font/google loader', () => { data: [{ display: 'invalid' }], config: { subsets: [] }, emitFontFile: jest.fn(), + resolve: jest.fn(), + fs: {} as any, }) ).rejects.toThrowErrorMatchingInlineSnapshot(` "Invalid display value \`invalid\` for font \`Inter\`. @@ -284,6 +308,8 @@ describe('@next/font/google loader', () => { data: [{ variant: '400', axes: [] }], config: { subsets: [] }, emitFontFile: jest.fn(), + resolve: jest.fn(), + fs: {} as any, }) ).rejects.toThrowErrorMatchingInlineSnapshot( `"Axes can only be defined for variable fonts"` @@ -297,6 +323,8 @@ describe('@next/font/google loader', () => { data: [{ axes: [] }], config: { subsets: [] }, emitFontFile: jest.fn(), + resolve: jest.fn(), + fs: {} as any, }) ).rejects.toThrowErrorMatchingInlineSnapshot( `"Font \`Lora\` has no definable \`axes\`"` @@ -310,6 +338,8 @@ describe('@next/font/google loader', () => { data: [{ axes: true }], config: { subsets: [] }, emitFontFile: jest.fn(), + resolve: jest.fn(), + fs: {} as any, }) ).rejects.toThrowErrorMatchingInlineSnapshot(` "Invalid axes value for font \`Inter\`, expected an array of axes. @@ -324,6 +354,8 @@ describe('@next/font/google loader', () => { data: [{ axes: ['INVALID'] }], config: { subsets: [] }, emitFontFile: jest.fn(), + resolve: jest.fn(), + fs: {} as any, }) ).rejects.toThrowErrorMatchingInlineSnapshot(` "Invalid axes value \`INVALID\` for font \`Roboto Flex\`. diff --git a/test/unit/local-font-loader.test.ts b/test/unit/local-font-loader.test.ts new file mode 100644 index 0000000000000..892ce9aa00dcf --- /dev/null +++ b/test/unit/local-font-loader.test.ts @@ -0,0 +1,315 @@ +import loader from '@next/font/local/loader' + +describe('@next/font/local', () => { + describe('generated CSS', () => { + test('Default CSS', async () => { + const { css } = await loader({ + functionName: '', + data: [{ src: './my-font.woff2' }], + config: {}, + emitFontFile: () => '/_next/static/fonts/my-font.woff2', + resolve: jest.fn(), + fs: { + readFile: (_, cb) => cb(null, 'fontdata'), + }, + }) + + expect(css).toMatchInlineSnapshot(` +"@font-face { +font-family: 'my-font'; +src: url(/_next/static/fonts/my-font.woff2) format('woff2'); +font-display: optional; +}" +`) + }) + + test('Default CSS - src array with unicodeRange', async () => { + const { css } = await loader({ + functionName: '', + data: [ + { src: [{ file: './my-font.woff2', unicodeRange: 'unicode-range' }] }, + ], + config: {}, + emitFontFile: () => '/_next/static/fonts/my-font.woff2', + resolve: jest.fn(), + fs: { + readFile: (_, cb) => cb(null, 'fontdata'), + }, + }) + + expect(css).toMatchInlineSnapshot(` +"@font-face { +font-family: 'my-font'; +src: url(/_next/static/fonts/my-font.woff2) format('woff2'); +font-display: optional; +unicode-range: unicode-range; +}" +`) + }) + + test('Default CSS - src array without unicodeRange', async () => { + const { css } = await loader({ + functionName: '', + data: [{ src: [{ file: './my-font.woff2' }] }], + config: {}, + emitFontFile: () => '/_next/static/fonts/my-font.woff2', + resolve: jest.fn(), + fs: { + readFile: (_, cb) => cb(null, 'fontdata'), + }, + }) + + expect(css).toMatchInlineSnapshot(` +"@font-face { +font-family: 'my-font'; +src: url(/_next/static/fonts/my-font.woff2) format('woff2'); +font-display: optional; +}" +`) + }) + + test('Weight and style', async () => { + const { css } = await loader({ + functionName: '', + data: [{ src: './my-font.woff2', weight: '100 900', style: 'italic' }], + config: {}, + emitFontFile: () => '/_next/static/fonts/my-font.woff2', + resolve: jest.fn(), + fs: { + readFile: (_, cb) => cb(null, 'fontdata'), + }, + }) + + expect(css).toMatchInlineSnapshot(` +"@font-face { +font-family: 'my-font'; +src: url(/_next/static/fonts/my-font.woff2) format('woff2'); +font-display: optional; +font-weight: 100 900; +font-style: italic; +}" +`) + }) + + test('Other properties', async () => { + const { css } = await loader({ + functionName: '', + data: [ + { + src: './my-font.woff2', + weight: '100 900', + style: 'italic', + ascentOverride: 'ascentOverride', + descentOverride: 'descentOverride', + lineGapOverride: 'lineGapOverride', + fontStretch: 'fontStretch', + fontFeatureSettings: 'fontFeatureSettings', + sizeAdjust: 'sizeAdjust', + }, + ], + config: {}, + emitFontFile: () => '/_next/static/fonts/my-font.woff2', + resolve: jest.fn(), + fs: { + readFile: (_, cb) => cb(null, 'fontdata'), + }, + }) + + expect(css).toMatchInlineSnapshot(` +"@font-face { +font-family: 'my-font'; +src: url(/_next/static/fonts/my-font.woff2) format('woff2'); +font-display: optional; +font-weight: 100 900; +font-style: italic; +ascent-override: ascentOverride; +descent-override: descentOverride; +line-gap-override: lineGapOverride; +font-stretch: fontStretch; +font-feature-settings: fontFeatureSettings; +size-adjust: sizeAdjust; +}" +`) + }) + + test('Multiple files', async () => { + const { css } = await loader({ + functionName: '', + data: [ + { + src: [ + { file: './my-font1.woff', unicodeRange: '1' }, + { file: './my-font2.woff2', unicodeRange: '2' }, + { file: './my-font3.eot', unicodeRange: '3' }, + { file: './my-font4.ttf', unicodeRange: '4' }, + { file: './my-font5.otf', unicodeRange: '5' }, + ], + }, + ], + config: {}, + emitFontFile: () => `/_next/static/fonts/font-file`, + resolve: jest.fn(), + fs: { + readFile: (_, cb) => cb(null, 'fontdata'), + }, + }) + + expect(css).toMatchInlineSnapshot(` +"@font-face { +font-family: 'my-font1'; +src: url(/_next/static/fonts/font-file) format('woff'); +font-display: optional; +unicode-range: 1; +} +@font-face { +font-family: 'my-font1'; +src: url(/_next/static/fonts/font-file) format('woff2'); +font-display: optional; +unicode-range: 2; +} +@font-face { +font-family: 'my-font1'; +src: url(/_next/static/fonts/font-file) format('embedded-opentype'); +font-display: optional; +unicode-range: 3; +} +@font-face { +font-family: 'my-font1'; +src: url(/_next/static/fonts/font-file) format('truetype'); +font-display: optional; +unicode-range: 4; +} +@font-face { +font-family: 'my-font1'; +src: url(/_next/static/fonts/font-file) format('opentype'); +font-display: optional; +unicode-range: 5; +}" +`) + }) + }) + + describe('Errors', () => { + test('Not using default export', async () => { + await expect( + loader({ + functionName: 'Named', + data: [], + config: {}, + emitFontFile: jest.fn(), + resolve: jest.fn(), + fs: {}, + }) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"@next/font/local has no named exports"` + ) + }) + + test('Invalid file extension', async () => { + await expect( + loader({ + functionName: '', + data: [{ src: './font/font-file.abc' }], + config: {}, + emitFontFile: jest.fn(), + resolve: jest.fn().mockResolvedValue(''), + fs: {}, + }) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Unexpected file \`./font/font-file.abc\`"` + ) + }) + + test('Invalid display value', async () => { + await expect( + loader({ + functionName: '', + data: [{ src: './font-file.woff2', display: 'invalid' }], + config: {}, + emitFontFile: jest.fn(), + resolve: jest.fn(), + fs: {}, + }) + ).rejects.toThrowErrorMatchingInlineSnapshot(` + "Invalid display value \`invalid\`. + Available display values: \`auto\`, \`block\`, \`swap\`, \`fallback\`, \`optional\`" + `) + }) + + test('Empty src array', async () => { + await expect( + loader({ + functionName: '', + data: [{ src: [] }], + config: {}, + emitFontFile: jest.fn(), + resolve: jest.fn(), + fs: {}, + }) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Src must contain one or more files"` + ) + }) + + test('Src array must have one or more elements', async () => { + await expect( + loader({ + functionName: '', + data: [{ src: [] }], + config: {}, + emitFontFile: jest.fn(), + resolve: jest.fn(), + fs: {}, + }) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Src must contain one or more files"` + ) + }) + + test('Src array elements must have file property', async () => { + await expect( + loader({ + functionName: '', + data: [ + { + src: [ + { file: './my-font1.woff2', unicodeRange: '1' }, + { unicodeRange: '2' }, + ], + }, + ], + + config: {}, + emitFontFile: jest.fn(), + resolve: jest.fn(), + fs: {}, + }) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Src array objects must have a \`file\` property"` + ) + }) + + test("Src array files must have unicodeRange if there's many files", async () => { + await expect( + loader({ + functionName: '', + data: [ + { + src: [ + { file: './my-font1.woff2', unicodeRange: '1' }, + { file: './my-font2.woff2' }, + ], + }, + ], + + config: {}, + emitFontFile: jest.fn(), + resolve: jest.fn(), + fs: {}, + }) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Files must have a unicode-range if there's more than one"` + ) + }) + }) +}) From 24f2c530255defa1d02d9a675beb06f229f984fc Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Thu, 22 Sep 2022 12:53:58 -0700 Subject: [PATCH 31/76] v12.3.2-canary.4 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-config-next/package.json | 4 ++-- packages/eslint-plugin-next/package.json | 2 +- packages/font/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next-swc/package.json | 2 +- packages/next/package.json | 14 +++++++------- packages/react-dev-overlay/package.json | 2 +- packages/react-refresh-utils/package.json | 2 +- pnpm-lock.yaml | 14 +++++++------- 17 files changed, 30 insertions(+), 30 deletions(-) diff --git a/lerna.json b/lerna.json index dba490cae4889..3c26b343c9ace 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "12.3.2-canary.3" + "version": "12.3.2-canary.4" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index c56dd62e4b76e..5906f61971e33 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "12.3.2-canary.3", + "version": "12.3.2-canary.4", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index cbcb88ae9dc75..62541ccf7f750 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "12.3.2-canary.3", + "version": "12.3.2-canary.4", "description": "ESLint configuration used by NextJS.", "main": "index.js", "license": "MIT", @@ -9,7 +9,7 @@ "directory": "packages/eslint-config-next" }, "dependencies": { - "@next/eslint-plugin-next": "12.3.2-canary.3", + "@next/eslint-plugin-next": "12.3.2-canary.4", "@rushstack/eslint-patch": "^1.1.3", "@typescript-eslint/parser": "^5.21.0", "eslint-import-resolver-node": "^0.3.6", diff --git a/packages/eslint-plugin-next/package.json b/packages/eslint-plugin-next/package.json index 2e09ac99f2f30..93094bd0b8fe0 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "12.3.2-canary.3", + "version": "12.3.2-canary.4", "description": "ESLint plugin for NextJS.", "main": "lib/index.js", "license": "MIT", diff --git a/packages/font/package.json b/packages/font/package.json index 6bdbc91ab325a..2a67fcc728d3f 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,6 +1,6 @@ { "name": "@next/font", - "version": "12.3.2-canary.3", + "version": "12.3.2-canary.4", "repository": { "url": "vercel/next.js", "directory": "packages/font" diff --git a/packages/next-bundle-analyzer/package.json b/packages/next-bundle-analyzer/package.json index 1c5486a250616..e8758f50894e0 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "12.3.2-canary.3", + "version": "12.3.2-canary.4", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index 8666907c3c7b1..ce925182e1d9c 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "12.3.2-canary.3", + "version": "12.3.2-canary.4", "license": "MIT", "dependencies": { "chalk": "4.1.0", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index 245b60c66e4ac..cbd46aad0c940 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "12.3.2-canary.3", + "version": "12.3.2-canary.4", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index b2dc30c024f70..1a4a1ba9e6fde 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "12.3.2-canary.3", + "version": "12.3.2-canary.4", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index 944d76a4a4a7e..797c75fc534fa 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "12.3.2-canary.3", + "version": "12.3.2-canary.4", "repository": { "url": "vercel/next.js", "directory": "packages/next-plugin-storybook" diff --git a/packages/next-polyfill-module/package.json b/packages/next-polyfill-module/package.json index 6f5c12c19a4c7..874e86d5a51bc 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "12.3.2-canary.3", + "version": "12.3.2-canary.4", "description": "A standard library polyfill for ES Modules supporting browsers (Edge 16+, Firefox 60+, Chrome 61+, Safari 10.1+)", "main": "dist/polyfill-module.js", "license": "MIT", diff --git a/packages/next-polyfill-nomodule/package.json b/packages/next-polyfill-nomodule/package.json index 96e3380e70c4a..978f00d53e08f 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "12.3.2-canary.3", + "version": "12.3.2-canary.4", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index 83beff8b84d23..8b87c6d5e3e82 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "12.3.2-canary.3", + "version": "12.3.2-canary.4", "private": true, "scripts": { "build-native": "napi build --platform -p next-swc-napi --cargo-name next_swc_napi native --features plugin", diff --git a/packages/next/package.json b/packages/next/package.json index 9c5e9cb3071a1..47ef826441fed 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "12.3.2-canary.3", + "version": "12.3.2-canary.4", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -68,7 +68,7 @@ ] }, "dependencies": { - "@next/env": "12.3.2-canary.3", + "@next/env": "12.3.2-canary.4", "@swc/helpers": "0.4.11", "caniuse-lite": "^1.0.30001406", "postcss": "8.4.14", @@ -119,11 +119,11 @@ "@hapi/accept": "5.0.2", "@napi-rs/cli": "2.7.0", "@napi-rs/triples": "1.1.0", - "@next/polyfill-module": "12.3.2-canary.3", - "@next/polyfill-nomodule": "12.3.2-canary.3", - "@next/react-dev-overlay": "12.3.2-canary.3", - "@next/react-refresh-utils": "12.3.2-canary.3", - "@next/swc": "12.3.2-canary.3", + "@next/polyfill-module": "12.3.2-canary.4", + "@next/polyfill-nomodule": "12.3.2-canary.4", + "@next/react-dev-overlay": "12.3.2-canary.4", + "@next/react-refresh-utils": "12.3.2-canary.4", + "@next/swc": "12.3.2-canary.4", "@segment/ajv-human-errors": "2.1.2", "@taskr/clear": "1.1.0", "@taskr/esnext": "1.1.0", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index acafb9daea8ce..78edeaa8c42e0 100644 --- a/packages/react-dev-overlay/package.json +++ b/packages/react-dev-overlay/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-dev-overlay", - "version": "12.3.2-canary.3", + "version": "12.3.2-canary.4", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index 7fe9d35cd45f2..0eecc16e3649c 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "12.3.2-canary.3", + "version": "12.3.2-canary.4", "description": "An experimental package providing utilities for React Refresh.", "repository": { "url": "vercel/next.js", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a7539b9c06e12..8190b2823ed44 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -369,7 +369,7 @@ importers: packages/eslint-config-next: specifiers: - '@next/eslint-plugin-next': 12.3.2-canary.3 + '@next/eslint-plugin-next': 12.3.2-canary.4 '@rushstack/eslint-patch': ^1.1.3 '@typescript-eslint/parser': ^5.21.0 eslint-import-resolver-node: ^0.3.6 @@ -428,12 +428,12 @@ importers: '@hapi/accept': 5.0.2 '@napi-rs/cli': 2.7.0 '@napi-rs/triples': 1.1.0 - '@next/env': 12.3.2-canary.3 - '@next/polyfill-module': 12.3.2-canary.3 - '@next/polyfill-nomodule': 12.3.2-canary.3 - '@next/react-dev-overlay': 12.3.2-canary.3 - '@next/react-refresh-utils': 12.3.2-canary.3 - '@next/swc': 12.3.2-canary.3 + '@next/env': 12.3.2-canary.4 + '@next/polyfill-module': 12.3.2-canary.4 + '@next/polyfill-nomodule': 12.3.2-canary.4 + '@next/react-dev-overlay': 12.3.2-canary.4 + '@next/react-refresh-utils': 12.3.2-canary.4 + '@next/swc': 12.3.2-canary.4 '@segment/ajv-human-errors': 2.1.2 '@swc/helpers': 0.4.11 '@taskr/clear': 1.1.0 From cbe0407b8b77d4cea988e766b7a6846f21017b83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Mutte?= Date: Thu, 22 Sep 2022 17:37:41 -0300 Subject: [PATCH 32/76] Update static-html-export.md (#40808) This fixes anchor link in `static-html-export.md` ## Documentation / Examples - [x] Make sure the linting passes by running `pnpm lint` - [x] The "examples guidelines" are followed from [our contributing doc](https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md) --- docs/advanced-features/static-html-export.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/advanced-features/static-html-export.md b/docs/advanced-features/static-html-export.md index 107a348a4f3f5..426a009edd040 100644 --- a/docs/advanced-features/static-html-export.md +++ b/docs/advanced-features/static-html-export.md @@ -45,7 +45,7 @@ The majority of core Next.js features needed to build a static site are supporte - [Client-side data fetching](/docs/basic-features/data-fetching/client-side.md) - [`getStaticProps`](/docs/basic-features/data-fetching/get-static-props.md) - [`getStaticPaths`](/docs/basic-features/data-fetching/get-static-paths.md) -- [Image Optimization](/docs/basic-features/image-optimization.md) using a [custom loader](/docs/basic-features/image-optimization.md#loader) +- [Image Optimization](/docs/basic-features/image-optimization.md) using a [custom loader](/docs/basic-features/image-optimization.md#loaders) ## Unsupported Features From 66ca4c21eb9504abd46b5d3064e905af52302bdc Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Thu, 22 Sep 2022 14:04:50 -0700 Subject: [PATCH 33/76] v12.3.2-canary.5 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-config-next/package.json | 4 ++-- packages/eslint-plugin-next/package.json | 2 +- packages/font/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next-swc/package.json | 2 +- packages/next/package.json | 14 +++++++------- packages/react-dev-overlay/package.json | 2 +- packages/react-refresh-utils/package.json | 2 +- pnpm-lock.yaml | 14 +++++++------- 17 files changed, 30 insertions(+), 30 deletions(-) diff --git a/lerna.json b/lerna.json index 3c26b343c9ace..a59fd30c5eddf 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "12.3.2-canary.4" + "version": "12.3.2-canary.5" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index 5906f61971e33..6afba6af53a43 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "12.3.2-canary.4", + "version": "12.3.2-canary.5", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index 62541ccf7f750..b10a7d0f0cdeb 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "12.3.2-canary.4", + "version": "12.3.2-canary.5", "description": "ESLint configuration used by NextJS.", "main": "index.js", "license": "MIT", @@ -9,7 +9,7 @@ "directory": "packages/eslint-config-next" }, "dependencies": { - "@next/eslint-plugin-next": "12.3.2-canary.4", + "@next/eslint-plugin-next": "12.3.2-canary.5", "@rushstack/eslint-patch": "^1.1.3", "@typescript-eslint/parser": "^5.21.0", "eslint-import-resolver-node": "^0.3.6", diff --git a/packages/eslint-plugin-next/package.json b/packages/eslint-plugin-next/package.json index 93094bd0b8fe0..296c72766a843 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "12.3.2-canary.4", + "version": "12.3.2-canary.5", "description": "ESLint plugin for NextJS.", "main": "lib/index.js", "license": "MIT", diff --git a/packages/font/package.json b/packages/font/package.json index 2a67fcc728d3f..0418f56aaeff0 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,6 +1,6 @@ { "name": "@next/font", - "version": "12.3.2-canary.4", + "version": "12.3.2-canary.5", "repository": { "url": "vercel/next.js", "directory": "packages/font" diff --git a/packages/next-bundle-analyzer/package.json b/packages/next-bundle-analyzer/package.json index e8758f50894e0..75654d60c019b 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "12.3.2-canary.4", + "version": "12.3.2-canary.5", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index ce925182e1d9c..12c3f608858fc 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "12.3.2-canary.4", + "version": "12.3.2-canary.5", "license": "MIT", "dependencies": { "chalk": "4.1.0", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index cbd46aad0c940..9c6be6b3d84a0 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "12.3.2-canary.4", + "version": "12.3.2-canary.5", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index 1a4a1ba9e6fde..6392434e9904d 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "12.3.2-canary.4", + "version": "12.3.2-canary.5", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index 797c75fc534fa..644e838a68ea5 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "12.3.2-canary.4", + "version": "12.3.2-canary.5", "repository": { "url": "vercel/next.js", "directory": "packages/next-plugin-storybook" diff --git a/packages/next-polyfill-module/package.json b/packages/next-polyfill-module/package.json index 874e86d5a51bc..d6354fac890f3 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "12.3.2-canary.4", + "version": "12.3.2-canary.5", "description": "A standard library polyfill for ES Modules supporting browsers (Edge 16+, Firefox 60+, Chrome 61+, Safari 10.1+)", "main": "dist/polyfill-module.js", "license": "MIT", diff --git a/packages/next-polyfill-nomodule/package.json b/packages/next-polyfill-nomodule/package.json index 978f00d53e08f..bd391d93f7d5c 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "12.3.2-canary.4", + "version": "12.3.2-canary.5", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index 8b87c6d5e3e82..228b62f4280c6 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "12.3.2-canary.4", + "version": "12.3.2-canary.5", "private": true, "scripts": { "build-native": "napi build --platform -p next-swc-napi --cargo-name next_swc_napi native --features plugin", diff --git a/packages/next/package.json b/packages/next/package.json index 47ef826441fed..9d31c782dc46b 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "12.3.2-canary.4", + "version": "12.3.2-canary.5", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -68,7 +68,7 @@ ] }, "dependencies": { - "@next/env": "12.3.2-canary.4", + "@next/env": "12.3.2-canary.5", "@swc/helpers": "0.4.11", "caniuse-lite": "^1.0.30001406", "postcss": "8.4.14", @@ -119,11 +119,11 @@ "@hapi/accept": "5.0.2", "@napi-rs/cli": "2.7.0", "@napi-rs/triples": "1.1.0", - "@next/polyfill-module": "12.3.2-canary.4", - "@next/polyfill-nomodule": "12.3.2-canary.4", - "@next/react-dev-overlay": "12.3.2-canary.4", - "@next/react-refresh-utils": "12.3.2-canary.4", - "@next/swc": "12.3.2-canary.4", + "@next/polyfill-module": "12.3.2-canary.5", + "@next/polyfill-nomodule": "12.3.2-canary.5", + "@next/react-dev-overlay": "12.3.2-canary.5", + "@next/react-refresh-utils": "12.3.2-canary.5", + "@next/swc": "12.3.2-canary.5", "@segment/ajv-human-errors": "2.1.2", "@taskr/clear": "1.1.0", "@taskr/esnext": "1.1.0", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index 78edeaa8c42e0..436ff840b868c 100644 --- a/packages/react-dev-overlay/package.json +++ b/packages/react-dev-overlay/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-dev-overlay", - "version": "12.3.2-canary.4", + "version": "12.3.2-canary.5", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index 0eecc16e3649c..8c02e4299d9ca 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "12.3.2-canary.4", + "version": "12.3.2-canary.5", "description": "An experimental package providing utilities for React Refresh.", "repository": { "url": "vercel/next.js", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8190b2823ed44..52c24403581f1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -369,7 +369,7 @@ importers: packages/eslint-config-next: specifiers: - '@next/eslint-plugin-next': 12.3.2-canary.4 + '@next/eslint-plugin-next': 12.3.2-canary.5 '@rushstack/eslint-patch': ^1.1.3 '@typescript-eslint/parser': ^5.21.0 eslint-import-resolver-node: ^0.3.6 @@ -428,12 +428,12 @@ importers: '@hapi/accept': 5.0.2 '@napi-rs/cli': 2.7.0 '@napi-rs/triples': 1.1.0 - '@next/env': 12.3.2-canary.4 - '@next/polyfill-module': 12.3.2-canary.4 - '@next/polyfill-nomodule': 12.3.2-canary.4 - '@next/react-dev-overlay': 12.3.2-canary.4 - '@next/react-refresh-utils': 12.3.2-canary.4 - '@next/swc': 12.3.2-canary.4 + '@next/env': 12.3.2-canary.5 + '@next/polyfill-module': 12.3.2-canary.5 + '@next/polyfill-nomodule': 12.3.2-canary.5 + '@next/react-dev-overlay': 12.3.2-canary.5 + '@next/react-refresh-utils': 12.3.2-canary.5 + '@next/swc': 12.3.2-canary.5 '@segment/ajv-human-errors': 2.1.2 '@swc/helpers': 0.4.11 '@taskr/clear': 1.1.0 From 50b98d50819cc1782c3a650fdb2f4a0edc0a9cff Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Thu, 22 Sep 2022 14:35:09 -0700 Subject: [PATCH 34/76] Tolerate already published error for retrying (#40812) This updates our `publish-native` script to tolerate the already published npm error so that we can retry publishing on an `npm` [service error like noticed here](https://github.com/vercel/next.js/actions/runs/3108335849/jobs/5037966318#step:10:2076). We probably want to migrate away from using `lerna` for publishing the non-swc packages as well so that we can retry there as well but will investigate that in a follow-up. x-ref: https://github.com/vercel/next.js/actions/runs/3108335849/jobs/5038069555 --- scripts/publish-native.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/scripts/publish-native.js b/scripts/publish-native.js index 9b3a4c5985c2d..491cca53b2ef4 100755 --- a/scripts/publish-native.js +++ b/scripts/publish-native.js @@ -46,7 +46,17 @@ const cwd = process.cwd() } catch (err) { // don't block publishing other versions on single platform error console.error(`Failed to publish`, platform) - throw err + + if ( + err.message && + err.message.includes( + 'You cannot publish over the previously published versions' + ) + ) { + console.error('Ignoring already published error', platform) + } else { + throw err + } } // lerna publish in next step will fail if git status is not clean execSync( From 2cbbd61b4a54ebf0c90fa1bd5fcc8cb89b9a3f31 Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Thu, 22 Sep 2022 16:22:17 -0700 Subject: [PATCH 35/76] Update publish script to skip lerna (#40815) This updates our `publish-release` script to bypass lerna so that we can retry publishing automatically when there is an npm error and tolerate non-fatal publish errors like already existing published versions. Currently this will only allow publishing a canary release to ensure it is working as expected and in a follow-up we can enable the stable publish handling. Separately we can investigate moving canaries away from `npm` to reduce the number of versions being created there. x-ref: https://github.com/vercel/next.js/pull/40812 x-ref: https://github.com/vercel/next.js/actions/runs/3108735543/jobs/5038717354#step:10:2332 x-ref: https://github.com/vercel/next.js/actions/runs/3108335849/jobs/5038069555 --- .github/workflows/build_test_deploy.yml | 2 +- scripts/publish-release.js | 77 +++++++++++++++++++++++++ scripts/publish-release.sh | 38 ------------ 3 files changed, 78 insertions(+), 39 deletions(-) create mode 100755 scripts/publish-release.js delete mode 100755 scripts/publish-release.sh diff --git a/.github/workflows/build_test_deploy.yml b/.github/workflows/build_test_deploy.yml index fe28799b023e8..85558349a7e79 100644 --- a/.github/workflows/build_test_deploy.yml +++ b/.github/workflows/build_test_deploy.yml @@ -1008,7 +1008,7 @@ jobs: - run: npm i -g pnpm@${PNPM_VERSION} - run: echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ~/.npmrc - run: ./scripts/publish-native.js $GITHUB_REF - - run: ./scripts/publish-release.sh + - run: ./scripts/publish-release.js testDeployE2E: name: E2E (deploy) diff --git a/scripts/publish-release.js b/scripts/publish-release.js new file mode 100755 index 0000000000000..8023406f94b1f --- /dev/null +++ b/scripts/publish-release.js @@ -0,0 +1,77 @@ +#!/usr/bin/env node +// @ts-check + +const path = require('path') +const { readdir } = require('fs/promises') +const { execSync } = require('child_process') + +const cwd = process.cwd() + +;(async function () { + let isCanary = false + + if (!process.env.NPM_TOKEN) { + console.log('No NPM_TOKEN, exiting...') + return + } + + try { + const tagOutput = execSync('git describe --exact-match').toString() + console.log(tagOutput) + isCanary = tagOutput.includes('-canary') + } catch (err) { + console.log(err) + + if (err.message && err.message.includes('no tag exactly matches')) { + console.log('Nothing to publish, exiting...') + return + } + throw err + } + console.log(`Publishing ${isCanary ? 'canary' : 'stable'}`) + + // TODO: remove after testing, this is a safe guard to ensure we + // don't publish stable unexpectedly + if (!isCanary) { + return + } + + const packagesDir = path.join(cwd, 'packages') + const packageDirs = await readdir(packagesDir) + + const publish = async (pkg, retry = 0) => { + try { + execSync( + `npm publish ${path.join(packagesDir, pkg)} --access public${ + isCanary ? ' --tag canary' : '' + }` + ) + } catch (err) { + console.error(`Failed to publish ${pkg}`, err) + + if ( + err.message && + err.message.includes( + 'You cannot publish over the previously published versions' + ) + ) { + console.error('Ignoring already published error', pkg) + return + } + + if (retry < 3) { + const retryDelaySeconds = 15 + console.log(`retrying in ${retryDelaySeconds}s`) + await new Promise((resolve) => + setTimeout(resolve, retryDelaySeconds * 1000) + ) + await publish(pkg, retry + 1) + } + throw err + } + } + + for (const packageDir of packageDirs) { + await publish(packageDir) + } +})() diff --git a/scripts/publish-release.sh b/scripts/publish-release.sh deleted file mode 100755 index a52671ccdf93e..0000000000000 --- a/scripts/publish-release.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/bash - -git describe --exact-match - -if [[ ! $? -eq 0 ]];then - echo "Nothing to publish, exiting.." - exit 0; -fi - -if [[ -z "$NPM_TOKEN" ]];then - echo "No NPM_TOKEN, exiting.." - exit 0; -fi - -if [[ $(git describe --exact-match 2> /dev/null || :) =~ -canary ]]; -then - echo "Publishing canary" - yarn run lerna publish from-git --npm-tag canary --no-git-reset --no-verify-access --yes - - # Make sure to exit script with code 1 if publish failed - if [[ ! $? -eq 0 ]];then - exit 1; - fi -else - echo "Did not publish canary" -fi - -if [[ ! $(git describe --exact-match 2> /dev/null || :) =~ -canary ]];then - echo "Publishing stable" - yarn run lerna publish from-git --no-git-reset --no-verify-access --yes - - # Make sure to exit script with code 1 if publish failed - if [[ ! $? -eq 0 ]];then - exit 1; - fi -else - echo "Did not publish stable" -fi From 0e3233de535d26cb76c221dbde5eb72c96e64305 Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Thu, 22 Sep 2022 16:26:31 -0700 Subject: [PATCH 36/76] Disable flakey dev app test temporarily (#40816) x-ref: [slack thread](https://vercel.slack.com/archives/C035J346QQL/p1663822388387959) x-ref: https://github.com/vercel/next.js/actions/runs/3108897192/jobs/5038639320 x-ref: https://github.com/vercel/next.js/actions/runs/3107019059/jobs/5034678245 x-ref: https://github.com/vercel/next.js/actions/runs/3104956805/jobs/5030065922 --- test/e2e/app-dir/prefetching.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/e2e/app-dir/prefetching.test.ts b/test/e2e/app-dir/prefetching.test.ts index 5f9f6bdb54747..fceb94836e9c9 100644 --- a/test/e2e/app-dir/prefetching.test.ts +++ b/test/e2e/app-dir/prefetching.test.ts @@ -5,7 +5,8 @@ import path from 'path' import webdriver from 'next-webdriver' describe('app dir prefetching', () => { - if ((global as any).isNextDeploy) { + // TODO: re-enable for dev after https://vercel.slack.com/archives/C035J346QQL/p1663822388387959 is resolved (Sep 22nd 2022) + if ((global as any).isNextDeploy || (global as any).isNextDev) { it('should skip next deploy for now', () => {}) return } From 8e1256d024208fbecfe0f436ac79a9ced1a0a7ac Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Thu, 22 Sep 2022 16:33:46 -0700 Subject: [PATCH 37/76] v12.3.2-canary.6 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-config-next/package.json | 4 ++-- packages/eslint-plugin-next/package.json | 2 +- packages/font/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next-swc/package.json | 2 +- packages/next/package.json | 14 +++++++------- packages/react-dev-overlay/package.json | 2 +- packages/react-refresh-utils/package.json | 2 +- pnpm-lock.yaml | 14 +++++++------- 17 files changed, 30 insertions(+), 30 deletions(-) diff --git a/lerna.json b/lerna.json index a59fd30c5eddf..75e007ac7339f 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "12.3.2-canary.5" + "version": "12.3.2-canary.6" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index 6afba6af53a43..d9d62269a949e 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "12.3.2-canary.5", + "version": "12.3.2-canary.6", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index b10a7d0f0cdeb..7ddf0594e4def 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "12.3.2-canary.5", + "version": "12.3.2-canary.6", "description": "ESLint configuration used by NextJS.", "main": "index.js", "license": "MIT", @@ -9,7 +9,7 @@ "directory": "packages/eslint-config-next" }, "dependencies": { - "@next/eslint-plugin-next": "12.3.2-canary.5", + "@next/eslint-plugin-next": "12.3.2-canary.6", "@rushstack/eslint-patch": "^1.1.3", "@typescript-eslint/parser": "^5.21.0", "eslint-import-resolver-node": "^0.3.6", diff --git a/packages/eslint-plugin-next/package.json b/packages/eslint-plugin-next/package.json index 296c72766a843..3643fd1fe1822 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "12.3.2-canary.5", + "version": "12.3.2-canary.6", "description": "ESLint plugin for NextJS.", "main": "lib/index.js", "license": "MIT", diff --git a/packages/font/package.json b/packages/font/package.json index 0418f56aaeff0..46159922ed612 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,6 +1,6 @@ { "name": "@next/font", - "version": "12.3.2-canary.5", + "version": "12.3.2-canary.6", "repository": { "url": "vercel/next.js", "directory": "packages/font" diff --git a/packages/next-bundle-analyzer/package.json b/packages/next-bundle-analyzer/package.json index 75654d60c019b..5d5f066105090 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "12.3.2-canary.5", + "version": "12.3.2-canary.6", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index 12c3f608858fc..0ef8232410112 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "12.3.2-canary.5", + "version": "12.3.2-canary.6", "license": "MIT", "dependencies": { "chalk": "4.1.0", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index 9c6be6b3d84a0..64f482b04f193 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "12.3.2-canary.5", + "version": "12.3.2-canary.6", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index 6392434e9904d..53b1c53f47f87 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "12.3.2-canary.5", + "version": "12.3.2-canary.6", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index 644e838a68ea5..c74b909d6fc1b 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "12.3.2-canary.5", + "version": "12.3.2-canary.6", "repository": { "url": "vercel/next.js", "directory": "packages/next-plugin-storybook" diff --git a/packages/next-polyfill-module/package.json b/packages/next-polyfill-module/package.json index d6354fac890f3..77bdf8fcd7406 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "12.3.2-canary.5", + "version": "12.3.2-canary.6", "description": "A standard library polyfill for ES Modules supporting browsers (Edge 16+, Firefox 60+, Chrome 61+, Safari 10.1+)", "main": "dist/polyfill-module.js", "license": "MIT", diff --git a/packages/next-polyfill-nomodule/package.json b/packages/next-polyfill-nomodule/package.json index bd391d93f7d5c..daf37e95e7354 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "12.3.2-canary.5", + "version": "12.3.2-canary.6", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index 228b62f4280c6..552adf22548c4 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "12.3.2-canary.5", + "version": "12.3.2-canary.6", "private": true, "scripts": { "build-native": "napi build --platform -p next-swc-napi --cargo-name next_swc_napi native --features plugin", diff --git a/packages/next/package.json b/packages/next/package.json index 9d31c782dc46b..6bdecdb8e0dcf 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "12.3.2-canary.5", + "version": "12.3.2-canary.6", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -68,7 +68,7 @@ ] }, "dependencies": { - "@next/env": "12.3.2-canary.5", + "@next/env": "12.3.2-canary.6", "@swc/helpers": "0.4.11", "caniuse-lite": "^1.0.30001406", "postcss": "8.4.14", @@ -119,11 +119,11 @@ "@hapi/accept": "5.0.2", "@napi-rs/cli": "2.7.0", "@napi-rs/triples": "1.1.0", - "@next/polyfill-module": "12.3.2-canary.5", - "@next/polyfill-nomodule": "12.3.2-canary.5", - "@next/react-dev-overlay": "12.3.2-canary.5", - "@next/react-refresh-utils": "12.3.2-canary.5", - "@next/swc": "12.3.2-canary.5", + "@next/polyfill-module": "12.3.2-canary.6", + "@next/polyfill-nomodule": "12.3.2-canary.6", + "@next/react-dev-overlay": "12.3.2-canary.6", + "@next/react-refresh-utils": "12.3.2-canary.6", + "@next/swc": "12.3.2-canary.6", "@segment/ajv-human-errors": "2.1.2", "@taskr/clear": "1.1.0", "@taskr/esnext": "1.1.0", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index 436ff840b868c..5bab96014ee83 100644 --- a/packages/react-dev-overlay/package.json +++ b/packages/react-dev-overlay/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-dev-overlay", - "version": "12.3.2-canary.5", + "version": "12.3.2-canary.6", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index 8c02e4299d9ca..a00bec60ff477 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "12.3.2-canary.5", + "version": "12.3.2-canary.6", "description": "An experimental package providing utilities for React Refresh.", "repository": { "url": "vercel/next.js", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 52c24403581f1..81665e581be07 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -369,7 +369,7 @@ importers: packages/eslint-config-next: specifiers: - '@next/eslint-plugin-next': 12.3.2-canary.5 + '@next/eslint-plugin-next': 12.3.2-canary.6 '@rushstack/eslint-patch': ^1.1.3 '@typescript-eslint/parser': ^5.21.0 eslint-import-resolver-node: ^0.3.6 @@ -428,12 +428,12 @@ importers: '@hapi/accept': 5.0.2 '@napi-rs/cli': 2.7.0 '@napi-rs/triples': 1.1.0 - '@next/env': 12.3.2-canary.5 - '@next/polyfill-module': 12.3.2-canary.5 - '@next/polyfill-nomodule': 12.3.2-canary.5 - '@next/react-dev-overlay': 12.3.2-canary.5 - '@next/react-refresh-utils': 12.3.2-canary.5 - '@next/swc': 12.3.2-canary.5 + '@next/env': 12.3.2-canary.6 + '@next/polyfill-module': 12.3.2-canary.6 + '@next/polyfill-nomodule': 12.3.2-canary.6 + '@next/react-dev-overlay': 12.3.2-canary.6 + '@next/react-refresh-utils': 12.3.2-canary.6 + '@next/swc': 12.3.2-canary.6 '@segment/ajv-human-errors': 2.1.2 '@swc/helpers': 0.4.11 '@taskr/clear': 1.1.0 From f19241bf33d0428ff08469913bca78e719147e48 Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Thu, 22 Sep 2022 17:49:44 -0700 Subject: [PATCH 38/76] Update publish to skip private package (#40822) Follow-up to https://github.com/vercel/next.js/pull/40815 ensures we skip attempting to publish private packages like `next-swc` x-ref: https://github.com/vercel/next.js/actions/runs/3109438515/jobs/5039954716 --- packages/font/package.json | 3 --- scripts/publish-release.js | 16 ++++++++++++++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/packages/font/package.json b/packages/font/package.json index 46159922ed612..0fa2d86a34779 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -16,8 +16,5 @@ "prepublishOnly": "cd ../../ && turbo run build", "dev": "tsc -d -w -p tsconfig.json", "typescript": "tsec --noEmit -p tsconfig.json" - }, - "publishConfig": { - "access": "public" } } diff --git a/scripts/publish-release.js b/scripts/publish-release.js index 8023406f94b1f..2cc606e068001 100755 --- a/scripts/publish-release.js +++ b/scripts/publish-release.js @@ -4,11 +4,12 @@ const path = require('path') const { readdir } = require('fs/promises') const { execSync } = require('child_process') +const { readJson } = require('fs-extra') const cwd = process.cwd() ;(async function () { - let isCanary = false + let isCanary = true if (!process.env.NPM_TOKEN) { console.log('No NPM_TOKEN, exiting...') @@ -18,7 +19,10 @@ const cwd = process.cwd() try { const tagOutput = execSync('git describe --exact-match').toString() console.log(tagOutput) - isCanary = tagOutput.includes('-canary') + + if (tagOutput.trim().startsWith('v')) { + isCanary = tagOutput.includes('-canary') + } } catch (err) { console.log(err) @@ -72,6 +76,14 @@ const cwd = process.cwd() } for (const packageDir of packageDirs) { + const pkgJson = await readJson( + path.join(packagesDir, packageDir, 'package.json') + ) + + if (pkgJson.private) { + console.log(`Skipping private package ${packageDir}`) + continue + } await publish(packageDir) } })() From bebf3725a83f59b3c07635f985fe6cec368c1b0b Mon Sep 17 00:00:00 2001 From: David Hay <89824813+hayitsdavid@users.noreply.github.com> Date: Thu, 22 Sep 2022 18:13:16 -0700 Subject: [PATCH 39/76] fix/window.gtag is not defined for Next.js-hydration event(#40410) (#40645) Next.js-hydration now triggered after gtag is initialized. Fixed by adding _document.js and appropriate script elements. --- ## Documentation / Examples - [X] Related issues linked using fixes #40410 - [X] Make sure the linting passes by running `pnpm lint` - [X] The "examples guidelines" are followed from [our contributing doc](https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md) Next.js-hydration now triggered after gtag is initialized. --- .../with-google-analytics/pages/_document.js | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 examples/with-google-analytics/pages/_document.js diff --git a/examples/with-google-analytics/pages/_document.js b/examples/with-google-analytics/pages/_document.js new file mode 100644 index 0000000000000..db3c34b900d5b --- /dev/null +++ b/examples/with-google-analytics/pages/_document.js @@ -0,0 +1,25 @@ +import { Html, Head, Main, NextScript } from 'next/document' + +export default function Document() { + return ( + + + +
+ + + {/* Global Site Tag (gtag.js) - Google Analytics */} + ` writer.write(encodeText(scripts)) - process() + read() } }) } - process() + read() return res } diff --git a/packages/next/server/dev/hot-reloader.ts b/packages/next/server/dev/hot-reloader.ts index cdf1c7c00904a..6a92fe1a1ddf7 100644 --- a/packages/next/server/dev/hot-reloader.ts +++ b/packages/next/server/dev/hot-reloader.ts @@ -626,6 +626,7 @@ export default class HotReloader { ), appDir: this.appDir!, pageExtensions: this.config.pageExtensions, + nextRuntime: 'edge', }).import : undefined @@ -705,6 +706,7 @@ export default class HotReloader { ), appDir: this.appDir!, pageExtensions: this.config.pageExtensions, + nextRuntime: 'nodejs', }) : relativeRequest, appDir: this.config.experimental.appDir, diff --git a/packages/next/taskfile-swc.js b/packages/next/taskfile-swc.js index bf61332c316a8..ea4bcf40ddec2 100644 --- a/packages/next/taskfile-swc.js +++ b/packages/next/taskfile-swc.js @@ -18,6 +18,7 @@ module.exports = function (task) { stripExtension, keepImportAssertions = false, interopClientDefaultExport = false, + esm = false, } = {} ) { // Don't compile .d.ts @@ -28,7 +29,7 @@ module.exports = function (task) { /** @type {import('@swc/core').Options} */ const swcClientOptions = { module: { - type: 'commonjs', + type: esm ? 'es6' : 'commonjs', ignoreDynamic: true, }, jsc: { @@ -59,7 +60,7 @@ module.exports = function (task) { /** @type {import('@swc/core').Options} */ const swcServerOptions = { module: { - type: 'commonjs', + type: esm ? 'es6' : 'commonjs', ignoreDynamic: true, }, env: { @@ -126,7 +127,7 @@ module.exports = function (task) { } if (output.map) { - if (interopClientDefaultExport) { + if (interopClientDefaultExport && !esm) { output.code += ` if ((typeof exports.default === 'function' || (typeof exports.default === 'object' && exports.default !== null)) && typeof exports.default.__esModule === 'undefined') { Object.defineProperty(exports.default, '__esModule', { value: true }); diff --git a/packages/next/taskfile.js b/packages/next/taskfile.js index 51c672b32a287..b91bf3be9ffa6 100644 --- a/packages/next/taskfile.js +++ b/packages/next/taskfile.js @@ -1935,16 +1935,23 @@ export async function compile(task, opts) { 'cli', 'bin', 'server', + 'server_esm', 'nextbuild', 'nextbuildjest', 'nextbuildstatic', + 'nextbuild_esm', 'pages', + 'pages_esm', 'lib', + 'lib_esm', 'client', + 'client_esm', 'telemetry', 'trace', 'shared', + 'shared_esm', 'shared_re_exported', + 'shared_re_exported_esm', 'server_wasm', // we compile this each time so that fresh runtime data is pulled // before each publish @@ -1979,6 +1986,14 @@ export async function lib(task, opts) { notify('Compiled lib files') } +export async function lib_esm(task, opts) { + await task + .source(opts.src || 'lib/**/*.+(js|ts|tsx)') + .swc('server', { dev: opts.dev, esm: true }) + .target('dist/esm/lib') + notify('Compiled lib files') +} + export async function server(task, opts) { await task .source(opts.src || 'server/**/*.+(js|ts|tsx)') @@ -1993,6 +2008,14 @@ export async function server(task, opts) { notify('Compiled server files') } +export async function server_esm(task, opts) { + await task + .source(opts.src || 'server/**/*.+(js|ts|tsx)') + .swc('server', { dev: opts.dev, esm: true }) + .target('dist/esm/server') + notify('Compiled server files to ESM') +} + export async function nextbuild(task, opts) { await task .source(opts.src || 'build/**/*.+(js|ts|tsx)', { @@ -2003,6 +2026,16 @@ export async function nextbuild(task, opts) { notify('Compiled build files') } +export async function nextbuild_esm(task, opts) { + await task + .source(opts.src || 'build/**/*.+(js|ts|tsx)', { + ignore: ['**/fixture/**', '**/tests/**', '**/jest/**'], + }) + .swc('server', { dev: opts.dev, esm: true }) + .target('dist/esm/build') + notify('Compiled build files to ESM') +} + export async function nextbuildjest(task, opts) { await task .source(opts.src || 'build/jest/**/*.+(js|ts|tsx)', { @@ -2021,6 +2054,14 @@ export async function client(task, opts) { notify('Compiled client files') } +export async function client_esm(task, opts) { + await task + .source(opts.src || 'client/**/*.+(js|ts|tsx)') + .swc('client', { dev: opts.dev, esm: true }) + .target('dist/esm/client') + notify('Compiled client files to ESM') +} + // export is a reserved keyword for functions export async function nextbuildstatic(task, opts) { await task @@ -2051,10 +2092,38 @@ export async function pages_document(task, opts) { .target('dist/pages') } +export async function pages_app_esm(task, opts) { + await task + .source('pages/_app.tsx') + .swc('client', { dev: opts.dev, keepImportAssertions: true, esm: true }) + .target('dist/esm/pages') +} + +export async function pages_error_esm(task, opts) { + await task + .source('pages/_error.tsx') + .swc('client', { dev: opts.dev, keepImportAssertions: true, esm: true }) + .target('dist/esm/pages') +} + +export async function pages_document_esm(task, opts) { + await task + .source('pages/_document.tsx') + .swc('server', { dev: opts.dev, keepImportAssertions: true, esm: true }) + .target('dist/esm/pages') +} + export async function pages(task, opts) { await task.parallel(['pages_app', 'pages_error', 'pages_document'], opts) } +export async function pages_esm(task, opts) { + await task.parallel( + ['pages_app_esm', 'pages_error_esm', 'pages_document_esm'], + opts + ) +} + export async function telemetry(task, opts) { await task .source(opts.src || 'telemetry/**/*.+(js|ts|tsx)') @@ -2082,11 +2151,15 @@ export default async function (task) { await task.watch('bin/*', 'bin', opts) await task.watch('pages/**/*.+(js|ts|tsx)', 'pages', opts) await task.watch('server/**/*.+(js|ts|tsx)', 'server', opts) + await task.watch('server/**/*.+(js|ts|tsx)', 'server_esm', opts) await task.watch('build/**/*.+(js|ts|tsx)', 'nextbuild', opts) + await task.watch('build/**/*.+(js|ts|tsx)', 'nextbuild_esm', opts) await task.watch('build/jest/**/*.+(js|ts|tsx)', 'nextbuildjest', opts) await task.watch('export/**/*.+(js|ts|tsx)', 'nextbuildstatic', opts) await task.watch('client/**/*.+(js|ts|tsx)', 'client', opts) + await task.watch('client/**/*.+(js|ts|tsx)', 'client_esm', opts) await task.watch('lib/**/*.+(js|ts|tsx)', 'lib', opts) + await task.watch('lib/**/*.+(js|ts|tsx)', 'lib_esm', opts) await task.watch('cli/**/*.+(js|ts|tsx)', 'cli', opts) await task.watch('telemetry/**/*.+(js|ts|tsx)', 'telemetry', opts) await task.watch('trace/**/*.+(js|ts|tsx)', 'trace', opts) @@ -2100,6 +2173,16 @@ export default async function (task) { 'shared', opts ) + await task.watch( + 'shared/**/!(amp|config|constants|dynamic|head).+(js|ts|tsx)', + 'shared_esm', + opts + ) + await task.watch( + 'shared/lib/{amp,config,constants,dynamic,head}.+(js|ts|tsx)', + 'shared_re_exported_esm', + opts + ) await task.watch('server/**/*.+(wasm)', 'server_wasm', opts) await task.watch( '../react-dev-overlay/dist/**/*.js', @@ -2119,6 +2202,16 @@ export async function shared(task, opts) { notify('Compiled shared files') } +export async function shared_esm(task, opts) { + await task + .source( + opts.src || 'shared/**/!(amp|config|constants|dynamic|head).+(js|ts|tsx)' + ) + .swc('client', { dev: opts.dev, esm: true }) + .target('dist/esm/shared') + notify('Compiled shared files to ESM') +} + export async function shared_re_exported(task, opts) { await task .source( @@ -2130,6 +2223,19 @@ export async function shared_re_exported(task, opts) { notify('Compiled shared re-exported files') } +export async function shared_re_exported_esm(task, opts) { + await task + .source( + opts.src || 'shared/**/{amp,config,constants,dynamic,head}.+(js|ts|tsx)' + ) + .swc('client', { + dev: opts.dev, + esm: true, + }) + .target('dist/esm/shared') + notify('Compiled shared re-exported files as ESM') +} + export async function server_wasm(task, opts) { await task.source(opts.src || 'server/**/*.+(wasm)').target('dist/server') notify('Moved server wasm files') From 3544c795828150f625e0c1ec78701bf7ac39a715 Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Mon, 26 Sep 2022 16:59:46 -0700 Subject: [PATCH 69/76] Bump TypeScript version in with-typescript (#40924) Bumps the version for the legacy `with-typescript` example as it's behind our recommended TypeScript version. We can investigate aliasing this example to the default template in a follow-up. ## Documentation / Examples - [x] 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) x-ref: https://github.com/vercel/next.js/pull/40863#issuecomment-1258771279 --- examples/with-typescript/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/with-typescript/package.json b/examples/with-typescript/package.json index 6c6b04565982e..a8b33ef1d976d 100644 --- a/examples/with-typescript/package.json +++ b/examples/with-typescript/package.json @@ -15,6 +15,6 @@ "@types/node": "^12.12.21", "@types/react": "^17.0.2", "@types/react-dom": "^17.0.1", - "typescript": "4.0" + "typescript": "^4.8.3" } } From 242bf65f987f63d58d14107e80c1fae90bd02480 Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Mon, 26 Sep 2022 17:01:54 -0700 Subject: [PATCH 70/76] Revert "Fix: Contentful webhook body parse." (#40925) Reverts vercel/next.js#40732 x-ref: https://github.com/vercel/next.js/pull/40732#issuecomment-1258779835 --- examples/cms-contentful/pages/api/revalidate.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/cms-contentful/pages/api/revalidate.js b/examples/cms-contentful/pages/api/revalidate.js index a4cf828e518fa..fd5a7078d37f8 100644 --- a/examples/cms-contentful/pages/api/revalidate.js +++ b/examples/cms-contentful/pages/api/revalidate.js @@ -14,7 +14,9 @@ export default async function handler(req, res) { } try { - let postSlug = JSON.parse(req.body).fields.slug['en-US'] + // Note: if this fails to parse you may have forget to set the + // "content-type" header correctly as mentioned here https://github.com/vercel/next.js/blob/canary/examples/cms-contentful/README.md#step-9-try-using-on-demand-revalidation + let postSlug = req.body.fields.slug['en-US'] // revalidate the individual post and the home page await res.revalidate(`/posts/${postSlug}`) From 7903b04bb42c07eab3cca2e4223c028cc2b31092 Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Mon, 26 Sep 2022 21:54:35 -0700 Subject: [PATCH 71/76] Remove extra pnp test (#40929) We already have quite a few PnP tests so this removes one of them that is causing issues with unrelated PRs. x-ref: https://github.com/vercel/next.js/actions/runs/3131979254/jobs/5084663564 --- test/e2e/yarn-pnp/test/with-typescript.test.ts | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 test/e2e/yarn-pnp/test/with-typescript.test.ts diff --git a/test/e2e/yarn-pnp/test/with-typescript.test.ts b/test/e2e/yarn-pnp/test/with-typescript.test.ts deleted file mode 100644 index 07a11a31cea7a..0000000000000 --- a/test/e2e/yarn-pnp/test/with-typescript.test.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { runTests } from './utils' - -describe('yarn PnP', () => { - runTests('with-typescript') -}) From 83f89c4f87a7d3bf90bf0b54a0ee7132fa769dfd Mon Sep 17 00:00:00 2001 From: Bruno Crosier Date: Tue, 27 Sep 2022 06:41:25 +0100 Subject: [PATCH 72/76] Improve types for `` and `responseLimit` (#40863) Currently, a developer building a website using Next.js could write this code with no type errors: ```tsx ``` This PR adds stricter type checking, which will catch this type of error earlier. Similarly, this PR adds stricter types for the `responseLimit`, to ensure the types align to: https://nextjs.org/docs/messages/api-routes-response-size-limit Co-authored-by: Steven Co-authored-by: JJ Kasper --- packages/next/client/future/image.tsx | 8 ++++--- packages/next/client/image.tsx | 8 ++++--- packages/next/server/api-utils/node.ts | 6 ++--- packages/next/server/base-http/node.ts | 3 ++- packages/next/types/index.d.ts | 24 +++++++++++++++++-- .../typescript/pages/invalid.tsx | 18 ++++++++++++++ .../typescript/pages/valid.tsx | 8 +++++++ .../image-future/typescript/pages/invalid.tsx | 18 ++++++++++++++ .../image-future/typescript/pages/valid.tsx | 10 ++++++++ 9 files changed, 91 insertions(+), 12 deletions(-) diff --git a/packages/next/client/future/image.tsx b/packages/next/client/future/image.tsx index dc64f1640d66b..49fea2b31e179 100644 --- a/packages/next/client/future/image.tsx +++ b/packages/next/client/future/image.tsx @@ -72,6 +72,8 @@ interface StaticRequire { type StaticImport = StaticRequire | StaticImageData +type SafeNumber = number | `${number}` + function isStaticRequire( src: StaticRequire | StaticImageData ): src is StaticRequire { @@ -98,11 +100,11 @@ export type ImageProps = Omit< > & { src: string | StaticImport alt: string - width?: number | string - height?: number | string + width?: SafeNumber + height?: SafeNumber fill?: boolean loader?: ImageLoader - quality?: number | string + quality?: SafeNumber priority?: boolean loading?: LoadingValue placeholder?: PlaceholderValue diff --git a/packages/next/client/image.tsx b/packages/next/client/image.tsx index 4018ca7b7e1f0..0d4e55f04e17e 100644 --- a/packages/next/client/image.tsx +++ b/packages/next/client/image.tsx @@ -218,6 +218,8 @@ interface StaticRequire { type StaticImport = StaticRequire | StaticImageData +type SafeNumber = number | `${number}` + function isStaticRequire( src: StaticRequire | StaticImageData ): src is StaticRequire { @@ -243,11 +245,11 @@ export type ImageProps = Omit< 'src' | 'srcSet' | 'ref' | 'width' | 'height' | 'loading' > & { src: string | StaticImport - width?: number | string - height?: number | string + width?: SafeNumber + height?: SafeNumber layout?: LayoutValue loader?: ImageLoader - quality?: number | string + quality?: SafeNumber priority?: boolean loading?: LoadingValue lazyRoot?: React.RefObject | null diff --git a/packages/next/server/api-utils/node.ts b/packages/next/server/api-utils/node.ts index a4fcdb5430843..3900fc214a03a 100644 --- a/packages/next/server/api-utils/node.ts +++ b/packages/next/server/api-utils/node.ts @@ -1,6 +1,6 @@ import type { IncomingMessage, ServerResponse } from 'http' import type { NextApiRequest, NextApiResponse } from '../../shared/lib/utils' -import type { PageConfig } from 'next/types' +import type { PageConfig, ResponseLimit, SizeLimit } from 'next/types' import { checkIsManualRevalidate, PRERENDER_REVALIDATE_ONLY_GENERATED_HEADER, @@ -140,7 +140,7 @@ function parseJson(str: string): object { */ export async function parseBody( req: IncomingMessage, - limit: string | number + limit: SizeLimit ): Promise { let contentType try { @@ -182,7 +182,7 @@ type ApiContext = __ApiPreviewProps & { revalidate?: (_req: IncomingMessage, _res: ServerResponse) => Promise } -function getMaxContentLength(responseLimit?: number | string | boolean) { +function getMaxContentLength(responseLimit?: ResponseLimit) { if (responseLimit && typeof responseLimit !== 'boolean') { return bytes.parse(responseLimit) } diff --git a/packages/next/server/base-http/node.ts b/packages/next/server/base-http/node.ts index 62db04b592379..4cb033d0ca5b7 100644 --- a/packages/next/server/base-http/node.ts +++ b/packages/next/server/base-http/node.ts @@ -1,5 +1,6 @@ import type { ServerResponse, IncomingMessage } from 'http' import type { Writable, Readable } from 'stream' +import type { SizeLimit } from 'next/types' import { NextApiRequestCookies, SYMBOL_CLEARED_COOKIES } from '../api-utils' import { parseBody } from '../api-utils/node' @@ -34,7 +35,7 @@ export class NodeNextRequest extends BaseNextRequest { super(_req.method!.toUpperCase(), _req.url!, _req) } - async parseBody(limit: string | number): Promise { + async parseBody(limit: SizeLimit): Promise { return parseBody(this._req, limit) } } diff --git a/packages/next/types/index.d.ts b/packages/next/types/index.d.ts index 7a2e2e55dc0ab..169111ff95097 100644 --- a/packages/next/types/index.d.ts +++ b/packages/next/types/index.d.ts @@ -61,6 +61,22 @@ export type Redirect = */ export type NextPage

= NextComponentType +export type FileSizeSuffix = `${ + | 'k' + | 'K' + | 'm' + | 'M' + | 'g' + | 'G' + | 't' + | 'T' + | 'p' + | 'P'}${'b' | 'B'}` + +export type SizeLimit = number | `${number}${FileSizeSuffix}` + +export type ResponseLimit = SizeLimit | boolean + /** * `Config` type, use it for export const config */ @@ -72,12 +88,16 @@ export type PageConfig = { * any string format supported by `bytes`, for example `1000`, `'500kb'` or * `'3mb'`. */ - responseLimit?: number | string | boolean + responseLimit?: ResponseLimit /** * The byte limit of the body. This is the number of bytes or any string * format supported by `bytes`, for example `1000`, `'500kb'` or `'3mb'`. */ - bodyParser?: { sizeLimit?: number | string } | false + bodyParser?: + | { + sizeLimit?: SizeLimit + } + | false /** * Flag to disable warning "API page resolved * without sending a response", due to explicitly diff --git a/test/integration/image-component/typescript/pages/invalid.tsx b/test/integration/image-component/typescript/pages/invalid.tsx index bb61eb14303cd..50f47c3f4f385 100644 --- a/test/integration/image-component/typescript/pages/invalid.tsx +++ b/test/integration/image-component/typescript/pages/invalid.tsx @@ -26,6 +26,24 @@ const Invalid = () => { height="500" placeholder="invalid" > + invalid-width-string-type + invalid-height-string-type + invalid-quality-string-type

This is the invalid usage

) diff --git a/test/integration/image-component/typescript/pages/valid.tsx b/test/integration/image-component/typescript/pages/valid.tsx index 14230a45ab1b9..23e2c8c838a89 100644 --- a/test/integration/image-component/typescript/pages/valid.tsx +++ b/test/integration/image-component/typescript/pages/valid.tsx @@ -43,6 +43,14 @@ const Page = () => { width={500} height={500} /> + numeric-string-types { height="500" placeholder="invalid" /> + invalid-width-string-type + invalid-height-string-type + invalid-quality-string-type { id="fill-no-width-and-height" src="https://image-optimization-test.vercel.app/test.jpg" fill + alt="" /> { quality={80} width={500} height={500} + alt="" /> { width={500} height={500} /> + numeric-string-types data-protocol Date: Tue, 27 Sep 2022 14:50:50 +0900 Subject: [PATCH 73/76] chore: Update swc (#40928) This PR updates swc crates to https://github.com/swc-project/swc/commit/3d393dd709f9a41dc53b15c0fc1edb93997f9d5b --- This PR applies - https://github.com/swc-project/swc/pull/5954 Closes https://github.com/vercel/next.js/issues/40803 - https://github.com/swc-project/swc/pull/5956 Resolves https://github.com/vercel/next.js/discussions/30237#discussioncomment-3717121 --- .github/workflows/build_test_deploy.yml | 2 +- packages/next-swc/Cargo.lock | 169 +++++++++--------- packages/next-swc/crates/core/Cargo.toml | 6 +- .../next-swc/crates/core/src/next_dynamic.rs | 2 +- .../font_imports_generator.rs | 6 +- packages/next-swc/crates/core/src/relay.rs | 6 +- packages/next-swc/crates/emotion/Cargo.toml | 8 +- .../crates/modularize_imports/Cargo.toml | 8 +- packages/next-swc/crates/napi/Cargo.toml | 2 +- .../crates/styled_components/Cargo.toml | 8 +- .../styled_components/src/utils/analyzer.rs | 4 +- .../src/visitors/display_name_and_id.rs | 12 +- .../visitors/transpile_css_prop/transpile.rs | 4 +- .../next-swc/crates/styled_jsx/Cargo.toml | 8 +- .../next-swc/crates/styled_jsx/src/lib.rs | 4 +- packages/next-swc/crates/wasm/Cargo.toml | 2 +- packages/next-swc/rust-toolchain | 2 +- 17 files changed, 123 insertions(+), 130 deletions(-) diff --git a/.github/workflows/build_test_deploy.yml b/.github/workflows/build_test_deploy.yml index 85558349a7e79..b50ad040edc54 100644 --- a/.github/workflows/build_test_deploy.yml +++ b/.github/workflows/build_test_deploy.yml @@ -9,7 +9,7 @@ name: Build, test, and deploy env: NAPI_CLI_VERSION: 2.7.0 TURBO_VERSION: 1.3.2-canary.1 - RUST_TOOLCHAIN: nightly-2022-06-12 + RUST_TOOLCHAIN: nightly-2022-09-14 PNPM_VERSION: 7.2.1 jobs: diff --git a/packages/next-swc/Cargo.lock b/packages/next-swc/Cargo.lock index f814c51d89312..4993b84fb399e 100644 --- a/packages/next-swc/Cargo.lock +++ b/packages/next-swc/Cargo.lock @@ -162,9 +162,9 @@ dependencies = [ [[package]] name = "binding_macros" -version = "0.16.0" +version = "0.17.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceea0286ed654e11f014210fbfd23c5d4aac93fc76809275f11062f07b1d09c8" +checksum = "544c4328d391914666891ceddf95b29c573ed80a48060f1a50cac203d8bba5b5" dependencies = [ "anyhow", "console_error_panic_hook", @@ -1531,7 +1531,7 @@ dependencies = [ [[package]] name = "modularize_imports" -version = "0.19.0" +version = "0.20.0" dependencies = [ "convert_case", "handlebars", @@ -2929,7 +2929,7 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "styled_components" -version = "0.44.0" +version = "0.45.0" dependencies = [ "Inflector", "once_cell", @@ -2943,7 +2943,7 @@ dependencies = [ [[package]] name = "styled_jsx" -version = "0.19.0" +version = "0.20.0" dependencies = [ "easy-error", "swc_core", @@ -2987,9 +2987,9 @@ dependencies = [ [[package]] name = "swc" -version = "0.228.0" +version = "0.229.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c6a3c9aa6fd3eb25e3e0eaa05ca6dc1705979badbec359fdf93ffa13c7f077e" +checksum = "a709e9a5a674d61d4f008049c63ba448f3503561ef79e666f7b04aee25882ea0" dependencies = [ "ahash", "anyhow", @@ -3051,9 +3051,9 @@ dependencies = [ [[package]] name = "swc_bundler" -version = "0.189.0" +version = "0.190.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5f3fbf030930093f3a2c5fa81aa5f23de59a35e1a09f433a2b50d6330e76959" +checksum = "74faca71deca740b65919a879582a480affcf15122bb839aa89db706a39fafe2" dependencies = [ "ahash", "anyhow", @@ -3100,9 +3100,9 @@ dependencies = [ [[package]] name = "swc_common" -version = "0.28.10" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3926afd43f50edea791744d97d5fa38bde997978531d36ed507b2b908f920695" +checksum = "4b95d085a4d538abe1559a48e52e294c04ec2a1dc6388227834e016b5247cad2" dependencies = [ "ahash", "anyhow", @@ -3159,9 +3159,9 @@ dependencies = [ [[package]] name = "swc_core" -version = "0.26.0" +version = "0.27.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2690f8c60fae7628d7def61441b48040aaaccfa1e05bbaae25845777cccca48e" +checksum = "85f56c4d3c88e027b0be8190622f35bf14950facd30a074205937647ddbe5d0c" dependencies = [ "binding_macros", "swc", @@ -3197,9 +3197,9 @@ dependencies = [ [[package]] name = "swc_css_ast" -version = "0.113.2" +version = "0.114.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f131c72ef8d472fc42d646ecfe57fe796a00e9239204faea329810d659436b9" +checksum = "6659ea06457fbcdc9c6e9e316f299ff9fc1b7c51f71b1bdb055bd40b54c39d77" dependencies = [ "is-macro", "serde", @@ -3210,9 +3210,9 @@ dependencies = [ [[package]] name = "swc_css_codegen" -version = "0.123.4" +version = "0.124.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd1aaa07d2079f789c258130a89a842f85fee092c8d2571cf7181f004352b863" +checksum = "464def2cb7c2d0cf2fda0671ac86ea60513481154e509be81fb572cce6e1aec8" dependencies = [ "auto_impl", "bitflags", @@ -3239,9 +3239,9 @@ dependencies = [ [[package]] name = "swc_css_parser" -version = "0.122.4" +version = "0.123.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04185aba148e49292f5ef767307c6079a79765e55d40c9f2c635068bf3293e37" +checksum = "1d2f4256093f4ae40309198abf2f73e71e2e703fb525b98524829abbd2496f13" dependencies = [ "bitflags", "lexical", @@ -3253,9 +3253,9 @@ dependencies = [ [[package]] name = "swc_css_prefixer" -version = "0.124.4" +version = "0.125.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ff72bb96537bf8ae56624547fc92f5bbf228ce3fe9582850527099ad4dae3a8" +checksum = "435b66fd766f61173446a37d260a25dbce1c3c74b28e70c1586f99d8bbb5245c" dependencies = [ "once_cell", "preset_env_base", @@ -3270,9 +3270,9 @@ dependencies = [ [[package]] name = "swc_css_utils" -version = "0.110.2" +version = "0.111.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15bea1364664e6b5e1681ae50b77a854988a3adc620430196cac480c0b388396" +checksum = "2989aeaf9dfddfe59bbdc9766d3dd454289c5f53abd93d947b39958941f4b155" dependencies = [ "once_cell", "serde", @@ -3285,9 +3285,9 @@ dependencies = [ [[package]] name = "swc_css_visit" -version = "0.112.3" +version = "0.113.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dd2e1949103f672b9f4401feedd2d4ba53a2295997d832e9c89e3a0b1769f00" +checksum = "a1f5a6a1faf28505c05603aa0d38e8444d6b3285b4e3c969a9713a8bbf42ca7f" dependencies = [ "serde", "swc_atoms", @@ -3298,9 +3298,9 @@ dependencies = [ [[package]] name = "swc_ecma_ast" -version = "0.93.0" +version = "0.94.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d9721a0e1a6a2ff6f0d127a337a5124e88be0429d93bd2833e83bad8d7bf324" +checksum = "f8626020a22a0691bf167b08617942364ee45590ac8f14a3a129c1ed5c31d054" dependencies = [ "bitflags", "is-macro", @@ -3316,9 +3316,9 @@ dependencies = [ [[package]] name = "swc_ecma_codegen" -version = "0.126.0" +version = "0.127.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40b63ef4fa9a6ff791c8b43a120e7f7386530e0970a53f69fee494388e2f0fc6" +checksum = "8f2fd4680eaee1cf7baf7e50f35b89ee49306a701c93d0c5a970912088f3af34" dependencies = [ "memchr", "num-bigint", @@ -3348,9 +3348,9 @@ dependencies = [ [[package]] name = "swc_ecma_ext_transforms" -version = "0.90.0" +version = "0.91.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5da0ab1b64fa81f2670e40a122a5ad8416a95bbb0425829c774088155358d45a" +checksum = "c3f5f951aa77cf9b3fd95259b5342eca82cbfb7534ebce206fa34795565d3ad4" dependencies = [ "phf", "swc_atoms", @@ -3362,9 +3362,9 @@ dependencies = [ [[package]] name = "swc_ecma_lints" -version = "0.65.0" +version = "0.66.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af606e1eebb93f1d9d09cdc5200ff7e6c491cbe0493948cb29ba5f8d3e6327d7" +checksum = "8d91d3e136e2c08ce22417daf988b2c41ae3ab7032c77cc848159f11ae71113a" dependencies = [ "ahash", "auto_impl", @@ -3383,9 +3383,9 @@ dependencies = [ [[package]] name = "swc_ecma_loader" -version = "0.40.10" +version = "0.41.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4cf15b506bf98839d91d0a5f7f21cd1ced9e3eeaa3be2664991f0b1788e8b9" +checksum = "350139badbf8e73a47377fe7ae0a1e149934b001f057f9f937404502480c6a88" dependencies = [ "ahash", "anyhow", @@ -3405,9 +3405,9 @@ dependencies = [ [[package]] name = "swc_ecma_minifier" -version = "0.156.0" +version = "0.157.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2a0efeb9a4954a5f2c1201c5ca13706f917fdd41928c412cd74746405aca372" +checksum = "c82fe448df0b80f5f0220615fa42a0a431a604e7c7703cac14918da8beb3931e" dependencies = [ "ahash", "arrayvec", @@ -3439,9 +3439,9 @@ dependencies = [ [[package]] name = "swc_ecma_parser" -version = "0.121.0" +version = "0.122.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b669d504192a57a6e7fdb801c980fcbd3c7447cd2e3750f21aaeb44092a96665" +checksum = "cb31221942e547f6bea8a7893f98687fbd804a689621ca4a9d0c77050a617516" dependencies = [ "either", "enum_kind", @@ -3458,9 +3458,9 @@ dependencies = [ [[package]] name = "swc_ecma_preset_env" -version = "0.171.0" +version = "0.172.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a428026cd44fee29c8bb566b610163b27a920ea85d2675d4261348f686657a7f" +checksum = "c5398a8c8e875a27e89082ae8240b6277011fcb5e41c4a0316025027322fb049" dependencies = [ "ahash", "anyhow", @@ -3483,9 +3483,9 @@ dependencies = [ [[package]] name = "swc_ecma_testing" -version = "0.19.0" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f66dbab0f4e3bdf728d0e60fb83672c52347da018de280868ce07ff53633fc7" +checksum = "e51e0ed2f95be51c6a8ae1180ffbe6bc8c3e0162d2e6a568b84c0437eebfc2bb" dependencies = [ "anyhow", "hex", @@ -3493,16 +3493,15 @@ dependencies = [ "swc_atoms", "swc_common", "swc_ecma_ast", - "swc_ecma_codegen", "testing", "tracing", ] [[package]] name = "swc_ecma_transforms" -version = "0.195.0" +version = "0.196.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ad3638d8e60c57b78cc2b6a5d25c19241ae6f9189ea3b9dd7b4b6eb1f313f3" +checksum = "51e750deaa69d95100659aad20505da9d4c400f84f00276d583927d1b2a663f3" dependencies = [ "swc_atoms", "swc_common", @@ -3520,9 +3519,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_base" -version = "0.110.0" +version = "0.111.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2066e43ea098251d8cd3bea4115a9139913e27cfbbe91377bee6126e5c54b04" +checksum = "5b0a1da8117284fe62eaccbd15a8f7ba36596a227168df5edb3a50fbf11f4e47" dependencies = [ "better_scoped_tls", "bitflags", @@ -3543,9 +3542,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_classes" -version = "0.99.0" +version = "0.100.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e1c67e13a366caff8c127c960d26494b9a50209c3da23baa53a3651db025b3f" +checksum = "cf689963f9c19940de02f491d8e24c1e714b74fc7fce27adbbf720edd95d827a" dependencies = [ "swc_atoms", "swc_common", @@ -3557,9 +3556,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_compat" -version = "0.133.0" +version = "0.134.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4894b38cec47aecf6b4e2fec852499c8c3577d8af25729146e98233015192576" +checksum = "f7100adc60c95490d6e06d72bb96dc7f778b5a204e26b85f533d6d4a7775179b" dependencies = [ "ahash", "arrayvec", @@ -3598,9 +3597,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_module" -version = "0.150.0" +version = "0.151.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1b204d3efdc29c84a0661480cc5d7bc917fa9062623b7fcca008c8efc568a40" +checksum = "63015aeabf9c9d234551b5417c9cc12ca0472969c0979e252c8d30274a1e76a6" dependencies = [ "Inflector", "ahash", @@ -3626,9 +3625,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_optimization" -version = "0.164.0" +version = "0.165.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9dc0c237a127b075942baf0796c788dbe1adfe6dd98a87fe50090aa026a0156" +checksum = "8341b29ba20abdb61b1d6eb78e40ec9f9f3817c5a77d7eaf243c4caa3d90f351" dependencies = [ "ahash", "dashmap", @@ -3652,9 +3651,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_proposal" -version = "0.141.0" +version = "0.142.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83ed71de103b38f257d962aa2289844011aee572861ff1490c061d2df8cc827c" +checksum = "2c11d788fc5e88614f8f13a182acebf838e66827e7f6a5a003ef7a31b886402a" dependencies = [ "either", "serde", @@ -3671,9 +3670,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_react" -version = "0.152.0" +version = "0.153.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e56ed952dd5a53b57b1b2b3e4bf26347f4af7f152ed621fe820f939678d570e" +checksum = "43c587cd309664b38257d5a790d49668f73cd6c24783d6d4784564a528f52c3b" dependencies = [ "ahash", "base64 0.13.0", @@ -3698,9 +3697,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_testing" -version = "0.112.0" +version = "0.113.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c5b3d434e5c38eab5ba74a474112c221f571f15acda24cc4b47ded516444b0e" +checksum = "cab0308971d9089e54e3cdcee32c55d88682bf93b7f12761a109897ee175c0ad" dependencies = [ "ansi_term", "anyhow", @@ -3722,9 +3721,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_typescript" -version = "0.156.0" +version = "0.157.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180e9cac5e6fb44a735aa5af23187f900fda02f98ee29d21ad88a90e21ec0b3c" +checksum = "ec559f7359507646bdbc3288122b5a04e3395f111ba70b58c012d749ba9f862b" dependencies = [ "serde", "swc_atoms", @@ -3738,9 +3737,9 @@ dependencies = [ [[package]] name = "swc_ecma_utils" -version = "0.104.0" +version = "0.105.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cb804f9c7d09b5bbae3daf0a9dc4d678b70c21b07cbb0c864e50a978a14502" +checksum = "c9edefea41d7ab524ecff81acd6c7a123547a74c696f380bcf42047abb1f3149" dependencies = [ "indexmap", "num_cpus", @@ -3756,9 +3755,9 @@ dependencies = [ [[package]] name = "swc_ecma_visit" -version = "0.79.0" +version = "0.80.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d041e63b7034961e52c969e094469fa01b22dbd840c928590e5cac2154f82d0b" +checksum = "8ddb5d0ee90a60e59fa61f275eaf5b5197d5b6dc30854c752b254ad067c54696" dependencies = [ "num-bigint", "swc_atoms", @@ -3770,7 +3769,7 @@ dependencies = [ [[package]] name = "swc_emotion" -version = "0.21.0" +version = "0.22.0" dependencies = [ "base64 0.13.0", "byteorder", @@ -3800,9 +3799,9 @@ dependencies = [ [[package]] name = "swc_error_reporters" -version = "0.12.10" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d57d1b1fb0da73e20caadb86755db4d3371849c704c86dbaecd3f3968fc1cb4" +checksum = "5799716d1810cb8525df980291de685b3d6c6bc65fb9582dd4167b8309a3bd58" dependencies = [ "anyhow", "miette", @@ -3813,9 +3812,9 @@ dependencies = [ [[package]] name = "swc_fast_graph" -version = "0.16.10" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97abd88688673d693aec09551783b067f4d4fff82f8e982b91160dd7febad484" +checksum = "b62ef71d800c58a2dc5b4e657e77c62543f0d15991063417acbd323dbd7e2c32" dependencies = [ "ahash", "indexmap", @@ -3825,9 +3824,9 @@ dependencies = [ [[package]] name = "swc_graph_analyzer" -version = "0.17.10" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "849c10de6bc42b930d54186137c177bfc5e4c525870ed0dccdd5bf963be1ea10" +checksum = "b414e0b8b6ff70348d44202584ca304b368dc5637ae274c654651d751644da71" dependencies = [ "ahash", "auto_impl", @@ -3860,9 +3859,9 @@ dependencies = [ [[package]] name = "swc_node_comments" -version = "0.15.10" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c7e415e35959e8118fd74ffee2d4a18bf459dac1293163735a294cba476cb9" +checksum = "e8e89032596708c0355644b3924a1cb9d88b07e0ed269a1e0bd6cc11c9920772" dependencies = [ "ahash", "dashmap", @@ -3872,9 +3871,9 @@ dependencies = [ [[package]] name = "swc_plugin_proxy" -version = "0.21.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e089036738edc1c1cd8d521226cbdb0235cc6bafde99b04baffb0133e5c238ae" +checksum = "f28339049cdb77f539250b9630fa7fc421eada85a992b63047c613cb46c8ef64" dependencies = [ "better_scoped_tls", "rkyv", @@ -3886,9 +3885,9 @@ dependencies = [ [[package]] name = "swc_plugin_runner" -version = "0.76.0" +version = "0.77.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd8229d2ed13027ddf59912ca973b8e062b368f32953e877498831e1ac6414bd" +checksum = "88359757a9b03ec4939dcb9799d61eb841d7d12be4f3f8b6839e1a400772a524" dependencies = [ "anyhow", "once_cell", @@ -3906,9 +3905,9 @@ dependencies = [ [[package]] name = "swc_timer" -version = "0.16.10" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e626e120ae437a135d679de736089493e5ba1c2d9b6e8c726f7105a17867858" +checksum = "81cec1c10268bcd3e134553483b6b964dade269d1d027046723b6c08fd22a73d" dependencies = [ "tracing", ] @@ -4000,9 +3999,9 @@ dependencies = [ [[package]] name = "testing" -version = "0.30.10" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5584041a02f6327d9ec378b4e389dc0b5e748bb99705b765941a8e55f7d83d14" +checksum = "8a1058cadca72c32c3a06b460cd6a025acc5655d058d476c8a636749618d02f7" dependencies = [ "ansi_term", "difference", diff --git a/packages/next-swc/crates/core/Cargo.toml b/packages/next-swc/crates/core/Cargo.toml index 867158924899c..2816c87b7bc14 100644 --- a/packages/next-swc/crates/core/Cargo.toml +++ b/packages/next-swc/crates/core/Cargo.toml @@ -28,7 +28,7 @@ styled_jsx = {path="../styled_jsx"} modularize_imports = {path="../modularize_imports"} tracing = { version = "0.1.32", features = ["release_max_level_info"] } -swc_core = { version = "0.26.0", features = [ +swc_core = { version = "0.27.4", features = [ "common_concurrent", "ecma_ast", "ecma_visit", @@ -48,6 +48,6 @@ swc_core = { version = "0.26.0", features = [ ] } [dev-dependencies] -swc_core = { version = "0.26.0", features = ["testing_transform"] } -testing = "0.30.10" +swc_core = { version = "0.27.4", features = ["testing_transform"] } +testing = "0.31.1" walkdir = "2.3.2" diff --git a/packages/next-swc/crates/core/src/next_dynamic.rs b/packages/next-swc/crates/core/src/next_dynamic.rs index 0bd30a6682b0e..ecc3d726cdcf4 100644 --- a/packages/next-swc/crates/core/src/next_dynamic.rs +++ b/packages/next-swc/crates/core/src/next_dynamic.rs @@ -319,7 +319,7 @@ fn rel_filename(base: Option<&Path>, file: &FileName) -> String { } }; - let rel_path = diff_paths(&file, base); + let rel_path = diff_paths(file, base); let rel_path = match rel_path { Some(v) => v, diff --git a/packages/next-swc/crates/core/src/next_font_loaders/font_imports_generator.rs b/packages/next-swc/crates/core/src/next_font_loaders/font_imports_generator.rs index ae92e811e406d..169a46c1d7262 100644 --- a/packages/next-swc/crates/core/src/next_font_loaders/font_imports_generator.rs +++ b/packages/next-swc/crates/core/src/next_font_loaders/font_imports_generator.rs @@ -31,7 +31,7 @@ impl<'a> FontImportsGenerator<'a> { }); } - expr_to_json(&*expr_or_spread.expr) + expr_to_json(&expr_or_spread.expr) }) .collect(); @@ -182,7 +182,7 @@ fn object_lit_to_json(object_lit: &ObjectLit) -> Value { Err(()) } }; - let val = expr_to_json(&*key_val.value); + let val = expr_to_json(&key_val.value); if let (Ok(key), Ok(val)) = (key, val) { values.insert(key, val); } @@ -226,7 +226,7 @@ fn expr_to_json(expr: &Expr) -> Result { .emit(); Err(()) }), - None => expr_to_json(&*expr.expr), + None => expr_to_json(&expr.expr), } } else { HANDLER.with(|handler| { diff --git a/packages/next-swc/crates/core/src/relay.rs b/packages/next-swc/crates/core/src/relay.rs index 934d9207716da..dfae8c6ccf16d 100644 --- a/packages/next-swc/crates/core/src/relay.rs +++ b/packages/next-swc/crates/core/src/relay.rs @@ -173,11 +173,7 @@ impl<'a> Relay<'a> { } } -pub fn relay<'a>( - config: &'a Config, - file_name: FileName, - pages_dir: Option, -) -> impl Fold + '_ { +pub fn relay(config: &Config, file_name: FileName, pages_dir: Option) -> impl Fold + '_ { Relay { root_dir: std::env::current_dir().unwrap(), file_name, diff --git a/packages/next-swc/crates/emotion/Cargo.toml b/packages/next-swc/crates/emotion/Cargo.toml index 32281c8865b5b..01d5eb73961c6 100644 --- a/packages/next-swc/crates/emotion/Cargo.toml +++ b/packages/next-swc/crates/emotion/Cargo.toml @@ -5,7 +5,7 @@ description = "AST Transforms for emotion" license = "Apache-2.0" name = "swc_emotion" repository = "https://github.com/vercel/next.js.git" -version = "0.21.0" +version = "0.22.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -19,9 +19,9 @@ regex = "1.5" serde = "1" sourcemap = "6.0.1" tracing = { version = "0.1.32", features = ["release_max_level_info"] } -swc_core = { version = "0.26.0", features = ["common", "ecma_ast","ecma_codegen", "ecma_utils", "ecma_visit", "trace_macro"] } +swc_core = { version = "0.27.4", features = ["common", "ecma_ast","ecma_codegen", "ecma_utils", "ecma_visit", "trace_macro"] } [dev-dependencies] -swc_core = { version = "0.26.0", features = ["testing_transform", "ecma_transforms_react"] } -testing = "0.30.10" +swc_core = { version = "0.27.4", features = ["testing_transform", "ecma_transforms_react"] } +testing = "0.31.1" serde_json = "1" diff --git a/packages/next-swc/crates/modularize_imports/Cargo.toml b/packages/next-swc/crates/modularize_imports/Cargo.toml index 3f3ad4b9b95c8..f798f0db7e4a8 100644 --- a/packages/next-swc/crates/modularize_imports/Cargo.toml +++ b/packages/next-swc/crates/modularize_imports/Cargo.toml @@ -5,7 +5,7 @@ edition = "2018" license = "Apache-2.0" name = "modularize_imports" repository = "https://github.com/vercel/next.js.git" -version = "0.19.0" +version = "0.20.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -15,8 +15,8 @@ handlebars = "4.2.1" once_cell = "1.13.0" regex = "1.5" serde = "1" -swc_core = { version = "0.26.0", features = ["cached", "ecma_ast", "ecma_visit"] } +swc_core = { version = "0.27.4", features = ["cached", "ecma_ast", "ecma_visit"] } [dev-dependencies] -swc_core = { version = "0.26.0", features = ["testing_transform"] } -testing = "0.30.10" +swc_core = { version = "0.27.4", features = ["testing_transform"] } +testing = "0.31.1" diff --git a/packages/next-swc/crates/napi/Cargo.toml b/packages/next-swc/crates/napi/Cargo.toml index d113298bd2722..7f1af952f2952 100644 --- a/packages/next-swc/crates/napi/Cargo.toml +++ b/packages/next-swc/crates/napi/Cargo.toml @@ -30,7 +30,7 @@ next-swc = {version = "0.0.0", path = "../core"} once_cell = "1.13.0" serde = "1" serde_json = "1" -swc_core = { version = "0.26.0", features = [ +swc_core = { version = "0.27.4", features = [ "allocator_node", "base_concurrent", # concurrent? "common_concurrent", diff --git a/packages/next-swc/crates/styled_components/Cargo.toml b/packages/next-swc/crates/styled_components/Cargo.toml index 98166ecf94210..59f2eafec5565 100644 --- a/packages/next-swc/crates/styled_components/Cargo.toml +++ b/packages/next-swc/crates/styled_components/Cargo.toml @@ -6,7 +6,7 @@ include = ["Cargo.toml", "src/**/*.rs"] license = "Apache-2.0" name = "styled_components" repository = "https://github.com/vercel/next.js.git" -version = "0.44.0" +version = "0.45.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -16,7 +16,7 @@ once_cell = "1.13.0" regex = {version = "1.5.4", features = ["std", "perf"], default-features = false} serde = {version = "1.0.130", features = ["derive"]} tracing = "0.1.32" -swc_core = { version = "0.26.0", features = [ +swc_core = { version = "0.27.4", features = [ "common", "ecma_ast", "ecma_utils", @@ -25,8 +25,8 @@ swc_core = { version = "0.26.0", features = [ [dev-dependencies] serde_json = "1" -testing = "0.30.10" -swc_core = { version = "0.26.0", features = [ +testing = "0.31.1" +swc_core = { version = "0.27.4", features = [ "ecma_parser", "ecma_transforms", "testing_transform" diff --git a/packages/next-swc/crates/styled_components/src/utils/analyzer.rs b/packages/next-swc/crates/styled_components/src/utils/analyzer.rs index 9336b6112aefa..47adc9970ff71 100644 --- a/packages/next-swc/crates/styled_components/src/utils/analyzer.rs +++ b/packages/next-swc/crates/styled_components/src/utils/analyzer.rs @@ -23,7 +23,7 @@ impl VisitMut for AsAnalyzer { fn visit_mut_module(&mut self, p: &mut Module) { let mut v = Analyzer { config: &self.config, - state: &mut *self.state.borrow_mut(), + state: &mut self.state.borrow_mut(), }; p.visit_with(&mut v); @@ -32,7 +32,7 @@ impl VisitMut for AsAnalyzer { fn visit_mut_script(&mut self, p: &mut Script) { let mut v = Analyzer { config: &self.config, - state: &mut *self.state.borrow_mut(), + state: &mut self.state.borrow_mut(), }; p.visit_with(&mut v); diff --git a/packages/next-swc/crates/styled_components/src/visitors/display_name_and_id.rs b/packages/next-swc/crates/styled_components/src/visitors/display_name_and_id.rs index 1df6852878851..12e3cc15be78b 100644 --- a/packages/next-swc/crates/styled_components/src/visitors/display_name_and_id.rs +++ b/packages/next-swc/crates/styled_components/src/visitors/display_name_and_id.rs @@ -309,12 +309,10 @@ impl VisitMut for DisplayNameAndId { PropOrSpread::Prop(prop) => { match get_prop_name(prop) { Some(PropName::Ident(prop_name)) => { - match &*prop_name.sym { - "componentId" | "displayName" => { - true - } - _ => false, - } + matches!( + &*prop_name.sym, + "componentId" | "displayName" + ) } _ => false, } @@ -354,7 +352,7 @@ impl VisitMut for DisplayNameAndId { self.add_config( expr, - display_name.map(|s| DISPLAY_NAME_REGEX.replace_all(&*s, "").into()), + display_name.map(|s| DISPLAY_NAME_REGEX.replace_all(&s, "").into()), component_id, ) } diff --git a/packages/next-swc/crates/styled_components/src/visitors/transpile_css_prop/transpile.rs b/packages/next-swc/crates/styled_components/src/visitors/transpile_css_prop/transpile.rs index fcc1b7e18eacc..8ad2a45d1a8fc 100644 --- a/packages/next-swc/crates/styled_components/src/visitors/transpile_css_prop/transpile.rs +++ b/packages/next-swc/crates/styled_components/src/visitors/transpile_css_prop/transpile.rs @@ -251,7 +251,7 @@ impl VisitMut for TranspileCssProp { if expr.is_fn_expr() || expr.is_arrow() { acc.push(expr); return acc; - } else if let Some(root) = trace_root_value(&mut *expr) { + } else if let Some(root) = trace_root_value(&mut expr) { let direct_access = match root { Expr::Lit(_) => true, Expr::Ident(id) if self.is_top_level_ident(id) => true, @@ -643,7 +643,7 @@ fn trace_root_value(e: &mut Expr) -> Option<&mut Expr> { match e { Expr::Member(e) => trace_root_value(&mut e.obj), Expr::Call(e) => match &mut e.callee { - Callee::Expr(e) => trace_root_value(&mut **e), + Callee::Expr(e) => trace_root_value(e), _ => None, }, Expr::Ident(_) => Some(e), diff --git a/packages/next-swc/crates/styled_jsx/Cargo.toml b/packages/next-swc/crates/styled_jsx/Cargo.toml index 2b44064f4704b..9764ed1923bf8 100644 --- a/packages/next-swc/crates/styled_jsx/Cargo.toml +++ b/packages/next-swc/crates/styled_jsx/Cargo.toml @@ -5,7 +5,7 @@ edition = "2018" license = "Apache-2.0" name = "styled_jsx" repository = "https://github.com/vercel/next.js.git" -version = "0.19.0" +version = "0.20.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -13,7 +13,7 @@ version = "0.19.0" easy-error = "1.0.0" tracing = "0.1.32" -swc_core = { version = "0.26.0", features = [ +swc_core = { version = "0.27.4", features = [ "common", "css_ast", "css_codegen", @@ -27,7 +27,7 @@ swc_core = { version = "0.26.0", features = [ ] } [dev-dependencies] -testing = "0.30.10" -swc_core = { version = "0.26.0", features = [ +testing = "0.31.1" +swc_core = { version = "0.27.4", features = [ "testing_transform" ] } diff --git a/packages/next-swc/crates/styled_jsx/src/lib.rs b/packages/next-swc/crates/styled_jsx/src/lib.rs index 86236d700100c..bbf88931d63c4 100644 --- a/packages/next-swc/crates/styled_jsx/src/lib.rs +++ b/packages/next-swc/crates/styled_jsx/src/lib.rs @@ -176,7 +176,7 @@ impl Fold for StyledJSXTransformer { if let JSXElementName::Ident(Ident { sym, span, .. }) = &el.name { if sym != "style" && sym != self.style_import_name.as_ref().unwrap() - && (!is_capitalized(&**sym) + && (!is_capitalized(sym) || self .nearest_scope_bindings .contains(&(sym.clone(), span.ctxt))) @@ -750,7 +750,7 @@ fn get_style_expr(el: &JSXElement) -> Result { { return Ok(match &**expr { Expr::Lit(Lit::Str(str)) => StyleExpr::Str(str), - Expr::Tpl(tpl) => StyleExpr::Tpl(tpl, &**expr), + Expr::Tpl(tpl) => StyleExpr::Tpl(tpl, expr), Expr::Ident(ident) => StyleExpr::Ident(ident), _ => { HANDLER.with(|handler| { diff --git a/packages/next-swc/crates/wasm/Cargo.toml b/packages/next-swc/crates/wasm/Cargo.toml index 3779772219e05..5f51c681093ea 100644 --- a/packages/next-swc/crates/wasm/Cargo.toml +++ b/packages/next-swc/crates/wasm/Cargo.toml @@ -31,7 +31,7 @@ wasm-bindgen-futures = "0.4.8" getrandom = { version = "0.2.5", optional = true, default-features = false } js-sys = "0.3.59" -swc_core = { version = "0.26.0", features = [ +swc_core = { version = "0.27.4", features = [ "common_concurrent", "binding_macro_wasm", "ecma_codegen", diff --git a/packages/next-swc/rust-toolchain b/packages/next-swc/rust-toolchain index 928512b397cc7..fdd6c8279e690 100644 --- a/packages/next-swc/rust-toolchain +++ b/packages/next-swc/rust-toolchain @@ -1 +1 @@ -nightly-2022-06-12 \ No newline at end of file +nightly-2022-09-14 From eb424042f83f1a1a04746734c3a75251d3ff7489 Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Mon, 26 Sep 2022 23:30:49 -0700 Subject: [PATCH 74/76] Ensure skipClientCache is honored for router.push (#40932) Fixes: https://github.com/vercel/next.js/issues/40927 ## Bug - [x] Related issues linked using `fixes #number` - [x] Integration tests added - [ ] Errors have a helpful link attached, see `contributing.md` --- packages/next/shared/lib/router/router.ts | 1 + .../prerender-prefetch/index.test.ts | 46 +++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/packages/next/shared/lib/router/router.ts b/packages/next/shared/lib/router/router.ts index c0e6bd190168d..b6d789925cacf 100644 --- a/packages/next/shared/lib/router/router.ts +++ b/packages/next/shared/lib/router/router.ts @@ -1550,6 +1550,7 @@ export default class Router implements BaseRouter { locale: nextState.locale, isPreview: nextState.isPreview, hasMiddleware: isMiddlewareMatch, + unstable_skipClientCache: options.unstable_skipClientCache, }) if ('route' in routeInfo && isMiddlewareMatch) { diff --git a/test/production/prerender-prefetch/index.test.ts b/test/production/prerender-prefetch/index.test.ts index 9ddd876114279..c15557c794503 100644 --- a/test/production/prerender-prefetch/index.test.ts +++ b/test/production/prerender-prefetch/index.test.ts @@ -135,6 +135,52 @@ describe('Prerender prefetch', () => { expect(isNaN(newTime)).toBe(false) }) + it('should update cache using router.push with unstable_skipClientCache', async () => { + const browser = await webdriver(next.url, '/') + const timeRes = await fetchViaHTTP( + next.url, + `/_next/data/${next.buildId}/blog/first.json`, + undefined, + { + headers: { + purpose: 'prefetch', + }, + } + ) + const startTime = (await timeRes.json()).pageProps.now + + // ensure stale data is used by default + await browser.elementByCss('#to-blog-first').click() + const outputIndex = next.cliOutput.length + + await check(() => browser.elementByCss('#page').text(), 'blog/[slug]') + + expect(JSON.parse(await browser.elementByCss('#props').text()).now).toBe( + startTime + ) + await browser.back().waitForElementByCss('#to-blog-first') + + // trigger revalidation of /blog/first + await check(async () => { + await renderViaHTTP(next.url, '/blog/first') + return next.cliOutput.substring(outputIndex) + }, /revalidating \/blog first/) + + // now trigger cache update and navigate again + await browser.eval( + 'next.router.push("/blog/first", undefined, { unstable_skipClientCache: true }).finally(() => { window.prefetchDone = "yes" })' + ) + await check(() => browser.eval('window.prefetchDone'), 'yes') + + await check(() => browser.elementByCss('#page').text(), 'blog/[slug]') + + const newTime = JSON.parse( + await browser.elementByCss('#props').text() + ).now + expect(newTime).not.toBe(startTime) + expect(isNaN(newTime)).toBe(false) + }) + if (optimisticClientCache) { it('should attempt cache update on link hover/touch start', async () => { const browser = await webdriver(next.url, '/') From 83c25b74d6dd0ee5abc44ea540301c310020e088 Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Mon, 26 Sep 2022 23:31:23 -0700 Subject: [PATCH 75/76] v12.3.2-canary.10 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-config-next/package.json | 4 ++-- packages/eslint-plugin-next/package.json | 2 +- packages/font/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next-swc/package.json | 2 +- packages/next/package.json | 14 +++++++------- packages/react-dev-overlay/package.json | 2 +- packages/react-refresh-utils/package.json | 2 +- pnpm-lock.yaml | 14 +++++++------- 17 files changed, 30 insertions(+), 30 deletions(-) diff --git a/lerna.json b/lerna.json index b45ccf0f78e2e..c0653dfe0812d 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "12.3.2-canary.9" + "version": "12.3.2-canary.10" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index e9e29e34788dd..4811518d7e0fc 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "12.3.2-canary.9", + "version": "12.3.2-canary.10", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index f3ee7eb2be5fb..7f66e95374319 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "12.3.2-canary.9", + "version": "12.3.2-canary.10", "description": "ESLint configuration used by NextJS.", "main": "index.js", "license": "MIT", @@ -9,7 +9,7 @@ "directory": "packages/eslint-config-next" }, "dependencies": { - "@next/eslint-plugin-next": "12.3.2-canary.9", + "@next/eslint-plugin-next": "12.3.2-canary.10", "@rushstack/eslint-patch": "^1.1.3", "@typescript-eslint/parser": "^5.21.0", "eslint-import-resolver-node": "^0.3.6", diff --git a/packages/eslint-plugin-next/package.json b/packages/eslint-plugin-next/package.json index 7043bfe1c4b42..c8b98090a2ead 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "12.3.2-canary.9", + "version": "12.3.2-canary.10", "description": "ESLint plugin for NextJS.", "main": "lib/index.js", "license": "MIT", diff --git a/packages/font/package.json b/packages/font/package.json index f5f29f3907e74..1a3ccaf47ebdc 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,6 +1,6 @@ { "name": "@next/font", - "version": "12.3.2-canary.9", + "version": "12.3.2-canary.10", "repository": { "url": "vercel/next.js", "directory": "packages/font" diff --git a/packages/next-bundle-analyzer/package.json b/packages/next-bundle-analyzer/package.json index 0a6a060d4bf43..29c86bf1adaf3 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "12.3.2-canary.9", + "version": "12.3.2-canary.10", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index fdbd95f97410d..d9f7fcac2fadc 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "12.3.2-canary.9", + "version": "12.3.2-canary.10", "license": "MIT", "dependencies": { "chalk": "4.1.0", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index 5e5bd5680b6da..e0a67f596284c 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "12.3.2-canary.9", + "version": "12.3.2-canary.10", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index 948ec09453acf..86ee6977d2534 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "12.3.2-canary.9", + "version": "12.3.2-canary.10", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index b4d9c35c606a3..e24317d4c1f18 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "12.3.2-canary.9", + "version": "12.3.2-canary.10", "repository": { "url": "vercel/next.js", "directory": "packages/next-plugin-storybook" diff --git a/packages/next-polyfill-module/package.json b/packages/next-polyfill-module/package.json index a0100dc3aa9bd..2695564a442ee 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "12.3.2-canary.9", + "version": "12.3.2-canary.10", "description": "A standard library polyfill for ES Modules supporting browsers (Edge 16+, Firefox 60+, Chrome 61+, Safari 10.1+)", "main": "dist/polyfill-module.js", "license": "MIT", diff --git a/packages/next-polyfill-nomodule/package.json b/packages/next-polyfill-nomodule/package.json index 4ffda06fea520..bf11cb59e6bdc 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "12.3.2-canary.9", + "version": "12.3.2-canary.10", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index e4035884b37f7..a2c1af3da0d64 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "12.3.2-canary.9", + "version": "12.3.2-canary.10", "private": true, "scripts": { "build-native": "napi build --platform -p next-swc-napi --cargo-name next_swc_napi native --features plugin", diff --git a/packages/next/package.json b/packages/next/package.json index f90ba894c2a53..284da86e1979f 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "12.3.2-canary.9", + "version": "12.3.2-canary.10", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -69,7 +69,7 @@ ] }, "dependencies": { - "@next/env": "12.3.2-canary.9", + "@next/env": "12.3.2-canary.10", "@swc/helpers": "0.4.11", "caniuse-lite": "^1.0.30001406", "postcss": "8.4.14", @@ -120,11 +120,11 @@ "@hapi/accept": "5.0.2", "@napi-rs/cli": "2.7.0", "@napi-rs/triples": "1.1.0", - "@next/polyfill-module": "12.3.2-canary.9", - "@next/polyfill-nomodule": "12.3.2-canary.9", - "@next/react-dev-overlay": "12.3.2-canary.9", - "@next/react-refresh-utils": "12.3.2-canary.9", - "@next/swc": "12.3.2-canary.9", + "@next/polyfill-module": "12.3.2-canary.10", + "@next/polyfill-nomodule": "12.3.2-canary.10", + "@next/react-dev-overlay": "12.3.2-canary.10", + "@next/react-refresh-utils": "12.3.2-canary.10", + "@next/swc": "12.3.2-canary.10", "@segment/ajv-human-errors": "2.1.2", "@taskr/clear": "1.1.0", "@taskr/esnext": "1.1.0", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index 430ffec50e5d9..44dcec6115f56 100644 --- a/packages/react-dev-overlay/package.json +++ b/packages/react-dev-overlay/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-dev-overlay", - "version": "12.3.2-canary.9", + "version": "12.3.2-canary.10", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index d52e0ea60dad0..f83d97879e7d2 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "12.3.2-canary.9", + "version": "12.3.2-canary.10", "description": "An experimental package providing utilities for React Refresh.", "repository": { "url": "vercel/next.js", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5448b68dd36f0..6b2c632861449 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -369,7 +369,7 @@ importers: packages/eslint-config-next: specifiers: - '@next/eslint-plugin-next': 12.3.2-canary.9 + '@next/eslint-plugin-next': 12.3.2-canary.10 '@rushstack/eslint-patch': ^1.1.3 '@typescript-eslint/parser': ^5.21.0 eslint-import-resolver-node: ^0.3.6 @@ -428,12 +428,12 @@ importers: '@hapi/accept': 5.0.2 '@napi-rs/cli': 2.7.0 '@napi-rs/triples': 1.1.0 - '@next/env': 12.3.2-canary.9 - '@next/polyfill-module': 12.3.2-canary.9 - '@next/polyfill-nomodule': 12.3.2-canary.9 - '@next/react-dev-overlay': 12.3.2-canary.9 - '@next/react-refresh-utils': 12.3.2-canary.9 - '@next/swc': 12.3.2-canary.9 + '@next/env': 12.3.2-canary.10 + '@next/polyfill-module': 12.3.2-canary.10 + '@next/polyfill-nomodule': 12.3.2-canary.10 + '@next/react-dev-overlay': 12.3.2-canary.10 + '@next/react-refresh-utils': 12.3.2-canary.10 + '@next/swc': 12.3.2-canary.10 '@segment/ajv-human-errors': 2.1.2 '@swc/helpers': 0.4.11 '@taskr/clear': 1.1.0 From 406d69d4d9f7d14b9bf497a134f0151914b13964 Mon Sep 17 00:00:00 2001 From: Shu Ding Date: Tue, 27 Sep 2022 10:18:06 +0200 Subject: [PATCH 76/76] Fix bundling and module resolution in the server layer (#40818) We currently resolve the `react-server` condition correctly inside `externals` for the server layer, however that will cause the resolved path to be external (as it is called "externals"). So we need a way to hook into the module resolution process to force it to use the `react-server` condition **when it's on the server layer**. The `resolve` option doesn't give us that ability, and the solution in this PR is to leverage `normalModuleFactory`'s resolve hook to override the resolve options before actually resolving it. And there we can have the `contextInfo`. One thing left out is bundling for the edge server, we need to add tests and sort that out carefully. ## Bug - [ ] Related issues linked using `fixes #number` - [x] 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) --- packages/next/build/webpack-config.ts | 95 +++++++++++-------- test/e2e/app-dir/rsc-basic.test.ts | 9 +- .../conditional-exports/index.js | 5 +- .../conditional-exports/index.server.js | 5 +- 4 files changed, 71 insertions(+), 43 deletions(-) diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts index 3c433b7c4b180..cf1a86226c309 100644 --- a/packages/next/build/webpack-config.ts +++ b/packages/next/build/webpack-config.ts @@ -1001,29 +1001,10 @@ export default async function getBaseWebpackConfig( return `commonjs next/dist/lib/import-next-warning` } - const resolveWithReactServerCondition = - layer === WEBPACK_LAYERS.server - ? getResolve({ - // If React is aliased to another channel during Next.js' local development, - // we need to provide that alias to webpack's resolver. - alias: process.env.__NEXT_REACT_CHANNEL - ? { - react: `react-${process.env.__NEXT_REACT_CHANNEL}`, - 'react-dom': `react-dom-${process.env.__NEXT_REACT_CHANNEL}`, - } - : false, - conditionNames: ['react-server'], - }) - : null - - // Special internal modules that require to be bundled for Server Components. + // Special internal modules that must be bundled for Server Components. if (layer === WEBPACK_LAYERS.server) { - if (!isLocal && /^react(?:$|\/)/.test(request)) { - const [resolved] = await resolveWithReactServerCondition!( - context, - request - ) - return resolved + if (!isLocal && /^react$/.test(request)) { + return } if ( request === @@ -1153,25 +1134,22 @@ export default async function getBaseWebpackConfig( } if (/node_modules[/\\].*\.[mc]?js$/.test(res)) { - if ( - layer === WEBPACK_LAYERS.server && - (!config.experimental?.optoutServerComponentsBundle || - !config.experimental?.optoutServerComponentsBundle.some( - // Check if a package is opt-out of Server Components bundling. - (packageName) => - new RegExp(`node_modules[/\\\\]${packageName}[/\\\\]`).test(res) - )) - ) { - try { - const [resolved] = await resolveWithReactServerCondition!( - context, - request + if (layer === WEBPACK_LAYERS.server) { + // All packages should be bundled for the server layer if they're not opted out. + if ( + config.experimental.optoutServerComponentsBundle?.some( + (p: string) => { + return ( + res.includes('node_modules/' + p + '/') || + res.includes('node_modules\\' + p + '\\') + ) + } ) - return `${externalType} ${resolved}` - } catch (err) { - return - // The `react-server` condition is not matched, fallback. + ) { + return `${externalType} ${request}` } + + return } // Anything else that is standard JavaScript within `node_modules` @@ -1528,6 +1506,45 @@ export default async function getBaseWebpackConfig( }, module: { rules: [ + ...(config.experimental.appDir && !isClient && !isEdgeServer + ? [ + { + issuerLayer: WEBPACK_LAYERS.server, + test: (req: string) => { + if ( + !/\.m?js/.test(req) || + config.experimental.optoutServerComponentsBundle?.some( + (mod) => { + return req.includes('/node_modules/' + mod + '/') + } + ) + ) { + return false + } + return true + }, + resolve: process.env.__NEXT_REACT_CHANNEL + ? { + conditionNames: ['react-server', 'node', 'require'], + alias: { + react: `react-${process.env.__NEXT_REACT_CHANNEL}`, + 'react-dom': `react-dom-${process.env.__NEXT_REACT_CHANNEL}`, + }, + } + : { + conditionNames: ['react-server', 'node', 'require'], + alias: { + // If missing the alias override here, the default alias will be used which aliases + // react to the direct file path, not the package name. In that case the condition + // will be ignored completely. + react: 'react', + 'react-dom': 'react-dom', + }, + }, + }, + ] + : []), + // TODO: FIXME: do NOT webpack 5 support with this // x-ref: https://github.com/webpack/webpack/issues/11467 ...(!config.experimental.fullySpecified diff --git a/test/e2e/app-dir/rsc-basic.test.ts b/test/e2e/app-dir/rsc-basic.test.ts index c7530e0831c03..b0757936bf378 100644 --- a/test/e2e/app-dir/rsc-basic.test.ts +++ b/test/e2e/app-dir/rsc-basic.test.ts @@ -403,9 +403,14 @@ describe('app dir - react server components', () => { await fetchViaHTTP(next.url, '/react-server/3rd-party-package').then( async (response) => { const result = await resolveStreamResponse(response) - expect(result).toContain('Server: index.react-server') + + // Package should be resolved based on the react-server condition, + // as well as package's dependencies. + expect(result).toContain('Server: index.react-server:react.subset') + expect(result).toContain('Client: index.default:react.full') + + // Subpath exports should be resolved based on the condition too. expect(result).toContain('Server subpath: subpath.react-server') - expect(result).toContain('Client: index.default') expect(result).toContain('Client subpath: subpath.default') } ) diff --git a/test/e2e/app-dir/rsc-basic/node_modules_bak/conditional-exports/index.js b/test/e2e/app-dir/rsc-basic/node_modules_bak/conditional-exports/index.js index 3a7bb344a967a..551639757e853 100644 --- a/test/e2e/app-dir/rsc-basic/node_modules_bak/conditional-exports/index.js +++ b/test/e2e/app-dir/rsc-basic/node_modules_bak/conditional-exports/index.js @@ -1 +1,4 @@ -module.exports = 'index.default' +const react = require('react') + +module.exports = + 'index.default:' + ('useState' in react ? 'react.full' : 'react.subset') diff --git a/test/e2e/app-dir/rsc-basic/node_modules_bak/conditional-exports/index.server.js b/test/e2e/app-dir/rsc-basic/node_modules_bak/conditional-exports/index.server.js index 5618abfbec839..c2efe324f74be 100644 --- a/test/e2e/app-dir/rsc-basic/node_modules_bak/conditional-exports/index.server.js +++ b/test/e2e/app-dir/rsc-basic/node_modules_bak/conditional-exports/index.server.js @@ -1 +1,4 @@ -module.exports = 'index.react-server' +const react = require('react') + +module.exports = + 'index.react-server:' + ('useState' in react ? 'react.full' : 'react.subset')