I'm exploring Nx with Angular (relatively new to both) and trying to figure out how to generate a component library that:
So the ideal setup is sort of like this:
repo
|--apps
|--normal-app (can import just card or button, without pulling in both)
|--libs
|--ui (lists individually exportable components, and has a servable Storybook)
|--.storybook
|--card
|--button
Following both a general Nx tutorial that showed how to create a shared component lib, as well as the guide for setting up Storybook in Nx, I generated a UI lib, and set up a Storybook schematic (if that's the right way to say it) for that lib directory.
The hope was to have all my shared components in one lib, and have Storybook set up to autogenerate and serve stories for each component -- but then be able to individually pull components from that lib into other applications without pulling in the whole, bulky UI library.
I successfully built out a UI lib and two components in it. I successfully set up Storybook in that lib. I then imported the UIModule
from the index.ts
file (the public API) in the UI lib, and used one of the two components in my template.
But then when I built the app that was importing the lib, the production build contained both components, although I had used one. This makes sense, since I'm importing the UiModule
. This is, however, non-ideal.
I'm hoping to create a setup that allows for collocated components in a lib with Storybook setup, which can be imported individually.
Is there a way to do this without drastically altering the NX setup? I've explored two main options so far. One is to break all the components into their own UI libs, import them all into a separate app that is set up for Storybook, and import them individually into a main app. Like this (attempt #1):
repo
|--apps
|--storybook-app (imports all)
|--other-app (imports just button)
|--libs
|--button
|--card
That's non-ideal, though, for several reasons:
As a second attempt (#2), I tried to generate each of the components as separate libs in a shared directory:
repo
|--apps
|--storybook-app (imports all)
|--other-app (imports just button)
|--libs
|--ui (just a directory; not a "project")
|--button (module; has separate component dir beneath)
|--card
This has a number of drawbacks of its own:
ui
directory, but since that's not a "project", I get a Cannot find project 'ui'
when I attempt to do so using the VSCode NX extension.I could build out one of the versions described above (#2, probably), but I suspect there are best practices for what seems like a common use case. It seems that much of my confusion stems from the Angular dependency-injection. (In a React app, you could just import a component, but in Angular, each component belongs to a module and that, specifically, needs to be injected as well. Is it a bad practice to have component-specific modules?)
Does anyone know of an idiomatic/best-practice way to meet these ideal specifications (shared storybook library with individual exported components, or split components with automatically generated stories in NX)?
I haven't found a totally satisfactory solution for this problem, but here's what I ended up doing. It's close to #2 above:
libs/ui
directory (not a project)component-lib
lib. (Rather than an app, because Storybook has its own separate run commands)..stories.ts
files under the libs/ui
directory.That way, the component-lib
directory automatically adds each new component as its added, and I don't have to worry about a bunch of boilerplate whenever I add a component. Also, each component can be individually imported, without dragging in the bundle.
I won't share my whole component-generator script, but it's a basic JS file that
ui
dirfs
to write an appropriate .stories.ts
file in that lib.Then, in my component-lib
directory, I modified the final line in .storybook/config.js
to require all stories under the ui
lib:
configure(require.context('../../ui', true, /\.stories\.tsx?$/), module);
It all feels a little hacky, particularly the generator script. But it works!
You could also use your initial approach and generate a module (not a lib) for each component set (or even only one component) you want to provide. Then export all modules in your index.ts
A angular lib in nrwl/nx must contain at least one module (Exceptions are data-libs), like your normal angular project must contain the app.module. But that doesn't mean that you cannot have multiple modules exportet throughout the lib. With multiple modules you can import them independently from your lib.
Example
import { module1 } from '@mylib'
import { module2 } from '@mylib'
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