next.js: Next.js 13 - appDir - Error: Unsupported Server Component type: undefined

Verify canary release

  • I verified that the issue exists in the latest Next.js canary release

Provide environment information

Operating System:
  Platform: win32
  Arch: x64
  Version: Windows 10 Pro for Workstations
Binaries:
  Node: 18.12.0
  npm: N/A
  Yarn: N/A
  pnpm: N/A
Relevant packages:
  next: 13.0.0
  eslint-config-next: N/A
  react: 18.2.0
  react-dom: 18.2.0

What browser are you using? (if relevant)

Chrome 106.0.5249.119 / Firefox Developer Edition 107.0b5

How are you deploying your application? (if relevant)

next start, Vercel (https://test-next-13-appdir.vercel.app/)

Describe the Bug

This issue only appears in dev mode

When I import a client component (the file has "use client" directive) from its exact location (e.g. ./src/components/Foo/Bar.tsx) and then use it in appDir, everything works fine, the component loads and there’s no issue.

But when I reexport it through ./src/components/Foo/index.ts with export * from "./Bar" and then import it in appDir like this: import { Bar } from "@/components", suddenly appDir stops working and then Next shows an issue like this: Error: Unsupported Server Component type: undefined (https://ibb.co/y01RPBv). I tried console.logging the component and what was logged is just undefined. The production build doesn’t have anything of the sort though, everything works just fine.

Thank you 😃

Expected Behavior

Everything should work just fine, the component should display as normal.

Link to reproduction

https://github.com/DuCanhGH/next-13-server-component-undefined

To Reproduce

  • Run pnpm i
  • Run pnpm dev
  • Go to http://localhost:3000 and it should fail to load the page. I find it to be reproducible on both Chrome and Firefox.

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 13
  • Comments: 35 (17 by maintainers)

Commits related to this issue

Most upvoted comments

a workaround for me:

from export * from './my-component'

to export { MyComponent } from './my-component'

This is “solved” if you add the "use client" directive to the top export (src/components/index.ts in this case).

I agree this issue is quite annoying in a monorepo context.

Thanks for the tips everyone, for now I chose to explicitly reexport everything:

packages/some-workspace/src/index.ts

// working
export * from './SomeServerComponent'

// not working
export * from './SomeClientComponent'

// working
export { SomeClientComponent, type SomeClientComponentProps } from './SomeClientComponent'

I recommend it over the client.ts trick because if the issue is fixed someday, there will be no need to update all the imports made within the apps:

apps/some-app/src/some-component.ts

// will not change in the future
import { SomeClientComponent, SomeServerComponent } from '@myrepo/some-workspace'

@cwikio that’s why you need Typescript 💀

@awareness481 it really did, doesn’t seem to be neat, but it works for now 😄

Ok, this bug put a nail in the coffin of my already fragile sanity after 10 years of js/node ecosystem.

So I started with this.

./src/foundations/typography/h1.tsx
ReactServerComponentsError:

You're importing a component that needs useRef. It only works in a Client Component but none of its parents are marked with "use client", so they're Server Components by default.

Ok, a seemingly understandable error, at least with some steps on how I should act upon it.

So adding 'use client' directive to it. (whoever thought of using this syntax is a fucking degenerate by the way)

Fine, now, how the hell is this error:

Error: Unsupported Server Component type: undefined with a callstack direct from hell, like

Call Stack
attemptResolveElement
node_modules/.pnpm/next@13.2.4_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/compiled/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.development.js (1491:8)
attemptResolveElement
node_modules/.pnpm/next@13.2.4_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/compiled/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.development.js (1992:20)
resolveModelToJSON
node_modules/.pnpm/next@13.2.4_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/compiled/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.development.js (1224:13)
stringify
<anonymous>
stringify
node_modules/.pnpm/next@13.2.4_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/compiled/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.development.js (192:13)
processModelChunk
node_modules/.pnpm/next@13.2.4_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/compiled/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.development.js (2271:25)
retryTask
node_modules/.pnpm/next@13.2.4_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/compiled/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.development.js (2318:6)
performWork
node_modules/.pnpm/next@13.2.4_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/compiled/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.development.js (1500:13)
listOnTimeout
node:internal/timers (564:17)
process.processTimers
node:internal/timers (507:7)

Is SOMEWHAT helpful or indicative of the fact that to make this work, I just have to add the use client instead of the component itself, to the index.ts where I re-export it.

I’m fucking done with software development.

Will become a farmer. Peace!

The best way I found to work around this issue is exporting all components separately and creating a compound component and exporting that as well. Then use separate exports in the the RSC and the compound in RCC.

Example:

const Popover = Object.assign(PopoverRoot, {
  Content: PopoverContent,
  Trigger: PopoverTrigger,
});

export default Popover;
export { PopoverRoot, PopoverTrigger, PopoverContent };

Same issue here with Next 13.1 and Typescript. I’ve found three workarounds for this:

  1. use default export MyComponent
  2. don’t reexport the component through an index: export * from './MyComponent'
  3. if you need the index add 'use client' in that index file:
'use client'

export * from './MyComponent'

Adding "use client" to each index.ts is not the ideal solution, because there may be components that are not client components, which can cause new problems when I use non-client components, such as when I use a server component and pass a function into the component

Impressive, thanks @shuding ! @akomm let’s wait for the next canary build to see if it’s working I guess?

components/Foo/index.ts

export * as Foo from "./foo.ts"

components/Foo/foo.ts

export * from "./Bar.ts"

This allows good “navigate to” and refactoring in IDEs and also better tree shaking as it purely uses ES style exports and not building “objects”. Imports like "import {Foo} from “~/app.src/components/foo” <- import autocomplete exists for the namespace. Then usage “Foo.Bar”.

Now If the Foo module has both client and RSC components, putting a “use client” at the top is a bad idea. But also working with “client.ts” makes things more complicated and cluttered than needed.

Sometimes, you also need the method mentioned by @feledori. For example when you have some root component and composition components to be used within it.

I’m seeing the same error when trying to import a client compound component in a server component, eg:

import List from './List';

export default function Home() {
  return (
    <List>
      <List.Item>Hello</List.Item>
    </List>
  );
}

Where List is a client component that exposes another component on the List.Item property:

'use client';
import React from 'react';

function List({ children }: { children: React.ReactNode }) {
  return <ul>{children}</ul>;
}

function ListItem({ children }: { children: React.ReactNode }) {
  return <li>{children}</li>;
}

List.Item = ListItem;
export default List;

Here’s a link to a reproduction: https://stackblitz.com/edit/vercel-next-js-jbt5nq?file=app/page.tsx

Thanks I will keep that in mind and proceed to do so

@richardHaggioGwati I’m having no problem using React’s Context API in appDir without adding a use client directive to the main layout.tsx. You just have to isolate the provider into a .tsx / .jsx file, add a use client to the top of that file, import the provider into the main layout.tsx and wrap your app with it. You can only use useContext within client components, however.

@awareness481 it really did, doesn’t seem to be neat, but it works for now 😄

Thanks for the advice. I’m doing the same thing now

@coderlfm you can add a client.ts or a client folder with a index.ts and put all the files that are Client Components in it just like how I currently do it. I don’t think this issue will be fixed anyway.

@HARAJLI98 I haven’t found a better solution as well, so for now I’m currently having a ./client.ts for components that use “use client”, and I plan to merge that file into ./index.ts when this gets resolved.

Any updates on this? I have a monorepo structure. When using barrel index.ts files in a library/package to re-export components, I get the same error.

Having to set “use client” on every index.ts file is not ideal.