diff --git a/packages/astro/src/assets/fonts/constants.ts b/packages/astro/src/assets/fonts/constants.ts new file mode 100644 index 000000000000..8a1868567134 --- /dev/null +++ b/packages/astro/src/assets/fonts/constants.ts @@ -0,0 +1,4 @@ +import { GOOGLE_PROVIDER_NAME } from "./providers/google.js"; +import { LOCAL_PROVIDER_NAME } from "./providers/local.js"; + +export const BUILTIN_PROVIDERS = [GOOGLE_PROVIDER_NAME, LOCAL_PROVIDER_NAME] as const; diff --git a/packages/astro/src/assets/fonts/helpers.ts b/packages/astro/src/assets/fonts/helpers.ts new file mode 100644 index 000000000000..e96a3b1a849b --- /dev/null +++ b/packages/astro/src/assets/fonts/helpers.ts @@ -0,0 +1,5 @@ +import type { FontProvider } from './types.js'; + +export function defineFontProvider(provider: FontProvider) { + return provider; +} diff --git a/packages/astro/src/assets/fonts/providers.ts b/packages/astro/src/assets/fonts/providers.ts new file mode 100644 index 000000000000..4ae9fda7cbfe --- /dev/null +++ b/packages/astro/src/assets/fonts/providers.ts @@ -0,0 +1,6 @@ +import { adobe } from './providers/adobe.js'; + +/** TODO: */ +export const fontProviders = { + adobe, +}; diff --git a/packages/astro/src/assets/fonts/providers/adobe.ts b/packages/astro/src/assets/fonts/providers/adobe.ts new file mode 100644 index 000000000000..a3a62e1ac578 --- /dev/null +++ b/packages/astro/src/assets/fonts/providers/adobe.ts @@ -0,0 +1,9 @@ +import { defineFontProvider } from '../helpers.js'; + +export function adobe(config: { apiKey: string }) { + return defineFontProvider({ + name: 'adobe', + entrypoint: 'astro/assets/fonts/providers/adobe', + config, + }); +} diff --git a/packages/astro/src/assets/fonts/providers/google.ts b/packages/astro/src/assets/fonts/providers/google.ts new file mode 100644 index 000000000000..d6b38f9b841a --- /dev/null +++ b/packages/astro/src/assets/fonts/providers/google.ts @@ -0,0 +1,10 @@ +import { defineFontProvider } from '../helpers.js'; + +export const GOOGLE_PROVIDER_NAME = 'google'; + +export function google() { + return defineFontProvider({ + name: GOOGLE_PROVIDER_NAME, + entrypoint: 'astro/assets/fonts/providers/google', + }); +} diff --git a/packages/astro/src/assets/fonts/providers/local.ts b/packages/astro/src/assets/fonts/providers/local.ts new file mode 100644 index 000000000000..6a3b8f9a14a4 --- /dev/null +++ b/packages/astro/src/assets/fonts/providers/local.ts @@ -0,0 +1,10 @@ +import { defineFontProvider } from '../helpers.js'; + +export const LOCAL_PROVIDER_NAME = 'local'; + +export function local() { + return defineFontProvider({ + name: LOCAL_PROVIDER_NAME, + entrypoint: 'astro/assets/fonts/providers/google', + }); +} diff --git a/packages/astro/src/assets/fonts/types.ts b/packages/astro/src/assets/fonts/types.ts new file mode 100644 index 000000000000..c00c44825771 --- /dev/null +++ b/packages/astro/src/assets/fonts/types.ts @@ -0,0 +1,27 @@ +import type { BUILTIN_PROVIDERS } from './constants.js'; +import type { GOOGLE_PROVIDER_NAME } from './providers/google.js'; +import type { LOCAL_PROVIDER_NAME } from './providers/local.js'; + +export interface FontProvider { + name: TName; + entrypoint: string; + config?: Record; +} + +type LocalFontFamily = { + provider: LocalProviderName; + // TODO: refine type + src: string; +}; + +type StandardFontFamily = { + provider: TProvider; +}; + +export type FontFamily = TProvider extends LocalProviderName + ? LocalFontFamily + : StandardFontFamily; + +export type LocalProviderName = typeof LOCAL_PROVIDER_NAME; +export type GoogleProviderName = typeof GOOGLE_PROVIDER_NAME; +export type BuiltInProvider = (typeof BUILTIN_PROVIDERS)[number]; diff --git a/packages/astro/src/config/entrypoint.ts b/packages/astro/src/config/entrypoint.ts index 4951792d63ae..614728b79c57 100644 --- a/packages/astro/src/config/entrypoint.ts +++ b/packages/astro/src/config/entrypoint.ts @@ -5,6 +5,7 @@ import type { ImageServiceConfig } from '../types/public/index.js'; export { defineConfig, getViteConfig } from './index.js'; export { envField } from '../env/config.js'; +export { fontProviders } from '../assets/fonts/providers.js'; /** * Return the configuration needed to use the Sharp-based image service diff --git a/packages/astro/src/config/index.ts b/packages/astro/src/config/index.ts index 7e7b548f1fcf..8dc0d0db25a5 100644 --- a/packages/astro/src/config/index.ts +++ b/packages/astro/src/config/index.ts @@ -7,6 +7,7 @@ import type { SessionDriverName, } from '../types/public/config.js'; import { createDevelopmentManifest } from '../vite-plugin-astro-server/plugin.js'; +import type { BuiltInProvider, FontFamily, FontProvider } from '../assets/fonts/types.js'; /** * See the full Astro Configuration API Documentation @@ -15,7 +16,11 @@ import { createDevelopmentManifest } from '../vite-plugin-astro-server/plugin.js export function defineConfig< const TLocales extends Locales = never, const TDriver extends SessionDriverName = never, ->(config: AstroUserConfig) { + TFontProviders extends FontProvider[] = never, + TFontFamilies extends FontFamily< + (TFontProviders extends never ? [] : TFontProviders)[number]['name'] | BuiltInProvider + >[] = never, +>(config: AstroUserConfig) { return config; } diff --git a/packages/astro/src/core/config/schema.ts b/packages/astro/src/core/config/schema.ts index 8e9f510f8923..cc775ae05afc 100644 --- a/packages/astro/src/core/config/schema.ts +++ b/packages/astro/src/core/config/schema.ts @@ -14,6 +14,7 @@ import type { SvgRenderMode } from '../../assets/utils/svg.js'; import { EnvSchema } from '../../env/schema.js'; import type { AstroUserConfig, ViteUserConfig } from '../../types/public/config.js'; import { appendForwardSlash, prependForwardSlash, removeTrailingForwardSlash } from '../path.js'; +import { BUILTIN_PROVIDERS } from '../../assets/fonts/constants.js'; // The below types are required boilerplate to workaround a Zod issue since v3.21.2. Since that version, // Zod's compiled TypeScript would "simplify" certain values to their base representation, causing references @@ -589,6 +590,53 @@ export const AstroConfigSchema = z.object({ } return svgConfig; }), + fonts: z + .object({ + providers: z + .array( + z + .object({ + name: z.string().superRefine((name, ctx) => { + if (BUILTIN_PROVIDERS.includes(name as any)) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: `"${name}" is a reserved provider name`, + }); + } + }), + entrypoint: z.string(), + config: z.record(z.string(), z.any()).optional(), + }) + .strict(), + ) + .optional(), + families: z.array( + z + .object({ + provider: z.string(), + }) + .strict(), + ), + }) + .strict() + .optional() + .superRefine((fonts, ctx) => { + if (!fonts) { + return; + } + const providersNames = [ + ...BUILTIN_PROVIDERS, + ...(fonts.providers ?? []).map((provider) => provider.name), + ]; + for (const family of fonts.families) { + if (!providersNames.includes(family.provider)) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: `Invalid provider "${family.provider}"`, + }); + } + } + }), }) .strict( `Invalid or outdated experimental feature.\nCheck for incorrect spelling or outdated Astro version.\nSee https://docs.astro.build/en/reference/experimental-flags/ for a list of all current experiments.`, diff --git a/packages/astro/src/types/public/config.ts b/packages/astro/src/types/public/config.ts index 635e57798c66..35553551099b 100644 --- a/packages/astro/src/types/public/config.ts +++ b/packages/astro/src/types/public/config.ts @@ -17,6 +17,7 @@ import type { AstroCookieSetOptions } from '../../core/cookies/cookies.js'; import type { Logger, LoggerLevel } from '../../core/logger/core.js'; import type { EnvSchema } from '../../env/schema.js'; import type { AstroIntegration } from './integrations.js'; +import type { BuiltInProvider, FontFamily, FontProvider } from '../../assets/fonts/types.js'; export type Locales = (string | { codes: string[]; path: string })[]; type NormalizeLocales = { @@ -164,6 +165,10 @@ export interface ViteUserConfig extends OriginalViteUserConfig { */ export interface AstroUserConfig< TLocales extends Locales = never, TSession extends SessionDriverName = never, + TFontProviders extends FontProvider[] = never, + TFontFamilies extends FontFamily< + (TFontProviders extends never ? [] : TFontProviders)[number]['name'] | BuiltInProvider + >[] = never, > { /** * @docs @@ -2059,6 +2064,40 @@ export interface ViteUserConfig extends OriginalViteUserConfig { */ mode: SvgRenderMode; }; + + /** + * + * @name experimental.fonts + * @type {object} + * @default `undefined` + * @version 5.x + * @description + * + * TODO: + */ + fonts?: { + /** + * + * @name experimental.fonts.providers + * @type {FontProvider[]} + * @version 5.x + * @description + * + * TODO: + */ + providers?: TFontProviders; + + /** + * + * @name experimental.fonts.families + * @type {FontFamily[]} + * @version 5.x + * @description + * + * TODO: + */ + families: TFontFamilies; + }; }; }