vue3前端组件库的搭建与发布(一)
前言:
最近在做公司项目中,有这么一件事情,很是头疼,就是同一套代码,不同项目,要改相同bug,改好多遍,改的都想吐,于是就想做一个组件库,这样更新一下就全都可以了,当然也是第一次主导组件库的搭建,有哪些不对的,还请各位大佬指出来哈。
准备:
1、node(18+)
2、Verdaccio :是一个Node.js创建的轻量的私有npm proxy registry,可以直接在你本地起一个私有库
npm i verdaccio -g启动:verdaccio
就会出现下面的页面
可以直接创建一个用户:
npm adduser --registry http://localhost:4873/
会让你输入用户名和密码,这个要记好哈,后面上传的时候要用到
开始
看到网上大佬们用的是Monorepo方式,那咱们也用这种方式(虽然不太懂为啥要这样,总之随主流指定出错少,哈哈)
-
创建文件夹:
mkdir?Monorepo? # 初始化文件 pnpm init -
在此目录下面创建.npmrc
# 和npm一样,将别的包的依赖都放在node_modules下,不加的话会放在.pnpm下 shamefully-hoist = true -
新建pnpm-workspace.yaml文件
packages:
# 将所有的项目都放到这里
- ‘packages/*’
# 示例
- ‘examples’
4.创建文件目录 packages、examples
packages – 将所有组件放到这里
examples – 测试组件
packages文件目录,里面的所有文件夹都要进行初始化 pnpm init

5、进入到components里面,一定要安装相应的依赖呀
?npm i vue typescript sass element-plus?decimal.js?@element-plus/icons-vue ?-D -w
-D 就不用介绍了
-w 是安装在根目录下
6、配置tsconfig.json文件
{"compilerOptions": {"allowJs": true, //允许编译器编译JS,JSX文件"target": "ES2015", //指定ECMAScript目标版本"useDefineForClassFields": true,"module": "ESNext", //设置程序的模块系统"moduleResolution": "Node", //模块解析策略。默认使用node的模块解析策略"strict": true, //启用所有严格类型检查选项"jsx": "preserve", //preserve模式,在preserve模式下生成代码中会保留JSX以供后续的转换操作使用"sourceMap": true, //生成目标文件的sourceMap文件"resolveJsonModule": true, //允许导入扩展名为“.json”的模块"esModuleInterop": false, //允许module.exports=xxx 导出,由import from 导入.因为很多老的js库使用了commonjs的导出方式,并且没有导出default属性"lib": [ //TS需要引用的库"ESNext","DOM"],"forceConsistentCasingInFileNames": true, //禁止对同一个文件的不一致的引用"allowSyntheticDefaultImports": true, //允许从没有设置默认导出的模块中默认导入"skipLibCheck": true, //忽略所有的声明文件( *.d.ts)的类型检查"baseUrl": "./", // 解析非相对模块的基地址,默认是当前目录"paths": { //模块名到基于 baseUrl的路径映射的列表"/@/*": ["src/*"],},"types": [ //要包含的类型声明文件名列表"vite/client","element-plus/global",]},"include": [ //包含的文件"src/**/*.ts","src/**/*.d.ts","src/**/*.tsx","src/**/*.js","src/**/*.jsx","src/**/*.vue",]
}
7、初始化 examples 文件夹
1、初始化
pnpm init2、安装 vite 和 @vitejs/plugin-vue
pnpm vite @vitejs/plugin-vue -D -w3.新建vite.config.ts 并配置 import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({plugins:[vue()]
})4、新建index.html
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body><div id="app"></div><script src="main.ts" type="module"></script></body>
</html>注意: vite 是基于 esmodule 的 所以 type="module"
@vitejs/plugin-vue 会默认加载 examples 下的 index.html5、新建app.vue<template><div>app</div>
</template><script setup lang="ts">
</script><style scoped>
</style>6、新建main.tsimport {createApp} from 'vue'
import App from './app.vue'
const app = createApp(App)
app.mount('#app')7、因为直接引入.vue 文件 TS 会找不到对应的类型声明;所以需要新建 typings(命名没有明确规定,TS 会自动寻找.d.ts 文件)文件夹来专门放这些声明文件。declare module '*.vue' {import type { DefineComponent } from "vue";const component:DefineComponent<{},{},any>
}8、在package.json 文件中配置 scripts 脚本"scripts": {"dev": "vite"},
9.pnpm run dev 启动项目
8、初始化packages/components 文件夹
components 文件夹1.目录结构
-- components-- src-- index.ts-- input-number-- inputNumber.vue-- index.ts
-- index.ts
-- package.json2.inputNumber.vue 如下代码3.input-number/index.tsimport InputNumber from './inputNumber.vue'
InputNumber.install = (app) => {app.component(InputNumber.name, InputNumber)
}
export default InputNumber4.components/index.ts
import InputNumber from "./src/input-number/inputNumber.vue";
// 将所有的组件都放到这里进行导出
const components = [InputNumber
]
// 定义install方法const install = (app) => {// 之策所有组件components.forEach(item => {app.component(item.name, item)})
}const DHSUI = {install
}// 支持按需引入
export {InputNumber
}// 导出install方法
export default DHSUI
以input框为例:
src/input-number/inputNumber.vue
<template><el-input v-model="inputValue" class="customInput" v-bind="$attrs" :maxlength="props.maxlength" @input="handleInput"><template #suffix><span class="iconBtn add" @click="add"><el-icon><ArrowUp /></el-icon></span><span class="iconBtn decrease" @click="decrease"><el-icon><ArrowDown /></el-icon></span></template><template v-if="props.isAppend" #append>{{ props.appendText }}</template></el-input>
</template>
<script lang="ts">export default {name: 'InputNumber'
}
</script>
<script setup lang="ts">import { ElInput, ElIcon } from 'element-plus'import 'element-plus/dist/index.css'import {ArrowUp, ArrowDown } from '@element-plus/icons-vue'import { Decimal } from "decimal.js";import { onlyNumOnePoint, canBeMinus } from "@dhs-ui/utils";
import { ref, watch } from 'vue';// 根据最长字符,生成最大值
const generateMaxString = (maxLength: any) => {const maxValue = "9".repeat(maxLength as unknown as number);return maxValue;
};
interface Props {modelValue: string;isAppend?: boolean;appendText?: string;min?: number;max?: number;step?: number;maxlength?: number | string;precision?: number;
}
const props = withDefaults(defineProps<Props>(), {modelValue: "",precision: 4,isAppend: false
});
const emits = defineEmits(["input", "update:modelValue"]);
const inputValue = ref(props.modelValue);
const add = () => {const step = props.step || 1;let val = inputValue.value;if (!val) {val = "0";}let decimalVal = new Decimal(val);if (maxNum() && new Decimal(maxNum()) <= decimalVal) {inputValue.value = decimalVal.toFixed();} else {inputValue.value = decimalVal.plus(step).toFixed();}
};
const decrease = () => {const step = props.step || 1;let val = inputValue.value;if (!val && parseFloat(val) !== 0) val = "0";if (props.min || props.min === 0) {if (parseFloat(val) <= props.min) {val = props.min.toFixed();inputValue.value = val;return;}}let decimalVal = new Decimal(val);inputValue.value = decimalVal.sub(step).toFixed();
};
// number 小数点位数
const vilidateNumberInput = (value: any, number: number) => {let result: any;if (props.min || props.min === 0) {result = onlyNumOnePoint(value, number, !!number);} else {result = canBeMinus(value, number);}return result;
};const maxNum = () => {if (props.max) {return props.max.toFixed();} else {return props.maxlength ? generateMaxString(props.maxlength) : null;}
};
watch(() => props.modelValue,( newValue: any) => {inputValue.value = newValue;},{ deep: true }
);
watch(inputValue, (nv: any) => {emits("update:modelValue", nv);
});
const handleInput = (val: any) => {inputValue.value = vilidateNumberInput(val, props.precision);emits("input", val);
};
</script><style scoped lang="scss">
.customInput {.iconBtn {position: absolute;right: 1px;display: block;width: 32px;background-color: #f5f7fa;border-left: 1px solid var(--default-border-color);height: 15px;line-height: 15px;cursor: pointer;}.add {top: 1px;border-radius: 0 4px 0 0;}.decrease {border-top: 1px solid var(--default-border-color);bottom: 1px;border-radius: 0 0 4px 0;}&.is-disabled {.add,.decrease {pointer-events: none;}}
}
</style>
9、在examples/app.vue测试组件
<template><div><InputNumber :modelValue="inputValue" /></div>
</template><script setup lang="ts">
import { ref } from 'vue';
import {InputNumber} from '../packages/components/src/input-number/inputNumber.vue';const inputValue = ref(0)
</script><style scoped></style>
出现了你所要的组件就说明可以进行打包了。
10、在components文件夹中打包组件
components 文件夹 新建vite.config.ts
这里我们选择打包cjs(CommonJS)和esm(ESModule)两种形式,cjs模式主要用于服务端引用(ssr),而esm就是我们现在经常使用的方式,它本身自带treeShaking而不需要额外配置按需引入(前提是你将模块分别导出),非常好用~
为了也能在ts项目中使用,还需要自动生成类型声明文件
pnpm add vite-plugin-dts@1.4.1 -D -wimport { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import dts from "vite-plugin-dts";
export default defineConfig({build: {//打包文件目录outDir: "es",//压缩//minify: false,rollupOptions: {//忽略打包的文件external: ["vue", "element-plus"],input: ["index.ts"],output: [{//打包格式format: "es",//打包后文件名entryFileNames: "[name].mjs",//让打包目录和我们目录对应preserveModules: false,exports: "named",//配置打包根目录dir: "../DHS-UI/es",},{//打包格式format: "cjs",//打包后文件名entryFileNames: "[name].js",//让打包目录和我们目录对应preserveModules: false,exports: "named",//配置打包根目录dir: "../DHS-UI/lib",},],},lib: {entry: "./index.ts",},},plugins: [vue(),dts({entryRoot: "./src",outputDir: ["../DHS-UI/es/src", "../DHS-UI/lib/src"],//指定使用的tsconfig.json为我们整个项目根目录下,如果不配置,你也可以在components下新建tsconfig.jsontsConfigFilePath: "../../tsconfig.json",}),],
});
配置同目录下的package.json文件
"scripts": {"build": "vite build"},
11、运行 build 进行打包,会在目录中生成打包好的包

11、打包好的文件,进行初始化
pnpm init
修改package.json 文件
{"name": "dhs-uii","version": "1.0.2","description": "","main": "lib/index.js","module": "es/index.mjs","files": ["es","lib"],"scripts": {"test": "echo "Error: no test specified" && exit 1"},"sideEffects": ["**/*.css"],"keywords": ["dhs-ui","vue3组件库","frontend","element-plus"],"author": "dengdeng","license": "ISC","typings": "lib/index.d.ts"
}
下一章进行发布,及遇到的问题。
感谢大佬文章:搭建一个组件库(vue3)_vue3组件库搭建-CSDN博客
相关文章:
vue3前端组件库的搭建与发布(一)
前言: 最近在做公司项目中,有这么一件事情,很是头疼,就是同一套代码,不同项目,要改相同bug,改好多遍,改的都想吐,于是就想做一个组件库,这样更新一下就全都可…...
COMSOL快捷键及内置函数
文章目录 COMSOL快捷键使用COMSOL算子求最大值和最小值COMSOL内置函数3.1 解析函数3.2 插值函数3.3 分段函数3.4 高斯脉冲函数3.5 斜坡函数3.6 矩形函数3.7 波形函数3.8 随机函数3.9 Matlab函数3.10 SWITCH函数 COMSOL快捷键 Ctrl+/ 可快速打开预定义的物理量列表。…...
HUAWEI-eNSP交换机链路聚合(手动负载分担模式)
配置思路:HUAWEI交换机链路聚合有LACP模式跟手动负载分担模式,本文主打手动负载分担模式:首先交换机-PC之间划分基本vlan,交换机-交换机之间创建链路聚合组,划分端口至链路聚合分组(缺省模式为手动负载分担模式)。结果验证要求同vlan可以ping通,关闭某个聚合端口后仍可…...
番外篇 | Hyper-YOLO:超图计算与YOLO架构相结合成为目标检测新的SOTA !
前言:Hello大家好,我是小哥谈。Hyper-YOLO,该方法融合了超图计算以捕捉视觉特征之间复杂的高阶关联。传统的YOLO模型虽然功能强大,但其颈部设计存在局限性,限制了跨层特征的融合以及高阶特征关系的利用。Hyper-YOLO在骨干和颈部的联合增强下,成为一个突破性的架构。在COC…...
【MATLAB第109期】基于MATLAB的带置信区间的RSA区域敏感性分析方法,无目标函数
【MATLAB第108期】基于MATLAB的带置信区间的RSA区域敏感性分析方法,无目标函数 参考第64期文章【MATLAB第64期】【保姆级教程】基于MATLAB的SOBOL全局敏感性分析模型运用(含无目标函数,考虑代理模型) 创新点: 1、采…...
Bootstrap 表格
Bootstrap 表格 引言 Bootstrap 是一个流行的前端框架,它提供了一套丰富的工具和组件,用于快速开发响应式和移动设备优先的网页。在本文中,我们将重点讨论 Bootstrap 中的表格组件,包括其基本结构、样式以及如何使用 Bootstrap …...
【论文阅读】Computing the Testing Error without a Testing Set
https://blog.csdn.net/qq_40021158/article/details/109485216 可以使用测试集来估计训练集和测试集之间的性能差距,但是要避免过度拟合测试数据几乎是不可能的。 使用隔离的测试集可能会解决此问题,但这需要不断更新数据集,这是一项非常昂贵…...
Visio——同一个工程导出的PDF文件大小不一样的原因分析
现象 在不同电脑,导出来的PDF文件大小不一样。 原因分析 文件小的未将字体嵌入,文件大的已经将字体嵌入了。...
【ETCD】ETCD 架构揭秘:内部各组件概览
ETCD 的主要组件及它们之间的关联关系如下: 目录 1. Client(客户端)2. gRPC 接口3. Etcd Server Main Loop(ETCD 主循环)4. Raft(共识模块)5. Peer Etcd Nodes(ETCD 集群节点&#x…...
Qt WORD/PDF(四)使用 QAxObject 对 Word 替换(QWidget)
关于QT Widget 其它文章请点击这里: QT Widget 国际站点 GitHub: https://github.com/chenchuhan 国内站点 Gitee : https://gitee.com/chuck_chee 姊妹篇: Qt WORD/PDF(一)使用 QtPdfium库实现 PDF 操作 Qt WORD/PDF(二…...
音视频学习(二十四):hls协议
基本原理 HLS协议通过将视频文件切分成多个小的媒体段(通常是10秒左右的.ts文件),并通过HTTP传输给客户端。视频播放过程中,客户端按顺序请求这些小段文件来逐步播放整个视频流。HLS还支持多种码率,以便适应不同网络条…...
UniDepth 学习笔记
摘要 准确的单目度量深度估计(MMDE)是解决三维感知和建模中下游任务的关键。然而,最近的MMDE方法的显著准确性仅限于其训练领域。这些方法存在适度的域间隙,也不能推广到看不见的域,这阻碍了它们的实际适用性。本文提出…...
PVE——OpenWRT 硬盘 size单位的调整
问题:初始状态为120MB 还需要进行计算,如果通过图形界面添加磁盘会出现单位不变的情况。 进入命令行前记得给你的虚拟机拍照,防止误操作 通过ssh 进入PVE命令行 按需添加容量即可 不到1G 会显示M 超过1G 不是G整数均为M单位。 …...
Android-ImagesPickers 拍照崩溃优化
Android-ImagesPickers 作为老牌图片选择器,帮助了很多牛马宝宝,刚好最近用到了多相册选择以及拍照,可能是高版本机型问题,导致拍照后就闪退 原作者文章以及git Android实用视图动画及工具系列之九:漂亮的图片选择器…...
Linux dd 命令详解:工作原理与实用指南(C/C++代码实现)
这段代码是一个模仿 Linux dd 命令的工具,它用于在不同文件之间复制数据。dd 是一个非常强大的命令行工具,可以用于数据备份、转换和复制。下面我将详细解释这段代码的原理、实现方式以及如何运行和测试。 Linux dd 命令的工作原理 dd 命令是 Unix 和 …...
Golang学习历程【第一篇 入门】
Golang学习历程【第一篇 入门Hello World】 1. 学习文档2. Window 本地安装Go2.1 安装2.2 验证 3. 开发环境——VsCode3.1 VsCode 安装3.2 安装插件3.2.1 language 语言汉化插件安装3.2.2 Go插件安装 4. Hello World 入门4.1 建工程4.2 创建项目文件4.3 编写Hello World程序4.4…...
青少年编程与数学 02-004 Go语言Web编程 01课题、Web应用程序
青少年编程与数学 02-004 Go语言Web编程 01课题、Web应用程序 课题摘要:一、Web应用程序二、Web服务器(一)什么是Web服务器(二)Web服务器配置1. 选择服务器软件2. 安装服务器软件3. 配置服务器4. 安全设置5. 部署网站内容6. 测试服…...
【mysql】如何解决主从架构从库延迟问题
目录 1. 说明2.优化主库的写入性能3. 优化网络性能4. 增强从库的硬件性能5. 调整从库的配置6. 主从架构优化7. 监控和调优8.使用 GTID 和 Group Replication 1. 说明 1.在 MySQL 数据库中,从库延迟(replication lag)是指主库和从库之间的数据…...
前端学习-获取DOM对象(二十一)
目录 前言 目标 提问 学习路径 根据CSS选择器来获取DOM元素 其他获取DOM元素的方法 根据CSS选择器来获取DOM元素 选择匹配的第一个元素 语法 示例 参数 返回值 选择匹配的多个元素语法 参数 字符串返回值 示例 补充 其它获取DOM元素方法 根据id获取一个元素 …...
PCL点云库入门——PCL库中Eigen数学工具库的基本使用(持续更新)
0、前言 PCL点云库中的算法都基于Eigen数学工具库来实现的,因此,掌握Eigen库对于深入理解和应用PCL点云库至关重要。Eigen库不仅提供了高效的矩阵和向量运算,还支持复杂的线性代数、几何变换等操作,为PCL点云处理提供了强大的数学…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...
什么是库存周转?如何用进销存系统提高库存周转率?
你可能听说过这样一句话: “利润不是赚出来的,是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业,很多企业看着销售不错,账上却没钱、利润也不见了,一翻库存才发现: 一堆卖不动的旧货…...
Spring Boot面试题精选汇总
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...
重启Eureka集群中的节点,对已经注册的服务有什么影响
先看答案,如果正确地操作,重启Eureka集群中的节点,对已经注册的服务影响非常小,甚至可以做到无感知。 但如果操作不当,可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...
视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)
前言: 最近在做行为检测相关的模型,用的是时空图卷积网络(STGCN),但原有kinetic-400数据集数据质量较低,需要进行细粒度的标注,同时粗略搜了下已有开源工具基本都集中于图像分割这块,…...
Linux离线(zip方式)安装docker
目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1:修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本:CentOS 7 64位 内核版本:3.10.0 相关命令: uname -rcat /etc/os-rele…...
保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek
文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama(有网络的电脑)2.2.3 安装Ollama(无网络的电脑)2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...
Mysql中select查询语句的执行过程
目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析(Parser) 2.4、执行sql 1. 预处理(Preprocessor) 2. 查询优化器(Optimizer) 3. 执行器…...
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...
