勿忘初心做自己 发表于 2026-2-26 17:05:07

【vue组件库搭建06】组件库构建及npm发包

一、格式化目次结构

根据以下图片搭建组件库目次
https://dis.qidao123.com/imgproxy/aHR0cHM6Ly9pLWJsb2cuY3NkbmltZy5jbi9kaXJlY3QvOGJmYmRhZmViMDFhNDM2YTgyZDE2MjRhNjczNDE2NGUucG5n
index.js作为入口文件,将全部组件引入,并注册组件名称

import { EButton } from "./Button";
export * from "./Button";
import { ECard } from "./Card";
export * from "./Card";

const cmpts = ;

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中展示:
https://dis.qidao123.com/imgproxy/aHR0cHM6Ly9pLWJsb2cuY3NkbmltZy5jbi9kaXJlY3QvOGY0NGQ2ZmIxZTc3NDdlN2IxYWNhNTU3MjUzMGY2ZTMucG5n
EButton是我们开辟的button组件,在Button.md中引入
https://dis.qidao123.com/imgproxy/aHR0cHM6Ly9pLWJsb2cuY3NkbmltZy5jbi9kaXJlY3QvY2Y5ZmUyMDFlODdhNGQ2YWE0NzEwYzYzZGVlNmMzZDAucG5n
 效果:
https://dis.qidao123.com/imgproxy/aHR0cHM6Ly9pLWJsb2cuY3NkbmltZy5jbi9kaXJlY3QvMTI1MTQyNTdmMzlhNGI0NjgzNTM2YTU1YjY4YjQ3YWEucG5n
二、组件库构建

 新建build文件夹,以及以下三个文件:
https://dis.qidao123.com/imgproxy/aHR0cHM6Ly9pLWJsb2cuY3NkbmltZy5jbi9kaXJlY3QvOGRhYTljZTE3ZDcyNDY1NTgxMTMwNDBkZmE1NjgwODUucG5n

// base.confi.js

import { 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.js

import { 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.js

import 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
https://dis.qidao123.com/imgproxy/aHR0cHM6Ly9pLWJsb2cuY3NkbmltZy5jbi9kaXJlY3QvNTI2YjI3NjIzMjE4NDk2YmJmM2YwODY5MGVjODhiMjcucG5n
查察npm,即发布乐成 
https://dis.qidao123.com/imgproxy/aHR0cHM6Ly9pLWJsb2cuY3NkbmltZy5jbi9kaXJlY3QvN2ZkZmFhNTgzY2IxNDIzMTk2NDZkZDU0NmYzYWM4ZTAucG5n
页: [1]
查看完整版本: 【vue组件库搭建06】组件库构建及npm发包