Search code examples
vue.jsionic-frameworkweb-componentstenciljs

Using Stencil components with Ionic Vue


In the Stencil docs section on framework integration with Vue it states the following:

In order to use the custom element library within the Vue app, the application must be modified to define the custom elements and to inform the Vue compiler which elements to ignore during compilation.

According to the same page this can be achieved by modifying the config of your Vue instance like this:

Vue.config.ignoredElements = [/test-\w*/];

This relates to Vue 2 however. With Vue 3 (which Ionic Vue uses) you have to use isCustomElement as stated here.

Regretably, I can’t for the life of me get Vue and Stencil to play nice. I have tried setting the config like this:

app.config.compilerOptions.isCustomElement = tag => /gc-\w*/.test(tag)

This causes Vue throw the following warning in the console:

[Vue warn]: The `compilerOptions` config option is only respected when using a build of Vue.js that includes the runtime compiler (aka "full build"). Since you are using the runtime-only build, `compilerOptions` must be passed to `@vue/compiler-dom` in the build setup instead.
- For vue-loader: pass it via vue-loader's `compilerOptions` loader option.
- For vue-cli: see https://cli.vuejs.org/guide/webpack.html#modifying-options-of-a-loader
- For vite: pass it via @vitejs/plugin-vue options. See https://github.com/vitejs/vite/tree/main/p

However, I have no idea how to implement any of the above suggestions using Ionic Vue. I have been messing around with chainWebpack in config.vue.js but without success so far.

Any help would be greatly appreciated.


Solution

  • I'm not an expert in Vue but here's how I did it:

    Add the following to your ./vue.config.js (or create it if it doesn't exist):

    /**
     * @type {import('@vue/cli-service').ProjectOptions}
     */
    module.exports = {
      // ignore Stencil web components
      chainWebpack: config => {
        config.module
          .rule('vue')
          .use('vue-loader')
          .tap(options => {
            options.compilerOptions = {
              ...options.compilerOptions,
              isCustomElement: tag => tag.startsWith('test-')
            }
            return options
          })
      },
    }
    

    This will instruct Vue to ignore the test-* components. Source: https://v3.vuejs.org/guide/web-components.html#skipping-component-resolution

    Next, load the components in ./src/main.ts.

    Import the Stencil project:

    import { applyPolyfills, defineCustomElements } from 'test-components/loader';
    

    Then replace createApp(App).use(router).mount('#app') with:

    const app = createApp(App).use(router);
    
    // Bind the custom elements to the window object
    applyPolyfills().then(() => {
        defineCustomElements();
    });
    
    app.mount('#app')
    

    Source: https://stenciljs.com/docs/vue