nx
nx copied to clipboard
Storybook v7 / React / Vite: can not import/resolve nx library
Current Behavior
Storybook's serve
target can not resolve import of nx library: import { DeleteUserConfirm } from '@libraryname/settings'
with following error:
Error: The following dependencies are imported but could not be resolved:
@libraryname/settings (imported by /home/username/dev/project/project/packages/app/src/app/SettingsStories/userForms.stories.tsx)
Are they installed?
Expected Behavior
I expect Storybook to be able to reslve aliases defined in base ts config, the same way as nx serve app
does.
GitHub Repo
No response
Steps to Reproduce
- Create react+vite+ts monorepo
- Create a react app
- Add storybook v7 to the app
- Create a react+ts+no bundler library
- Create a story in the App project that imports any entity from the nx library using alias (e.g.
@workspace/library
)
Nx Report
> NX Report complete - copy this into the issue template
Node : 16.15.1
OS : linux x64
yarn : 3.5.0
Hasher : Native
nx : 16.0.1
@nx/js : 16.1.4
@nx/linter : 16.0.3
@nx/workspace : 16.0.1
@nx/cypress : 16.0.3
@nx/eslint-plugin : 16.0.3
@nx/react : 16.0.3
@nx/storybook : 16.1.4
@nx/vite : 16.0.3
@nx/web : 16.1.4
typescript : 5.0.4
---------------------------------------
The following packages should match the installed version of nx
- @nx/[email protected]
- @nx/[email protected]
- @nx/[email protected]
- @nx/[email protected]
- @nx/[email protected]
- @nx/[email protected]
- @nx/[email protected]
- @nx/[email protected]
To fix this, run `nx migrate [email protected]`
Failure Logs
Error: The following dependencies are imported but could not be resolved:
@libraryname/settings (imported by /home/username/dev/project/project/packages/app/src/app/SettingsStories/userForms.stories.tsx)
Are they installed?
Operating System
- [ ] macOS
- [X] Linux
- [ ] Windows
- [ ] Other (Please specify)
Additional Information
This should be possible to workaround using viteFinal
and resolver property in the .storybook/main
, but that should work by default.
main.ts (default):
import type { StorybookConfig } from '@storybook/react-vite';
const config: StorybookConfig = {
stories: ['../src/app/**/*.stories.@(js|jsx|ts|tsx|mdx)'],
addons: ['@storybook/addon-essentials'],
framework: {
name: '@storybook/react-vite',
options: {
builder: {
viteConfigPath: 'packages/app/vite.config.ts',
},
},
},
};
export default config;
// To customize your Vite configuration you can use the viteFinal field.
// Check https://storybook.js.org/docs/react/builders/vite#configuration
// and https://nx.dev/packages/storybook/documents/custom-builder-configs
ts/vite config are also default. Related issues #16208 (for WebPack)
For anyone looking for a quick workaround:
import type { StorybookConfig } from '@storybook/react-vite';
import { mergeConfig } from 'vite';
import path from 'path';
const config: StorybookConfig = {
stories: ['../src/app/**/*.stories.@(js|jsx|ts|tsx|mdx)'],
addons: ['@storybook/addon-essentials'],
framework: {
name: '@storybook/react-vite',
options: {
builder: {
viteConfigPath: 'packages/app/vite.config.ts',
},
},
},
viteFinal: async (config, { configType }) => {
console.log(__dirname);
return mergeConfig(config, {
resolve: {
alias: {
'@workspacename/libraryname': path.resolve(
__dirname,
'../../libraryname/src/index.ts'
),
},
},
});
},
};
getting the exact same issue in windows. within the scope of an nx library using vite, storybook presents that same error for any nx libraries imported into a component used in a story.
Good temp fix recommendation @unrealsolver, saved me breaking another keyboard...
@binaryartifex @unrealsolver
The issue is the following:
If you import a workspace library (a Nx library) into another Nx project (library or app) that's using @storybook/react-vite
or some Storybook vite builder, then:
- Storybook WILL find the paths correctly if the library is imported in a component file
- Storybook WILL NOT find the paths correctly if the library is imported in a story file.
Here is a reproduction I've created and shared with the Storybook team, because I think that this is an issue on the Storybook side at the moment.
In that reproduction, you will see that if you remove the library imports from the .stories.ts
files then Storybook builds correctly, and I am still importing the library into the components.
Potentially related: https://github.com/nrwl/nx/issues/17257
Totally looks the same @mandarini ! Except on my repro in #17257 it works for the stories of the app, but not in libs …
Thanks @unrealsolver for the workaround !
for anyone finding it annoying to keep adding the same config to every lib's .storybook/main.js
, i made a simple JS config file in the root of my monorepo and exported it:
import { mergeConfig } from "vite";
import path from 'path'
export const viteModuleResolver = async (config) => mergeConfig(config, {
resolve: {
alias: {
'@monorepo/core': path.resolve(
__dirname,
'./libs/core/src/index.ts'
),
'@monorepo/blocks': path.resolve(
__dirname,
'./libs/blocks/src/index.ts'
),
// add rest of libs!
},
},
});
export default viteModuleResolver
then i imported the file in each .storybook/main.js
import viteModuleResolver from '../../../vite.config'
const config = {
...rest of config...
viteFinal: viteModuleResolver
}
in this case, blocks
and core
were 2 libs i had
worked like a charm. props again to @unrealsolver for the solution!
Thank you all for all these workarounds. I want to find a good solution to solve this internally, but have not managed to do it yet.
for anyone finding it annoying to keep adding the same config to every lib's
.storybook/main.js
, i made a simple JS config file in the root of my monorepo and exported it:import { mergeConfig } from "vite"; import path from 'path' export const viteModuleResolver = async (config) => mergeConfig(config, { resolve: { alias: { '@monorepo/core': path.resolve( __dirname, './libs/core/src/index.ts' ), '@monorepo/blocks': path.resolve( __dirname, './libs/blocks/src/index.ts' ), // add rest of libs! }, }, }); export default viteModuleResolver
then i imported the file in each
.storybook/main.js
import viteModuleResolver from '../../../vite.config'
const config = { ...rest of config... viteFinal: viteModuleResolver }
in this case,
blocks
andcore
were 2 libs i hadworked like a charm. props again to @unrealsolver for the solution!
I had trouble generating the list of aliases, taking your idea a little further, here is an alias generator, that read libs paths from tsconfig.
const fs=require("fs");
const data = fs.readFileSync("tsconfig.base.json");
const json = JSON.parse(data);
const paths = json.compilerOptions.paths;
const list = Object.keys(paths).map(pkg => {
return `'${pkg}': path.resolve(__dirname,'./${paths[pkg]}')`
});
console.log(list.join(",\n"));
Save this as gen-alias.js at the top of your project and run node gen-alias.js
, it will use console.log to print the config in stdout, then paste into vite.config alias section.
Ok found the issue - solved the issue - with the help of @shilman!!! In your project's tsconfig.app.json
or tsconfig.lib.json
, remove the .stories.*
paths from the excludes
array. Then it works!!!!! :D No need for resolve.alias.
Once #17749 is merged and makes into our next minor release, you can nx migrate
and a better solution will take effect!
This issue has been closed for more than 30 days. If this issue is still occuring, please open a new issue with more recent context.