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

news2024/11/22 16:42:34

一、格式化目录结构

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

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,即发布成功 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1904883.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

并查集(还有反集也在)

一.定义 定义: 并查集是一种树型的数据结构,用于处理一些不相交集合的合并及查询问题(即所谓的并、查)。比如说,我们可以用并查集来判断一个森林中有几棵树、某个节点是否属于某棵树等。 主要构成: 并查集…

如何将Grammarly内嵌到word中(超简单!)

1、下载 安装包下载链接见文章结尾 官网的grammarly好像只能作为单独软件使用,无法内嵌到word中🧐🧐🧐 2、双击安装包(安装之前把Office文件都关掉) 3、安装完成,在桌面新建个word文件并打开 注…

【Spring AOP 源码解析前篇】什么是 AOP | 通知类型 | 切点表达式| AOP 如何使用

前言(关于源码航行) 在准备面试和学习的过程中,我阅读了还算多的源码,比如 JUC、Spring、MyBatis,收获了很多代码的设计思想,也对平时调用的 API 有了更深入的理解;但过多散乱的笔记给我的整理…

PXIe-7976【K410T】

起售价 RMB 152,880.00 块RAM(BRAM): 28620 kbit 动态RAM(DRAM): 2 GB FPGA: Kintex-7 410T PXI背板链路: PCI-Express Gen2 x 8 FPGA片: 63550 DSP片: 1540

240707-Sphinx配置Pydata-Sphinx-Theme

Step A. 最终效果 Step B. 为什么选择Pydata-Sphinx-Theme主题 Gallery of sites using this theme — PyData Theme 0.15.4 documentation Step 1. 创建并激活Conda环境 conda create -n rtd_pydata python3.10 conda activate rtd_pydataStep 2. 安装默认的工具包 pip in…

基于Java的水果商品销售网站

1 水果商品销售网站概述 1.1 课题简介 随着电子商务在当今社会的迅猛发展,水果在线销售已逐渐演变为一种极为便捷的购物方式,日益受到人们的青睐。本系统的设计初衷便是构建一个功能完备、用户体验友好的水果销售平台,致力于为用户提供优质、…

入门PHP就来我这(高级)12 ~ 获取数据

有胆量你就来跟着路老师卷起来! -- 纯干货,技术知识分享 路老师给大家分享PHP语言的知识了,旨在想让大家入门PHP,并深入了解PHP语言。 1 从结果集中获取一行作为对象 表中数据行如下: 利用mysqli_fetch_array()函数获…

SLF4J的介绍与使用(有logback和log4j2的具体实现案例)

目录 1.日志门面的介绍 常见的日志门面 : 常见的日志实现: 日志门面和日志实现的关系: 2.SLF4J 的介绍 业务场景(问题): SLF4J的作用 SLF4J 的基本介绍 日志框架的绑定(重点&#xff09…

【CSS in Depth 2精译】2.5 无单位的数值与行高

当前内容所在位置 第一章 层叠、优先级与继承第二章 相对单位 2.1 相对单位的威力2.2 em 与 rem2.3 告别像素思维2.4 视口的相对单位2.5 无单位的数值与行高 ✔️2.6 自定义属性2.7 本章小结 2.5 无单位的数值与行高 有些属性允许使用无单位的数值(unitless value…

Linux:DHCP服务配置

目录 一、DHCP概述以及DHCP的好处 1.1、概述 1.2、DHCP的好处 二、DHCP的模式与分配方式 2.1、模式 2.2、DHCP的分配方式 三、DHCP工作原理 四、安装DHCP服务 五、DHCP局部配置并且测试 5.1、subnet 网段声明 5.2、客户机预留指定的固定ip地址 一、DHCP概述以及DHCP…

【Java13】包

“包”这个机制,类似于分组。主要作用是区分不同组内的同名类。例如,高三三班有一个“王五”,高二八班也有一个“王五”。高三三班和高三八班就是两个不同的包。 Java中的包(package)机制主要提供了类的多层命名空间&…

驾校管理系统设计

驾校管理系统设计旨在提高驾校运营效率、学员管理、教练安排、考试预约、财务结算等方面的能力。以下是一个基本的设计框架,包括关键模块和数据表设计: 1. 系统架构设计 前端界面:提供给学员、教练和管理员使用的Web界面或移动应用&#xf…

51单片机STC89C52RC——16.1 五项四线步进电机

目的/效果 让步进电机 正向转90度,逆向转90度 一,STC单片机模块 二,步进电机 2.2 什么是步进电机? 步进电机可以理解为:是一个按照固定步幅运动的“小型机器”。它与普通电机不同点在于,普通电机可以持…

插入排序——C语言

假设我们现在有一个数组,对它进行排序,插入排序的算法如同它的名字一样,就是将元素一个一个插入到合适的位置,那么,该如何做呢? 如果我们要从小到大进行排序的话,步骤如下: 1.对于…

WAWA鱼曲折的大学四年回忆录

声明:本文内容纯属个人主观臆断,如与事实不符,请参考事实 前言: 早想写一下大学四年的总结了,但总是感觉无从下手,不知道从哪里开始写,通过这篇文章主要想做一个记录,并从现在的认…

大数据之路 读书笔记 Day4 数据同步

回顾: Day 3 总结了无限客户端的日志采集 大数据之路 读书笔记 Day 3Day 2总结了浏览器端的日志采集 大数据之路 读书笔记 Day 2 数据同步 阿里数据体系中的数据同步,主要指的是在不同的数据存储系统之间进行数据的传输与更新,以保证数据的一…

自用款 复制粘贴工具 Paste macOS电脑适配

Paste是一款专为Mac和iOS用户设计的剪贴板管理工具,它提供了强大的剪贴板增强功能。Paste能够实时记录用户复制和剪切的内容,包括文本、图片、链接等多种数据类型,并形成一个可视化的剪贴板历史记录,方便用户随时访问和检索。此外…

【密码学】密码学中的四种攻击方式和两种攻击手段

在密码学中,攻击方式通常指的是密码分析者试图破解加密信息或绕过安全机制的各种策略。根据密码分析者对明文、密文以及加密算法的知识程度,攻击可以分为以下四种基本类型: 一、四种攻击的定义 (1)唯密文攻击(COA, C…

蚂蚁全媒体总编刘鑫炜谈新媒体时代艺术家如何创建及提升个人品牌

新媒体时代艺术家如何创建及提升个人品牌形象——专访蚂蚁全媒体总编刘鑫炜 图为蚂蚁全媒体总编刘鑫炜 在新媒体风潮席卷全球的今天,传统艺术与新媒体技术的融合越来越紧密。这种变革不仅改变了艺术作品的呈现方式,也给艺术家们提供了更多的可能性。那么…

python 10个自动化脚本

目录 🌟 引言 📚 理论基础 🛠️ 使用场景与代码示例 场景一:批量重命名文件 场景二:自动下载网页内容 场景三:数据清洗 场景四:定时执行任务 场景五:自动化邮件发送 场景六…