Storybook fails to show stories - reactjs

the problem we are encountering when trying to add storybook to our project is, that when we run development server, webpack builds every part of the app (resolves ~50,000 dependencies), therefore, when we run it, on network tab we can see unnecessary file downloaded (which contains entire app) that causes entire story (which is downloaded as separate file due to storyStoreV7 flag) to crash, because some lines of unnecessary bundle are raising errors (files aren't even required to display stories). Example error:
TypeError: Cannot read properties of undefined (reading 'CheckboxList')
at Module.CheckboxList (http://localhost:6007/js_components_index_tsx-node_modules_django-channels_dist_sync_recursive-node_modules_moment_-6a9914.iframe.bundle.js:35683:111)
at Module../js/forms/fields/checkbox-list/index.tsx (http://localhost:6007/js_components_index_tsx-node_modules_django-channels_dist_sync_recursive-node_modules_moment_-6a9914.iframe.bundle.js:41141:103)
at __webpack_require__ (http://localhost:6007/runtime~main.iframe.bundle.js:28:33)
at fn (http://localhost:6007/runtime~main.iframe.bundle.js:352:21)
at Module../js/forms/fields/index.js (http://localhost:6007/js_components_index_tsx-node_modules_django-channels_dist_sync_recursive-node_modules_moment_-6a9914.iframe.bundle.js:43187:73)
at __webpack_require__ (http://localhost:6007/runtime~main.iframe.bundle.js:28:33)
at fn (http://localhost:6007/runtime~main.iframe.bundle.js:352:21)
at Module../js/apps/admin/forms/add-reward-rule/index.tsx (http://localhost:6007/js_components_index_tsx-node_modules_django-channels_dist_sync_recursive-node_modules_moment_-6a9914.iframe.bundle.js:1726:71)
at __webpack_require__ (http://localhost:6007/runtime~main.iframe.bundle.js:28:33)
at fn (http://localhost:6007/runtime~main.iframe.bundle.js:352:21)
We found out, that when importing components with React.lazy issue is not present, we can use it this way, but it would be better to use it the "proper" way.
Storybook version: 6.5.0-alpha.42
.storybook/main.js
const webpack = require('webpack');
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin')
const path = require('path');
const globImporter = require('node-sass-glob-importer');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
"stories": [
"../js/**/*.stories.*",
],
"addons": [
"#storybook/addon-links",
"#storybook/addon-essentials",
"#storybook/addon-interactions",
{
"name": '#storybook/preset-scss',
"options": {
"sassLoaderOptions": {
"sourceMap": true,
"sassOptions": {
"includePaths": [path.resolve(__dirname, '../js')],
"importer": globImporter(),
}
},
"cssLoaderOptions": {
"url": false,
}
}
}
],
"features": {
"storyStoreV7": true,
},
"framework": "#storybook/react",
"core": {
"builder": "webpack5"
},
"staticDirs": [path.resolve(__dirname, '../../static')],
"webpackFinal": async (config) => {
config.entry.push(path.resolve(__dirname, '../scss/main.scss'))
config.resolve.plugins = [
...(config.resolve.plugins || []),
new TsconfigPathsPlugin({
extensions: config.resolve.extensions,
}),
];
config.resolve.alias = {
...(config.resolve.alias || {}),
'#js': path.resolve(__dirname, '../js'),
}
config.plugins = [
...(config.plugins || []),
new webpack.ProvidePlugin({
process: 'process/browser',
Buffer: ['buffer', 'Buffer'],
}),
new MiniCssExtractPlugin({
filename: 'style.css'
}),
]
config.module.rules.push(
{
test: /\.svg$/i,
issuer: /\.[jt]sx?$/,
use: [{ loader: '#svgr/webpack', options: { ref: true } }],
}
)
return config
}
}
.storybook/preview.tsx
import { ThemeProvider, StyledEngineProvider } from '#mui/material/styles';
import { Parameters } from '#storybook/react'
import { HistoryRouter } from '../js/routes/history-router';
import { browserHistory } from '../js/routes/history';
import '../scss/main.scss';
import theme from '../js/theme'
export const decorators = [
(Story) => {
return <StyledEngineProvider injectFirst>
<ThemeProvider theme={theme}>
<HistoryRouter history={browserHistory}>
{Story()}
</HistoryRouter>
</ThemeProvider>
</StyledEngineProvider>
}
]
export const parameters: Parameters = {
actions: { argTypesRegex: "^on[A-Z].*" },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
}
export const argTypes = { children: { type: 'string' }}
example story: Button.stories.tsx:
import React from 'react';
import { ComponentMeta, ComponentStory } from '#storybook/react';
import { Button } from './index';
export default {
component: Button,
} as ComponentMeta<typeof Button>;
const Template: ComponentStory<typeof Button> = (args) => {
return <Button {...args}>{args.children || 'Button'}</Button>;
};
export const Common = Template.bind({});
Common.args = { variant: 'primary' };

In our case, the issue was actually a circular dependency between a few files that used the component we wanted to create stories for.

Related

MFE module federation cannot find module for remote child import

Im trying to build out a micro frontend for the first time so my main application can support a sub application. I have it all working when everything is just rendering App.tsx (remote) but as soon as I try and render a child within the remote application I get the Cannot find module error from webpack
Container craco.congig.js
/* eslint-disable #typescript-eslint/no-var-requires */
const CracoEsbuildPlugin = require('craco-esbuild');
const { ModuleFederationPlugin } = require("webpack").container;
const deps = require("./package.json").dependencies;
module.exports = {
webpack: {
plugins: {
add: [
new ModuleFederationPlugin({
name: "Dashboard",
remotes: {
DigitalCanopy: "DigitalCanopy#//localhost:3001/remoteEntry.js",
},
shared: {
react: {
singleton: true,
strictVersion: true,
requiredVersion: deps['react']
},
"react-dom": {
singleton: true,
strictVersion: true,
requiredVersion: deps['react-dom']
},
},
}),
],
},
...
My remote craco.config.js
/* eslint-disable #typescript-eslint/no-var-requires */
const CracoEsbuildPlugin = require('craco-esbuild');
const { ModuleFederationPlugin } = require("webpack").container;
const deps = require("./package.json").dependencies;
module.exports = {
devServer: {
port: 3001
},
webpack: {
plugins: {
add: [
new ModuleFederationPlugin({
name: "DigitalCanopy",
exposes: {
"./DigitalCanopy": "./src/App.tsx",
},
filename: "remoteEntry.js",
shared: {
react: { singleton: true },
"react-dom": { singleton: true },
},
}),
],
},
configure: (webpackConfig) => ({
...webpackConfig,
output: {
...webpackConfig.output,
publicPath: "auto",
},
}),
},
plugins: [
{
plugin: CracoEsbuildPlugin,
options: {
esbuildLoaderOptions: {
// Optional. Defaults to auto-detect loader.
loader: 'tsx', // Set the value to 'tsx' if you use typescript
target: 'es2018',
},
esbuildMinimizerOptions: {
target: 'es2018',
css: true, // if true, OptimizeCssAssetsWebpackPlugin will also be replaced by esbuild.
},
skipEsbuildJest: false, // Optional. Set to true if you want to use babel for jest tests,
esbuildJestOptions: {
loaders: {
'.ts': 'ts',
'.tsx': 'tsx',
},
},
},
},
],
};
My remote App.tsx
import { createTheme, ThemeProvider } from '#mui/material';
import React from 'react';
import './App.css';
import App1 from './App1';
const baseTheme = createTheme({
...MUI THEME STUFF
});
function App() {
return (
<ThemeProvider theme={baseTheme}>
<div className="App">Digital Canopy App</div>;
<App1 />
</ThemeProvider>
);
}
export default App;
This works and renders fine until I try and render <App1 />
Then I get this error Module not found: Error: Can't resolve './App1' in ...
Any ideas? I feel like this should just work. Importing children components from within the remote is pretty standard doesnt seem unique but I cannot find anything similar online which makes me think Im missing something obvious.
Thanks for the help
My issue was I was missing the .tsx extension on the import. I have no idea why that is required by the sub application. My build configs are identical for typescript and my main app does not require that. I'll dig in and try and figure out why

Uncaught ReferenceError: process is not defined after vite update, why?

I have a react/typescript app and before I updated vite I had this solution to check either env is development or production by this code:
function getEnvironment(): "production" | "development" {
if (process.env.NODE_ENV === "production") {
return "production";
}
return "development";
}
type EnvUrl = { development: string; production: string };
const API_URL: EnvUrl = {
development: "http://localhost:5173/api/endpoint",
production: "https://ingress-url/api/endpoint",
};
export const apiUrl = API_URL[getEnvironment()];
But after i updated vite to version 3.1.0 I got error when serving production build with following error: Uncaught ReferenceError: process is not defined.
By vite config is:
import react from "#vitejs/plugin-react";
import { resolve } from "path";
import { rollupImportMapPlugin } from "rollup-plugin-import-map";
import { terser } from "rollup-plugin-terser";
import { ConfigEnv } from "vite";
import viteCompression from "vite-plugin-compression";
import cssInjectedByJsPlugin from "vite-plugin-css-injected-by-js";
import { viteMockServe } from "vite-plugin-mock";
import { UserConfigExport } from "vitest/config";
const reactUrl = "my-cdn-url/react/18/esm/index.js";
const reactDomUrl = "my-cdn-url/react-dom/18/esm/index.js";
const imports = {
react: reactUrl,
"react-dom": reactDomUrl,
};
export default ({ command }: ConfigEnv): UserConfigExport => ({
plugins: [
react(),
terser(),
cssInjectedByJsPlugin(),
viteCompression({
algorithm: "gzip",
}),
viteCompression({
algorithm: "brotliCompress",
}),
viteMockServe({
mockPath: "mock",
localEnabled: command === "serve",
}),
{
...rollupImportMapPlugin([{ imports }]),
enforce: "pre",
apply: "build",
},
],
build: {
lib: {
entry: resolve(__dirname, "src/Mikrofrontend.tsx"),
name: "sokos-attestasjon-frontend",
formats: ["es"],
fileName: () => `bundle.js`,
},
},
test: {
globals: true,
environment: "jsdom",
deps: {
inline: ["#testing-library/user-event"],
},
},
});
Is there another way to fix the problem or am I missing something in my vite.config.js ? If its another solution after upgrade, what the recommended one so my application behave the same as before?
Thank you.
Use import.meta.env.MODE to get the mode string:
if (import.meta.env.MODE === "production") {
return "production";
}
Or more simply, use import.meta.env.PROD to get a Boolean indicating production mode:
if (import.meta.env.PROD) {
return "production";
}

Invalid value for prop `css` when using #emotion/react with Vite

I couldn't find any information on how to make #emotion/react work in Storybook when using Vite as a bundler in a React application.
I'm getting errors like Invalid value for prop 'css' in <div> tag in almost every story.
Even though, #emotion/react is working fine for the webapp itself.
Here's my vite.config.js configuration:
import { defineConfig } from 'vite';
import react from '#vitejs/plugin-react';
export default defineConfig({
esbuild: {
jsxFactory: 'jsx',
jsxInject: `import { jsx } from '#emotion/react'`,
},
plugins: [
react({
jsxImportSource: '#emotion/react',
babel: {
plugins: ['#emotion/babel-plugin'],
},
}),
],
});
And here's my main.js for Storybook:
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, { configType }) => {
config.define = {
'window.process': {
env: {
NODE_ENV: configType.toLowerCase(),
},
},
};
return {
...config,
plugins: [
...config.plugins,
svgrPlugin({
svgrOptions: {
icon: true,
},
}),
],
};
},
};
The solution was found in storybook-builder-vite's github page here.

Import fonts to next.js react project with webpack and styled components

For some reason with next.js I just cant get importing local fonts into this project I have done it multiple times before but with next.js + react + webpack + styled components it seems to store the font in a _next folder which is or isn't right.
next.config.js
require('dotenv').config();
const autoPrefixer = require('autoprefixer');
const hash = require('string-hash');
const path = require('path');
const transpileModules = require('next-transpile-modules');
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
const withPlugins = require('next-compose-plugins');
const runtimeConfig = {
EXAMPLE_CONFIG: process.env.EXAMPLE_CONFIG || ''
};
const nextConfig = {
distDir: 'build',
publicRuntimeConfig: runtimeConfig,
webpack: (config) => {
// Next.js currently ignores "baseUrl" in tsconfig.json. This fixes it.
if (config.resolve.plugins) {
config.resolve.plugins.push(new TsconfigPathsPlugin);
} else {
config.resolve.plugins = [new TsconfigPathsPlugin];
}
// For inline SVGs.
config.module.rules.push({
test: /\.svg$/,
use: ({
issuer,
resource
}) => ({
loader: '#svgr/webpack',
options: {
dimensions: false,
svgo: true,
svgoConfig: {
plugins: [{
cleanupListOfValues: true
},
{
cleanupNumericValues: true
},
{
removeDesc: true
},
{
removeEmptyAttrs: true
},
{
removeEmptyContainers: true
},
{
removeEmptyText: true
},
{
removeRasterImages: true
},
{
removeTitle: true
},
{
removeUselessDefs: true
},
{
removeUnusedNS: true
},
{
cleanupIDs: {
prefix: `${hash(issuer + resource)}`
}
}
]
}
}
})
});
// For loading file types.
config.module.rules.push({
test: /\.(eot|otf|woff|woff2|ttf|png|jpg|gif)$/,
use: {
loader: 'file-loader',
options: {
limit: 100000,
name: '[name].[ext]',
},
},
});
return config;
}
};
// node_module packages that contain TypeScript that we want to compile.
const withTm = transpileModules([
'frontend-utilities'
]);
const withFonts = require('next-fonts');
module.exports = withPlugins([
[withTm],
[withFonts],
], nextConfig);
fonts.ts
import { css } from 'styled-components';
import CircularStdFont from '../public/static/fonts/CircularStdFont.otf';
export const GlobalFonts = css`
#font-face {
font-family: 'CircularStdFont';
src: url(${CircularStdFont}) format('opentype');
font-weight: normal;
font-style: normal;
}
`;
fonts folder
--- public
-- fonts
- CircularStdFont.otf
Error
Any ideas?
Please see screenshot below for the 404 get error.

Error- Hooks can only be called inside the body of a function component

I am getting an error: Hooks can only be called inside the body of a function componen
On image you can see that I am using function component: http://prntscr.com/rgk36s
My code is bundled using rollup.
What is wrong?
My rollup config is:
import { readdirSync } from 'fs';
import path from 'path';
import babel from 'rollup-plugin-babel';
import commonjs from 'rollup-plugin-commonjs';
import external from 'rollup-plugin-peer-deps-external';
import pkg from './package.json';
import replace from 'rollup-plugin-replace';
import resolve from 'rollup-plugin-node-resolve';
import { terser } from 'rollup-plugin-terser';
const EXTENSIONS = ['.ts', '.tsx', '.js', '.jsx', '.json'];
const CODES = [
'THIS_IS_UNDEFINED',
'MISSING_GLOBAL_NAME',
'CIRCULAR_DEPENDENCY',
];
const getChunks = URI =>
readdirSync(path.resolve(URI))
.filter(x => x.includes('.js'))
.reduce((a, c) => ({ ...a, [c.replace('.js', '')]: `src/${c}` }), {});
const discardWarning = warning => {
if (CODES.includes(warning.code)) {
return;
}
console.error(warning);
};
const env = process.env.NODE_ENV;
const commonPlugins = () => [
external({
includeDependencies: true,
}),
babel({
babelrc: false,
presets: [['#babel/preset-env', { modules: false }], '#babel/preset-react'],
extensions: EXTENSIONS,
exclude: 'node_modules/**',
}),
commonjs({
include: /node_modules/,
}),
replace({ 'process.env.NODE_ENV': JSON.stringify(env) }),
resolve({
extensions: EXTENSIONS,
preferBuiltins: false,
}),
];
export default [
{
onwarn: discardWarning,
input: 'src/index.js',
output: {
esModule: false,
file: pkg.unpkg,
format: 'umd',
name: 'myLibrary',
exports: 'named',
globals: {
react: 'React',
'react-dom': 'ReactDOM',
'styled-components': 'styled',
},
},
plugins: [...commonPlugins(), env === 'production' && terser()],
},
{
onwarn: discardWarning,
input: getChunks('src'),
output: [
{ dir: 'esm', format: 'esm', sourcemap: true },
{ dir: 'cjs', format: 'cjs', exports: 'named', sourcemap: true },
],
plugins: commonPlugins(),
},
];
I don't know what is wrong, can you help me to solve my problem? Looks like that react is not bundled with code.
I am trying to build my react library
My component is simple:
import React, {useState} from 'react';
const Bar = () => {
const [value, setValue] = useState(0)
return (
<button onClick={() => setValue(value + 1)}>
{value}
</button>
)
}
export default Bar
exported by index file : export { default as Bar } from './Bar';
And usage of my component in react-create-app:
import * as React from 'react';
import './App.css';
import {Bar} from 'my-library';
function App () {
return (
<div className="App">
<hr />
<Bar />
</div>
);
}
export default App;

Resources