'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>&#9650;</span> : <span>&#9660;</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