storybookjs / addon-react-native-web

Build react-native-web projects in Storybook for React
MIT License
79 stars 21 forks source link

Error in in ../../../node_modules/ #86

Open simonwalker-celadin opened 7 months ago

simonwalker-celadin commented 7 months ago

Running @storybook/addon-react-native-web via "storybook:web": "storybook dev -p 6006 -c .storybook-web" and "build-storybook": "storybook --debug-webpack build -c .storybook-web". Getting errors from building files in node_modules. See attached screen shot as an example.

.storybook/index.tsx

import { view } from "./storybook.requires";
import AsyncStorage from "@react-native-async-storage/async-storage";

const StorybookUIRoot = view.getStorybookUI({
  storage: {
    getItem: AsyncStorage.getItem,
    setItem: AsyncStorage.setItem,
  },
  enableWebsockets: true,
  host: "localhost",
  port: 7007,
});

export default StorybookUIRoot;

.storybook-web/main.ts

import type { StorybookConfig } from "@storybook/react-webpack5";

type ServerStorybookConfig = StorybookConfig & {
  reactNativeServerOptions: { host: string; port: number };
};

const main: ServerStorybookConfig = {
  stories: [
    "../assemblies/**/*.stories.?(ts|tsx|js|jsx)",
    "../components/**/*.stories.?(ts|tsx|js|jsx)",
  ],
  addons: [
    "@storybook/addon-actions",
    "@storybook/addon-controls",
    "@storybook/addon-essentials",
    "@storybook/addon-interactions",
    "@storybook/addon-react-native-web",
    "@storybook/addon-react-native-server",
  ],
  framework: {
    name: "@storybook/react-webpack5",
    options: {},
  },

  reactNativeServerOptions: {
    // for android you should use your local ip address here
    host: "localhost",
    port: 7007,
  },

  docs: {
    autodocs: "tag",
  },
};

export default main;

.storybook-web/preview.tsx

import type { Preview } from "@storybook/react";

const preview: Preview = {
  decorators: [],
  parameters: {
    actions: { argTypesRegex: "^on[A-Z].*" },
    controls: {
      matchers: {
        color: /(background|color)$/i,
        date: /Date$/,
      },
    },
  },
};
export default preview;
Screenshot 2024-02-12 at 10 37 19
dannyhw commented 7 months ago

This issue is for http://github.com/storybookjs/addon-react-native-web

@simonwalker-celadin Also please explain how to reproduce this issue. For example what packages should I add and what code. Alternatively provide a minimal reproduction public repository.

simonwalker-celadin commented 7 months ago

Our Storybook implementation is part of an expo-50 monorepro. Our Storybook package.json is:

{
  "name": "@celadin/attendee-app-storybook",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "start": "sb-rn-get-stories && expo start",
    "android": "sb-rn-get-stories && expo start --android",
    "ios": "sb-rn-get-stories && expo start --ios",
    "web": "sb-rn-get-stories && expo start --web",
    "storybook-generate": "sb-rn-get-stories --config-path .ondevice",
    "storybook-watch": "sb-rn-watcher",
    "storybook:web": "storybook dev -p 6006 -c .storybook-web",
    "build-storybook": "storybook --debug-webpack build -c .storybook-web"
  },
  "dependencies": {
    "@celadin/attendee-app-core": "*",
    "@expo/vector-icons": "^14.0.0",
    "@expo/webpack-config": "^19.0.0",
    "@reduxjs/toolkit": "^2.0.1",
    "expo": "^50.0.0",
    "expo-constants": "^15.0.0",
    "expo-font": "~11.10.0",
    "expo-splash-screen": "~0.26.4",
    "react-dom": "18.2.0",
    "react-native-web": "~0.19.6",
    "react-redux": "^9.0.4"
  },
  "devDependencies": {
    "@babel/core": "^7.20.0",
    "@babel/preset-env": "^7.20.0",
    "@babel/runtime": "^7.20.0",
    "@react-native-async-storage/async-storage": "1.18.2",
    "@react-native-community/datetimepicker": "7.6.1",
    "@react-native-community/slider": "4.4.2",
    "@storybook/addon-actions": "^7.6.10",
    "@storybook/addon-controls": "^7.6.10",
    "@storybook/addon-essentials": "^7.6.10",
    "@storybook/addon-interactions": "^7.6.10",
    "@storybook/addon-links": "^7.6.10",
    "@storybook/addon-ondevice-actions": "^7.6.11",
    "@storybook/addon-ondevice-backgrounds": "^7.6.11",
    "@storybook/addon-ondevice-controls": "^7.6.11",
    "@storybook/addon-ondevice-notes": "^7.6.11",
    "@storybook/react": "^7.6.10",
    "@storybook/react-native": "^7.6.11",
    "@storybook/addon-react-native-web": "^0.0.23",
    "@storybook/react-webpack5": "^7.6.12",
    "@storybook/addon-react-native-server": "^0.0.5",
    "storybook": "^7.6.12",
    "babel-preset-expo": "^10.0.0",
    "react-native-safe-area-context": "^4.6.3",
    "babel-plugin-react-native-web": "^0.19.10",
    "@expo/metro-runtime": "^3.1.2"
  },
  "private": true,
  "overrides": {
    "react-refresh": "~0.14.0"
  }
}

