"Enhance your Vue 3 projects with a dynamic library featuring universal components and full

Currently, I am in the process of developing a Vue 3 component library using Vue 3, Vite, and TypeScript. The unique aspect about this library is that it installs as a plugin and registers all components as global entities. Here is an overview of how this process looks:

// src/index.ts
const globalComponents = import.meta.glob("./components/**/*.vue", {
  eager: true,
});

export default {
  install(app: App, options: Record<string, string>) {
    Object.entries(globalComponents).forEach(
      ([item, definition]: [string, any]) => {
        const componentName = item
          ?.split("/")
          ?.pop()
          ?.replace(/\.\w+$/, "");

        app.component(componentName, definition.default);
      }
    );
  },
};

export { /* other exports */ };

In order to build this library, I utilize Vite's Library Mode, which involves the following configuration:

// vite.config.ts
export default defineConfig({
  plugins: [vue()],
  build: {
    target: "esnext",
    lib: {
      formats: ["es"],
      entry: path.resolve(__dirname, "src/index.ts"),
      fileName: (format) => `bundle.${format}.js`,
    },
    rollupOptions: {
      external: [...Object.keys(pkg.dependencies || {})],
    },
  },
});

Furthermore, the build command I use for this project includes the following steps:

vite build && vue-tsc --emitDeclarationOnly && mv dist/src dist/types

This generates a dist directory containing a .d.ts file for each individual component. Despite being able to successfully import the library into various projects, unfortunately, TypeScript support is lacking for the global components.

In my search for a solution, I came across a helpful post on Stack Overflow that suggests adding globals through augmentation:

// src/global-components.d.ts
import Component1 from "@/components/Component1.vue";

declare module "@vue/runtime-core" {
  export interface GlobalComponents {
    Component1: typeof Component1;
  }
}

Although I attempted adding a similar file directly to the library, it did not yield the desired outcome. As a workaround, I included a comparable file in the project and imported each Vue component .d.ts file from the library's dist/types/* directory to provide TypeScript support within the project. While this method works, ideally, I would prefer this functionality to be intrinsic to the library itself.

With that context in mind, my primary question is regarding the implementation of TypeScript support for global components in my library, ensuring its availability to projects utilizing it. If additional details are necessary, please feel free to request them.

Answer №1

My search led me to the original Stack Overflow answer, where I encountered a similar problem. The solution involved replacing

declare module '@vue/runtime-core'
with declare module 'vue'.

This issue arises because many applications do not include @vue/runtime-core, as discussed here and here:

Due to @vue/runtime-core not being installed in multiple projects (especially pnpm projects), the types generated by unplugin-vue-components may not function correctly. With vue already present in Vue projects, augmenting vue is sufficient for the types to work with Volar.

The same approach is outlined in the official Vue documentation on registering web components with TypeScript:

If you are working on an application or library and need to type-check your Vue components, custom elements included, it's essential to register global component typings for Vue templates and/or JSX.

Since custom elements are globally registered using native APIs, they lack type inference when used in Vue templates by default. To enable type support for Vue components registered as custom elements, we can declare global component typings through the GlobalComponents interface in Vue templates or JSX:

import { defineCustomElement } from 'vue'

// Vue Single File Component
import CounterSFC from './src/components/counter.ce.vue'

// Transform component into web components
export const Counter = defineCustomElement(CounterSFC)

