一、格式化目录结构
根据以下图片搭建组件库目录
index.js作为入口文件,将所有组件引入,并注册组件名称
import { EButton } from "./Button";
export * from "./Button";
import { ECard } from "./Card";
export * from "./Card";const cmpts = [EButton, ECard];const EricUI = {install(Vue) {cmpts.forEach(cmpt => {Vue.component(cmpt.name, cmpt);});},
};export default EricUI;
utils.js:给组件绑定注册方法
export function withInstall(component) {component.install = app => {app.component(component.name, component);};return component;
}
在main.js中引入,方便后续使用
import { createApp } from "vue";
import "./style.css";
import App from "./App.vue";import Antd from "ant-design-vue";
import "ant-design-vue/dist/antd.less";import EricUI from "../components";const app = createApp(App).use(Antd).use(EricUI).mount("#app");
在docs\.vitepress\theme\index.ts同样引入
// https://vitepress.dev/guide/custom-theme
import { h } from 'vue'
import type { Theme } from 'vitepress'
import DefaultTheme from 'vitepress/theme'import Antd from 'ant-design-vue';
import './antd-overwrite.less'import { AntDesignContainer } from '@vitepress-demo-preview/component'
import '@vitepress-demo-preview/component/dist/style.css'import './style.css'import HomeImage from './HomeImage.vue'
import EricUI from "../../../components";export default {extends: DefaultTheme,Layout: () => {return h(DefaultTheme.Layout, null, {// https://vitepress.dev/guide/extending-default-theme#layout-slots'home-hero-image': () => h(HomeImage)})},enhanceApp({ app, router, siteData }) {app.use(Antd)app.use(EricUI)app.component('demo-preview', AntDesignContainer)}
} satisfies Theme
到此为止,组件库开发的组件可以在docs中展示:
EButton是我们开发的button组件,在Button.md中引入
效果:
二、组件库构建
新建build文件夹,以及以下三个文件:
// base.confi.jsimport { fileURLToPath, URL } from "node:url";
import { defineConfig } from "vite";// 文档: https://vitejs.dev/config/
export default defineConfig({minify: false,css: {preprocessorOptions: {less: {javascriptEnabled: true,modifyVars: {"ant-prefix": "ant",},},},},plugins: [],resolve: {alias: {"@": fileURLToPath(new URL("../src", import.meta.url)),},},
});
// lib.config.jsimport { defineConfig } from "vite";
import { fileURLToPath, URL } from "node:url";
import vue from "@vitejs/plugin-vue";
import lessEntry from "./vite-plugin-less-entry";
import baseConfig from "./base.config";
import vueJsx from "@vitejs/plugin-vue-jsx";
import { viteStaticCopy } from "vite-plugin-static-copy";export default defineConfig({...baseConfig,build: {sourcemap: true,outDir: "lib",lib: {entry: fileURLToPath(new URL("../components/index.js", import.meta.url)),name: "EricUI",fileName: format => `eric-ui.${format}.js`,},rollupOptions: {// 确保外部化处理那些你不想打包进库的依赖external: ["vue","@ant-design/icons-vue","vxe-table","xe-utils","@vitepress-demo-preview/component","@vitepress-demo-preview/plugin",],},},plugins: [vue(),vueJsx(),viteStaticCopy({targets: [{src: "components/**/*.less",dest: "/",},],structured: true,}),lessEntry({// 生成的入口文件名entry: "components",// libPath需要与viteStaticCopy中的dest保持一致libPath: "components",name: "style",}),],
});
// vite-plugin-less-entry.jsimport path from "node:path";
import fs from "fs-extra";const name = "vite-plugin-custom-less-entry";
export const formatConsole = msg => `[${name}] ${msg}`;
/*** 生成项目less的入口文件*/
export default function lessEntryPlugin({ entry, libPath, name }) {let outputed = false;let rootConfig = null;return {name,apply: "build",order: "post",configResolved(config) {rootConfig = config;},writeBundle() {if (outputed) {return;}outputed = true;// 遍历entry下的index.less文件,生成${name}.less文件const componentsPath = path.join(rootConfig.root, entry);let componentsLessContent = "";fs.readdir(componentsPath, (err, files) => {files.forEach(file => {if (fs.existsSync(path.join(componentsPath, file, "index.less"))) {componentsLessContent += `@import "./${libPath}/${path.posix.join(file,"index.less")}";\n`;}});const lessEntryFile = path.join(rootConfig.root,rootConfig.build.outDir,`${name}.less`);fs.outputFile(lessEntryFile, componentsLessContent, err => {if (err) {console.error(formatConsole("Failed to generate less entry file"));} else {console.info(formatConsole("Successfully generated less entry file"));}});});},};
}
配置package.json:
{"name": "eric-ui-lib","version": "0.0.2","description": "eric-ui组件库","main": "lib/eric-ui.umd.js","module": "lib/eric-ui.es.js","files": ["lib"],"keywords": ["eric-ui","eric","ui"],"author": "Eric","type": "module","scripts": {"dev": "vite","build": "vite build","build:lib": "vite build --config ./build/lib.config.js","preview": "vite preview","docs:dev": "vitepress dev docs","docs:build": "vitepress build docs","docs:preview": "vitepress preview docs"},"dependencies": {"@vitepress-demo-preview/component": "^2.3.2","@vitepress-demo-preview/plugin": "^1.2.3","ant-design-vue": "^3.2.20","fs-extra": "^11.2.0","less-loader": "^12.2.0","vite-plugin-static-copy": "^1.0.6","vue": "^3.4.29"},"devDependencies": {"@vitejs/plugin-vue": "^5.0.5","@vitejs/plugin-vue-jsx": "^4.0.0","less": "^4.2.0","vite": "^5.3.1","vitepress": "^1.2.3"}
}
三、npm发布
npm login 登录,没有注册的自行注册
npm publish
查看npm,即发布成功