Description
Describe the bug
I'm building a component library using React / TypeScript / Vite. For a few components, I assign a sub-component as a property on another component, when their functionality is tied, e.g. in my case:
<Grid>
<Grid.Cell>...</Grid.Cell>
<Grid.Cell>...</Grid.Cell>
</Grid>
But furthermore, my export process looks something like:
export default function Grid() { ... }
export function Cell() { ... }
Grid.Cell = Cell;
Now, this pattern I've tested and confirmed that it works fine in a normal Vite project. But when running it specifically in the Storybook iframe, it fails with Unexpected token 'default'
.
Because Grid
is the default export, it appears the compiled code includes default
in the exported code because it thinks that default.Cell
is another component:
try {
// @ts-ignore
Grid.displayName = "Grid";
// @ts-ignore
Grid.__docgenInfo = { /* ... JSON details ... */ };
}
catch (__react_docgen_typescript_loader_error) { }
try {
// @ts-ignore
default.Cell.displayName = "default.Cell";
// @ts-ignore
default.Cell.__docgenInfo = { /* ... JSON details ... */ };
}
catch (__react_docgen_typescript_loader_error) { }
try {
// @ts-ignore
Cell.displayName = "Cell";
// @ts-ignore
Cell.__docgenInfo = { /* ... JSON details ... */ };
}
catch (__react_docgen_typescript_loader_error) { }
The default.Cell
in the middle section is a syntax error, not even something try catch
can handle. Thus the whole module throws the unhelpful error: Unexpected token 'default'
, even though VSCode, ESLint, etc. find no errors project-wide.
To Reproduce
It can be reproduced with the following component:
test.tsx
import React from "react"
export default function Test({children}:React.ComponentProps<"div">) {
return (
<div className="test">
{children}
</div>
)
}
export function Sub({children}:React.ComponentProps<"div">) {
return (
<div className="sub">
{children}
</div>
)
}
Test.Sub = Sub;
and the following story:
Test.stories.tsx
import React from "react";
import { Meta, StoryObj } from "@storybook/react";
import Test from "./test";
const meta = {
title: "Test/Error Example",
parameters: {
layout: "centered",
},
} satisfies Meta<typeof Test>
export default meta;
type Story = StoryObj<typeof meta>
export const Example:Story = {
args: {},
render: () => <>
<Test>
<Test.Sub>Hello World</Test.Sub>
</Test>
</>
}
But bear in mind, the storybook server must be started after the code is written.
That is,
- Comment out the
Test.Sub = Sub
line oftest.tsx
- Save, then restart the server
- Then uncomment it and save again
At this point, the storybook works fine. Restart the storybook server again, and it'll crash. I presume this means the code is only compiling during storybook startup time (or maybe I have a poor config?).
System
Output of npx storybook@latest info
Storybook Environment Info:
System:
OS: Windows 10 10.0.19045
CPU: (8) x64 11th Gen Intel(R) Core(TM) i5-1135G7 @ 2.40GHz
Binaries:
Node: 18.18.0 - D:\Apps\nodejs\node.EXE
npm: 9.8.1 - D:\Apps\nodejs\npm.CMD <----- active
pnpm: 8.8.0 - D:\Apps\nodejs\pnpm.CMD
Browsers:
Edge: Spartan (44.19041.3570.0), Chromium (118.0.2088.76)
npmPackages:
@storybook/addon-essentials: ^7.5.2 => 7.5.2
@storybook/addon-interactions: ^7.5.2 => 7.5.2
@storybook/addon-links: ^7.5.2 => 7.5.2
@storybook/addon-onboarding: ^1.0.8 => 1.0.8
@storybook/blocks: ^7.5.2 => 7.5.2
@storybook/react: ^7.5.2 => 7.5.2
@storybook/react-vite: ^7.5.2 => 7.5.2
@storybook/testing-library: ^0.2.2 => 0.2.2
eslint-plugin-storybook: ^0.6.15 => 0.6.15
storybook: ^7.5.2 => 7.5.2
Additional context
This seems like it may actually be a problem with @storybook/builder-vite
or another package. As I couldn't really determine which, I figured I'd start by posting it here. But I will see if I can make any further discoveries on its source.