Storybook with Vite error: fn.apply is not a function - reactjs

I'm refactoring a React webapp from CRA to using Vite and having issues with Storybook. The storybook's GUI opens, and I see a list of stories on the left panel. But whichever story I choose I get an error TypeError: fn.apply is not a function in Canvas tab like shown here:
I found a similar issue on Storybook's GitHub, and tried to change names StorybookName to storybookName in all the stories, also checked all the React components in the stories to make sure all of them are correctly defined as functions.
When it was using CRA storybook worked fine, but with Vite it's not working. Maybe I'm missing some configuration for Vite, so here's my vite.config.js as well:
import react from '#vitejs/plugin-react';
import { defineConfig } from 'vite';
import svgrPlugin from 'vite-plugin-svgr';
const path = require('path');
export default defineConfig({
esbuild: {
jsxFactory: 'jsx',
jsxInject: `import { jsx } from '#emotion/react'`,
},
optimizeDeps: {
include: ['#emotion/react'],
},
plugins: [
react({
jsxImportSource: '#emotion/react',
babel: {
plugins: ['#emotion/babel-plugin'],
},
}),
svgrPlugin({
svgrOptions: {
icon: true,
},
}),
],
});
And here's main.js from storybook:
const path = require('path');
const svgrPlugin = require('vite-plugin-svgr');
module.exports = {
core: {
builder: 'storybook-builder-vite',
},
stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.#(js|jsx|ts|tsx)'],
addons: ['#storybook/addon-links', '#storybook/addon-essentials'],
viteFinal: (config) => {
return {
...config,
plugins: [
...config.plugins,
svgrPlugin({
svgrOptions: {
icon: true,
},
}),
],
};
},
};
In Chrome Dev Tools I get this error:

I found the reason and it appears that all the configurations I had were correct. The problem was in the way how I aplied one of the decorators for Storybook. Basically, I wasn't correctly exporting one of the decorators and therefore was applying undefined instead of a decorator.
So, for whoever faces this issue, please note that it's most of the time a problem with syntax. Check all your functions, components, decorators and so on and make sure they are all correctly defined and exported.
The error message itself doesn't give any clue where to dig, which is a big shame, so this one is pretty tough to debug.

Related

Configuring Vite with styled-jsx

