Consuming a Stencil JS component in several frameworks
Tags: javascript, react, angular, vue
Published: 2020-08-15 23:51:57

## Introduction
The Stencil JS idea of writing a component once, and using it everywhere, is something I've been meaning to put into practice for a long time. This post will go over the easy and straightforward process of creating and publishing a simple Stencil component. Then, I'll go over consuming that component in React, Vue, and Angular. Anything more elaborate than the basics will be saved for the conclusion. Here we go! 

## Creating Stencil JS project
```
npm init stencil
```
The CLI will give you a few options. In this example I am going to choose `component`, and when prompted, name the project `test-demo-seanmclem`. I've included my username in the project name to ensure it's unique. If the name is taken then you will not be able to publish to NPM.

You will also need to change to your projects directory, and install the stencil dependency.
```
cd test-demo-seanmclem
npm install
```

The Stencil CLI will create our project, but it will not just be a lone, single component as the name suggests. It will generate a full Stencil project with a `components` folder. This folder will contain any components we wish export. The exported components will be included in the production build, published to NPM, and can then each be imported individually into consuming projects. The rest of the Stencil project helps facilitate publishing and consuming the project's components.

### Our Stencil Component
The Stencil CLI will add one example component to this components folder. It is called `my-component`, and it takes 3 props, `first`, `middle`, and `last`. Each being part of your name. The rendered component takes these inputs and outputs a string like `Hello, World!? I'm Your Full Name`.

Run the following to prep the project for publishing
```
npm run build
```

## Publish to NPM
We're moving quickly because this project and `my-component` already have everything we need. Let's publish it to NPM.

You will need to have an account on NPM to proceed. It's simple and free to [sign-up](https://www.npmjs.com/signup) if you haven't already. Then login to the CLI
```
npm login
```
Follow the prompts to login to the CLI, and then run -
```
npm publish
```
If everything went well the CLI should return your new libraries name@version, like mine `test-demo-seanmclem@0.0.1`. You can also find this in your npm settings>packages page.


## React
### Create project
```
npx create-react-app stencil-in-react
```
### Add component
We will need to go the index.js file and add an import. We will not import a particular component though. Instead we will import a function that will _define_ all our components exported by the Stencil project, and make them available to the react project. This is how native web components, known as Custom Elements, are added to projects. They are typically registered globally as early as possible -rather than imported where ever they are needed. 

So we'll add an import to [index.js](https://github.com/Seanmclem/stencil-in-react/blob/master/src/index.tsx) like this:
```javascript
import { defineCustomElements } from 'test-demo-seanmclem/loader';
```
And somewhere near the bottom we'll call this function. I'll go over polyfills later.
```javascript
defineCustomElements();
```

Next, in [app.js](https://github.com/Seanmclem/stencil-in-react/blob/master/src/App.tsx) you utilize your new custom element
```javascript
function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />

        <my-component first='Your' middle='Full' last='Name'></my-component>

      </header>
    </div>
  );
}
```
I replaced everything below the img tag in [my app.js](https://github.com/Seanmclem/stencil-in-react/blob/master/src/App.tsx).
That's pretty much it. You can consume simple Stencil components with simple props in React without doing anything special. More complex components might require extra work for certain props and event listeners. I'd like to do another post on this soon, but that's it for React for now.


## Vue
### Create project
```
npm install -g @vue/cli
vue create stencil-in-vue
cd stencil-in-vue
```

### Add component
```
npm install test-demo-seanmclem
```

Now we'll add defineCustomElements to one of our main files. Specifically [main.js](https://github.com/Seanmclem/stencil-in-vue2/blob/master/src/main.js) for Vue. 
```javascript
import { defineCustomElements } from 'test-demo-seanmclem/loader';
```
And again, somewhere near the bottom we'll call this function.
```javascript
defineCustomElements();
```

Next, in [App.Vue](https://github.com/Seanmclem/stencil-in-vue2/blob/master/src/App.vue) you consume the custom element. You could place it above the HelloWorld component, but I removed it entirely
```html
<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png">
    <my-component first="Your" middle="Full" last="Name"></my-component>
  </div>
</template>

<script>
export default {
  name: 'App',
}
</script>
```


## Angular
### Create project
```
npm install -g @angular/cli 
ng new stencil-in-angular
cd stencil-in-angular
```

### Add component
```
npm install test-demo-seanmclem
```
Now we'll add an import to [main.js](https://github.com/Seanmclem/stencil-in-angular2/blob/master/src/main.ts)
```javascript
import { defineCustomElements } from 'test-demo-seanmclem/loader';
```
And somewhere near the bottom we'll call this function.
```javascript
defineCustomElements();
```

Next, in [app.component.html](https://github.com/Seanmclem/stencil-in-angular2/blob/master/src/app/app.component.html) you utilize your new custom element. I replaced pretty much everything in that file.
```html
<div class="content" role="main">
  <my-component first="Your" middle="Full" last="Name"></my-component>
</div>
```
That's it for the basic implementations of Stencil generated web-components in the big 3 frameworks. I'll be writing more on the topic going forward. So feel free to follow me for more. 

## Conclusion/More Info
### Polyfills
These days you might be done supporting IE and legacy browsers. However, Stencil includes some optional polyfills for those that are easy to implement. You would just add an additional `applyPolyfills` import to your `defineCustomElements` import statement, and wrap your `defineCustomElements` call in an async `applyPolyfills().then()`. 
Read more about that [here](https://stenciljs.com/docs/react).
### React
As I mentioned react has some complications with more advanced event and prop bindings. Most can be mitigated with a manual wrapping-component, or a `react-output-target`. Read more about that [here](https://stenciljs.com/docs/react#properties-and-events) also.
### Angular ViewChild
Angular docs call out a specialized way of accessing functions on your component. Which can be useful but not always necessary. Read more about that [Here](https://stenciljs.com/docs/angular#accessing-components-using-viewchild-and-viewchildren)


Thanks for reading!