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

[doc] How to configure for NativeWind #45

Closed
jbtheard opened this issue Nov 23, 2022 · 15 comments
Closed

[doc] How to configure for NativeWind #45

jbtheard opened this issue Nov 23, 2022 · 15 comments
Labels
bug Something isn't working

Comments

@jbtheard
Copy link

NativeWind allows to use tailwind css across platforms, leveraging react-native Stylesheet for mobile and acting as a compatibility layer with Tailwind on web. It's a replacement to tailwinds-react-native and is used in more and more projects such as Solito for their Tailwind starter kit.

As we test components across platforms, a guide on how to implement it for Storybook would come handy

@jbtheard jbtheard added the bug Something isn't working label Nov 23, 2022
@dannyhw
Copy link
Member

dannyhw commented Nov 23, 2022

Yeah that could be cool, actually its not very hard to setup I could write something but I think there are some details to figure out on that before I do. However there is an example here:

https://github.com/dohomi/nativewind-solito-kitchen-sink/blob/master/apps/storybook-react/.storybook/main.ts

@jbtheard
Copy link
Author

Oh I didn't identify that one in my search. I'll have a look at it first. Thanks for pointing at it.
(and thanks for this package)

kimchouard added a commit to kimchouard/expo-nativewind-storybook-template that referenced this issue Feb 7, 2024
NOT working with the full-web version. See issue [#45](storybookjs/addon-react-native-web#45) on `@storybook/addon-react-native-web`
@kimchouard
Copy link
Contributor

Alright, reviving this thread since I can't get @dannyhw's expo-template-storybook to work with NativeWind. 😬

Here's a boilerplate I'm trying to put together: expo-nativewind-template-storybook 👨🏼‍🍳

👉 It works great with yarn storybook, both on native and web (styles are properly picked up)
❗️ BUT fails with yarn storybook (using the React Native Web Addon through webpack) with this error:

CleanShot 2024-02-07 at 16 08 08@2x

Here's my .storybook/main.js config:

import path from 'path';

/** @type{import("@storybook/react-webpack5").StorybookConfig} */
module.exports = {
  stories: [
    "../components/**/*.stories.mdx",
    "../components/**/*.stories.@(js|jsx|ts|tsx)",
  ],
  addons: [
    "@storybook/addon-links",
    "@storybook/addon-essentials",
    {
      name: '@storybook/addon-react-native-web',
      options: {
        modulesToTranspile: [
          'nativewind',
          // 'react-native-css-interop', // Needed?
          'react-native-reanimated',
        ],
        babelPlugins: [
          '@babel/plugin-proposal-export-namespace-from',
          'react-native-reanimated/plugin',
          // 👇 This is what makes it crash 👇 
          'nativewind/babel', 
        ],
      },
    },
  ],
  framework: {
    name: "@storybook/react-webpack5",
    options: {},
  },
  docs: {
    autodocs: true,
  },
  webpackFinal: async (config, { configType }) => {
    config.module.rules.push({
      test: /\.css$/,
      use: [
        {
          loader: 'postcss-loader',
          options: {
            postcssOptions: {
              plugins: [require('tailwindcss'), require('autoprefixer')]
            }
          }
        }
      ],
      include: path.resolve(__dirname, '../')
    })

    return {
      ...config
    }
  }
};

Feel free to clone the repo and test for yourself! Looking forward to get your take on this @dannyhw 🤔 Thanks for all your work to date to bring Storybook to the RN community 🙌🏻

Notes:

  • Based on the example shared on earlier on this thread, I had to install postcss-loader and autoprefixer too, to make the webpackFinal script to run.
  • Nativewind v4 is tailored to Metro whereas the web-only Storybook is using webpack.
  • When configuring your metro.config.js file, you need to add a wrapper with withNativeWind(config, { input: './global.css' });. How is that done with webpack?

@dannyhw
Copy link
Member

dannyhw commented Feb 7, 2024

You should import global css in your preview.js but i can take a look, seems like theres an issue with a plugin too 🤔

@dannyhw
Copy link
Member

dannyhw commented Feb 7, 2024

@kimchouard "nativewind/babel" is a preset and not a plugin thats why you get that error, I can provide the option to add presets.

@kimchouard
Copy link
Contributor

kimchouard commented Feb 7, 2024

You should import global css in your preview.js but i can take a look, seems like theres an issue with a plugin too 🤔

Indeed, this is done here already:

import "../global.css"

@kimchouard "nativewind/babel" is a preset and not a plugin thats why you get that error

Yes, it looked odd to me but it was in the main.ts example shared previously.

        babelPlugins: [
          '@babel/plugin-proposal-export-namespace-from',
          'react-native-reanimated/plugin',
          // 'nativewind/babel', ➡️ Need to be moved to a new `babelPresets` option?
        ],

☝️ If you simply comment the 'nativewind/babel' line, the web server will run smoothly but the Nativewind styles won't be picked up... Maybe due to another babel setting missing? 🤷🏼‍♂️


I can provide the option to add presets.

It would be GREAT to be able to set babelPresets in the @storybook/addon-react-native-web options indeed, I think this might be the issue!
👉 If you look at line 5 (and 6) from the babel.config.js there is a specific NativeWind preset configuration that needs to be added:

    presets: [
      ["babel-preset-expo", { jsxImportSource: "nativewind" }],
      "nativewind/babel",
    ],

⚠️ That means that we would need to be able to add babelPresets in the form of string OR array.

Thanks for looking into it! 😎

@dannyhw
Copy link
Member

dannyhw commented Feb 7, 2024

@kimchouard just got everything working in #81 but need some time to figure out a few details then you can pass all the needed options

@dannyhw
Copy link
Member

dannyhw commented Feb 7, 2024

@kimchouard update to 0.0.23 and this kind of config should work

const path = require('path');

/** @type{import("@storybook/react-webpack5").StorybookConfig} */
export default {
  stories: [
    '../stories/**/*.stories.mdx',
    '../stories/**/*.stories.@(js|jsx|ts|tsx)', // your path here
  ],
  addons: [
    {
      name: '@storybook/addon-react-native-web',
      options: {
        modulesToTranspile: [
          'react-native-reanimated',
          'nativewind',
          'react-native-css-interop',
        ],
        babelPresets: ['nativewind/babel'],
        babelPresetReactOptions: { jsxImportSource: 'nativewind' },
        babelPlugins: [
          'react-native-reanimated/plugin',
        ],
      },
    },
    '@storybook/addon-essentials',
  ],
  framework: {
    name: '@storybook/react-webpack5',
    options: {},
  },
  webpackFinal: async (config) => {
    config.module?.rules?.push({
      test: /\.css$/,
      use: [
        {
          loader: 'postcss-loader',
          options: {
            postcssOptions: {
              plugins: [require('tailwindcss'), require('autoprefixer')],
            },
          },
        },
      ],
      include: [
        path.resolve(__dirname, '../'), // path to project root
      ],
    });

    return config,
  },
};

@dannyhw
Copy link
Member

dannyhw commented Feb 7, 2024

there should be a way to make this work with the storybook styling addon instead of adding a postcss-loader manually but I haven't got around to trying that out

@dannyhw
Copy link
Member

dannyhw commented Feb 7, 2024

There is also now a nativewind setup in this repo if you want to see a working setup

You can see it working here

and you can find the example config here
https://github.com/storybookjs/addon-react-native-web/blob/main/.storybook/main.js

@kimchouard
Copy link
Contributor

@dannyhw YOU'RE THE MAN!!! 🙌🏻

FYI, I got it to work but I had to add an extra babelPlugin:

        babelPlugins: [
          // (...)
          [
            '@babel/plugin-transform-react-jsx',
            {
              runtime: 'automatic',
              importSource: 'nativewind',
            },
          ],
        ],

Not sure what's different in your example that makes it work without this plugin configuration? 🤷🏼‍♂️

@kimchouard
Copy link
Contributor

I've updated the expo-nativewind-template-storybook boilerplate to match.

@dannyhw I think you can safely close this issue now. :)

Merci!

@kimchouard
Copy link
Contributor

Since this issue is called [doc] ..., I've created #85 to add the working config to the doc. :)

@dannyhw
Copy link
Member

dannyhw commented Feb 7, 2024

I believe this is now completed, please let me know if more information is needed and you want to reopen.

@dannyhw dannyhw closed this as completed Feb 7, 2024
@rwitchell
Copy link

for anyone else trying to get Expo v50+ and NativeWind v4+ and Storybook v8.3+ working:

Tip: Use the web version of storybook to receive compilation and runtime errors that may not bubble up from the mobile simulators.

// .ondevice/main.ts 
// AND/OR .storybook/main.ts

module.exports = {
  addons: [
    /*existing addons,*/
    {
      name: '@storybook/addon-react-native-web',
      options: {
        modulesToTranspile: [
          'react-native-reanimated',
          'nativewind',
          'react-native-css-interop',
        ],
        babelPresetReactOptions: { jsxImportSource: 'nativewind' },
        // If you have a bable.config.js file: this can also be placed there, and removed from here
        babelPresets: ['nativewind/babel'],
        babelPlugins: [
          // If you have a bable.config.js file: this can also be placed there, and removed from here
          'react-native-reanimated/plugin',
          // If you have a bable.config.js file: this can also be placed there, and removed from here
           [
            '@babel/plugin-transform-react-jsx',
            {
              runtime: 'automatic',
              importSource: 'nativewind',
            },
           ],
         ],
      },
    },
  ],
};
// .ondevice/preview.tsx
// add the following
import '../styles/global.css'
// metro.config.js
const path = require("path");
const { getDefaultConfig } = require("expo/metro-config");
const { withNativeWind } = require("nativewind/metro");
const withStorybook = require("@storybook/react-native/metro/withStorybook");

const defaultConfig = getDefaultConfig(__dirname);

// 👇 important: nativeWindConfig is defined and passed to withStorybook!
// replace this: module.exports = withNativeWind(config, { input: "./global.css" });
// with the below (and update your input):
const nativeWindConfig = withNativeWind(defaultConfig, { input: "./styles/global.css" });

module.exports = withStorybook(nativeWindConfig, {
  // this line helps you switch between app and storybook using variable in package.json script,
  // and changes to your app's main entry point.
  enabled: process.env.EXPO_PUBLIC_STORYBOOK_ENABLED === "true",
  configPath: path.resolve(__dirname, "./.ondevice"),
  onDisabledRemoveStorybook: true,
});
// babel.config.js
module.exports = function (api) {
  api.cache(true);
  return {
    presets: [
      ["babel-preset-expo", { jsxImportSource: "nativewind" }],
      "nativewind/babel",
    ],
    plugins: [
      ["babel-plugin-react-docgen-typescript", { exclude: "node_modules" }],
      'react-native-reanimated/plugin',
      [
        '@babel/plugin-transform-react-jsx',
        {
          runtime: 'automatic',
          importSource: 'nativewind',
        },
      ],
    ],
  };
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants