Vue component auto-importing plugin for multiple build tools including Vite, Webpack, Rollup, and esbuild
—
Built-in component discovery from directories and extensible resolver system for UI libraries, with support for custom resolution logic and namespace management.
Automatic component discovery from configured directories with flexible naming and namespace support.
/**
* Component discovery configuration
*/
interface ComponentDiscoveryOptions {
/** Directories to search for components */
dirs?: string | string[];
/** File extensions to consider as components */
extensions?: string | string[];
/** Search subdirectories recursively */
deep?: boolean;
/** Use directory structure as component namespaces */
directoryAsNamespace?: boolean;
/** Component name prefix */
prefix?: string;
}Usage Examples:
// Basic directory discovery
Components({
dirs: ["src/components"],
extensions: ["vue", "tsx"],
deep: true,
});
// With namespacing
Components({
dirs: ["src/components"],
directoryAsNamespace: true,
// src/components/form/Input.vue becomes <FormInput>
});Extensible resolver system for custom component resolution logic, supporting both function-based and object-based resolvers.
/**
* Function-based component resolver
* @param name - Component name to resolve
* @returns Component resolution result
*/
type ComponentResolverFunction = (name: string) => ComponentResolveResult;
/**
* Object-based component resolver with type specification
*/
interface ComponentResolverObject {
/** Type of items this resolver handles */
type: "component" | "directive";
/** Resolution function */
resolve: ComponentResolverFunction;
}
/**
* Union type for all resolver types
*/
type ComponentResolver = ComponentResolverFunction | ComponentResolverObject;
/**
* Result of component resolution
*/
type ComponentResolveResult = Awaitable<string | ComponentInfo | null | undefined | void>;
/**
* Component information returned by resolvers
*/
interface ComponentInfo {
/** Import alias name */
as?: string;
/** Component name */
name?: string;
/** Import path or module name */
from: string;
/** Side effect imports (CSS, etc.) */
sideEffects?: SideEffectsInfo;
}
type SideEffectsInfo = (ImportInfo | string)[] | ImportInfo | string | undefined;
interface ImportInfo {
as?: string;
name?: string;
from: string;
}Usage Examples:
// Function-based resolver
Components({
resolvers: [
(name: string) => {
if (name.startsWith("My")) {
return {
name,
from: `@/components/${name}.vue`,
};
}
},
],
});
// Object-based resolver with type
Components({
resolvers: [
{
type: "component",
resolve: (name: string) => {
if (name.match(/^V[A-Z]/)) {
return {
name,
from: "vuetify/components",
sideEffects: "vuetify/styles",
};
}
},
},
],
});Multiple resolvers can be configured and will be called in order until one returns a result.
/**
* Multiple resolvers are processed in order
*/
interface ResolverChainOptions {
resolvers?: ComponentResolver[];
}Usage Examples:
Components({
resolvers: [
// First try UI library resolvers
ElementPlusResolver(),
AntDesignVueResolver(),
// Then custom business logic
(name: string) => {
if (name.startsWith("App")) {
return { name, from: `@/components/app/${name}.vue` };
}
},
// Finally fallback resolver
(name: string) => {
return { name, from: `@/components/fallback/${name}.vue` };
},
],
});Advanced features for complex resolution scenarios including conditional resolution and dynamic imports.
/**
* Advanced resolver with conditional logic
*/
interface AdvancedResolverResult {
/** Component name override */
name?: string;
/** Import source */
from: string;
/** Import alias */
as?: string;
/** Side effects to import */
sideEffects?: SideEffectsInfo;
}Usage Examples:
// Conditional resolution based on environment
Components({
resolvers: [
(name: string) => {
// Use different components for different environments
if (name === "DataGrid") {
const isDev = process.env.NODE_ENV === "development";
return {
name,
from: isDev ? "@/components/dev/DataGrid.vue" : "@/components/prod/DataGrid.vue",
};
}
},
],
});
// Dynamic resolution with side effects
Components({
resolvers: [
(name: string) => {
if (name.startsWith("Chart")) {
return {
name,
from: "chart-library",
sideEffects: [
"chart-library/styles/index.css",
{ from: "chart-library/themes", name: "defaultTheme" },
],
};
}
},
],
});Access to resolution context for advanced use cases.
/**
* Extended resolver function with context
*/
type ContextualResolverFunction = (
name: string,
context?: ResolutionContext
) => ComponentResolveResult;
interface ResolutionContext {
/** File path where component is being used */
filename?: string;
/** Additional context information */
[key: string]: any;
}Usage Examples:
// Context-aware resolution
Components({
resolvers: [
(name: string, context?: ResolutionContext) => {
if (context?.filename?.includes("/admin/")) {
// Use admin-specific components
return { name, from: `@/components/admin/${name}.vue` };
}
return { name, from: `@/components/public/${name}.vue` };
},
],
});Utility functions commonly used in custom resolvers.
/**
* String case conversion utilities
*/
function camelCase(str: string): string;
function kebabCase(str: string): string;
function pascalCase(str: string): string;Usage Examples:
import { camelCase, kebabCase, pascalCase } from "unplugin-vue-components";
Components({
resolvers: [
(name: string) => {
// Convert PascalCase component name to kebab-case file name
const fileName = kebabCase(name);
return {
name,
from: `@/components/${fileName}.vue`,
};
},
],
});Common patterns for component name resolution and transformation.
Usage Examples:
// Prefix-based resolution
Components({
resolvers: [
(name: string) => {
// Handle prefixed components: AppButton -> app/Button.vue
const match = name.match(/^App(.+)$/);
if (match) {
return {
name,
from: `@/components/app/${match[1]}.vue`,
};
}
},
],
});
// Namespace-based resolution
Components({
resolvers: [
(name: string) => {
// Handle namespaced components: FormInput -> form/Input.vue
const parts = name.match(/^([A-Z][a-z]+)([A-Z].+)$/);
if (parts) {
const [, namespace, component] = parts;
return {
name,
from: `@/components/${namespace.toLowerCase()}/${component}.vue`,
};
}
},
],
});Proper error handling in custom resolvers.
Usage Examples:
Components({
resolvers: [
(name: string) => {
try {
// Custom resolution logic that might fail
if (name.startsWith("External")) {
const moduleName = name.replace("External", "").toLowerCase();
// Validate module exists
require.resolve(`external-components/${moduleName}`);
return {
name,
from: `external-components/${moduleName}`,
};
}
} catch (error) {
// Silently fail - let other resolvers handle it
return null;
}
},
],
});Install with Tessl CLI
npx tessl i tessl/npm-unplugin-vue-components