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

一、格式化目录结构

根据以下图片搭建组件库目录

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.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

查看npm,即发布成功

相关推荐
Json_181790144804 分钟前
电商拍立淘按图搜索API接口系列,文档说明参考
前端·数据库
风尚云网27 分钟前
风尚云网前端学习:一个简易前端新手友好的HTML5页面布局与样式设计
前端·css·学习·html·html5·风尚云网
木子020430 分钟前
前端VUE项目启动方式
前端·javascript·vue.js
GISer_Jing32 分钟前
React核心功能详解(一)
前端·react.js·前端框架
捂月35 分钟前
Spring Boot 深度解析:快速构建高效、现代化的 Web 应用程序
前端·spring boot·后端
深度混淆42 分钟前
实用功能,觊觎(Edge)浏览器的内置截(长)图功能
前端·edge
Smartdaili China43 分钟前
如何在 Microsoft Edge 中设置代理: 快速而简单的方法
前端·爬虫·安全·microsoft·edge·社交·动态住宅代理
秦老师Q44 分钟前
「Chromeg谷歌浏览器/Edge浏览器」篡改猴Tempermongkey插件的安装与使用
前端·chrome·edge
滴水可藏海1 小时前
Chrome离线安装包下载
前端·chrome
endingCode1 小时前
45.坑王驾到第九期:Mac安装typescript后tsc命令无效的问题
javascript·macos·typescript