Closed juliencurro-aptar closed 20 hours ago
You can use vite for react native web but this addon currently is webpack specific
I have a vite example though
https://github.com/dannyhw/rn-web-vite-storybook-example/tree/main
The vite config is the important part
Thanks to your example (and other github repos), I am able to run storybook, but I have a lot of remaining issues.
Major one is tailwind styles not being applied, would you have a repo mixing vite and tailwind ?
And the other one "String contains an invalid character", for a component that uses an Svg icon.
Here is my config :
// vite.config.ts
import react from '@vitejs/plugin-react';
import { defineConfig } from 'vite';
import tsconfigPaths from "vite-tsconfig-paths";
import tailwindcss from "tailwindcss";
import svgr from 'vite-plugin-svgr';
import path from 'path';
const extensions = [
".web.tsx",
".tsx",
".web.ts",
".ts",
".web.jsx",
".jsx",
".web.js",
".js",
".css",
".json",
];
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react(), tsconfigPaths(), svgr()],
server: {
open: true,
port: 3000,
},
css: {
postcss: {
plugins: [tailwindcss()],
},
},
optimizeDeps: {
esbuildOptions: {
resolveExtensions: extensions,
},
},
resolve: {
extensions: extensions,
alias: {
'react-native': 'react-native-web',
'tailwindConfig': path.resolve(__dirname, './tailwind.config.ts')
}
},
})
// tsconfig.json
{
"extends": "@react-native/typescript-config/tsconfig.json",
"include": [
"./src/**/*",
"./globals.d.ts",
"./tailwind.config.ts"
],
"exclude": [
"node_modules"
],
"compilerOptions": {
"allowJs": true,
"importHelpers": true,
"forceConsistentCasingInFileNames": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"moduleResolution": "Bundler",
"noUncheckedIndexedAccess": true,
"noEmit": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"jsx": "react-native",
"target": "es6",
"module": "ESNext",
"baseUrl": "./src/",
"paths": {
"@src/*": ["./*"],
"@assets/*": ["./../assets/*"],
"@component/*": ["./src/components/*"],
"tailwindConfig": ["./../tailwind.config.js"]
},
"strict": true,
"noImplicitAny": true,
"pretty": true,
"removeComments": true,
"strictFunctionTypes": true,
"traceResolution": true
}
}
// tailwind.config.ts
export default {
content: ["./index.{js,jsx,ts,tsx}", "./src/**/*.{js,jsx,ts,tsx}", "./.storybook/preview.js"],
theme: {
// ...
}
plugins: [],
}
// globals.css
@tailwind base;
@tailwind components;
@tailwind utilities;
// .storybook/main.js
import { join, dirname } from "path";
/**
* This function is used to resolve the absolute path of a package.
* It is needed in projects that use Yarn PnP or are set up within a monorepo.
*/
function getAbsolutePath(value) {
return dirname(require.resolve(join(value, "package.json")));
}
/** @type { import('@storybook/react-vite').StorybookConfig } */
const config = {
stories: [
"../src/**/*.stories.@(js|jsx|mjs|ts|tsx)",
],
addons: [
getAbsolutePath("@storybook/addon-onboarding"),
getAbsolutePath("@storybook/addon-links"),
getAbsolutePath("@storybook/addon-essentials"),
getAbsolutePath("@chromatic-com/storybook"),
getAbsolutePath("@storybook/addon-interactions"),
{ name: getAbsolutePath("@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',
[
'@babel/plugin-transform-react-jsx',
{
runtime: 'automatic',
importSource: 'nativewind',
},
],
],
},
},
],
framework: {
name: getAbsolutePath("@storybook/react-vite"),
options: {},
},
core: {
disableTelemetry: true,
builder: '@storybook/builder-vite',
},
};
export default config;
// preview.js
/** @type { import('@storybook/react').Preview } */
import "../globals.css";
const preview = {
parameters: {
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/i,
},
},
},
};
export default preview;
// package.json
{
"name": "BreatheSmart",
"packageManager": "yarn@4.2.2",
"type": "module",
"devDependencies": {
"@babel/preset-react": "^7.24.7",
"@chromatic-com/storybook": "^1.9.0",
"@react-native/babel-preset": "^0.75.3",
"@storybook/addon-essentials": "^8.3.3",
"@storybook/addon-interactions": "^8.3.3",
"@storybook/addon-links": "^8.3.3",
"@storybook/addon-onboarding": "^8.3.3",
"@storybook/addon-react-native-web": "^0.0.25",
"@storybook/blocks": "^8.3.3",
"@storybook/builder-vite": "^8.3.3",
"@storybook/react": "^8.3.3",
"@storybook/react-vite": "^8.3.3",
"@storybook/test": "^8.3.3",
"@types/react-dom": "^18.3.0",
"@types/tailwindcss": "^3.1.0",
"@vitejs/plugin-react": "^4.3.1",
"babel-plugin-react-native-web": "^0.19.12",
"prettier": "^3.3.3",
"prop-types": "^15.8.1",
"react-dom": "^18.3.1",
"react-native-web": "^0.19.12",
"storybook": "^8.3.3",
"tailwindcss": "3.3.2",
"typescript": "^5.6.2",
"vite-plugin-svgr": "^4.2.0"
},
"scripts": {
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build"
},
"peerDependencies": {
"nativewind": "^2.0.11"
},
"dependencies": {
"nativewind": "^2.0.11",
"react": "^18.3.1",
"react-native-gesture-handler": "^2.19.0",
"vite": "^5.4.7",
"webpack": "^5.94.0"
}
}
If you have few minutes to look at what could be wrong in my configuration, that would be really helpful, thanks :)
I solved the 2nd issue by changing the svgr() call inside the vite.config.ts with that :
plugins: [react(), tsconfigPaths(), svgr({svgrOptions: { exportType: "default", ref: true, svgo: false, titleProp: true },
source : https://medium.com/@praizjosh/how-to-import-svg-files-as-react-components-in-vite-97d6e1f2c046
Also If that can be helpful to someone, I had an issue with a component wrapped inside a SafeAreaView that needed a SafeAreaProvider (which is usually in another component), and for that I added a decorator to my story like that :
decorators: [
(Story) => (
<SafeAreaProvider>
<Story />
</SafeAreaProvider>
),
Remains the main issue with NativeWind...
regarding tailwind styles you probably need to apply the nativewind babel stuff to the vite setup
You mean in vite.config.ts ? or a viteFinal block in the .storybook/main.js ?
in the vite.config.ts since thats getting used by storybook anyway
I am wondering if I am not falling into this bug : https://github.com/nativewind/nativewind/issues/992 Because it's only the className that doesn't seem to be working.
Heres a new example with nativewind https://github.com/dannyhw/vite-rnw-example
It works, thanks.
Not a bug, but a question :
I tried to run this addon without webpack package and got failures, given the addon is almost a single "webpack.ts" file, I assume that webpack is required. But then can I have Vite for storybook itself and webpack for this addon ?