diff --git a/packages/next/src/build/webpack-config.ts b/packages/next/src/build/webpack-config.ts index fd9e9a76380ce..fb6e5b1cfd12a 100644 --- a/packages/next/src/build/webpack-config.ts +++ b/packages/next/src/build/webpack-config.ts @@ -1077,6 +1077,9 @@ export default async function getBaseWebpackConfig( ...nodePathList, // Support for NODE_PATH environment variable ], alias: { + // Alias 3rd party @vercel/og package to vendored og image package to reduce bundle size + '@vercel/og': 'next/dist/server/web/spec-extension/image-response', + // Alias next/dist imports to next/dist/esm assets, // let this alias hit before `next` alias. ...(isEdgeServer @@ -1088,25 +1091,27 @@ export default async function getBaseWebpackConfig( 'next/dist/server': 'next/dist/esm/server', // Alias the usage of next public APIs - [require.resolve('next/dist/client/link')]: + [`${NEXT_PROJECT_ROOT}/server`]: + 'next/dist/esm/server/web/exports/index', + [`${NEXT_PROJECT_ROOT}/dist/client/link`]: 'next/dist/esm/client/link', - [require.resolve('next/dist/client/image')]: + [`${NEXT_PROJECT_ROOT}/dist/client/image`]: 'next/dist/esm/client/image', - [require.resolve('next/dist/client/script')]: + [`${NEXT_PROJECT_ROOT}/dist/client/script`]: 'next/dist/esm/client/script', - [require.resolve('next/dist/client/router')]: + [`${NEXT_PROJECT_ROOT}/dist/client/router`]: 'next/dist/esm/client/router', - [require.resolve('next/dist/shared/lib/head')]: + [`${NEXT_PROJECT_ROOT}/dist/shared/lib/head`]: 'next/dist/esm/shared/lib/head', - [require.resolve('next/dist/shared/lib/dynamic')]: + [`${NEXT_PROJECT_ROOT}/dist/shared/lib/dynamic`]: 'next/dist/esm/shared/lib/dynamic', - [require.resolve('next/dist/pages/_document')]: + [`${NEXT_PROJECT_ROOT}/dist/pages/_document`]: 'next/dist/esm/pages/_document', - [require.resolve('next/dist/pages/_app')]: + [`${NEXT_PROJECT_ROOT}/dist/pages/_app`]: 'next/dist/esm/pages/_app', - [require.resolve('next/dist/client/components/navigation')]: + [`${NEXT_PROJECT_ROOT}/dist/client/components/navigation`]: 'next/dist/esm/client/components/navigation', - [require.resolve('next/dist/client/components/headers')]: + [`${NEXT_PROJECT_ROOT}/dist/client/components/headers`]: 'next/dist/esm/client/components/headers', } : undefined), @@ -1433,8 +1438,8 @@ export default async function getBaseWebpackConfig( resolveResult.res = require.resolve(request) } - // Don't bundle @vercel/og nodejs bundle for nodejs runtime - // TODO-APP: bundle route.js with different layer that externals common node_module deps + // Don't bundle @vercel/og nodejs bundle for nodejs runtime. + // TODO-APP: bundle route.js with different layer that externals common node_module deps. if ( layer === WEBPACK_LAYERS.server && request === 'next/dist/compiled/@vercel/og/index.node.js' diff --git a/packages/next/src/build/webpack/plugins/middleware-plugin.ts b/packages/next/src/build/webpack/plugins/middleware-plugin.ts index 709a4626f0fd4..00cb6b889e251 100644 --- a/packages/next/src/build/webpack/plugins/middleware-plugin.ts +++ b/packages/next/src/build/webpack/plugins/middleware-plugin.ts @@ -570,7 +570,7 @@ function getExtractMetadata(params: { const resource = module.resource const hasOGImageGeneration = resource && - /[\\/]node_modules[\\/]@vercel[\\/]og[\\/]dist[\\/]index\.(edge|node)\.js$|[\\/]next[\\/]dist[\\/]server[\\/]web[\\/]spec-extension[\\/]image-response\.js$/.test( + /[\\/]node_modules[\\/]@vercel[\\/]og[\\/]dist[\\/]index\.(edge|node)\.js$|[\\/]next[\\/]dist[\\/](esm[\\/])?server[\\/]web[\\/]spec-extension[\\/]image-response\.js$/.test( resource ) diff --git a/packages/next/src/lib/server-external-packages.json b/packages/next/src/lib/server-external-packages.json index 9fed54504e6c6..7ed606365109a 100644 --- a/packages/next/src/lib/server-external-packages.json +++ b/packages/next/src/lib/server-external-packages.json @@ -7,7 +7,6 @@ "@sentry/nextjs", "@sentry/node", "@swc/core", - "@vercel/og", "argon2", "autoprefixer", "aws-crt", diff --git a/packages/next/src/server/web/exports/index.ts b/packages/next/src/server/web/exports/index.ts new file mode 100644 index 0000000000000..d461efb78dc12 --- /dev/null +++ b/packages/next/src/server/web/exports/index.ts @@ -0,0 +1,8 @@ +// Alias index file of next/server for edge runtime for tree-shaking purpose + +export { default as ImageResponse } from './image-response' +export { default as NextRequest } from './next-request' +export { default as NextResponse } from './next-response' +export { default as userAgent } from './user-agent' +export { default as userAgentFromString } from './user-agent-from-string' +export { default as URLPattern } from './url-pattern' diff --git a/packages/next/src/server/web/spec-extension/image-response.ts b/packages/next/src/server/web/spec-extension/image-response.ts index fdbb4e974ee98..bccd7401a2556 100644 --- a/packages/next/src/server/web/spec-extension/image-response.ts +++ b/packages/next/src/server/web/spec-extension/image-response.ts @@ -1,4 +1,5 @@ export class ImageResponse { + public static displayName = 'NextImageResponse' constructor( ...args: ConstructorParameters< typeof import('next/dist/compiled/@vercel/og').ImageResponse diff --git a/test/e2e/app-dir/metadata-dynamic-routes/app/twitter-image.tsx b/test/e2e/app-dir/metadata-dynamic-routes/app/twitter-image.tsx index ec3e38f7c3e54..aaa0f49e5b2ae 100644 --- a/test/e2e/app-dir/metadata-dynamic-routes/app/twitter-image.tsx +++ b/test/e2e/app-dir/metadata-dynamic-routes/app/twitter-image.tsx @@ -1,4 +1,14 @@ import { ImageResponse } from 'next/server' +// @ts-ignore +import { ImageResponse as ImageResponse2 } from '@vercel/og' + +// Node.js: Using @vercel/og external package, and should be aliased to "next/server" ImageResponse +if (ImageResponse.displayName !== 'NextImageResponse') + throw new Error('ImageResponse mismatch: ' + ImageResponse.displayName) +// @ts-ignore +if (ImageResponse2.displayName !== 'NextImageResponse') + // @ts-ignore + throw new Error('ImageResponse mismatch: ' + ImageResponse2.displayName) export const alt = 'Twitter' export const size = { width: 1600, height: 900 } diff --git a/test/e2e/app-dir/metadata-dynamic-routes/app/twitter-image2.tsx b/test/e2e/app-dir/metadata-dynamic-routes/app/twitter-image2.tsx new file mode 100644 index 0000000000000..6fac563558bba --- /dev/null +++ b/test/e2e/app-dir/metadata-dynamic-routes/app/twitter-image2.tsx @@ -0,0 +1,37 @@ +import { ImageResponse } from 'next/server' +// @ts-ignore +import { ImageResponse as ImageResponse2 } from '@vercel/og' + +// Edge: Using @vercel/og external package, and should be aliased to "next/server" ImageResponse +if (ImageResponse.displayName !== 'NextImageResponse') + throw new Error('ImageResponse mismatch: ' + ImageResponse.displayName) +// @ts-ignore +if (ImageResponse2.displayName !== 'NextImageResponse') + // @ts-ignore + throw new Error('ImageResponse2 mismatch: ' + ImageResponse2.displayName) + +export const alt = 'Twitter' +export const size = { width: 1600, height: 900 } + +export default function twitter() { + return new ImageResponse( + ( +