当前位置: 首页 > news >正文

Vite+Vue3 开发UI组件库并发布到npm

        一直对开源UI组件库比较感兴趣,摸索着开发了一套,虽然还只是开始,但是从搭建到发布这套流程基本弄明白了,现在分享给大家,希望对同样感兴趣的同学有所帮助。

        目前我的这套名为hasaki-ui的组件库仅有两个组件,大致成果如下,后续有时间会继续完善。

         该项目采用的技术栈为Vite + Vue3,还使用了一些基本的Markdown知识,阅读本文档前,希望你至少对vue有些基础,那么我们正式开始。

一、创建一个Vite项目

        参照vite官网,打开命令行,执行上述命令之一,按提示操作即可,创建完成后,你得到了一个以你创建的项目名为名的一个文件夹,我的为hasaki-ui,直接以成品进行说明吧。

二、组件开发 

         本文重点不在于某个组件的开发,而是库开发的配置、发布流程,所以在此以一个很简单的demo组件作为说明。

        doc.md为组件的说明文档,一般是用 Markdown 来写。这里我们需要使用 vite-plugin-vue-markdown插件来将 md 文件转换成 vue 文件。

// doc.md
<script setup>
import doc from './doc.vue';
import PreviewCode from '@/components/PreviewCode.vue'
</script># DEMO<doc/>
<PreviewCode compName="demo" />

doc.vue 为展示demo组件的vue文件

// doc.vue
<template><div class="demo-doc"><Demo /></div>
</template>
<script lang="ts">
export default {name: 'DemoDoc'
}
</script>
<script lang="ts" setup></script>
<style lang="scss" scoped>
.demo-doc {width: 100%;height: 100%;padding: 20px;
}
</style>

 库组件

// Demo.vue
<template><div class="demo">Demo is here</div>
</template>
<script lang="ts">
export default {name: 'Demo'
}
</script>
<script lang="ts" setup>
import { onMounted } from 'vue'onMounted(() => {console.log('demo 出现啦')
})
// endregion
</script>
<style lang="scss" scoped>
.demo {height: 100%;width: 100%;display: flex;flex-direction: column;overflow: hidden;
}
</style>

 PreviewCode.vue组件用于获取组件源码,用于在页面展示源码

