vercel / next.js

The React Framework
https://nextjs.org
MIT License
127.19k stars 27.02k forks source link

OpenGraph images are not statically generated for dynamic routes #51147

Open Cretezy opened 1 year ago

Cretezy commented 1 year ago

Verify canary release

Provide environment information

Operating System:
      Platform: linux
      Arch: x64
      Version: #1 ZEN SMP PREEMPT_DYNAMIC Sun, 04 Jun 2023 11:52:10 +0000
    Binaries:
      Node: 18.16.0
      npm: 9.5.1
      Yarn: 1.22.10
      pnpm: 8.6.1
    Relevant packages:
      next: 13.4.5-canary.12
      eslint-config-next: 13.4.5
      react: 18.2.0
      react-dom: 18.2.0
      typescript: 5.1.3

Which area(s) of Next.js are affected? (leave empty if unsure)

App directory (appDir: true), Metadata (metadata, generateMetadata, next/head, head.js), Static HTML Export (output: "export")

Link to the code that reproduces this issue or a replay of the bug

https://codesandbox.io/p/sandbox/reverent-feather-2sycr6

To Reproduce

Describe the Bug

The opengraph-image is not generated for dynamic paths when statically rendering.

In the output, it's marked as λ (Server) server-side renders at runtime for the dynamic paths (e.g. /[id]/opengraph-image), without listing each generated path (which /[id] would have, e.g. /1, /2,).

I can confirm it generates a .html for each path in out, but no opengraph-image is preset.

(It does work if it has no parameter in the path)

Example build output: image

Expected Behavior

A opengraph-image would be generated for each path returned by generateStaticParams, same as the page.tsx file would.

Which browser are you using? (if relevant)

No response

How are you deploying your application? (if relevant)

Statically rendered

NEXT-1458

joeyiny commented 1 year ago

Having this issue as well.

altano commented 1 year ago

@huozhi it looks like you fixed this for server rendered dynamic routes in https://github.com/vercel/next.js/issues/48704. Any chance you could take a look if the fix is just as easy for output: "export" dynamic routes?

chakkun1121 commented 1 year ago

You forgot the generateStaticParams function in opengraph-image.tsx. But when I add generateStaticParams function like below, an error has occurred like below.

// opengraph-image.tsx
...
+ export function generateStaticParams() {
+   return [{ id: "1" }, { id: "2" }];
+ }

error

Error: Page "/[id]/opengraph-image" is missing "generateStaticParams()" so it cannot be used with "output: export" config.
    at /project/sandbox/node_modules/next/dist/build/index.js:909:59
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at async Span.traceAsyncFn (/project/sandbox/node_modules/next/dist/trace/trace.js:105:20)
    at async Promise.all (index 6)
    at async /project/sandbox/node_modules/next/dist/build/index.js:802:17
    at async Span.traceAsyncFn (/project/sandbox/node_modules/next/dist/trace/trace.js:105:20)
    at async /project/sandbox/node_modules/next/dist/build/index.js:741:124
    at async Span.traceAsyncFn (/project/sandbox/node_modules/next/dist/trace/trace.js:105:20)
    at async build (/project/sandbox/node_modules/next/dist/build/index.js:184:29)
    at async main (/project/sandbox/node_modules/next/dist/bin/next:156:5)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

(I updated all the libraries.) (I'm Japanese, so please forgive me if my English is strange.)

altano commented 1 year ago

@chakkun1121 yes this is broken. There is no known workaround.

You can’t use export and opengraph images in dynamic routes. It won’t work.

Cretezy commented 1 year ago

I'm getting the same behavior as @chakkun1121 in Next 13.5 now too.

beeirl commented 1 year ago

Opengraph Image generation doesn't seem to work with output: "export" being set in next.config.js. Getting a 404 error when trying to access the og image. Using Next 14.0.2. Any ideas for potential workarounds? cc @huozhi

loganzartman commented 1 year ago

In dev mode with output: export, I can't load the opengraph-images even for un-parameterized routes. When I try to visit the generated OG image URL, I get:

Error: Page "/opengraph-image/[[...__metadata_id__]]/route" is missing exported function "generateStaticParams()", which is required with "output: export" config.

Maybe the problem is that Next.js is generating this route /opengraph-image/[[...__metadata_id__]]/route, which obviously won't work with output: export unless it has generateStaticParams(). If there were some way to remove the randomized ID param for the opengraph-image and have this be a non-parameterized route, maybe that would work?

Kind of odd that the images are generated in the build output (for non-parameterized routes), and they work in dev mode if I remove output: export.

altano commented 11 months ago

@loganzartman yes I believe opengraph images ALSO don't work with catch-all routes (whether output:exporting or not). Someone else reported that in https://github.com/vercel/next.js/issues/57403 and https://github.com/vercel/next.js/issues/57349.

Opengraph images are pretty broken right now. There are no known workarounds for these issues.

steventhanna commented 11 months ago

I was able to get something working by doing the following:

In my page.js file located: /app/[[...slug]]/page.js

import Logo from '../opengraph-image.png';

export function generateMetadata() {
    return {
        openGraph: {
            images: [Logo.src]
        }
    }
}

I also was not able to get it working just by dropping the file in the tree, after much trial and error I had to manually add this piece.

loganzartman commented 11 months ago

I should point out that you can work around this for dynamic routes too. I created a route handler called [slug]/og.png/route.ts and defined both generateStaticParams and a GET handler that generates an image:

// [slug]/og.png/route.ts

export async function generateStaticParams() {
  // your logic here; this is copied directly from my dynamic route `[slug]/page.tsx`
  return getAllPosts().map(({data: {slug}}) => ({slug}));
}

export async function GET(req: Request, {params}: {params: {slug: string}}) {
  return new ImageResponse(...);
}

example

In output: export mode, this generates image files in the output. Then you can manually link these images as OpenGraph metadata using generateMetadata() in [slug]/page.tsx:

// [slug]/page.tsx

export async function generateStaticParams() {
  // again, duplicated in `[slug]/og.png/route.ts`
  return getAllPosts().map(({data: {slug}}) => ({slug}));
}

export function generateMetadata({params}: Props): Metadata {
  const post = getPostBySlug(params.slug);
  return {
    openGraph: {
      images: `/blog/${params.slug}/og.png`,
    },
  };
}

example

rusakovic commented 9 months ago

@loganzartman thank you for your solution. Did you work with no output: export, but dynamic? To rebuild OG images?

altano commented 8 months ago

@loganzartman neat idea. that worked perfectly for my site: I was able to switch to output: export and my OG images load instantly now.

It's a shame the built-in OG support is busted but this hack will do. Thanks!

suyalcinkaya commented 7 months ago

@loganzartman Thanks for the solution ❤️

artginzburg commented 2 months ago

@loganzartman's solution — https://github.com/vercel/next.js/issues/51147#issuecomment-1842197049 — works as expected. I'd just like to add some details:

tiavina-mika commented 1 month ago

That's strange that there's no mention of this in the official documentation, even more than a year later.