Building React and Angular Component Libraries with Stencil and Nx

Originally published at: Building React and Angular Component Libraries with Stencil and Nx - Ionic Blog

One of the greatest advantages of using Stencil to build a design system is that Stencil components are compatible with multiple different frontend frameworks. This means that you can write one core component library with Stencil and generate multiple component libraries for different frameworks based on that core. These components can then be consumed by…

4 Likes

Thanks for the great writeup and an introduction to Nx.
I was already able to integrate react with stencil components using the documentation available on ionic site - Stencil integration with react.

But can you throw some light on how we can publish this to private NPM packages? After all, this is why we are creating components.

I’m glad you found the tutorial useful! For publishing your component libraries as private NPM packages, NPM has a great guide for doing just that Creating and publishing private packages | npm Docs. They also have a few other guides for a variety of use cases Contributing packages to the registry | npm Docs. Let me know if you’re still having trouble, happy to dive deeper.

Thanks for the link, but I have already tried the steps mentioned in NPM to publish the private package. I am able to publish and use it in a react application.

But when it comes to this monorepo, I figured out that when creating a stencil component library, we have to use --publishable and --importPath so that the generator puts the correct package.json for the npm publish command to work.

With this, we can change directory to dist/packages/core-components/dist and run npm publish. But this does not work, I am not able to access demo MyComponent component created by stencil.

We should be accessing MyComponent from core-component-react.

Same problem here. How i can publish my angular library built by angular output target? The core-components-angular folder do not have its own package.json

Hi Anthony,

first of, great article ! This is a stack that I’ve been looking into for a while now and it looks like we are ALMOST there.

The reason I say almost is the following: whenever we change the Stencil source component the dependency graph (nx affected:graph) doesn’t show modifications on the React wrapper component library meaning it is not possible to see who was affected by the change. From what I understand it is because the wrappers are generated through HOC thus no change is triggered when rebuilding our components.

Do you have any suggestions on howto deal, manage or workaround this ?

Thanks again for this article!

Hi @pallard-src,

This is a great question. To achieve the effect you’re describing, you’ll want to add your Stencil component library as an implicit dependency of your React wrapper component library. You can do this via the β€œimplicitDependencies” option in the project.json file of your React wrapper component library. So, following the package names from the tutorial, it might look something like this "implicitDependencies": ["core-components"]. This will inform Nx that your Stencil library is a dependency of your React library and thus update your dependency graph accordingly.

Here is Nx’s documentation on implicit dependencies: Configuration: project.json and nx.json | Nx

I hope this is helpful. Feel free to let me know if you have any other questions.

This does solve the issue, thank you very much. I’m really looking forward to see what can be done with this stack.

Hi @agiuliano, thanks for your post. Everything looks great, but we have a problem.
When we run the build for angular, we get an error because our kebapcase events on the stencil side do not convert to camelcase.

For example, this is how we define it in the stencil.

@Event({ eventName: 'bcm-change' }) change: EventEmitter

Angular output:


export declare interface BcmList extends Components.BcmList {
   /**
    *
    */
   bcm-change: EventEmitter<CustomEvent<any>>;

}

How we can solve this problem. Do you have a suggestion?

Thanks for detailed one. I am having doubt on how TreeShaking will be achieved in core-components. I am using Nx lib for my react app. In that app, I am having 100 widgets in libs/assets location. When I import any one of a widget from 100, The bundle includes all 100 widgets. How to avoid and includes only what is imported into React app.
Would be appreciated by providing some sample.

Hey @agiuliano, I added your mentions of directivesProxyFile and directivesArrayFile for the Angular output targets and the module file. That’s the default now :slight_smile:

1 Like

When i follow this tutorial, (a few times now), I end up with the following error. Any assistance would be greatly appreciated. Reproducible REPO here: GitHub - chogland/nxext-stencil

$ nx build core-components --verbose

nx run core-components:build --verbose=true

NX Cannot read properties of null (reading β€˜flags’)

TypeError: Cannot read properties of null (reading β€˜flags’)
at C:\code\rds-core-nx-2\rds-core\node_modules@nxext\stencil\src\executors\stencil-runtime\stencil-config.js:43:26
at Generator.next ()
at fulfilled (C:\code\rds-core-nx-2\rds-core\node_modules\tslib\tslib.js:115:62)
at processTicksAndRejections (node:internal/process/task_queues:96:5)

β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”

NX Ran target build for project core-components (6s)

     With additional flags:
       --verbose=true

Γ—    1/1 failed
√    0/1 succeeded [0 read from cache]