Reputation: 33
I am currently testing stencil js. For now I want to write stencil components and include them within a VUE/React project. The official website of stencil already shows how to integrate them within a framework (https://stenciljs.com/docs/overview). But they assume that your own stencil component library has already been published to npm.
Is there a way to integrate stencil components locally into a framework to test them without publishing them first?
Upvotes: 3
Views: 3557
Reputation: 1285
I've had quite a bit of trouble with this myself so will provide an answer specifically for Vue 3 as Stencil's Framework Integrations guide seems to refer only to Vue 2.
Following the Getting Started guide run npm init stencil
. Choose the component
option.
There was a bug in v2.7.0
so I update to v2.8.0
with npm i @stencil/core@latest --save-exact
Build the project with npm run build
By default, the stencil project configures multiple build targets, to make it easier to see what build files are being used you can edit the stencil config to only include the custom elements bundle:
\\ stencil.config.ts
outputTargets: [
{
type: 'dist-custom-elements-bundle',
},
{
type: 'dist',
esmLoaderPath: '../loader',
},
],
You also need the 'dist' type for the .d.ts
typings file to be generated with your custom-elements (not sure why).
Using a globally installed Vue CLI @vue/[email protected]
create a new Vue 3 default project.
Install your stencil component project
npm install --save ../<path>/stencil-component
as a dependency of your vue app.
Following the Vue CLI - Troubleshooting guide add a vue.config.js
file to the root of your Vue 3 project with the line config.resolve.symlinks(false),
In the same file we need to configure Using Custom Elements in View
\\ vue.config.js
module.exports = {
chainWebpack: (config) => {
config.resolve.symlinks(false),
config.module
.rule("vue")
.use("vue-loader")
.tap((options) => ({
...options,
compilerOptions: {
isCustomElement: (tag) => tag.includes("my-"),
},
}));
},
};
Now we can declare the custom elements, but in the Vue 3 way
\\ main.js
import { createApp } from 'vue'
import App from './App.vue'
import { defineCustomElements } from "stencil-component";
defineCustomElements();
createApp(App).mount('#app');
You can now use your custom component as normal. Here's what my App.vue
file looked like after hacking the example starter code:
<template>
<my-component first="Andy" middle="2K" last="11"></my-component>
</template>
<script>
import { MyComponent } from "stencil-component";
export default {
name: 'App',
components: {
MyComponent
}
}
</script>
No ESLint configuration found in /<path>/stencil-component/dist/custom-elements.
Fixed by telling webpack not to resolve symlinks in vue.config.js
This error occurs in the browser after a successful compilation.
Resolved by telling webpack / vue not to resolve your custom components
There are no errors and your component is showing in the DOM inspector but not appearing on the page.
You need to defineCustomElements()
in main.js
.
I've had some variation of this error when trying to import and use my component but haven't been able to reproduce it just now. Doing all of the above and restarting the dev server works fine for me.
Upvotes: 3
Reputation: 1113
For local integration, you can reference the esm.js
file inside www/build
folder which can be used in the head tag of the Vue/React project.
For eg if you have the below 2 apps
stencil-components
- stencil components
stencil-react
- sample react app which will consume the components.
Once you run stencil-components by npm run start
it will be hosted at 3333 (by default).
Including below line in head ofindex.html
of stencil-react
will integrate components with live reloading on change.
<script type="module" src="http://localhost:3333/build/stencil-components.esm.js"></script>
Upvotes: 1
Reputation: 23311
Instead of publishing or packing your packages, you could utilize TypeScript's path mapping feature.
This allows you to write your import statements just as you would with a published package, but behind the scenes TypeScript maps the imports to their given source code location.
Here's an example of a tsconfig.json with path mapping added to the compiler options:
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"ui-components": ["libs/ui-components"],
"ui-components/loader": ["libs/ui-components/dist/loader/index.cjs.js"],
"ui-components-react": ["generated/ui-components-react/src/components.ts"]
},
...
As you can see, it has 3 mappings: the path to the core Stencil components ui-components
, the path to the generated React components which are exposed as ui-components-react
, as well as the generated loader ui-components/loader
which provides the bridge between the Custom elements and the React wrappers.
I created a full working example for Stencil Web Components with generated bindings and wrappers for React that comes without the need of publishing any package: Nx Stencil React.
Please note that this answer is based on @stencil/core 1.14.0
or below. Future versions may have a different approach on generating the framework integrations.
Upvotes: 5
Reputation: 4968
Yes, you can use npm-link for that.
cd my-component-lib
npm link
cd ../my-app
npm link my-component-lib # or whatever you have named the project in package.json
If you have any problems with that (e. g. with paths not resolving properly), you can also try to pack your package and install the packed version instead, using npm-pack:
cd my-component-lib
npm pack
cd ../my-app
npm install ../my-component-lib/my-component-lib-1.0.0.tgz
Linking is preferable though because changes to your component library will be reflected immediately (after a rebuild), whereas with packing you'd have to re-pack and re-install it after every change to your lib.
Upvotes: 9