From 7fa4946b4254906f466cfe556ee00102b73b7b0c Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Thu, 4 May 2023 21:50:13 +0200 Subject: [PATCH] Apply basePath for metadata image (#49226) Fixes #49162 When user configures the `basePath` in `next.config.js`, we need to apply it to metadata image path resolving fix NEXT-1087 --- packages/next/src/build/entries.ts | 2 ++ .../build/webpack/loaders/metadata/discover.ts | 3 +++ .../src/build/webpack/loaders/next-app-loader.ts | 8 +++++++- .../loaders/next-metadata-image-loader.ts | 8 +++++--- packages/next/src/server/dev/hot-reloader.ts | 2 ++ .../app-basepath/app/another/opengraph-image.png | Bin 0 -> 1661 bytes test/e2e/app-dir/app-basepath/index.test.ts | 7 +++++++ 7 files changed, 26 insertions(+), 4 deletions(-) create mode 100644 test/e2e/app-dir/app-basepath/app/another/opengraph-image.png diff --git a/packages/next/src/build/entries.ts b/packages/next/src/build/entries.ts index 5abc264d3ad91..2c25c58cc5476 100644 --- a/packages/next/src/build/entries.ts +++ b/packages/next/src/build/entries.ts @@ -553,6 +553,7 @@ export async function createEntrypoints( appDir, appPaths: matchedAppPaths, pageExtensions, + basePath: config.basePath, assetPrefix: config.assetPrefix, nextConfigOutput: config.output, preferredRegion: staticInfo.preferredRegion, @@ -580,6 +581,7 @@ export async function createEntrypoints( appDir: appDir!, appPaths: matchedAppPaths, pageExtensions, + basePath: config.basePath, assetPrefix: config.assetPrefix, nextConfigOutput: config.output, // This isn't used with edge as it needs to be set on the entry module, which will be the `edgeServerEntry` instead. diff --git a/packages/next/src/build/webpack/loaders/metadata/discover.ts b/packages/next/src/build/webpack/loaders/metadata/discover.ts index 7f74b0256dec0..563cff23fa294 100644 --- a/packages/next/src/build/webpack/loaders/metadata/discover.ts +++ b/packages/next/src/build/webpack/loaders/metadata/discover.ts @@ -64,12 +64,14 @@ export async function createStaticMetadataFromRoute( isRootLayoutOrRootPage, loaderContext, pageExtensions, + basePath, }: { segment: string resolvePath: (pathname: string) => Promise isRootLayoutOrRootPage: boolean loaderContext: webpack.LoaderContext pageExtensions: string[] + basePath: string } ) { let hasStaticMetadataFiles = false @@ -124,6 +126,7 @@ export async function createStaticMetadataFromRoute( { type, segment, + basePath, pageExtensions, } )}!${filepath}${METADATA_RESOURCE_QUERY}` diff --git a/packages/next/src/build/webpack/loaders/next-app-loader.ts b/packages/next/src/build/webpack/loaders/next-app-loader.ts index 15d0b1ab228b2..b3c2627d4e961 100644 --- a/packages/next/src/build/webpack/loaders/next-app-loader.ts +++ b/packages/next/src/build/webpack/loaders/next-app-loader.ts @@ -33,6 +33,7 @@ export type AppLoaderOptions = { rootDir?: string tsconfigPath?: string isDev?: boolean + basePath: string nextConfigOutput?: NextConfig['output'] } type AppLoader = webpack.LoaderDefinitionFunction @@ -176,6 +177,7 @@ async function createTreeCodeFromPath( resolveParallelSegments, loaderContext, pageExtensions, + basePath, }: { resolver: PathResolver resolvePath: (pathname: string) => Promise @@ -184,6 +186,7 @@ async function createTreeCodeFromPath( ) => [key: string, segment: string | string[]][] loaderContext: webpack.LoaderContext pageExtensions: string[] + basePath: string } ) { const splittedPath = pagePath.split(/[\\/]/) @@ -258,6 +261,7 @@ async function createTreeCodeFromPath( if (resolvedRouteDir) { metadata = await createStaticMetadataFromRoute(resolvedRouteDir, { + basePath, segment: segmentPath, resolvePath, isRootLayoutOrRootPage, @@ -427,6 +431,7 @@ const nextAppLoader: AppLoader = async function nextAppLoader() { isDev, nextConfigOutput, preferredRegion, + basePath, } = loaderOptions const buildInfo = getModuleBuildInfo((this as any)._module) @@ -535,6 +540,7 @@ const nextAppLoader: AppLoader = async function nextAppLoader() { resolveParallelSegments, loaderContext: this, pageExtensions, + basePath, }) if (!rootLayout) { @@ -599,7 +605,7 @@ const nextAppLoader: AppLoader = async function nextAppLoader() { export { renderToReadableStream, decodeReply, decodeAction } from 'react-server-dom-webpack/server.edge' export const __next_app_webpack_require__ = __webpack_require__ export { preloadStyle, preloadFont, preconnect } from 'next/dist/server/app-render/rsc/preloads' - + export const originalPathname = "${page}" ` 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 94bee7ce5045c..abe5e3e0f0673 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 @@ -17,11 +17,12 @@ interface Options { segment: string type: PossibleImageFileNameConvention pageExtensions: string[] + basePath: string } async function nextMetadataImageLoader(this: any, content: Buffer) { const options: Options = this.getOptions() - const { type, segment, pageExtensions } = options + const { type, segment, pageExtensions, basePath } = options const numericSizes = type === 'twitter' || type === 'openGraph' const { resourcePath, rootContext: context } = this const { name: fileNameBase, ext } = path.parse(resourcePath) @@ -48,6 +49,7 @@ async function nextMetadataImageLoader(this: any, content: Buffer) { const isDynamicResource = pageExtensions.includes(extension) const pageSegment = isDynamicResource ? fileNameBase : interpolatedName const hashQuery = contentHash ? '?' + contentHash : '' + const pathnamePrefix = path.join(basePath, segment) if (isDynamicResource) { // re-export and spread as `exportedImageData` to avoid non-exported error @@ -59,7 +61,7 @@ async function nextMetadataImageLoader(this: any, content: Buffer) { export default async function (props) { const { __metadata_id__: _, ...params } = props.params const imageUrl = fillMetadataSegment(${JSON.stringify( - segment + pathnamePrefix )}, params, ${JSON.stringify(pageSegment)}) const { generateImageMetadata } = imageModule @@ -136,7 +138,7 @@ async function nextMetadataImageLoader(this: any, content: Buffer) { export default (props) => { const imageData = ${JSON.stringify(imageData)} const imageUrl = fillMetadataSegment(${JSON.stringify( - segment + pathnamePrefix )}, props.params, ${JSON.stringify(pageSegment)}) return [{ diff --git a/packages/next/src/server/dev/hot-reloader.ts b/packages/next/src/server/dev/hot-reloader.ts index cef06135f331d..0cdd2be15041d 100644 --- a/packages/next/src/server/dev/hot-reloader.ts +++ b/packages/next/src/server/dev/hot-reloader.ts @@ -755,6 +755,7 @@ export default class HotReloader { rootDir: this.dir, isDev: true, tsconfigPath: this.config.typescript.tsconfigPath, + basePath: this.config.basePath, assetPrefix: this.config.assetPrefix, nextConfigOutput: this.config.output, preferredRegion: staticInfo.preferredRegion, @@ -840,6 +841,7 @@ export default class HotReloader { rootDir: this.dir, isDev: true, tsconfigPath: this.config.typescript.tsconfigPath, + basePath: this.config.basePath, assetPrefix: this.config.assetPrefix, nextConfigOutput: this.config.output, preferredRegion: staticInfo.preferredRegion, diff --git a/test/e2e/app-dir/app-basepath/app/another/opengraph-image.png b/test/e2e/app-dir/app-basepath/app/another/opengraph-image.png new file mode 100644 index 0000000000000000000000000000000000000000..7cbc1d26733614b83dcc25b9cfcd5e06dffb147c GIT binary patch literal 1661 zcmV-@27>vCP)LUUqAigYBsiM4LpbwXrcM#DLg%sv zqYV7atJ2!&9+4a}Z~>mx*QQG8O{j2%jKM&gp$l9QGmOhXo1ym@G1NiGAj_1lhANDV z1!S4frxq9i3di1^l$}15Gz3>C_2kBUE^I5>7jp>X5wdo&Pd!2a6f5GP)GgXa3QSQ5 zJ0>bk8Vt=;h$f0RQz4ot-b{sPqIfeEqKV?oREQ=HW#$APi4kKst#JY0qCFI7KO!;| z-{Dx5|6)LB*iF*ATe1cl&QpkEr#`hqi_TA*>5v*DyuQX9nwI%PlNUBUM=lW0iy@%% zB^BF?>xE4!QsG#Qk#JB|Zt7m}4cuf9&Sc^>nhincOJ6g{>L6IPUat?vOi^vN=pG%= zK#)fFriX`z1CgewsCHXKz1WKmEejx6qkEB3>Y%mGjoj^a`R9__Z&8YtD2$*QSF6?G zlq}0cwcn!FRXGQOH@cIk`fMagBI@t3C`Ai25VWzK_5A#7HS(IOas~u%Y$wfTvqK&8 z`CQcBV^O1VSn-#r$_`Ey)bSA>M>05=GHK|=D&vNW5yX)MHLMsk@M4|D4HqMbBTuM7 zGiqpSoyQFq!aF`YRFE)gWNTH$4Hv@WNCFEhW{qs6s<<)osDkweD~7ZT#gP4NM1Ob2K1o@yQY z{T_FBclnkpP431DijTPALP{KAd${l!H(UsaBYd9=;5%-(VBYcJ89zeB4Hrz~h-Q0^ ze0=2jeA>lg0fywgunf%JVWH!O3x;tdBO_PL8pWoAQw77TBTG88Zovo+al-|}I6`Y+ z^0|$UQ`~UDEROt4MzXmBi(A}q!6=R-WF(8pS6t(U3np>o%N@)*bYntY-RKH~s(kZ& z*Hy^IaE}`<0>_c%sgbjQ4H479sUmP3xhDh5k)0O=LPFed5jc*#o_|5Z^Sen>+;9;n zj%ZkT@@=HFxZxr|$7g9XGV$36sd2-F=Qxs}0&mwQrN#{x9;;HL1}}$K>2bq_r#P}a zHSYXT*aJ@Mua=>9?N1|Wq^)( z8lD&1iZo_xba(zmTSe0Rk3SIMiq)H{bw6TN@?>lD0hU=ERkP?~Rr2IdR7}mOTZt!D zB`>zHoEuB(=Cx8){)z|}QgkGPtc*2AX*g)I$Qez}x@fuBNN>;~bzAp>Cd&@~hoj*M zA|d$Q=r7lc+AIW0RXIh(CtK8Xa87A+6VERwZWf7nf%f%>rY~-@>N)-3|BZe^#0S3_ z{euDVJ|*M|Rl5{KpJV_IQG>{9LMTUlr0g6i(g^TuK!s?gcoRz$qM71NEK!JNiZ`)D zA(|=P#1e&Qrg#%e6h^R+s0U>ba-BC08dS?$*zXIv&y4Nk(E@0PhHE2pL?NCxNoxpO z1fYr(vUYr*N-;7NuB$pTjQslT4C6MG&V~25B2tXY&|UF2UFGyqg=0@nLzZdLz#3+d zHJFeYJs=ub33U)w;8~?qeH7>uL|Ty`ys7lN*_+p9I%H@Rjysd|J%;PrZ*hEp)N8Tb zLI9GCJcrIr)06Ejj%H5^Da-fl@pVe)w$P_yyD7FJr+j_}po~WmWUki$00000NkvXX Hu0mjfdKc_u literal 0 HcmV?d00001 diff --git a/test/e2e/app-dir/app-basepath/index.test.ts b/test/e2e/app-dir/app-basepath/index.test.ts index ae6893aa93843..3479296baf5d9 100644 --- a/test/e2e/app-dir/app-basepath/index.test.ts +++ b/test/e2e/app-dir/app-basepath/index.test.ts @@ -27,5 +27,12 @@ createNextDescribe( .text() ).toBe(`Page 2`) }) + + it('should prefix metadata og image with basePath', async () => { + const $ = await next.render$('/base/another') + const ogImageHref = $('meta[property="og:image"]').attr('content') + + expect(ogImageHref).toContain('/base/another/opengraph-image.png') + }) } )