I want to be able to add classes through styled-jsx which can be nested and have tailwind directives(#apply screen etc.). Right now it's working on imported css files.
Here's my Vite config:
import { defineConfig } from "vite";
import react from "#vitejs/plugin-react";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
react({
babel: {
parserOpts: {
plugins: [
"styled-jsx/babel",
// {
// plugins: ["styled-jsx-plugin-postcss"],
// },
],
},
},
}),
],
});
As you see plugins: ["styled-jsx-plugin-postcss"] is commented, because it results in an error, but it's essential to use postcss settings.
If somebody interested, here's the postcss.config.cjs(for non Vite it's .js):
module.exports = {
plugins: {
'tailwindcss/nesting': 'postcss-nesting',
'postcss-preset-env': {
stage: 1
},
tailwindcss: {},
autoprefixer: {},
}
}
Is there a way to configure it in Vite.js ( in Next.js it's trivial, so if someone wants to suggest this idea, just don't, it's about Vite!)

Create a UI package with Emotion and consume it with Next.js application

Problem:
We've built a UI package using React, Emotion, and Vite. We're consuming it in a Next.js app.
But when we import a component, we get the following ServerError -
TypeError: Cannot read properties of null (reading 'registered')
Seems like the cache object is null on the server.
Even when adding <CacheProvider> to the Next.js app, we still get the same error.
Extra information:
Here's how our vite.config.js loos like -
import { defineConfig } from 'vite';
import react from '#vitejs/plugin-react';
import packageJson from './package.json';
export default defineConfig({
plugins: [
react({
jsxImportSource: '#emotion/react',
babel: {
plugins: ['#emotion/babel-plugin'],
},
}),
],
esbuild: {
jsxInject: "import React from 'react'",
},
build: {
outDir: 'lib',
lib: {
entry: './src/index',
formats: ['esm'],
fileName: (format) => `ui.${format}.js`,
},
rollupOptions: {
// Externalize dependencies that shouldn't be bundled into library
external: [...Object.keys(packageJson.peerDependencies)],
},
},
});

Jest cannot find module #env React Native

I'm currently facing some problem I'm using in my react native app https://github.com/goatandsheep/react-native-dotenv for handling .env.
Error => Cannot find module '#env' from 'src/api/api.ts'
I'm testing currently my redux saga to call the api endpoint:
import axios from 'axios';
import {API_URL} from '#env';
export default axios.create({
baseURL: API_URL,
responseType: 'json',
});
API Endpoint
export const sendCheckNumber = async (
phoneNumber: string,
): Promise<AuthenticationTO> => {
const response = await axios.get<AuthenticationTO>(
`SendCheckNumber/${phoneNumber}`,
);
return response.data;
};
I'm using ts-jest package.json. I saw in the docs its possible to include bable in ts-jest because I'm using bable to import the 'module:react-native-dotenv', as plugin. I thought that will already solve my problem but unfortunately it still fails. Maybe someone of you have some suggestion what could cause this error.
Thank you!!!
package.json
"jest": {
"preset": "react-native",
"transform": {
"^.+\\.js$": "<rootDir>/node_modules/react-native/jest/preprocessor.js",
"\\.(ts|tsx)$": "ts-jest"
},
"globals": {
"ts-jest": {
"babelConfig": "babel.config.js",
"tsConfig": "tsconfig.jest.json"
}
},
"moduleFileExtensions": [
"ts",
"tsx",
"js"
],
"modulePaths": [
"<rootDir>/src"
],
"testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$"
}
Maintainer goatandsheep here. I recently added some documentation on how this is done. Take a look at the documentation section on TypeScript. Here is the excerpt:
Create a types folder in your project
Inside that folder, create a *.d.tsfile, say, env.d.ts
in that file, declare a module as the following format:
declare module '#env' {
export const API_BASE: string;
}
Add all of your .env variables inside this module.
Finally, add this folder into the typeRoots field in your tsconfig.json file:
{
"typeRoots": ["./src/types"],
}
Let me know if that works!
I fixed this problem like following.
import {API_URL} from '#env';`
Added this instead:
import {API_URL} from 'react-native-dotenv';
And add the next in babel.config.js
module.exports = function (api) {
api.cache(true)
return {
presets: ["babel-preset-expo"],
plugins: [
[
"module:react-native-dotenv",
{
moduleName: "react-native-dotenv",
},
],
],
}
}
It works well for me.

Storybook Can't Find Components in React, Next.JS, Typescript Project

I have storybook setup with my next.js, typescript and react project. The project renders fine but storybook breaks and give me the me error: "Module not found: Error: Can't resolve 'components/atoms' in...." It seems like the path to components is causing it to break:
import { Element } from 'components/atoms';
but the following works:
import { Element } from '../../atoms
I have a tsconfig.json file with the following:
"compilerOptions": {
"baseUrl": "src",
},
"include": [
"src/**/*.ts",
"src/**/*.tsx"
],
...
I tried some of the suggestions online but none seems to resolve the path issue. I created a webpack.config.js in my .storybook folder with the following, but still get errors.
module.exports = {
...
resolve: {
modules: [path.resolve(__dirname, 'src'), 'node_modules']
}
};
I would like to not use the ../../ when calling files and just be able to use the ./components structure.
Spent some time fighting with Storybook )
Here is my .storybook/main.js version, that finally worked:
const path = require("path");
module.exports = {
webpackFinal: async (config, { configType }) => {
config.resolve.modules.push(path.resolve(__dirname, '../src'));
return config;
},
stories: [
"../src/**/*.stories.mdx",
"../src/**/*.stories.#(js|jsx|ts|tsx)"
],
addons: [
"#storybook/addon-links",
"#storybook/addon-essentials",
"#storybook/preset-create-react-app"
]
}
For someone who is still looking for a solution, try adding the below inside your webpackFinal before returning config. It is because storybook isn't configured to access files using absolute paths.
config.resolve.modules = [...(config.resolve.modules || []), path.resolve('./')]
I was having an issue resolving aliases
Error: Can't resolve '#foo/bar'
In root > .storybook/main.js I added the property config.resolve.alias
const path = require('path');
module.exports = {
stories: ['../libs/feature/src/**/*.stories.#(js|jsx|ts|tsx)'],
addons: [
'#storybook/addon-links',
'#storybook/addon-essentials',
'#storybook/addon-interactions',
],
framework: '#storybook/react',
webpackFinal: async (config, { configType }) => {
config.resolve.alias = {
...config.resolve.alias,
'#foo/bar': path.resolve(__dirname, '../libs/bar/src/'),
};
return config;
},
};
I think what you need is path aliases.
If you're working on a typescript project, you can declare aliases that map to a certain absolute path in your application using tsconfig.json paths compiler option:
"baseUrl": "./src",
"paths": {
"components/*": ["components/*"],
"#/common/*": ["common/*"],
}
Official link => typescriptlang.org
Here you have a good explanation about this typescript feature.
Path aliases with TypeScript in Node.js
Be aware that is not always that easy because in production your build toolchain will have to translate them to the correct paths as tsc doesn’t do it.
Fortunately nexjts has added this feature recently => https://nextjs.org/docs/advanced-features/module-path-aliases

Storybook throws unexpected default export without title with Docs addon and .mdx file

I'm trying to use the docs addon with my Storybook. I've configured my Storybook as follows:
module.exports = {
stories: [
'../src/**/*.stories.([tj]sx|mdx)',
'../docs/**/*.([tj]sx|mdx)'
],
addons: [
'#storybook/preset-typescript',
'#storybook/addon-actions/register',
'#storybook/addon-storysource',
'#storybook/addon-docs'
],
webpackFinal: async config => {
config.module.rules.push({
test: /\.(ts|tsx)$/,
loader: require.resolve('babel-loader'),
options: {
presets: [['react-app', { flow: false, typescript: true }]],
},
});
config.resolve.extensions.push('.ts', '.tsx');
return config;
},
};
I've created the following file docs/welcome.mdx:
import { Meta, Story, Preview } from '#storybook/addon-docs/blocks';
<Meta title="Welcome" />
Test
The story book successfully builds, but displays the following error for any component:
Unexpected default export without title: undefined
loadStories/</<#http://localhost:6006/vendors~main.7a0ff0b8bf0e3413b462.bundle.js:20821:17
loadStories/<#http://localhost:6006/vendors~main.7a0ff0b8bf0e3413b462.bundle.js:20814:13
render#http://localhost:6006/vendors~main.7a0ff0b8bf0e3413b462.bundle.js:11229:13
ConfigApi/this.configure#http://localhost:6006/vendors~main.7a0ff0b8bf0e3413b462.bundle.js:11264:9
configure#http://localhost:6006/vendors~main.7a0ff0b8bf0e3413b462.bundle.js:20921:15
configure#http://localhost:6006/vendors~main.7a0ff0b8bf0e3413b462.bundle.js:21366:24
./.storybook/generated-entry.js/<#http://localhost:6006/main.7a0ff0b8bf0e3413b462.bundle.js:16:67
./.storybook/generated-entry.js#http://localhost:6006/main.7a0ff0b8bf0e3413b462.bundle.js:17:30
__webpack_require__#http://localhost:6006/runtime~main.7a0ff0b8bf0e3413b462.bundle.js:785:30
hotApply#http://localhost:6006/runtime~main.7a0ff0b8bf0e3413b462.bundle.js:709:33
cb#http://localhost:6006/vendors~main.7a0ff0b8bf0e3413b462.bundle.js:178512:36
check/<#http://localhost:6006/vendors~main.7a0ff0b8bf0e3413b462.bundle.js:178527:11
What am I doing wrong?
I'm using the version 5.3.18 of Storybook.
The way I resolved this is by using the extension ".stories.mdx" for my stories, in ".storybook/main.js",using any other extension like ".storybook.mdx", gave this error
In addition to the solution above, story files need to have a prefix, eg button.stories.mdx.
Just stories.mdx will give you the error as well.

Resources