I'm trying to configure Storybook to run from a directory that is not the root of the project and I'm having a little trouble. I've setup a mono-rep using https://github.com/jibin2706/cra-monorepo-demo as base.
My project directory looks like this:
- project
-- packages
---- app
---- components
---- utils
---- stories
------ .storybook
-------- main.js
------ ComponentA
-------- ComponentA.stories.mdx
Because I'm using a monorep with aliases (e.g. a component can import from @project/utils
) I've configured webpack in .storybook/main.js
to read like:
const path = require('path');
module.exports = {
stories: ['../**/*.stories.mdx', '../../**/*.stories.@(js|jsx|ts|tsx)'],
addons: [
'@storybook/addon-links',
'@storybook/addon-essentials',
'@storybook/preset-create-react-app',
],
webpackFinal: async (config, { configType }) => {
const result = {
...config,
resolve: {
...config.resolve,
alias: {
...config.resolve.alias,
'@project/components': path.resolve(
process.cwd(),
'packages/components'
),
},
},
};
},
};
Then within my ComponentA.stories.mdx
I have an import like import { ComponentA } from '@project/components';
When I run this however, I'm always hitting an error when it encounters JSX within a .js
file:
ERROR in ./packages/components/MyComponent1/MyComponent1.js 106:11 Module parse failed: Unexpected token (106:11) File was processed with these loaders:
- ./node_modules/@pmmmwh/react-refresh-webpack-plugin/loader/index.js You may need an additional loader to handle the result of these loaders. |
return <React.Fragment>{children}</React.Fragment>;
I can't seem to work out why this error is throwing. I've tried running with yarn storybook --debug-webpack
which seems to include a loader for both jsx
and js
files. I'm not 100% sure if this is correct, but it looks roughly right from other docs I've read.
module: {
rules: [
{
test: /\.(mjs|tsx?|jsx?)$/,
use: [
{
loader: '/home/ian/src/cra-monorepo-demo/node_modules/babel-loader/lib/index.js',
options: {
sourceType: 'unambiguous',
presets: [
[
'/home/ian/src/cra-monorepo-demo/node_modules/@babel/preset-env/lib/index.js',
{ shippedProposals: true, loose: true }
],
'/home/ian/src/cra-monorepo-demo/node_modules/@babel/preset-typescript/lib/index.js',
'/home/ian/src/cra-monorepo-demo/node_modules/@babel/preset-react/lib/index.js'
],
plugins: [
'/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-transform-shorthand-properties/lib/index.js',
'/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-transform-block-scoping/lib/index.js',
[
'/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-proposal-decorators/lib/index.js',
{ legacy: true }
],
[
'/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-proposal-class-properties/lib/index.js',
{ loose: true }
],
[
'/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-proposal-private-methods/lib/index.js',
{ loose: true }
],
'/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-proposal-export-default-from/lib/index.js',
'/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-syntax-dynamic-import/lib/index.js',
[
'/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-proposal-object-rest-spread/lib/index.js',
{ loose: true, useBuiltIns: true }
],
'/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-transform-classes/lib/index.js',
'/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-transform-arrow-functions/lib/index.js',
'/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-transform-parameters/lib/index.js',
'/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-transform-destructuring/lib/index.js',
'/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-transform-spread/lib/index.js',
'/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-transform-for-of/lib/index.js',
'/home/ian/src/cra-monorepo-demo/node_modules/@storybook/core-common/node_modules/babel-plugin-macros/dist/index.js',
'/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-proposal-optional-chaining/lib/index.js',
'/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-proposal-nullish-coalescing-operator/lib/index.js',
[
'/home/ian/src/cra-monorepo-demo/node_modules/babel-plugin-polyfill-corejs3/lib/index.js',
{
method: 'usage-global',
absoluteImports: '/home/ian/src/cra-monorepo-demo/node_modules/core-js/index.js',
version: '3.16.1'
}
],
'/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-transform-template-literals/lib/index.js'
]
}
}
],
include: [ '/home/ian/src/cra-monorepo-demo' ],
exclude: [ /node_modules/, /dist/ ]
},
{
test: /\.js$/,
use: [
{
loader: '/home/ian/src/cra-monorepo-demo/node_modules/babel-loader/lib/index.js',
options: {
sourceType: 'unambiguous',
presets: [
[
'/home/ian/src/cra-monorepo-demo/node_modules/@babel/preset-env/lib/index.js',
{
shippedProposals: true,
modules: false,
loose: true,
targets: 'defaults'
}
],
'/home/ian/src/cra-monorepo-demo/node_modules/@babel/preset-react/lib/index.js'
],
plugins: [
'/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-transform-shorthand-properties/lib/index.js',
'/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-transform-block-scoping/lib/index.js',
[
'/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-proposal-decorators/lib/index.js',
{ legacy: true }
],
[
'/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-proposal-class-properties/lib/index.js',
{ loose: true }
],
[
'/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-proposal-private-methods/lib/index.js',
{ loose: true }
],
'/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-proposal-export-default-from/lib/index.js',
'/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-syntax-dynamic-import/lib/index.js',
[
'/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-proposal-object-rest-spread/lib/index.js',
{ loose: true, useBuiltIns: true }
],
'/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-transform-classes/lib/index.js',
'/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-transform-arrow-functions/lib/index.js',
'/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-transform-parameters/lib/index.js',
'/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-transform-destructuring/lib/index.js',
'/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-transform-spread/lib/index.js',
'/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-transform-for-of/lib/index.js',
'/home/ian/src/cra-monorepo-demo/node_modules/@storybook/core-common/node_modules/babel-plugin-macros/dist/index.js',
'/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-proposal-optional-chaining/lib/index.js',
'/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-proposal-nullish-coalescing-operator/lib/index.js',
[
'/home/ian/src/cra-monorepo-demo/node_modules/babel-plugin-polyfill-corejs3/lib/index.js',
{
method: 'usage-global',
absoluteImports: '/home/ian/src/cra-monorepo-demo/node_modules/core-js/index.js',
version: '3.16.1'
}
]
]
}
}
],
include: [Function: include]
},
...
Can anyone see what I might be missing here, or what additional config is required?
To deploy Storybook, we first need to export it as a static web app. This functionality is already built-in to Storybook and pre-configured. Running yarn build-storybook will output a static Storybook in the storybook-static directory, which can then be deployed to any static site hosting service.
Storybook is configured via a folder, called.storybook which contains various configuration files. Note you can change the folder that Storybook uses by setting the -c flag to your start-storybook and build-storybook scripts. Configure your Storybook project The main configuration file is main.js.
The main configuration file is main.js. This file controls the behavior of the Storybook server, and so you must restart Storybook’s process when you change it. It contains the following:
Note you can change the folder that Storybook uses by setting the -c flag to your start-storybook and build-storybook scripts. The main configuration file is main.js. This file controls the behavior of the Storybook server, and so you must restart Storybook’s process when you change it.
Tip: Customize your default story by referencing it first in the `stories` array. By default, Storybook will load stories from your project based on a glob (pattern matching string) in .storybook/main.js that matches all files in your project with extension .stories.js. The intention is you colocate a story file with the component it documents.
The issue is probably with the Storybook project root. The default babel-loader
defines an include that is equal to the project root. And the "project root" is usually the closest .git
folder.
A workaround is to set the correct project root:
const path = require("path");
module.exports = {
// ...
webpackFinal: async (config, { configType }) => {
const babelLoaderRule = config.module.rules.find(
(rule) => rule.test.toString() === /\.(mjs|tsx?|jsx?)$/.toString()
);
// set correct project root
babelLoaderRule.include = [path.resolve(__dirname, "../..")];
return config;
}
};
What "correct" path is, depends on your setup.
Check my post for a longer write-up.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With