// Register global typings
declare module 'vue' {
  export interface GlobalComponents {
    'Counter': typeof Counter,
  }
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Switch back and forth between two pages within the same tab on an Ionic 3 app depending on the user's login information

I am seeking a way to switch between two profile pages using the profile tab based on whether the user is a student or tutor in an ionic 3 application. ...

Utilizing the colon (:) in Vue Router: A Guide

My URL is not updating correctly after the push. I am trying to format it as: www.abc.com/istanbul-taksim-otelleri?checkin=2019-05-08&checkout=2019-05-16&filters=meal_types:full,half,etc;stars:1,2,4 const query = { checkin: '2019-05-08& ...

What is the process for incorporating a Static Class into a Declaration File in TypeScript?

I'm in the process of developing a UMD library using TypeScript. The first class I have created is a static one with a method. The name of my Library is SuperLib and here is the code snippet: export class Security { static userExists ( user: string ...

Sharing an object with a child component in Angular 2

After receiving data from a subscription, I am encountering an issue where my data is not binding to the local variable as expected. The scenario involves two components and a service. The parent component triggers a method in the service to perform an HT ...

Encountered Angular SSR Serve Error: NullInjectorError - StaticInjectorError in AppServerModule with the following reference:

While working on building an application with Angular's SSR and serving it, I encountered a specific error. All services and components have been properly injected. Error: ERROR Error [NullInjectorError]: StaticInjectorError(AppServerModule)[REQUEST] ...

The failure of lazy loading in production is a common issue faced by developers using the Cordova

My Vue.js CLI 3 application has default settings that use webpack for lazy loading the pages as needed. Here is an example: { path: "videos", component: () => import("./../views/root/videos/VideosController"), } This setup works pe ...

Discover how to set up lazy loaded child routes within a parent route that is also loaded lazily in Angular 2

Struggling to implement lazy loading for my app has been a series of challenges. I successfully implemented lazy loading for the main route, /admin, but now I am facing issues while adding another route, /admin/login. This is what I tried: admin-router.m ...

What is the best way to indicate a particular element within a subdocument array has been altered in mongoose?

I have a specific structure in my Mongoose schema, shown as follows: let ChildSchema = new Schema({ name:String }); ChildSchema.pre('save', function(next){ if(this.isNew) /*this part works correctly upon creation*/; if(this.isModifi ...

Using "array_agg" in a "having clause" with Sequelize

I am facing a particular scenario with my database setup. I have three tables named computers, flags, and computerFlags that establish relationships between them. The structure of the computerFlags table is as follows: computerName | flagId computer1 | ...

Is it possible for Vue js to display an image from the /dist/ directory even if it is not present?

Currently, I am in the process of learning Vue.js + webpack and have started a project by following these steps: f:www\> npm install -g vue-cli f:www\> vue init webpack-simple my-project f:www\> cd my-project f:www\> npm in ...

Ensuring User Authentication in Angular with Firebase: How to Dynamically Hide the Login Link in Navigation Based on User's Login Status

After successfully implementing Angular Firebase email and password registration and login, the next step is to check the user's state in the navigation template. If the user is logged in, I want to hide the login button and register button. I tried s ...

What is the method for including a dynamic image within the 'startAdornment' of MUI's Autocomplete component?

I'm currently utilizing MUI's autocomplete component to showcase some of my objects as recommendations. Everything is functioning correctly, however, I am attempting to include an avatar as a start adornment within the textfield (inside renderInp ...

Tips on utilizing the translate feature of vue-i18n within the script section of a component

For text translation in my laravel project, I am utilizing the laravel-vue-i18n-generator package to handle it in vuejs components. Below is how I have set up app.js: import VueInternationalization from 'vue-i18n'; import Locale from './vue ...

Why is the Routes module failing to acknowledge the component?

I am in the process of developing my own Portfolio and decided to use Angular 12. Despite following all of the instructions on angular.io, I am facing challenges with Routing. To demonstrate my work more effectively, I have created a Stack Blitz: My Portf ...

Incorporate CloudKit JS into Vue Application

I want to integrate CloudKit JS into my new Vue project so I can access its functions from any component within my app. As a newcomer to Vue, I appreciate your patience with me. :) Currently, I attempted adding the following code snippet in main.js: var ...

Troubleshooting Bootstrap 4 Modal in JavaScript and Vue: Uncaught ReferenceError: $ is not defined

I'm struggling to figure out how to trigger a Bootstrap 4 modal from my Vue 3 app using JavaScript. Whenever I try to launch the modal, I keep encountering this error message: $ is not defined at eval When looking for solutions, I noticed that most a ...

Updating Vue.js asynchronously using JavaScript import

I am facing a challenge with two form components that share a common JS validator. import { validateInput } from './validateInput.js' export default { data () { return { email: '<a href="/cdn-cgi/l/email-protection" class="_ ...

Adjusting the audio length in React/Typescript: A simple guide

I'm currently developing a web app with React and TypeScript. One of the components I created is called SoundEffect, which plays an mp3 file based on the type of sound passed as a prop. interface ISoundEffectProps { soundType: string, // durat ...

VueJS together with Firebase: The guide to password validation

I am currently working on a web form developed using VueJS that enables authenticated users to modify their passwords. The backend system relies on Firebase, and I am facing a challenge in validating the user's current password before initiating the p ...

Encountering an unexpected error with the InvalidCharacterError in IE11 when using VEE Validate in conjunction with Vue.js and babel-p

Encountering an issue in IE11 where I receive an InvalidCharacterError when attempting to validate a form using vee validate in vue.js. It seems like it might be related to a polyfill error, but I'm uncertain. I have tried debugging by removing certai ...