nrwl / nx

Smart Monorepos · Fast CI
https://nx.dev
MIT License
23.74k stars 2.37k forks source link

react-native:storybook-configuration does not work with TS or React Native? #28802

Open fwielstra opened 2 weeks ago

fwielstra commented 2 weeks ago

UPDATE

I've started a new project from scratch with a similar setup using the "React Native" recipe:

npx create-nx-workspace nx-react-native --preset=react-native --appName=storybookdemo
npx nx g @nx/react-native:lib libs/shared-ui-layout

Added a Button component, used it in the app, all good. Then adding Storybook using the @nx/storybook documentation:

nx add @nx/storybook
nx g @nx/react-native:storybook-configuration shared-ui-layout

Then starting Storybook using

nx run shared-ui-layout:storybook

This leads to the following compiler error:

✘ [ERROR] Unexpected "typeof"

    ../../node_modules/react-native/index.js:14:7:
      14 │ import typeof ActionSheetIOS from './Libraries/ActionSheetIOS/ActionSheetIOS';

According to this issue, this should be fixable by adding an alias in the resolve section of the Vite config, but this is all set up by the generators already. I'm stuck at this point now. I've uploaded the whole project here: https://github.com/fwielstra/nx-react-native-storybook-bug, if anyone can point out anything I've missed, that would be appreciated.


Current Behavior

I have an existing React Native monorepo with three apps and a dozen libraries. I've built my own 'component demo' app because when we started, Storybook didn't work well with React Native yet, however this should have improved by now.

I've followed the instructions on the @nx/storybook page:

nx add @nx/storybook
# generate Storybook configuration for `components` library
nx g @nx/react-native:storybook-configuration components

The wizard and output:

 NX  Generating @nx/react-native:storybook-configuration

✔ Do you want to set up Storybook interaction tests? (Y/n) · true
✔ Automatically generate *.stories.ts files for components declared in this project? (Y/n) · true
✔ Configure a static file server for the storybook instance? (Y/n) · true
Please run 'nx run @nx/react:storybook-configuration components' instead.
Fetching prettier...
UPDATE package.json
CREATE .prettierrc
CREATE .prettierignore
CREATE libs/components/.storybook/main.ts
CREATE libs/components/.storybook/preview.ts
CREATE libs/components/tsconfig.storybook.json
UPDATE libs/components/tsconfig.lib.json
UPDATE libs/components/tsconfig.json
UPDATE libs/components/.eslintrc.json
UPDATE nx.json
UPDATE libs/components/project.json

[omitted irrellevant npm output]

The first signal something is up is the line "Please run 'nx run @nx/react:storybook-configuration components' instead.". It doesn't generate configuration that works with React Native components, but does something with vite (which is otherwise unused in our application) and vanilla react instead, while I expect that it should generate a Metro configuration and the like.

Anyway, then I started Storybook using

nx run components:storybook

So far so good; it says No story files found for the specified pattern: libs/components/src/lib/**/*.@(mdx|stories.@(js|jsx|ts|tsx)) but that's alright because I don't have a lib folder under src, it's all straight under src. I updated the config accordingly:

stories: ['../src/**/*.@(mdx|stories.@(js|jsx|ts|tsx))'],

and restarted Storybook:

nx run components:storybook

I had Storybook generate a story for one of my components:

import type { Meta, StoryObj } from '@storybook/react';

import { PrimaryButton } from './PrimaryButton';

const meta = {
  component: PrimaryButton,
} satisfies Meta<typeof PrimaryButton>;

export default meta;

type Story = StoryObj<typeof meta>;

// this has an error in my editor:
/*  Property 'args' is missing in type '{}' but required in type '{ args: { children: string; accessibilityHint?: string | undefined; onPress: (e: GestureResponderEvent) => void; loading?: boolean | undefined; disabled?: boolean | undefined; ... 6 more ...; disableSkeleton?: boolean | undefined; }; }'.ts(2322)
index.d.ts(458, 5): 'args' is declared here.
*/
export const Default: Story = {};

Then I restarted / reloaded Storybook, and this is where things fall apart:

In the Storybook web interface itself:

TypeError: importers[path] is not a function
    at un.importFn (http://localhost:4400/@id/__x00__/virtual:/@storybook/builder-vite/storybook-stories.js:6:31)
    at un.loadCSFFileByStoryId (http://localhost:4400/sb-preview/runtime.js:5577:89)
    at un.loadStory (http://localhost:4400/sb-preview/runtime.js:5607:24)
    at http://localhost:4400/sb-preview/runtime.js:5879:37
    at mn.runPhase (http://localhost:4400/sb-preview/runtime.js:5872:100)
    at mn.prepare (http://localhost:4400/sb-preview/runtime.js:5878:20)
    at Un.renderSelection (http://localhost:4400/sb-preview/runtime.js:6750:15)
    at async Un.onStoriesChanged (http://localhost:4400/sb-preview/runtime.js:6674:99)
    at async Un.onStoryIndexChanged (http://localhost:4400/sb-preview/runtime.js:6172:9)

In the terminal:

15:45:43 [vite] Internal server error: /Users/[my project folder]/libs/components/src/Buttons/PrimaryButton.stories.tsx: Unexpected token, expected "from" (1:12)

> 1 | import type { Meta, StoryObj } from '@storybook/react';
    |             ^
  2 |
  3 | import { PrimaryButton } from './PrimaryButton';

One possible solution suggested by the internet is to add "@babel/preset-typescript" to .babelrc (in our codebase we still use babel.config.json), but this does not seem to get picked up, nor does it appear anywhere else in our exclusively Typescript project. For completeness, this is the babel.config.json from the components library:

{
  "presets": [
    [
      "@nx/react/babel",
      {
        "runtime": "automatic",
        "useBuiltIns": "usage"
      }
    ]
  ],
  "plugins": [["react-native-reanimated/plugin"]],
  "env": {
    "test": {
      "plugins": [
        [
          "react-native-reanimated/plugin",
          {
            "relativeSourceLocation": true
          }
        ]
      ],
      "presets": ["module:@react-native/babel-preset"]
    }
  }
}

I hope that it's something simple or something I missed from the (incredibly straightforward) instructions. I've followed similar instructions from 3rd party websites as well.

One other thing I can try is to generate an Expo app using nx g @nx/expo:app apps/storybook, then try and apply the configuration changes from the example React Native / Storybook template, but I'd prefer if things like this work out of the box.

Expected Behavior

Adding @nx/storybook and running nx g @nx/react-native:storybook-configuration components should generate a working and running Storybook instance for an existing React Native component library.

GitHub Repo

No response

Steps to Reproduce

  1. Have an existing React Native based NX repo with apps and a components library, generated around two and a half years ago
  2. Add Storybook according to the instructions on https://nx.dev/nx-api/storybook, specifically the react native variant under the "Generating Storybook Configuration" heading
  3. Update libs/components/.storybook/main.ts, remove the /lib path part from the stories field
  4. Run Storybook using nx run components:storybook
  5. Use the '+'

Nx Report

NX Report complete - copy this into the issue template

Node : 18.20.4 OS : darwin-arm64 Native Target : aarch64-macos npm : 10.7.0

nx (global) : 20.0.0 nx : 20.0.8 @nx/js : 20.0.8 @nx/jest : 20.0.8 @nx/eslint : 20.0.8 @nx/workspace : 20.0.8 @nx/cypress : 20.0.8 @nx/devkit : 20.0.8 @nx/eslint-plugin : 20.0.8 @nx/react : 20.0.8 @nx/react-native : 20.0.8 @nx/storybook : 20.0.8 @nx/vite : 20.0.8 @nx/web : 20.0.8 typescript : 5.5.2

Community plugins: @diogovcs/stryker-mutator : 0.2.6

Failure Logs

15:45:43 [vite] Internal server error: /Users/[my project folder]/libs/components/src/Buttons/PrimaryButton.stories.tsx: Unexpected token, expected "from" (1:12)

1 | import type { Meta, StoryObj } from '@storybook/react'; | ^ 2 | 3 | import { PrimaryButton } from './PrimaryButton';

Package Manager Version

No response

Operating System

Additional Information

I know this is a lot of information to parse and yet probably not enough information, and I don't have a reproduction yet without starting a new project from scratch emulating the circumstances of the large project I'm working in right now. It's possible that if I start from scratch, everything will work out of the box, but I can't be sure. I just hope there's something obvious I missed.

jnbt commented 2 days ago

I experience the same situation with nx and "@nx/storybook (20.1.2) on react-native. My current guess is that some "unification" of react / react-native and vite leads to an incorrect state of the project.

Especially on a fresh project, which is setup like @fwielstra described, the storyboard integration via nx doesn't work on React Native.