'Stencil usage - how to load external dependent stencil component in stencil module - but not to add in final build
I am planning to create filter box web component using @stencil/core library. In this filter component, i need to load external atomic web components like (dropdown, input, radio) implemented using @stencil/core itself. But i dont want these external web component to be part of final bundle of filter web component
Usage: I want to use this filter component in host application using Angular.
And its responsibility of HOST application to import all atomic web component/external dependencies like dropdown/radio web component. Filter web component should not load these dependencies or take them in its build
Example: **Dropdown **component's tsx file - bundled as dropdown npm package
import { Component, Prop, State, Event, EventEmitter, h } from '@stencil/core';
@Component({
tag: 'my-dropdown',
styleUrl: 'dropdown.scss'
})
export class myDropdown {
/**
* @public
* @property items
*
* Defines the data that we want to load into our dropdown area
*
*/
public items: Array<any> = [
{
heading: 'Virtual DOM',
description: 'A tree of custom objects representing a part of the DOM which can be acted upon quicker than manipulating the DOM itself'
},
{
heading: 'Async rendering',
description: 'Allows parts of a component state to be rendered asynchronously (I.e. via XHR)'
},
{
heading: 'Reactive data-binding',
description: 'Allows data binding to be implemented through binding a state variable to an onChange event which allows the state to be changed as the input value changes'
}
];
/**
* @public
* @property name
* @type String
*
* This will accept values supplied by a name attribute
* on the component HTML
*/
@Prop() name: string;
/**
* @type boolean
*
* This will track state changes (I.e. whether the
* dropdown component is open or closed)
*/
@State() toggle: boolean = false;
@Event({
eventName: 'itemClicked',
composed: true,
bubbles: true,
cancelable: true
}) itemClicked: EventEmitter;
/**
* @type EventEmitter
*
* Track component events (I.e. activation of dropdown component)
*/
@Event({
composed: true,
bubbles: true,
eventName: 'toggleDropdown',
cancelable: true
}) onToggle: EventEmitter;
/**
* @public
* @method toggleComponent
*
* This will manage the dropdown component event and state changes
*/
toggleComponent(): void {
this.toggle = !this.toggle;
// When the user click emit the toggle state value
// A event can emit any type of value
this.onToggle.emit({ visible: this.toggle });
}
onListItemClicked(ind) {
console.log(ind);
this.itemClicked.emit({ index: ind });
}
/**
* Create HTML representation of component DOM and return this
for output to the browser DOM
*/
render() {
return (
<div class="container">
<h2 onClick={() => this.toggleComponent()}>{this.name} {this.toggle ? <span>▲</span> : <span>▼</span>}</h2>
<ul class={this.toggle ? 'active' : 'inactive'}>
{this.items.map((item, index) => <li onClick={this.onListItemClicked.bind(this, index)}><h3>{item.heading}</h3><p>{item.description}</p></li>)}
</ul>
</div>
)
}
}
In my wrapper web component - MyComponent.tsx
import { Component, Prop, h, Listen } from '@stencil/core';
import { IButtonClickEvent } from '../simple-button/simple-button.model';
import 'dropdown';
@Component({
tag: 'my-component',
styleUrl: 'my-component.css',
shadow: true
})
export class MyComponent {
/**
* The first name
*/
@Prop() first: string;
/**
* The middle name
*/
@Prop() middle: string;
/**
* The last name
*/
@Prop() last: string;
private getText(): string {
return this.first + this.middle + this.last;
}
@Listen('buttonClicked')
onButtonClickHandler(evt:CustomEvent<IButtonClickEvent>){
console.log(evt)
}
@Listen('itemClicked')
itemClickedHandler(event: CustomEvent) {
console.log('Received the custom itemClicked event: ', event.detail);
}
render() {
return (
<div class="container" style={{
'font-size': '12px',
'padding':'10px',
'border':'2px solid red'
}}>
<div class="sc-abc abc">Hello, World! I'm {this.getText()}</div>
<simple-button type="raised" color="primary">Child</simple-button>
<my-dropdown name="Stencil key features"></my-dropdown>
</div>
);
}
}
I m loading this dropdown using 'import dropdown' - this works fine. But issue with this is - stencil config considers this dropdown as well in final build of MyComponent. I want to ignore dropdown bundle to be included in final build. Host application (Angular app) to install and load dropdown as per requirement
Solution 1:[1]
After some debugging found issue
- Since i need to load dropdown component as external dependency, it cannot be imported in MyComponent tsx.
- loaded external dropdown component in index.html directly via below script inclusion
<script type="module" src="/build/dropdown/dist/dropdown/dropdown.esm.js"></script>
<script nomodule src="/build/dropdown/dist/esm/dropdown.js"></script>
Also made changes in stencil config to copy dropdown component while working on local
import { Config } from '@stencil/core';
import { sass } from '@stencil/sass';
export const config: Config = {
namespace: 'demo',
outputTargets: [
{
type: 'dist',
esmLoaderPath: '../loader',
},
{
type: 'dist-custom-elements',
},
{
type: 'docs-readme',
},
{
type: 'www',
serviceWorker: null, // disable service workers
copy: [
{
src: '../node_modules/dropdown/',
dest: 'build/dropdown'
}
]
},
],
plugins: [sass()]
};
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | hakimuddin noor |
