Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using next-yak converts server components to client components #112

Open
inuwan opened this issue Jul 8, 2024 · 11 comments
Open

Using next-yak converts server components to client components #112

inuwan opened this issue Jul 8, 2024 · 11 comments
Labels
bug Something isn't working

Comments

@inuwan
Copy link

inuwan commented Jul 8, 2024

Using a next-yak styled component with a server component (page.tsx) that defines the Next.js special function generateMetadata. I get the following error:

You are attempting to export "generateMetadata" from a component marked with "use client", which is disallowed. Either remove the export, or the "use client" directive. Read more: https:// │ nextjs.org/docs/getting-started/react-essentials#the-use-client-directive

If I remove the next-yak styled component, the error is eliminated.

@jantimon
Copy link
Collaborator

jantimon commented Jul 9, 2024

hi @inuwan

thanks for reporting the issue

could you please set up a minimal reproduction example?

@jantimon jantimon added the bug Something isn't working label Jul 9, 2024
@jantimon
Copy link
Collaborator

jantimon commented Jul 9, 2024

it looks like there is a bug in next.js and or css-loader but I am still investigating it

the error NextRscErrClientMetadataExport is thrown by some rust code which shouldn't mess with the css at all 🤷‍♂️

https://github.com/vercel/next.js/blob/8f93430080f1c18b3f25a0b9c842063f6dc9c9e8/packages/next-swc/crates/next-custom-transforms/src/transforms/react_server_components.rs#L738-L749

error definition:

https://github.com/vercel/next.js/blob/8f93430080f1c18b3f25a0b9c842063f6dc9c9e8/packages/next-swc/crates/next-custom-transforms/src/transforms/react_server_components.rs#L281-L283

@jantimon
Copy link
Collaborator

jantimon commented Jul 9, 2024

Created a reproduction example here:

https://github.com/jantimon/reproduction-next-server-component-css-error

@jantimon
Copy link
Collaborator

jantimon commented Jul 9, 2024

Reported at next.js: vercel/next.js#67591

@jantimon
Copy link
Collaborator

jantimon commented Jul 9, 2024

As a intermediate solution you could split the code - everything works as long as metadata and yak styled components are not used within the same file

@Mad-Kat
Copy link
Collaborator

Mad-Kat commented Jul 9, 2024

I think we should create another example with this case in our repo. What do you think @jantimon ?

@jantimon
Copy link
Collaborator

@Mad-Kat - yes we should definitely improve our examples (a more realistic one and a very basic one) 👍

Btw I found the reason for this bug.

During processing Next.js identifies import __styleYak from "./page.yak.module.css!=!./page?./page.yak.module.css as a page and therefore creates an entry out of it:

vercel/next.js#67591 (comment)

@laem
Copy link

laem commented Nov 28, 2024

As a intermediate solution you could split the code - everything works as long as metadata and yak styled components are not used within the same file

I tried this, it worked at first. But the navigating on the page triggered the error again...

@jantimon
Copy link
Collaborator

jantimon commented Nov 28, 2024

There is an open bug in next.js but I believe nobody is working on it

vercel/next.js#67591

can you please show us how you are splitting it?
maybe we can help you to fix it

@jantimon
Copy link
Collaborator

jantimon commented Jan 7, 2025

This bug is tricky but we have not forgotten about it 😄
Luca and me did another session and can now explain what happens behind the scenes. The error message mentions a "use client" directive conflict, even though no such directive is explicitly present in the code. Here's what we found during our investigation:

How next-yak CSS Extraction Works

First, let's understand how next-yak normally processes styled components. When you write:

const Button = styled.button`
  background-color: #007bff;
  color: #fff;
`;

The next-yak SWC plugin transforms this into two parts:

  1. A special CSS import using webpack's resource query syntax:
    import __styleYak from "./input.yak.module.css!=!./input?./input.yak.module.css";
  2. A transformed component that references the imported styles:
    const Button = styled.button(__styleYak.Button);

This !=! syntax tells webpack to handle the import as a CSS module, similar to how Next.js handles regular CSS modules internally.

The Compilation Layer Challenge

The issue emerges due to how Next.js App Router handles compilations. There are three parallel webpack compilations happening:

  1. RSC (React Server Components) compilation
  2. SSR (Server-Side Rendering) compilation
  3. Browser/Client compilation

During development, Next.js moves CSS processing from the RSC layer to the browser layer for better developer experience (enabling features like hot reload and sourcemaps). This is where our bug surfaces:

  1. When an RSC file contains both generateMetadata and a next-yak styled component, the CSS gets moved to the browser compilation layer
  2. The file gets recompiled in the browser layer through the standard Next.js SWC pipeline
  3. Since generateMetadata is a server-only API, Next.js's RSC boundary checks (implemented in next-custom-transforms/src/transforms/react_server_components.rs) detect this as a violation

This creates a paradox where:

  • The CSS needs to be processed in the browser layer
  • But the presence of generateMetadata makes Next.js treat this as an invalid client/server boundary crossing

The error message about "use client" is somewhat misleading - it's not that a directive is being added, but rather that Next.js detects server-only code attempting to run in a client context.

Diagram of the Issue

flowchart TB
    source["page.tsx
    (generateMetadata and styled-components)"]
    
    subgraph "RSC Layer"
        rsc_process["yak-swc processes page.tsx
        and adds a CSS import with !=!"]
    end
    
    subgraph "Browser Layer"
        css_file["page.tsx (as CSS)"]
        css_loader["yak css-loader"]
        swc_loader["swc-loader with yak-swc"]
        error["❌ Conflict:
        Server-only API detected
        in browser context"]
    end
    
    source --> rsc_process
    rsc_process --"The CSS import can only be
    processed in the browser layer"--> css_file
    css_file --> css_loader
    css_loader --"uses swc to compile the tsx to css code"--> swc_loader
    swc_loader --> error
    
    style source stroke-width:2px
    style error stroke-width:2px,stroke-dasharray: 5 5
Loading

@jantimon
Copy link
Collaborator

blocked by vercel/next.js#74821

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Development

No branches or pull requests

4 participants