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

[Bug]: "async/await is not yet supported in Client Components, only Server Components." - since 8.0.0--alpha.13 #25891

Open
sedlukha opened this issue Feb 2, 2024 · 8 comments

Comments

@sedlukha
Copy link

sedlukha commented Feb 2, 2024

Describe the bug

Since 8.0.0--alpha.13 there is an error in console.
The problem still exists in the latest 8.0.0--beta.0 version.

Error message:

Warning: async/await is not yet supported in Client Components, only Server Components. This error is often caused by accidentally adding 'use client' to a module that was originally written for the server.

image

To Reproduce

Try to update storybook version for repo from storybook's official article

System

System:
    OS: macOS 14.1.1
    CPU: (8) arm64 Apple M1 Pro
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 18.18.2 - ~/.nvm/versions/node/v18.18.2/bin/node
    Yarn: 1.22.17 - /opt/homebrew/bin/yarn
    npm: 9.8.1 - ~/.nvm/versions/node/v18.18.2/bin/npm
    pnpm: 8.5.0 - ~/Library/pnpm/pnpm <----- active
  Browsers:
    Chrome: 121.0.6167.139
    Safari: 17.1
  npmPackages:
    @storybook/addon-essentials: 8.0.0-alpha.13 => 8.0.0-alpha.13 
    @storybook/addon-interactions: 8.0.0-alpha.13 => 8.0.0-alpha.13 
    @storybook/addon-links: 8.0.0-alpha.13 => 8.0.0-alpha.13 
    @storybook/blocks: 8.0.0-alpha.13 => 8.0.0-alpha.13 
    @storybook/nextjs: 8.0.0-alpha.13 => 8.0.0-alpha.13 
    @storybook/react: 8.0.0-alpha.13 => 8.0.0-alpha.13 
    @storybook/test: 8.0.0-alpha.13 => 8.0.0-alpha.13 
    msw-storybook-addon: 2.0.0--canary.122.06f0c92.0 => 2.0.0--canary.122.06f0c92.0 
    storybook: 8.0.0-alpha.13 => 8.0.0-alpha.13

Additional context

No response

@valentinpalkovic
Copy link
Contributor

cc @shilman Do you have any context why this throws?

@shilman
Copy link
Member

shilman commented Feb 3, 2024

@valentinpalkovic no idea. i just bisected and it looks like it broke in https://github.com/storybookjs/storybook/releases/tag/v8.0.0-alpha.13

So I guess I had only tested it with Babel before, due to that bug, and then SWC does something differently which causes this error. I would note, though, that although there is an error in the console, it appears that everything renders correctly.

@shilman shilman added this to the 8.0-RC milestone Feb 3, 2024
@vanessayuenn vanessayuenn modified the milestones: 8.0-RC, 8.0-Stable Feb 12, 2024
@mdhmaiti
Copy link

mdhmaiti commented Feb 13, 2024

Maybe you are using the export default async await function in the ' use client', Next js does not support that. You can separate the component and use the async await or use like this instead - export default normal function and then inside create another function and use the async await . Maybe this will work

@SalahAdDin
Copy link

SalahAdDin commented Feb 28, 2024

I'm having the same issue with a lower version and no any of my components use async/await:

import React from "react";
import { Metadata, ResolvingMetadata } from "next";

import { useFormatter, useNow, useTranslations } from "next-intl";

import { RichTextRender } from "@/app/_components/richtext/RichTextRender/RichTextRender";
import { Avatar } from "@/app/_components/visuals/Avatar/Avatar";
import { Chip } from "@/app/_components/visuals/Chip/Chip";
import { NEXT_PUBLIC_DOMAIN } from "@/common/constants/env.data";
import { DEFAULT_HEIGHT, DEFAULT_WIDTH } from "@/common/constants/media.data";
import { request } from "@/common/service/api.service";
import { isUploadImageNode } from "@/common/utils/richtext.utils";
import { Separator } from "@radix-ui/react-separator";

import { ContinueReadingArticleCard } from "./_components/ContinueReadingArticleCard/ContinueReadingArticleCard";
import { Hero } from "./_components/Hero/Hero";
import { RelatedArticleCard } from "./_components/RelatedArticleCard/RelatedArticleCard";
import { TArticle } from "./article.model";
import { isCaptionedImage } from "./article.utils";

type NewsDetailPageProps = {
  /** URL's params */
  params: {
    /** article's category's slug */
    category: string;
    /** article's slug */
    article: string;
  };
};

export async function generatedStaticParams() {
  const { data: news } = await request<Array<TArticle>>("news", ["news"]);

  return news.map((item) => ({
    category: item.category,
    slug: item.slug,
  }));
}

