diff --git a/packages/next/src/build/webpack/loaders/metadata/types.ts b/packages/next/src/build/webpack/loaders/metadata/types.ts index 8e0143a20f..89b2bfd480 100644 --- a/packages/next/src/build/webpack/loaders/metadata/types.ts +++ b/packages/next/src/build/webpack/loaders/metadata/types.ts @@ -24,6 +24,7 @@ export type CollectedMetadata = { export type MetadataImageModule = { url: string type?: string + alt?: string } & ( | { sizes?: string } | { diff --git a/packages/next/src/build/webpack/loaders/next-metadata-image-loader.ts b/packages/next/src/build/webpack/loaders/next-metadata-image-loader.ts index 1db894b21b..ae623b8cd9 100644 --- a/packages/next/src/build/webpack/loaders/next-metadata-image-loader.ts +++ b/packages/next/src/build/webpack/loaders/next-metadata-image-loader.ts @@ -6,10 +6,12 @@ import type { MetadataImageModule, PossibleImageFileNameConvention, } from './metadata/types' +import fs from 'fs/promises' import path from 'path' import loaderUtils from 'next/dist/compiled/loader-utils3' import { getImageSize } from '../../../server/image-optimizer' import { imageExtMimeTypeMap } from '../../../lib/mime-type' +import { fileExists } from '../../../lib/file-exists' interface Options { route: string @@ -109,6 +111,16 @@ async function nextMetadataImageLoader(this: any, content: Buffer) { : `${imageSize.width}x${imageSize.height}`, }), } + if (type === 'openGraph' || type === 'twitter') { + const altPath = path.join( + path.dirname(resourcePath), + fileNameBase + '.alt.txt' + ) + + if (await fileExists(altPath)) { + imageData.alt = await fs.readFile(altPath, 'utf8') + } + } return `\ import path from 'next/dist/shared/lib/isomorphic/path' diff --git a/test/e2e/app-dir/metadata/app/opengraph/static/opengraph-image.alt.txt b/test/e2e/app-dir/metadata/app/opengraph/static/opengraph-image.alt.txt new file mode 100644 index 0000000000..0c9fb4f080 --- /dev/null +++ b/test/e2e/app-dir/metadata/app/opengraph/static/opengraph-image.alt.txt @@ -0,0 +1 @@ +A alt txt for og \ No newline at end of file diff --git a/test/e2e/app-dir/metadata/app/opengraph/static/twitter-image.alt.txt b/test/e2e/app-dir/metadata/app/opengraph/static/twitter-image.alt.txt new file mode 100644 index 0000000000..88557877d3 --- /dev/null +++ b/test/e2e/app-dir/metadata/app/opengraph/static/twitter-image.alt.txt @@ -0,0 +1 @@ +A alt txt for twitter \ No newline at end of file diff --git a/test/e2e/app-dir/metadata/metadata.test.ts b/test/e2e/app-dir/metadata/metadata.test.ts index e53ce22293..55fb430b00 100644 --- a/test/e2e/app-dir/metadata/metadata.test.ts +++ b/test/e2e/app-dir/metadata/metadata.test.ts @@ -478,21 +478,23 @@ createNextDescribe( it('should pick up opengraph-image and twitter-image as static metadata files', async () => { const $ = await next.render$('/opengraph/static') - expect($('[property="og:image"]').attr('content')).toBe( - 'https://example.com/opengraph/static/opengraph-image.png?b76e8f0282c93c8e' - ) - expect($('[property="og:image:type"]').attr('content')).toBe( - 'image/png' - ) - expect($('[property="og:image:width"]').attr('content')).toBe('114') - expect($('[property="og:image:height"]').attr('content')).toBe('114') - expect($('[name="twitter:image"]').attr('content')).toBe( - 'https://example.com/opengraph/static/twitter-image.png?b76e8f0282c93c8e' - ) - expect($('[name="twitter:card"]').attr('content')).toBe( - 'summary_large_image' - ) + const match = createMultiHtmlMatcher($) + await match('meta', 'property', 'content', { + 'og:image:width': '114', + 'og:image:height': '114', + 'og:image:type': 'image/png', + 'og:image:alt': 'A alt txt for og', + 'og:image': + 'https://example.com/opengraph/static/opengraph-image.png?b76e8f0282c93c8e', + }) + + await match('meta', 'name', 'content', { + 'twitter:image': + 'https://example.com/opengraph/static/twitter-image.png?b76e8f0282c93c8e', + 'twitter:image:alt': 'A alt txt for twitter', + 'twitter:card': 'summary_large_image', + }) // favicon shouldn't be overridden const $icon = $('link[rel="icon"]')