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点云处理提供了强大的数学…...

CLion Inlay Hints - 取消 CLion 灰色的参数和类型提示
CLion Inlay Hints - 取消 CLion 灰色的参数和类型提示 1. Parameter hints for C/C1.1. Toggle parameter hints globally 2. Type hints for C/C2.1. Toggle type hints globally 3. Toggle inlay hints globallyReferences https://www.jetbrains.com/help/clio…...

2025山东科技大学考研专业课复习资料一览
[冲刺]2025年山东科技大学020200应用经济学《814经济学之西方经济学[宏观部分]》考研学霸狂刷870题[简答论述计算题]1小时前[强化]2025年山东科技大学085600材料与化工《817物理化学》考研强化检测5套卷22小时前[冲刺]2025年山东科技大学030100法学《704综合一[法理学、国际法学…...

vue3 v-model实例之二,tab标签页的实现
<template><div><Tab v-model"activeTab" :list"tabs" /><div><p>当前激活的 Tab 索引: {{ activeTab }}</p></div></div> </template><script setup> import { ref } from vue; import Tab …...

东方通TongWeb7.0.4.9M4部署SuperMap iServer 11.2.1
一、软件版本 操作系统: CentOS Linux release 7.5.1804 (Core)JDK:11.0.18东方通:TongWeb7.0.4.9M4SuperMap iServer:11.2.1 JDK和TongWeb软件分享: 链接: https://pan.baidu.com/s/1HGDTPnPID0PEOMbg3FjTVQ?pwdbh8v 提取码: bh8v 东方通软…...

QT绘制同心扇形
void ChartForm::paintEvent(QPaintEvent *) {QPainter painter(this);painter.setRenderHint(QPainter::Antialiasing);// 设置抗锯齿painter.save();// 设置无边框(不需要设置QPen,因为默认是不绘制边框的)QPen pen(Qt::NoPen);// QPen pen…...

2012年西部数学奥林匹克试题(几何)
2012/G1 △ A B C \triangle ABC △ABC 内有一点 P P P, P P P 在 A B AB AB, A C AC AC 上的投影分别为 E E E, F F F, 射线 B P BP BP, C P CP CP 分别交 △ A B C \triangle ABC △ABC 的外接圆于点 M M M, N N N. r r r 为 △ A B C \triangle ABC △ABC 的内…...

8位移位寄存器的verilog语言
module shift_register (output reg [7:0] Q, // 8位移位寄存器输出input D, // 输入数据input rst, // 复位信号input clk // 时钟信号 );always (posedge clk) beginif (!rst)Q < 8b00000000; // 复位时将Q清零elseQ < {Q[6:0], D}; // 否则…...

【苍穹外卖】学习心得体会-随笔
前言 写了很久,终于可以完整运行项目了,记录下这几天的心得体会回顾一下知识点 第一天、Git 分布式版本控制工具 一、Git概述 定义:是分布式版本控制工具,用于管理软件开发中的源代码文件,像Java类、xml文件、html…...

MySQL学习之表的增删改
MySQL学习之表的增删改 语法总结: INSERT INTO 表名 (字段名1, 字段名2, ...) VALUES (值1, 值2, ...); //指定字段添加数据 INSERT INTO 表名 VALUES (值1, 值2, ...); //给全部字段添加数据 INSERT INTO 表名 VALUES (值1, 值2, ...), (值1, 值2, ...), (值1, …...

电脑excel词典(xllex.dll)文件丢失是或损坏是什么原因?“xllex.dll文件缺失“要怎么解决?
Excel词典(xllex.dll)文件丢失或损坏?别担心,这里有解决之道! 在日常的电脑使用和办公软件操作中,我们偶尔会碰到一些让人头疼的问题,比如Excel突然提示“Excel词典(xllex.dll&…...