export async function generateMetadata(
  { params }: NewsDetailPageProps,
  parent: ResolvingMetadata
): Promise<Metadata> {
  const { category, article } = params;

  console.log("Params 1:", params);

  const { data } = await request<TArticle>(`news/${category}/${article}`);

  const news = data;

  const previousImages = (await parent).openGraph?.images ?? [];

  const heroImage = isCaptionedImage(news.hero)
    ? [
        {
          url: news.hero.url,
          alt: news.hero.alt,
          height: news.hero.height ?? DEFAULT_HEIGHT,
          width: news.hero.width ?? DEFAULT_WIDTH,
        },
      ]
    : [];

  const contentImages = news.content.root.children
    .filter(isUploadImageNode)
    .map(({ value: { url, alt, width, height } }) => ({
      url,
      alt: alt ?? news.title,
      height: height ?? DEFAULT_HEIGHT,
      width: width ?? DEFAULT_WIDTH,
    }));

  return {
    title: news.title,
    description: news.introduction,
    authors: news.author?.map((author) => ({
      name: author.fullName,
      url: `${NEXT_PUBLIC_DOMAIN}${author.slug}`,
    })),
    openGraph: {
      url: `${NEXT_PUBLIC_DOMAIN}${news.slug}`,
      images: [...previousImages, ...heroImage, ...contentImages],
    },
  };
}

/**
 * Detailed News page.
 * @param params
 * @returns
 */
const News = async ({ params }: NewsDetailPageProps) => {
  const { category, article } = params;

  console.log("Params 2: ", params);

  const format = useFormatter();
  const t = useTranslations();
  const now = useNow({
    updateInterval: 1000 * 10,
  });

  const { data: news } = await request<TArticle>(`news/${category}/${article}`);

  return (
    <article className="container my-20">
...
    </article>
  );
};

export default News;
Storybook Environment Info:

  System:
    OS: Linux 6.1 Manjaro Linux
    CPU: (16) x64 AMD Ryzen 9 5900HX with Radeon Graphics
    Shell: 5.2.26 - /bin/bash
  Binaries:
    Node: 20.11.0 - ~/.nvm/versions/node/v20.11.0/bin/node
    Yarn: 1.22.21 - /usr/bin/yarn
    npm: 10.2.4 - ~/.nvm/versions/node/v20.11.0/bin/npm
    pnpm: 8.15.4 - /usr/bin/pnpm <----- active
  npmPackages:
    @storybook/addon-a11y: 7.6.17 => 7.6.17 
    @storybook/addon-essentials: 7.6.17 => 7.6.17 
    @storybook/addon-interactions: 7.6.17 => 7.6.17 
    @storybook/addon-links: 7.6.17 => 7.6.17 
    @storybook/addon-onboarding: 1.0.11 => 1.0.11 
    @storybook/addon-storysource: 7.6.17 => 7.6.17 
    @storybook/addon-themes: 7.6.17 => 7.6.17 
    @storybook/blocks: 7.6.17 => 7.6.17 
    @storybook/nextjs: 7.6.17 => 7.6.17 
    @storybook/react: 7.6.17 => 7.6.17 
    @storybook/test: 8.0.0-alpha.16 => 8.0.0-alpha.16 
    @storybook/theming: 7.6.17 => 7.6.17 
    eslint-plugin-storybook: 0.8.0 => 0.8.0 
    msw-storybook-addon: 2.0.0-beta.1 => 2.0.0-beta.1 
    storybook: 7.6.17 => 7.6.17 
    storybook-addon-pseudo-states: 2.1.2 => 2.1.2 
    storybook-addon-rtl: 1.0.0 => 1.0.0 

@valentinpalkovic
Copy link
Contributor

valentinpalkovic commented Mar 4, 2024

Thanks for reporting the issue!

We can't fix this quickly.

Let's try to understand what we are doing to support rendering of async/await components in the browser:

First, the react version, defined in your package.json, is a kind of alibi package. Next.js and Storybook are doing some aliasing in the background to alias the React version to a precompiled canary version of React, which Next.js ships. Therefore, although you likely have React 18.2 defined in your package.json, the truth is that you are using a prerelease version under the hood—some canary 18.3 version of React.

The problem with this is that for over one year, Next.js has used undocumented canary features to build up on, like the React Server Components/Async API.

React Server Components and async components are meant to be rendered on the server. Storybook tries to render async components in the browser by wrapping the component by a React.Suspense boundary. And this kind of trick works. As of now, this is different from the wished behaviour though. In the future, it might be possible to render async components without a warning/error in the browser, but I guess we have to accept this error message for now.

Strangely, this error appears when Storybook uses SWC to compile the code. In babel mode, this error isn't triggered. This is even worse to investigate because Storybook reuses a custom precompiled version of SWC, which Next.js provides. It's not easy to hook into this custom SWC built, since the source code is entirely written in Rust and our Rust expertise at Storybook is limited. Even if we could figure it out, because of our limited resources, Storybook wouldn't provide a custom precompiled SWC compiler to fix this issue. We will always reuse whatever Next.js ships.

At some point, we might follow a different approach to render Server-side components on some server and then ship it to the browser to show it in Storybook. We are investigating different approaches currently, and we will let you know as soon as we have something to ship to the Storybook community.

@vanessayuenn vanessayuenn removed this from the 8.0-Stable milestone Mar 4, 2024
@naveenkumarkosari
Copy link

can anyone explain for the reason behind having async components in only server components but not client components

@SalahAdDin
Copy link

@naveenkumarkosari It is something related to NextJS and how it handles the server components.

@valentinpalkovic @shilman OK, it seems the components are not really handled as server components but just rendered wrappers by a Suspend.

Here is a bug related to next-intl:
image
We have to use getFormatter when we are working with serverside components.

The only way it is giving such an error is because it is not being handled as a server-side component; it was not failing before cause we were using hooks.

@SalahAdDin
Copy link

And I got the same issue from another component using next-intl:
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants