Closed jbtheard closed 9 months ago
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:
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)
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:
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:
postcss-loader
and autoprefixer
too, to make the webpackFinal
script to run.Metro
whereas the web-only Storybook is using webpack
.metro.config.js
file, you need to add a wrapper with withNativeWind(config, { input: './global.css' });
. How is that done with webpack?You should import global css in your preview.js but i can take a look, seems like theres an issue with a plugin too 🤔
@kimchouard "nativewind/babel" is a preset and not a plugin thats why you get that error, I can provide the option to add presets.
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! 😎
@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
@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,
},
};
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
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
@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? 🤷🏼♂️
I've updated the expo-nativewind-template-storybook boilerplate to match.
@dannyhw I think you can safely close this issue now. :)
Merci!
Since this issue is called [doc] ...
, I've created #85 to add the working config to the doc. :)
I believe this is now completed, please let me know if more information is needed and you want to reopen.
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',
},
],
],
};
};
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