the package.json in our packages/xxx/core is:

{
  "name": "@celadin/attendee-app-core",
  "version": "0.0.0",
  "private": true,
  "main": "src/index.ts",
  "devDependencies": {
    "@react-native/typescript-config": "^0.73.1"
  },
  "dependencies": {
    "@react-navigation/material-top-tabs": "^6.6.5",
    "deepmerge": "^4.3.1",
    "expo-constants": "^15.4.5",
    "expo-linear-gradient": "^12.7.0",
    "expo-linking": "^6.2.2",
    "expo-router": "^3.4.6",
    "expo-secure-store": "^12.8.1",
    "expo-status-bar": "^1.11.1",
    "react": "18.2.0",
    "react-native": "^0.73.0",
    "react-native-pager-view": "^6.2.3",
    "react-native-render-html": "^6.3.4",
    "react-native-safe-area-context": "^4.8.2",
    "react-native-screens": "^3.29.0",
    "react-native-svg": "^14.1.0",
    "react-native-tab-view": "^3.5.2",
    "type-fest": "^4.10.1"
  }
}

our babel.config.js is:

module.exports = function (api) {
    api.cache(true);
    return {
      presets: ['babel-preset-expo': 'babel-plugin-react-native-web'],
    };
  };

our metro.config.js is:

const path = require('path');
const { getDefaultConfig } = require('expo/metro-config');

const { generate } = require("@storybook/react-native/scripts/generate");

generate({
  configPath: path.resolve(__dirname, "./.storybook"),
});

// Find the project and workspace directories
const projectRoot = __dirname;
// This can be replaced with `find-yarn-workspace-root`
const workspaceRoot = path.resolve(projectRoot, '../..');

const config = getDefaultConfig(projectRoot);

config.transformer.unstable_allowRequireContext = true;

config.resolver.sourceExts.push('mjs');

// 1. Watch all files within the monorepo
config.watchFolders = [
  workspaceRoot,
  // path.resolve(projectRoot,  '../../', 'attendee-app/core'),
];
console.log('config.watchFolders', config.watchFolders);
// 2. Let Metro know where to resolve packages and in what order

config.resolver.nodeModulesPaths = [
  path.resolve(projectRoot, 'node_modules'),

];

// 3. Force Metro to resolve (sub)dependencies only from the `nodeModulesPaths`
// config.resolver.disableHierarchicalLookup = true;

module.exports = config;
dannyhw commented 7 months ago

@simonwalker-celadin in your error screenshot it says expected fromDir but the image is cut off, where does that fromDir come from?

dannyhw commented 7 months ago

My guess is that you might need to transpile some libraries (using modulesToTranspile) and make sure that your libraries are web compatible. In the case that they are not you can try the deviceOnly parameter from the addon-react-native-server package.

simonadenic commented 7 months ago

Im getting a similar error, by only installing this addon and applying it into the storybook configuration (with no loaded react native stories yet). Here's some examples:

Screenshot 2024-02-12 at 19 47 11

When I comment out the line here (getAbsolutePath('@storybook/addon-react-native-web')), everything works as expected:

Screenshot 2024-02-12 at 19 47 57
dannyhw commented 7 months ago

what if you don't wrap it in getAbsolutePath?

dannyhw commented 7 months ago

@simonadenic seem like you are missing an alias configuration too @/Button for example. You should add those aliases to your storybook config. For example with

        modulesToAlias: {
          '@/Button/types': '../path/to/button/types',
        },

see https://github.com/storybookjs/addon-react-native-web/#aliasing-react-native-web-libraries

If you can provide a reproduction I can look deeper at your problem

dannyhw commented 7 months ago

I think the original issue is potentially related to using expo router outside of its Provider but its hard to say without more of the code or a minimal repro

simonadenic commented 7 months ago

what if you don't wrap it in getAbsolutePath?

Still doesnt work

seem like you are missing an alias configuration too @/Button for example.

This didn't help either.

Its weird because it only fails when I add the addon for react native web. All stories work properly when I remove the addon. I also see that stories are rendered when the addon is present (I can see the UI behind the screen with errors).
Note: These are React stories Im trying to show (my idea is to have both mobile and web stories in one storybook app).

If you can provide a reproduction I can look deeper at your problem Will try to do this later :)

dannyhw commented 7 months ago

@simonadenic it would be better if you made a separate issue or start a thread on discord this doesn't seem related to the original issue. The difference is that this addon is more rigorous with transpiling because of how react native code needs to be transformed to be able to run at all. Because of this you need to configure it to handle most files in your project.

However I have been thinking of rewriting the include logic since it might be too much.

simonwalker-celadin commented 7 months ago

Still trying to get to a solution for this problem. Here is hopefully a better screen shot of the issue

Screenshot 2024-02-20 at 15 38 19

package.json

{ "name": "storybook", "version": "1.0.0", "main": "index.js", "license": "MIT", "scripts": { "storybook:web": "storybook dev -p 6006", "build-storybook": "storybook build", "storybook-generate": "sb-rn-get-stories --config-path .ondevice", "storybook": "cross-env STORYBOOK_ENABLED='true' expo start", "storybook:ios": "cross-env STORYBOOK_ENABLED='true' expo start --ios", "storybook:android": "cross-env STORYBOOK_ENABLED='true' expo start --android" }, "dependencies": { "@react-native-async-storage/async-storage": "1.21.0", "@react-native-community/datetimepicker": "7.6.1", "@react-native-community/slider": "4.4.2", "expo": "~50.0.6", "expo-constants": "~15.4.5", "expo-font": "^11.10.3", "expo-status-bar": "~1.11.1", "react": "18.2.0", "react-dom": "18.2.0", "react-native": "0.73.4", "react-native-safe-area-context": "4.8.2", "react-native-web": "~0.19.10" }, "devDependencies": { "@babel/core": "^7.19.3", "@expo/metro-runtime": "~3.1.3", "@storybook/addon-actions": "^7.6.13", "@storybook/addon-controls": "^7.6.13", "@storybook/addon-essentials": "^7.6.13", "@storybook/addon-links": "^7.6.13", "@storybook/addon-ondevice-actions": "^7.6.15", "@storybook/addon-ondevice-backgrounds": "^7.6.15", "@storybook/addon-ondevice-controls": "^7.6.15", "@storybook/addon-ondevice-notes": "^7.6.15", "@storybook/addon-react-native-web": "^0.0.22", "@storybook/react": "^7.6.13", "@storybook/react-native": "^7.6.15", "@storybook/react-webpack5": "^7.6.13", "@types/react": "~18.2.45", "babel-loader": "^8.2.3", "babel-plugin-react-docgen-typescript": "^1.5.1", "babel-plugin-react-native-web": "^0.19.10", "cross-env": "^7.0.3", "storybook": "^7.6.13", "typescript": "^5.3.0" }, "resolutions": { "react-docgen-typescript": "2.2.2" }, "overrides": { "react-docgen-typescript": "2.2.2" }, "pnpm": { "overrides": { "react-docgen-typescript": "2.2.2" } }, "private": true }

metro.config.js

const path = require('path'); const { getDefaultConfig } = require('expo/metro-config');

const { generate } = require("@storybook/react-native/scripts/generate");

generate({ configPath: path.resolve(__dirname , "./.ondevice"), });

const defaultConfig = getDefaultConfig(__dirname, '../..');

defaultConfig.transformer.unstable_allowRequireContext = true;

// Find the project and workspace directories const projectRoot = __dirname;

// This can be replaced with find-yarn-workspace-root const workspaceRoot = path.resolve(projectRoot, '../..');

const config = getDefaultConfig(projectRoot);

config.transformer.unstable_allowRequireContext = true;

config.resolver.sourceExts.push('mjs');

// 1. Watch all files within the monorepo config.watchFolders = [ workspaceRoot, path.resolve(projectRoot, '../..', 'apps/attendee-app'), ];

console.log('config.watchFolders', config.watchFolders);

// 2. Let Metro know where to resolve packages and in what order

const monorepoRoot = path.resolve(projectRoot);

config.resolver.nodeModulesPaths = [ path.resolve(projectRoot, 'node_modules'), path.resolve(monorepoRoot, '../..', 'node_modules'), ];

console.log('config.resolver.nodeModulesPaths', config.resolver.nodeModulesPaths);

// 3. Force Metro to resolve (sub)dependencies only from the nodeModulesPaths // config.resolver.disableHierarchicalLookup = true;

module.exports = config;

babel.config.js

module.exports = function (api) { api.cache(true); return { presets: ["babel-preset-expo"], }; };

dannyhw commented 7 months ago

@simonwalker-celadin can you please provide a public repo with a minimal reproduction? I can't really see much from your screenshots. If you can setup a reproduction I can debug it and send you a fix.

zuffik commented 4 months ago

@dannyhw I have the very same problem and would appreciate some help on this. I prepared minimal reproduction repository which emits this error: https://github.com/zuffik/rn-web-expo-sb-minimal-repo

Thank you

dannyhw commented 4 months ago

looking into it