// PreviewCode.vue
<template><div class="preview-code"><div class="showCode" @click="showOrhideCode"><span>{{ showCode ? '隐藏代码' : '显示代码' }} &lt; &gt;</span></div><el-scrollbar><transition><pre v-highlight v-if="showCode"><code>{{ sourceCode }}</code></pre></transition></el-scrollbar></div>
</template><script setup>
import { onMounted, ref } from 'vue'const props = defineProps({compName: {type: String,default: '',require: true}
})const showCode = ref(false)
const sourceCode = ref('')const showOrhideCode = () => {showCode.value = !showCode.value
}const getSourceCode = async () => {let code = await import(/* @vite-ignore */ `@/components/hasaki-ui/${props.compName}/doc/doc.vue?raw`)sourceCode.value = code.default
}onMounted(() => {getSourceCode()
})
</script>
<style lang="scss">
.preview-code {height: 300px;.showCode {cursor: pointer;color: #777;text-align: right;padding-right: 50px;&:hover {color: #409eff;}}
}.v-enter-active,
.v-leave-active {transition: all 0.5s ease;
}.v-enter-from,
.v-leave-to {opacity: 0;transform: translateY(200px);
}
</style>

 组件出口

// index.ts
import ElTablePagination from './ElTablePagination/ElTablePagination.vue'
import SelectTree from './SelectTree/SelectTree.vue'
import Demo from './demo/Demo.vue'// 按需引入
export { ElTablePagination, SelectTree, Demo }const component = [ElTablePagination, SelectTree, Demo]const HasakiUI = {install(App: any) {component.forEach((item) => {App.component(item.name, item)})}
}export default HasakiUI

在src的main.ts中引入组件库

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import HasakiUI from './components/hasaki-ui'import hljs from 'highlight.js' // 引入代码高亮文件
import 'highlight.js/styles/color-brewer.css'const app = createApp(App)app.directive('highlight', function (el) {const blocks = el.querySelectorAll('pre code')blocks.forEach((block) => {hljs.highlightBlock(block)})
})app.use(router)
app.use(HasakiUI)
app.mount('#app')

接下来我们简单写下项目外壳样式

// views/home-page.vue
<template><div class="home-page"><div class="home-page-sidebar"><div class="logo"><img src="/favicon.ico" alt="" />hasaki-ui</div><ul v-for="item in routes" :key="item"><liv-for="(ele, index) in item.children":key="ele":class="{ active: mIndex == index }"@click="goPath(ele, index)">{{ ele.name }}</li></ul></div><main class="home-page-main"><router-view></router-view></main></div>
</template><script setup>
import { computed, ref } from 'vue'
import { useRouter } from 'vue-router'const router = useRouter()
const mIndex = ref(sessionStorage.getItem('mIndex') || '0')
const routes = computed(() => router.options.routes)const goPath = (ele, index) => {mIndex.value = indexrouter.push({path: ele.path})sessionStorage.setItem('mIndex', index)
}
</script><style lang="scss" scoped>
.home-page {display: flex;justify-content: space-between;width: 100%;height: 100%;overflow: hidden;&-sidebar {width: 200px;height: 100%;border-right: 1px solid #eee;text-align: center;.logo {display: flex;align-items: center;padding: 15px;font-size: 20px;img {width: 25px;margin-right: 10px;}}ul {li {height: 50px;line-height: 50px;cursor: pointer;}.active {color: #409eff;background-color: #ecf5ff;border-right: 1px solid #409eff;}}}&-main {flex: 1;padding: 20px 50px;overflow-y: auto;}
}
</style>

配置路由

// router/index.ts
import { createRouter, createWebHistory } from 'vue-router'
const routes = [{path: '/',name: '组件页面',component: () => import('@/views/home-page.vue'),redirect: '/demo',children: [{path: '/demo',name: 'Demo',// @ts-ignorecomponent: () => import('@/components/hasaki-ui/demo/doc/doc.md')},{path: '/el-table-pagination',name: '分页表格',// @ts-ignorecomponent: () => import('@/components/hasaki-ui/ElTablePagination/doc/doc.md')},{path: '/select-tree',name: '树选择器',// @ts-ignorecomponent: () => import('@/components/hasaki-ui/SelectTree/doc/doc.md')}]}
]
const router = createRouter({history: createWebHistory(import.meta.env.BASE_URL),routes
})export default router
// App.vue
<script setup lang="ts"></script>
<template><div class="main"><RouterView /></div>
</template>
<style scoped lang="scss">
.main {width: 100vw;height: 100vh;
}
</style>

Markdown 插件需要我们在vite.config.ts中进行配置

到这里我们的一个简单的组件库demo就完成了

三、库模式开发打包配置 

        在此我们介绍如何把我们开发的组件库进行打包,重点是配置lib字段来进行库开发

// vite.config.ts
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import Markdown from 'vite-plugin-vue-markdown'// https://vitejs.dev/config/
export default defineConfig({base: '/hasaki-ui/',plugins: [vue({include: [/\.vue$/, /\.md$/]}),vueJsx(),Markdown()],build: {outDir: 'hasaki-ui', //输出文件名称lib: {entry: fileURLToPath(new URL('./src/components/hasaki-ui/index.ts', import.meta.url)), //指定组件编译入口文件name: 'hasaki-ui', // 包名fileName: 'hasaki-ui' // 打包文件名}, //库编译模式配置rollupOptions: {// 确保外部化处理那些你不想打包进库的依赖external: ['vue', 'vue-router'],output: {// 在 UMD 构建模式下为这些外部化的依赖提供一个全局变量globals: {vue: 'Vue'}}}, // rollup打包配置terserOptions: {// 在打包代码时移除 console、debugger 和 注释compress: {/* (default: false) -- Pass true to discard calls to console.* functions.If you wish to drop a specific function call such as console.info and/orretain side effects from function arguments after dropping the functioncall then use pure_funcs instead*/drop_console: true, // 生产环境时移除consoledrop_debugger: true // 生产环境时移除debugger},format: {comments: false // 删除注释comments}}},resolve: {alias: {'@': fileURLToPath(new URL('./src', import.meta.url))}}
})

在package.json中配置发布信息

{"name": "hasaki-ui", // 发布包的名称"version": "0.0.5",  // 版本号,每次更新注意升级版本号"private": false, // 是否为私有,这里注意应为false"main": "./hasaki-ui/hasaki-ui.umd.js", // 入口文件"module": "./hasaki-ui/hasaki-ui.mjs", // 模块入口"sideEffects": false,"keywords": ["hasaki","hasaki-ui","HasakiUI"], // 搜索关键词"description": "一款基于Element-Plus开发的UI组件库,适用于vue3,大多为PC端后台管理系统常用组件", // 描述"author": "YXX", // 作者"exports": {"./hasaki-ui/style.css": "./hasaki-ui/style.css",".": {"import": "./hasaki-ui/hasaki-ui.mjs","require": "./hasaki-ui/hasaki-ui.umd.js"}}, // 引用路径映射,解决加载样式失败问题"files": ["hasaki-ui/*"], // 描述了将软件包作为依赖项安装时要包括的条目,默认值为[“*”],这意味着它将包括所有文件,我们指定我们自己组件文件夹即可// ..重要的就上面这些
}

执行 npm/yarn/pnpm run build进行打包,出现如下表示打包成功了

四、发布

这一步其实很简单,一个命令搞定,npm publish,但是初次发布需要登录你的npm:

1、执行npm login 命令,输入用户名和密码,输入密码时是看不到的,之后按提示输入绑定的邮箱,成功后你的邮箱会收到一个one-time password,填入后即登录成功。

2、登录之后,就可以执行npm publish进行发布。

3、发布前要注意查看你的npm源是否为官方源https://registry.npmjs.org ,如果不是要切回官方源,否则发布失败

4、发布成功后,到npm上就可以看到我们的包了,至此我们就有了自己的一个开源包。

相关文章:

Vite+Vue3 开发UI组件库并发布到npm

一直对开源UI组件库比较感兴趣&#xff0c;摸索着开发了一套&#xff0c;虽然还只是开始&#xff0c;但是从搭建到发布这套流程基本弄明白了&#xff0c;现在分享给大家&#xff0c;希望对同样感兴趣的同学有所帮助。 目前我的这套名为hasaki-ui的组件库仅有两个组件&#xff0…...

vue- form动态表单验证规则-表单验证

前言 以element官网的form表单的-动态增减表单项为例讲解表单验证规则 动态的功能就是v-model配合push v-for 便利来实现的 我们需要熟知2个知识点prop表单验证需要跟v-model绑定的值是一样的&#xff0c; 如果是一个数组便利的表单&#xff0c;那就需要绑定这个数组每一项…...

FPGA学习—通过数码管实现电子秒表模拟

文章目录 一、数码管简介二、项目分析三、项目源码及分析四、实现效果五、总结 一、数码管简介 请参阅博主以前写过的一篇电子时钟模拟&#xff0c;在此不再赘述。 https://blog.csdn.net/qq_54347584/article/details/130402287 二、项目分析 项目说明&#xff1a;本次项目…...

区块链媒体发稿:区块链媒体宣发常见问题解析

据统计&#xff0c;由于区块链应用和虚拟货币的兴起&#xff0c;越来越多媒体对区块链领域开展报导&#xff0c;特别是世界各国媒体宣发全是热火朝天。但是&#xff0c;随着推卸责任媒体宣发的五花八门&#xff0c;让很多人因而上当受骗&#xff0c;乃至伤害一大笔资产。身为投…...

openGauss学习笔记-28 openGauss 高级数据管理-NULL值

文章目录 openGauss学习笔记-28 openGauss 高级数据管理-NULL值28.1 IS NOT NULL28.2 IS NULL openGauss学习笔记-28 openGauss 高级数据管理-NULL值 NULL值代表未知数据。无法比较NULL和0&#xff0c;因为它们是不等价的。 创建表时&#xff0c;可以指定列可以存放或者不能存…...

DAO和XML文件参数和返回值

①MyBatis中resultType和resultMap的区别 1.使用MyBatis查询数据库记录时&#xff0c;返回类型常用的有两种&#xff1a;resultType和resultMap。那么两者之间有什么区别呢&#xff1f; 如果只是返回一个值&#xff0c;简单类型&#xff0c;比如说String或者int&#xff0c;那…...

vue 浏览器右侧可拖拽小组件

目录 0. 使用场景 1. 动图示例 2. 实现方式 2.1 创建drag.js 2.2 使用v-drag 3. 结尾 0. 使用场景 很多网页在浏览器右侧有"导航"或者“智能助手”的悬浮小气泡框&#xff0c;比如我们的csdn☞ 作为页面友好型的引导标注&#xff0c;某些场景下这些小气泡可以…...

SpringMvc学习笔记五

Restful 风格路由 1. 配置类 1.1、SpringMvcConfig配置类 Configuration ComponentScan({"com.itheima.controller", "com.itheima.config"}) 方式1.2 添加com.itheima.config 扫描目录 EnableWebMvc public class SpringMvcConfig { } 1.2、ServletCo…...

ORACLE-DG总结

述 当主库的某些日志没有成功传送到备库,那么这时候就发生了归档裂缝(Archive Gap)。目前Oracle提供了两种日志GAP的检测和处理机制,分别是自动GAP处理(Automatic Gap Resolution)和FAL进程GAP处理(FAL Gap Resolution)。自动GAP处理即主库上的ARCn进程会每分钟检查备库…...

机器学习中的 K-均值聚类算法及其优缺点

K-均值聚类算法是一种常用的无监督学习算法&#xff0c;用于将相似的数据点分组为聚类。 其步骤如下&#xff1a; 1. 初始化&#xff1a;选择聚类数K&#xff0c;随机选取K个聚类中心。 2. 计算距离&#xff1a;计算每个数据点与K个聚类中心的距离&#xff0c;将其分配到距离最…...

【数据化分析和建模】一般步骤(个人工作经验总结)

近期关于【数据化分析和建模】一般步骤的思考如下。 以终为始&#xff0c;要解决什么问题&#xff0c;实现什么效果&#xff1f; 数据可视化分析的首要目标是通过将数据以可视化图表的形式真实、完整地呈现业务现状&#xff0c;为发现业务问题打好基础&#xff0c;包括实时的…...

视频安防监控EasyCVR平台海康大华设备国标GB28181告警布防的报文说明

TSINGSEE青犀视频监控综合管理平台EasyCVR基于云边端协同&#xff0c;可支持海量视频的轻量化接入与汇聚管理。平台既具备传统安防视频监控的能力&#xff0c;比如&#xff1a;视频监控直播、云端录像、云存储、录像检索与回看、告警上报、平台级联、云台控制、语音对讲等&…...

T31开发笔记:librtmp拉流测试

若该文为原创文章&#xff0c;转载请注明原文出处。 T31使用librtmp拉流并保存成FLV文件或H264和AAC文件。 librtmp编译在前面有教程&#xff0c;自行编译。 实现的目的是想要获取获取rtmp的AAC流并播放&#xff0c;实时双向对讲功能。 一、硬件和开发环境 1、硬件&#xff1…...

2308C++概念化

原文 库 //概念化(需要C20) struct 可画 {void 画(小出流 &out) const {te::call([](auto const &s, auto &out)-> decltype(s.画(out)) { s.画(out); }, *this, out);} }; struct 方形 {void 画(小出流 &out) const { out << "方形"; } }…...

flutter开发实战-实现自定义按钮类似UIButton效果

flutter开发实战-实现自定义按钮类似UIButton效果 最近开发过程中需要实现一下UIButton效果的flutter按钮&#xff0c;这里使用的是监听手势点击事件。 一、GestureDetector GestureDetector属性定义 GestureDetector({super.key,this.child,this.onTapDown,this.onTapUp,t…...

深度优先搜索|1034, 1020, 1254

深度优先搜索|1034. 边界着色&#xff0c; 机器人的运动范围&#xff0c;529. 扫雷游戏 边界着色机器人的运动范围扫雷问题 边界着色 把这个题分段了&#xff0c;先找到包括 (row, col) 的连通分量&#xff0c;然后再去找符合条件的边界&#xff0c;找到以后涂上颜色就行。 c…...

都市信息供求网servlet+jsp新闻广告出售java源代码mysql

本项目为前几天收费帮学妹做的一个项目&#xff0c;Java EE JSP项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 都市信息供求网servletjsp 系统1权限&#xff1a;管理…...

kubeadm init:failed to pull image registry.k8s.io/pause:3.6

错误信息&#xff1a; Unfortunately, an error has occurred: timed out waiting for the condition This error is likely caused by: - The kubelet is not running - The kubelet is unhealthy due to a misconfiguration of the node in some way…...

设计模式之简单工厂模式、工厂模式、抽象工厂模式

参考&#xff1a; 设计模式笔记 简单工厂模式 ● 将类的创建过程交给工厂类实现&#xff0c;如果需要一个类对象&#xff0c;则直接通过工厂创建一个类。 ● 简单工厂模式不符合开闭原则 ● 适用场景&#xff1a;工厂类负责创建的对象比较少&#xff1b;客户端只知道传入工厂…...

C# 控制台彩色深度打印 工具类

文章目录 前言Nuget 环境安装代码使用打印结果 总结 前言 有时候我们想要靠打印获得程序信息&#xff0c;因为Dubeg模式需要一点一点断点进入进出&#xff0c;但是我们觉得断点运行实在是太慢了&#xff0c;还是直接打印后找结果会好一点。 Nuget 环境安装 想自己写的话可以看…...

【杂谈】-递归进化:人工智能的自我改进与监管挑战

递归进化&#xff1a;人工智能的自我改进与监管挑战 文章目录 递归进化&#xff1a;人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管&#xff1f;3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...

Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动

一、前言说明 在2011版本的gb28181协议中&#xff0c;拉取视频流只要求udp方式&#xff0c;从2016开始要求新增支持tcp被动和tcp主动两种方式&#xff0c;udp理论上会丢包的&#xff0c;所以实际使用过程可能会出现画面花屏的情况&#xff0c;而tcp肯定不丢包&#xff0c;起码…...

centos 7 部署awstats 网站访问检测

一、基础环境准备&#xff08;两种安装方式都要做&#xff09; bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats&#xff0…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例

文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

【项目实战】通过多模态+LangGraph实现PPT生成助手

PPT自动生成系统 基于LangGraph的PPT自动生成系统&#xff0c;可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析&#xff1a;自动解析Markdown文档结构PPT模板分析&#xff1a;分析PPT模板的布局和风格智能布局决策&#xff1a;匹配内容与合适的PPT布局自动…...

Neo4j 集群管理:原理、技术与最佳实践深度解析

Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...

浪潮交换机配置track检测实现高速公路收费网络主备切换NQA

浪潮交换机track配置 项目背景高速网络拓扑网络情况分析通信线路收费网络路由 收费汇聚交换机相应配置收费汇聚track配置 项目背景 在实施省内一条高速公路时遇到的需求&#xff0c;本次涉及的主要是收费汇聚交换机的配置&#xff0c;浪潮网络设备在高速项目很少&#xff0c;通…...

GitFlow 工作模式(详解)

今天再学项目的过程中遇到使用gitflow模式管理代码&#xff0c;因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存&#xff0c;无论是github还是gittee&#xff0c;都是一种基于git去保存代码的形式&#xff0c;这样保存代码…...

MySQL JOIN 表过多的优化思路

当 MySQL 查询涉及大量表 JOIN 时&#xff0c;性能会显著下降。以下是优化思路和简易实现方法&#xff1a; 一、核心优化思路 减少 JOIN 数量 数据冗余&#xff1a;添加必要的冗余字段&#xff08;如订单表直接存储用户名&#xff09;合并表&#xff1a;将频繁关联的小表合并成…...

GitHub 趋势日报 (2025年06月06日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 590 cognee 551 onlook 399 project-based-learning 348 build-your-own-x 320 ne…...