Skip to content

Commit 61d1d7f

Browse files
committed
fix: remove default component option
1 parent bf6fec2 commit 61d1d7f

9 files changed

Lines changed: 55 additions & 50 deletions

File tree

src/module.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,9 @@ export interface ModuleOptions {
7171
*
7272
* You can use this to change the default template, image sizing and more.
7373
*
74-
* @default { component: 'NuxtSeo', width: 1200, height: 630, cache: true, cacheTtl: 24 * 60 * 60 * 1000 }
74+
* @default { width: 1200, height: 600, cache: true, cacheTtl: 24 * 60 * 60 * 1000 }
7575
*/
76-
defaults: OgImageOptions
76+
defaults: Omit<OgImageOptions, 'component' | 'renderer' | 'props' | 'url' | 'html' | 'key' | 'cacheKey' | '_query' | '_hash' | 'socialPreview'>
7777
/**
7878
* Options to pass to satori.
7979
*
@@ -224,7 +224,6 @@ export default defineNuxtModule<ModuleOptions>({
224224
enabled: true,
225225
defaults: {
226226
emojis: 'noto',
227-
component: 'NuxtSeo',
228227
extension: 'png',
229228
width: 1200,
230229
height: 600,
@@ -866,7 +865,7 @@ export default defineNuxtModule<ModuleOptions>({
866865
// No user components — auto-detect from installed deps, prompt only if none installed
867866
if (!nuxt.options._prepare && !hasUserComponents) {
868867
const installedProviders = await getInstalledProviders()
869-
const preferred = installedProviders.find(p => p.provider === 'satori') || installedProviders[0]
868+
const preferred = installedProviders.find(p => p.provider === 'takumi') || installedProviders[0]
870869
if (preferred) {
871870
ogImageComponentCtx.detectedRenderers.add(preferred.provider)
872871
logger.debug(`Using ${preferred.provider} renderer`)
@@ -877,7 +876,7 @@ export default defineNuxtModule<ModuleOptions>({
877876
logger.debug(`Using ${renderer} renderer`)
878877
}
879878
else {
880-
ogImageComponentCtx.detectedRenderers.add(config.defaults.renderer || 'satori')
879+
ogImageComponentCtx.detectedRenderers.add('takumi')
881880
}
882881
}
883882

src/runtime/app/composables/defineOgImage.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { OgImageComponents } from '#og-image/components'
2-
import type { OgImageOptions, ReactiveComponentProps } from '../../types'
2+
import type { OgImageOptions, OgImageOptionsInternal, ReactiveComponentProps } from '../../types'
33
import { _defineOgImageRaw } from './_defineOgImageRaw'
44

55
type OgImageComponentOptions<T extends keyof OgImageComponents> = OgImageOptions & {
@@ -33,7 +33,7 @@ export function defineOgImage<T extends keyof OgImageComponents>(
3333
// Handle shared props + array of variants
3434
if (Array.isArray(options)) {
3535
return _defineOgImageRaw(options.map((opt) => {
36-
const input: OgImageOptions = {
36+
const input: OgImageOptionsInternal = {
3737
...opt,
3838
component: component as string,
3939
}
@@ -46,7 +46,7 @@ export function defineOgImage<T extends keyof OgImageComponents>(
4646
}
4747

4848
// Single image
49-
const input: OgImageOptions = {
49+
const input: OgImageOptionsInternal = {
5050
...options,
5151
component: component as string,
5252
}

src/runtime/app/utils.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { ActiveHeadEntry, Head } from '@unhead/vue'
22
import type { NuxtSSRContext } from 'nuxt/app'
3-
import type { OgImageOptions, OgImagePrebuilt, OgImageRuntimeConfig } from '../types'
3+
import type { OgImageOptions, OgImageOptionsInternal, OgImagePrebuilt, OgImageRuntimeConfig } from '../types'
44
import { componentNames } from '#build/nuxt-og-image/components.mjs'
55
import { resolveUnrefHeadInput } from '@unhead/vue'
66
import { defu } from 'defu'
@@ -9,7 +9,7 @@ import { useHead, useRuntimeConfig } from 'nuxt/app'
99
import { joinURL, withQuery } from 'ufo'
1010
import { buildOgImageUrl, generateMeta, separateProps } from '../shared'
1111

12-
type OgImagePayload = [string, OgImageOptions, Required<Head>['meta']]
12+
type OgImagePayload = [string, OgImageOptionsInternal, Required<Head>['meta']]
1313

1414
declare module 'nuxt/app' {
1515
interface NuxtSSRContext {
@@ -77,7 +77,7 @@ export function createOgImageMeta(src: string, input: OgImageOptions | OgImagePr
7777
const payload = resolveUnrefHeadInput(options) as any
7878
if (payload.props && typeof payload.props.title === 'undefined')
7979
payload.props.title = '%s'
80-
payload.component = resolveComponentName(options.component, defaults.component || '')
80+
payload.component = resolveComponentName(options.component)
8181
payload.key = key
8282
delete payload.url
8383
if (payload._query && Object.keys(payload._query).length === 0) {
@@ -107,8 +107,8 @@ export function createOgImageMeta(src: string, input: OgImageOptions | OgImagePr
107107
ssrContext._ogImagePayloads = payloads
108108
}
109109

110-
export function resolveComponentName(component: OgImageOptions['component'], fallback: string): OgImageOptions['component'] {
111-
component = component || fallback || componentNames?.[0]?.pascalName
110+
export function resolveComponentName(component: OgImageOptionsInternal['component']): OgImageOptionsInternal['component'] {
111+
component = component || componentNames?.[0]?.pascalName
112112
// try and fix component name if we're using a shorthand (i.e Banner instead of OgImageBanner)
113113
if (component && componentNames) {
114114
const originalName = component

src/runtime/server/og-image/cache/buildCache.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export function generateBuildCacheKey(
3030
extension: string,
3131
): string {
3232
const { version } = useOgImageRuntimeConfig()
33-
const componentHash = getComponentHash(options.component || 'NuxtSeo')
33+
const componentHash = getComponentHash(options.component || 'default')
3434
const hash = hashOgImageOptions(options, componentHash, version)
3535
return `${hash}.${extension}`
3636
}

src/runtime/server/og-image/context.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { H3Error, H3Event } from 'h3'
22
import type {
3-
OgImageOptions,
3+
OgImageOptionsInternal,
44
OgImageRenderEventContext,
55
RouteRulesOgImage,
66
} from '../../types'
@@ -125,7 +125,7 @@ export async function resolveContext(e: H3Event): Promise<H3Error | OgImageRende
125125
const routeRuleMatcher = createNitroRouteRuleMatcher()
126126
const routeRules = routeRuleMatcher(basePath)
127127
const ogImageRouteRules = separateProps(routeRules.ogImage as RouteRulesOgImage)
128-
const options: OgImageOptions = defu(queryParams, urlOptions, ogImageRouteRules, runtimeConfig.defaults) as OgImageOptions
128+
const options = defu(queryParams, urlOptions, ogImageRouteRules, runtimeConfig.defaults) as OgImageOptionsInternal
129129

130130
if (!options) {
131131
return createError({

src/runtime/server/og-image/devtools.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import type { H3Error, H3Event } from 'h3'
2-
import type { DevToolsMetaDataExtraction, OgImageOptions } from '../../types'
2+
import type { DevToolsMetaDataExtraction, OgImageOptionsInternal } from '../../types'
33
import { htmlPayloadCache } from '#og-image-cache'
44
import { parse } from 'devalue'
55
import { createError } from 'h3'
66
import { extractSocialPreviewTags } from '../../pure'
77
import { logger } from '../util/logger'
88

99
export interface DevToolsExtractPayload {
10-
options: OgImageOptions[]
10+
options: OgImageOptionsInternal[]
1111
socialPreview: {
1212
root: Record<string, string>
1313
images: DevToolsMetaDataExtraction[]
@@ -16,11 +16,11 @@ export interface DevToolsExtractPayload {
1616

1717
const PAYLOAD_REGEX = /<script.+id="nuxt-og-image-options"[^>]*>(.+?)<\/script>/
1818

19-
function extractOptionsFromHtml(html: string): OgImageOptions[] {
19+
function extractOptionsFromHtml(html: string): OgImageOptionsInternal[] {
2020
const match = String(html).match(PAYLOAD_REGEX)
2121
if (!match?.[1])
2222
return []
23-
return parse(match[1]) as OgImageOptions[]
23+
return parse(match[1]) as OgImageOptionsInternal[]
2424
}
2525

2626
async function doFetchWithErrorHandling(fetch: any, path: string) {

src/runtime/server/util/options.ts

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import type { DefineOgImageInput, OgImageComponent, OgImageOptions, OgImagePrebuilt, RendererType } from '../../types'
1+
import type { DefineOgImageInput, OgImageComponent, OgImageOptionsInternal, OgImagePrebuilt, RendererType } from '../../types'
22
import { componentNames } from '#og-image-virtual/component-names.mjs'
33
import { createError } from 'h3'
44

55
export interface NormalisedOptions {
6-
options: OgImageOptions | OgImagePrebuilt
6+
options: OgImageOptionsInternal | OgImagePrebuilt
77
renderer: RendererType
88
component?: OgImageComponent
99
}
@@ -141,7 +141,7 @@ function resolveComponent(name: string): { component: OgImageComponent, renderer
141141
}
142142

143143
export function normaliseOptions(_options: DefineOgImageInput): NormalisedOptions {
144-
const options = { ..._options } as OgImageOptions
144+
const options = { ..._options } as OgImageOptionsInternal
145145

146146
// Special case: PageScreenshot is a virtual component for page screenshots
147147
// It always uses browser renderer and doesn't need a real component
@@ -180,14 +180,19 @@ export function normaliseOptions(_options: DefineOgImageInput): NormalisedOption
180180
// check if using a community template - auto-ejected in dev, error in prod
181181
if (resolved.category === 'community') {
182182
if (!import.meta.dev) {
183-
const requestedName = (_options as OgImageOptions).component || '(default)'
184-
const appNames = componentNames.filter((c: OgImageComponent) => c.category !== 'community').map((c: OgImageComponent) => c.pascalName)
185-
throw createError({
186-
statusCode: 500,
187-
message: `Community template "${resolved.pascalName}" must be ejected before production use. Run: npx nuxt-og-image eject ${resolved.pascalName}${
188-
requestedName !== '(default)' ? `\n Requested component: "${requestedName}"` : ''
189-
}${appNames.length ? `\n Available app components: ${appNames.join(', ')}` : '\n No app components found — create one in components/OgImage/'}`,
190-
})
183+
// In production, fall back to an app component if available
184+
const appComponent = componentNames.find((c: OgImageComponent) => c.category !== 'community')
185+
if (appComponent) {
186+
resolved = appComponent
187+
renderer = resolved.renderer
188+
options.component = resolved.pascalName
189+
}
190+
else {
191+
throw createError({
192+
statusCode: 500,
193+
message: `Community template "${resolved.pascalName}" must be ejected before production use. Run: npx nuxt-og-image eject ${resolved.pascalName}\n No app components found — create one in components/OgImage/`,
194+
})
195+
}
191196
}
192197
}
193198

src/runtime/shared.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { ResolvableMeta } from '@unhead/vue'
2-
import type { OgImageOptions, OgImagePrebuilt } from './types'
2+
import type { OgImageOptions, OgImageOptionsInternal, OgImagePrebuilt } from './types'
33
import { defu } from 'defu'
44
import { toValue } from 'vue'
55

@@ -50,14 +50,14 @@ export function isInternalRoute(path: string) {
5050
}
5151

5252
function filterIsOgImageOption(key: string) {
53-
const keys: (keyof OgImageOptions)[] = [
53+
const keys: (keyof OgImageOptionsInternal)[] = [
5454
'url',
5555
'extension',
5656
'width',
5757
'height',
5858
'alt',
5959
'props',
60-
'renderer', // internal use only (screenshots)
60+
'renderer',
6161
'html',
6262
'component',
6363
'emojis',
@@ -71,7 +71,7 @@ function filterIsOgImageOption(key: string) {
7171
'cacheMaxAgeSeconds',
7272
'key',
7373
]
74-
return keys.includes(key as keyof OgImageOptions)
74+
return keys.includes(key as keyof OgImageOptionsInternal)
7575
}
7676

7777
export function separateProps(options: OgImageOptions | undefined, ignoreKeys: string[] = []): OgImageOptions {

src/runtime/types.ts

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export interface OgImageRenderEventContext {
1818
key: string
1919
basePath: string
2020
renderer: Renderer
21-
options: OgImageOptions
21+
options: OgImageOptionsInternal
2222
isDevToolsContextRequest: boolean
2323
publicStoragePath: string
2424
runtimeConfig: OgImageRuntimeConfig
@@ -37,7 +37,7 @@ export interface OgImageRuntimeConfig {
3737

3838
publicStoragePath: string
3939

40-
defaults: OgImageOptions
40+
defaults: Omit<OgImageOptions, 'component' | 'renderer' | 'props' | 'url' | 'html' | 'key' | 'cacheKey' | '_query' | '_hash' | 'socialPreview'>
4141
debug: boolean
4242
baseCacheKey: string
4343
hasNuxtIcon: boolean
@@ -103,7 +103,7 @@ export interface ScreenshotOptions {
103103
/**
104104
* The height of the screenshot.
105105
*
106-
* @default 630
106+
* @default 600
107107
*/
108108
height: number
109109
/**
@@ -115,7 +115,7 @@ export interface ScreenshotOptions {
115115
export interface OgImagePrebuilt extends OgImageOptions {
116116
}
117117

118-
export type DefineOgImageInput = OgImageOptions | OgImagePrebuilt | false
118+
export type DefineOgImageInput = OgImageOptionsInternal | OgImagePrebuilt | false
119119

120120
export interface OgImageOptions {
121121
/**
@@ -127,7 +127,7 @@ export interface OgImageOptions {
127127
/**
128128
* The height of the screenshot.
129129
*
130-
* @default 630
130+
* @default 600
131131
*/
132132
height?: number | (() => number) | Ref<number>
133133
/**
@@ -140,20 +140,10 @@ export interface OgImageOptions {
140140
* Should be an absolute URL.
141141
*/
142142
url?: string | (() => string) | Ref<string>
143-
/**
144-
* The name of the component to render.
145-
*/
146-
component?: string
147143
/**
148144
* Props to pass to the component.
149145
*/
150146
props?: Record<string, any>
151-
/**
152-
* Override renderer. Only used internally for screenshots.
153-
* For normal usage, renderer is determined by component filename suffix.
154-
* @internal
155-
*/
156-
renderer?: RendererType
157147
extension?: 'png' | 'jpeg' | 'jpg' | 'svg' | 'html'
158148
emojis?: IconifyEmojiIconSets | false
159149
/**
@@ -200,6 +190,17 @@ export interface OgImageOptions {
200190
cacheKey?: string
201191
}
202192

193+
/**
194+
* Internal options type used throughout the rendering pipeline.
195+
* Extends OgImageOptions with fields set by defineOgImage() and the module internals.
196+
*/
197+
export interface OgImageOptionsInternal extends OgImageOptions {
198+
/** Set by defineOgImage() — the resolved component PascalName */
199+
component?: string
200+
/** Determined by component filename suffix (.satori.vue, .takumi.vue, .browser.vue) */
201+
renderer?: RendererType
202+
}
203+
203204
export interface FontConfig {
204205
family: string
205206
weight: number

0 commit comments

Comments
 (0)