搜索并参考资料
- Vue Amazing UI | Amazing UI Components Library (themusecatcher.github.io) 好看 搜索不能使用
- pnpm monorepo+vue3+vite组件库搭建_pnpm 私有组件库-CSDN博客 基本
- Vue3+Vite+Element-plus搭建组件库并使用Vitepress编辑组件库文档且发布到 npm并且部署 github pages(vitepress文档渲染.vue组件-推荐使用第二种)_element-plus目录结构-CSDN博客 vue2组件库作者
- 如何写一个属于自己的vue3组件库 - 掘金 (juejin.cn) 搜索
- 手把手从零搭建一个 vue3 组件库 (二):为组件编写文档_组件库文档-CSDN博客 文档可以 搜索不行 存在bug
- 从零搭建VUE3组件库 - 掘金 (juejin.cn) 有点复杂
- vue3+vite+ts搭建组件库 - 掘金 (juejin.cn) 搜索可以
- 记Vue+vite+pnpm UI组件库搭建过程 - 掘金 (juejin.cn)
最终选择 5 3 1
搜索 4 7
经过验证第5个代码存在问题
因此使用第三个
其他资料:
创建vue3项目
执行命令npm init vue@latest
PS E:\nasGit\demo> npm init vue@latest
Vue.js - The Progressive JavaScript Framework
√ 请输入项目名称: ... v3-elp-ui
√ 是否使用 TypeScript 语法? ... 否 / 是
√ 是否启用 JSX 支持? ... 否 / 是
√ 是否引入 Vue Router 进行单页面应用开发? ... 否 / 是
√ 是否引入 Pinia 用于状态管理? ... 否 / 是
√ 是否引入 Vitest 用于单元测试? ... 否 / 是
√ 是否要引入一款端到端(End to End)测试工具? » 不需要
√ 是否引入 ESLint 用于代码质量检测? ... 否 / 是
√ 是否引入 Prettier 用于代码格式化? ... 否 / 是
√ 是否引入 Vue DevTools 7 扩展用于调试? (试验阶段) ... 否 / 是
正在初始化项目 E:\nasGit\demo\v3-elp-ui...
项目初始化完成,可执行以下命令:
cd v3-elp-ui
npm install
npm run format
npm run dev
将项目中无用的代码删掉,只保留基本的文件
配置prettier和eslint
.prettierrc.cjs
//配置参照 https://prettier.io/docs/en/options.html
module.exports = {
tabWidth: 2, // tab 使用两个空格
endOfLine: "auto", // 保持现有的行尾
useTabs: false, // 不使用制表符缩进,使用空格缩进
semi: true, // 代码需要分号结尾
quotes: false,
// 使用单引号而不是双引号,默认false
singleQuote: false,
bracketSpacing: true, // 对象左右两侧需要空格
jsxBracketSameLine: false, // html 关闭标签换行
jsxSingleQuote: false, //在JSX中使用单引号
arrowParens: "avoid", // 单参数的箭头函数参数不需要括号
proseWrap: "never", // markdown文档不换行
trailingComma: "all", // 结尾处不加逗号
quoteProps: "as-needed", //自定义引号配置
$schema: "https://json.schemastore.org/prettierrc",
printWidth: 100,
};
.eslintrc.cjs
/* eslint-env node */
require("@rushstack/eslint-patch/modern-module-resolution");
module.exports = {
root: true,
extends: [
"plugin:vue/vue3-essential",
"eslint:recommended",
"@vue/eslint-config-typescript",
"@vue/eslint-config-prettier/skip-formatting",
],
parserOptions: {
ecmaVersion: "latest",
},
rules: {
// 'no-console': import.meta.env.NODE_ENV === 'production' ? 'warn' : 'off',
// 'no-debugger': import.meta.env.NODE_ENV === 'production' ? 'warn' : 'off',
// 强制使用一致的缩进
indent: ["error", 2],
// 强制使用一致的换行风格
// LF
// "linebreak-style": ["error", "unix"],
// CRLF
"linebreak-style": [0, "error", "windows"],
// 强制使用一致的反勾号、双引号或单引号
quotes: [
"error",
"double", // backtick、double、single
],
// 要求或禁止使用分号代替 ASI
semi: ["error", "always"],
// 禁止空格和 tab 的混合缩进
"no-mixed-spaces-and-tabs": ["error", "smart-tabs"],
// 强制在 function的左括号之前使用一致的空格
// 'space-before-function-paren': [2, 'always'],
// 禁止或强制在单行代码块中使用空格(禁用)
"block-spacing": [1, "never"],
"no-cond-assign": 2,
// 禁止 function 定义中出现重名参数
"no-dupe-args": 2,
// 禁止对象字面量中出现重复的 key
"no-dupe-keys": 2,
// 禁止重复的 case 标签
"no-duplicate-case": 2,
// 禁止空语句块
"no-empty": 2,
// 禁止对 catch 子句的参数重新赋值
"no-ex-assign": 2,
// 禁止不必要的布尔转换
"no-extra-boolean-cast": 2,
// 禁止不必要的括号 //(a * b) + c;//报错
"no-extra-parens": 0,
// 强制所有控制语句使用一致的括号风格
curly: [2, "all"],
// 禁止 catch 子句的参数与外层作用域中的变量同名
"no-catch-shadow": 0,
// 不允许标签与变量同名
"no-label-var": 2,
// 禁用特定的全局变量
"no-restricted-globals": 2,
// 禁止 var 声明 与外层作用域的变量同名
"no-shadow": 0,
// 禁止覆盖受限制的标识符
"no-shadow-restricted-names": 2,
// 禁止将变量初始化为 undefined
"no-undef-init": 2,
// 禁止将 undefined 作为标识符
"no-undefined": 0,
// 不允许在变量定义之前使用它们
"no-use-before-define": 0,
// ////////////
// 风格指南 //
// ////////////
// 指定数组的元素之间要以空格隔开(, 后面), never参数:[ 之前和 ] 之后不能带空格,always参数:[ 之前和 ] 之后必须带空格
"array-bracket-spacing": [2, "never"],
// 强制使用一致的缩进 第二个参数为 "tab" 时,会使用tab,
// if while function 后面的{必须与if在同一行,java风格。
"brace-style": [
2,
"1tbs",
{
allowSingleLine: true,
},
],
// 控制逗号前后的空格
"comma-spacing": [
2,
{
before: false,
after: true,
},
],
// 控制逗号在行尾出现还是在行首出现 (默认行尾)
// http://eslint.org/docs/rules/comma-style
"comma-style": [2, "last"],
// "SwitchCase" (默认:0) 强制 switch 语句中的 case 子句的缩进水平
// 以方括号取对象属性时,[ 后面和 ] 前面是否需要空格, 可选参数 never, always
"computed-property-spacing": [2, "never"],
// 用于指统一在回调函数中指向this的变量名,箭头函数中的this已经可以指向外层调用者,应该没卵用了
// e.g [0,"self"] 指定只能 var that = this. self不能指向其他任何值,this也不能赋值给self以外的其他值
"consistent-this": [2, "self", "that", "_self", "_that", "me", "_this"],
// 强制使用命名的 function 表达式
"func-names": 0,
// 文件末尾强制换行
"eol-last": 0,
// 要求或禁止在函数标识符和其调用之间有空格
"func-call-spacing": 2,
// 强制在对象字面量的属性中键和值之间使用一致的间距
"key-spacing": [
2,
{
beforeColon: false,
afterColon: true,
},
],
// 要求在注释周围有空行 ( 要求在块级注释之前有一空行)
"lines-around-comment": [
0,
{
beforeBlockComment: true,
},
],
"func-style": 0,
// 强制回调函数最大嵌套深度 5层
"max-nested-callbacks": [2, 5],
// 禁止使用指定的标识符
"id-blacklist": 0,
// 强制标识符的最新和最大长度
"id-length": 0,
// 要求标识符匹配一个指定的正则表达式
"id-match": 0,
// 强制在 JSX 属性中一致地使用双引号或单引号
"jsx-quotes": 0,
// 强制在关键字前后使用一致的空格 (前后腰需要)
"keyword-spacing": 2,
// 强制最大行数
"max-lines": 0,
// 强制 function 定义中最多允许的参数数量
"max-params": [1, 5],
// 强制 function 块最多允许的的语句数量
"max-statements": [1, 200],
// 强制每一行中所允许的最大语句数量
"max-statements-per-line": 0,
// 要求构造函数首字母大写 (要求调用 new 操作符时有首字母大小的函数,允许调用首字母大写的函数时没有 new 操作符。)
"new-cap": [
2,
{
newIsCap: true,
capIsNew: false,
},
],
// 要求调用无参构造函数时有圆括号
"new-parens": 2,
// 要求或禁止 var 声明语句后有一行空行
"newline-after-var": 0,
// 禁止使用 Array 构造函数
"no-array-constructor": 2,
// 禁用按位运算符
"no-bitwise": 0,
// 要求 return 语句之前有一空行
"newline-before-return": 0,
// 要求方法链中每个调用都有一个换行符
"newline-per-chained-call": 1,
// 禁用 continue 语句
"no-continue": 0,
// 禁止在代码行后使用内联注释
"no-inline-comments": 0,
// 禁止 if 作为唯一的语句出现在 else 语句中
"no-lonely-if": 0,
// 禁止混合使用不同的操作符
"no-mixed-operators": 0,
// 不允许多个空行
"no-multiple-empty-lines": [
2,
{
max: 2,
},
],
// 不允许否定的表达式
"no-negated-condition": 0,
// 不允许使用嵌套的三元表达式
"no-nested-ternary": 0,
// 禁止使用 Object 的构造函数
"no-new-object": 2,
// 禁止使用一元操作符 ++ 和 --
"no-plusplus": 0,
// 禁止使用特定的语法
"no-restricted-syntax": 0,
// 禁止 function 标识符和括号之间出现空格
"no-spaced-func": 2,
// 不允许使用三元操作符
"no-ternary": 0,
// 禁用行尾空格
"no-trailing-spaces": 2,
// 禁止标识符中有悬空下划线_bar
"no-underscore-dangle": 0,
// 禁止可以在有更简单的可替代的表达式时使用三元操作符
"no-unneeded-ternary": 2,
// 禁止属性前有空白
"no-whitespace-before-property": 2,
// 要求或禁止在 var 声明周围换行
"one-var-declaration-per-line": 0,
// 要求或禁止在可能的情况下要求使用简化的赋值操作符
"operator-assignment": 0,
// 强制操作符使用一致的换行符
"operator-linebreak": [
2,
"after",
{
overrides: {
"?": "before",
":": "before",
},
},
],
// 要求或禁止块内填充
"padded-blocks": 0,
// 要求对象字面量属性名称用引号括起来
"quote-props": 0,
// 要求使用 JSDoc 注释
"require-jsdoc": 0,
// 要求或禁止使用分号而不是 ASI(这个才是控制行尾部分号的,)
// "semi": [2, "always"],
// 强制分号之前和之后使用一致的空格
"semi-spacing": 2,
// 要求同一个声明块中的变量按顺序排列
"sort-vars": 0,
// 强制在块之前使用一致的空格
"space-before-blocks": [2, "always"],
// 强制在圆括号内使用一致的空格
"space-in-parens": [2, "never"],
// 要求操作符周围有空格
"space-infix-ops": 2,
// 强制在一元操作符前后使用一致的空格
"space-unary-ops": [
2,
{
words: true,
nonwords: false,
},
],
// 强制在注释中 // 或 /* 使用一致的空格
"spaced-comment": [
2,
"always",
{
markers: ["global", "globals", "eslint", "eslint-disable", "*package", "!"],
},
],
// 要求或禁止 Unicode BOM
"unicode-bom": 2,
// 要求正则表达式被括号括起来
"wrap-regex": 0,
// 禁止词法声明 (let、const、function 和 class) 出现在 case或default 子句中
"no-case-declarations": ["warn"],
// ////////////
// ES6.相关 //
// ////////////
// 每个模块只能使用一个import
"no-duplicate-imports": 2,
// 要求箭头函数体使用大括号
"arrow-body-style": 2,
// 要求箭头函数的参数使用圆括号
"arrow-parens": 0,
"arrow-spacing": [
2,
{
before: true,
after: true,
},
],
// 强制 generator 函数中 * 号周围使用一致的空格
"generator-star-spacing": [
2,
{
before: true,
after: true,
},
],
// 禁止修改类声明的变量
"no-class-assign": 2,
// 不允许箭头功能,在那里他们可以混淆的比较
"no-confusing-arrow": 0,
// 禁止修改 const 声明的变量
"no-const-assign": 2,
// 禁止类成员中出现重复的名称
"no-dupe-class-members": 2,
// 禁止 Symbolnew 操作符和 new 一起使用
"no-new-symbol": 2,
// 允许指定模块加载时的进口
"no-restricted-imports": 0,
// 禁止在构造函数中,在调用 super() 之前使用 this 或 super
"no-this-before-super": 2,
// 禁止不必要的计算性能键对象的文字
"no-useless-computed-key": 0,
// 要求使用 let 或 const 而不是 var
"no-var": 1,
// 要求或禁止对象字面量中方法和属性使用简写语法
"object-shorthand": 0,
// 要求使用箭头函数作为回调
"prefer-arrow-callback": 0,
// 要求使用 const 声明那些声明后不再被修改的变量
"prefer-const": 0,
// 要求在合适的地方使用 Reflect 方法
"prefer-reflect": 0,
// 要求使用扩展运算符而非 .apply()
"prefer-spread": 0,
// 要求使用模板字面量而非字符串连接
"prefer-template": 0,
// Suggest using the rest parameters instead of arguments
"prefer-rest-params": 0,
// 要求generator 函数内有 yield
"require-yield": 2,
// 要求或禁止模板字符串中的嵌入表达式周围空格的使用
"template-curly-spacing": 1,
// 强制在 yield* 表达式中 * 周围使用空格
"yield-star-spacing": 2,
// 要求或禁止使用拖尾逗号
"comma-dangle": 0,
// 禁止在条件中使用常量表达式
"no-constant-condition": 0,
// 强制一行的最大长度
"max-len": [
0,
200,
{
ignoreUrls: true,
},
],
// 禁止出现未使用过的变量
"no-unused-vars": [
0,
{
vars: "all", // all 检测所有变量,包括全局环境中的变量。这是默认值。
args: "none", // none - 不检查参数。
},
],
// 去除插槽报错
"vue/no-deprecated-slot-attribute": "off",
// 关掉命名规范
"vue/multi-word-component-names": "off",
},
};
创建组件
在项目根目录下面创建packages用来存放组件,在packages下面创建每个组件的文件夹
组件目录下面创建index.ts、src文件夹,在src文件夹下面创建index.vue
src用来存放组件index.vue是组件内容index.ts用来导出组件
在packages下面创建index.ts用来导出全部组件或按需引入,创建withInstall.ts用来注册组件,创建components.d.ts支持Volar
withInstall.ts
import { App, Plugin } from 'vue'
type SFCWithInstall<T> = T & Plugin
export const withInstall = <T, E extends Record<string, any>>(
main: T,
extra?: E
) => {
;(main as SFCWithInstall<T>).install = (app: App) => {
for (const comp of [main, ...Object.values(extra ?? {})]) {
app.component(comp.name, comp)
}
}
if (extra) {
for (const [compName, comp] of Object.entries(extra)) {
;(main as Record<string, any>)[compName] = comp
}
}
// 将 T 断言为具体的类型 T & plugin & Record<string, any>
return main as SFCWithInstall<T> & E
}
index.ts
// 公共方法
/* import {
debounce,
throttle,
formatNumber
} from './utils' */
import type { Component, App } from "vue";
import Btn from "./button";
import labelInput from "./labelInput";
// 存储组件列表
const components: {
[propName: string]: Component;
} = {
Btn,
labelInput,
};
// 插件声明:声明所有插件
// 插件注册:在 Vue 项目的入口文件中,通过 ( app.use(插件) ) 进行注册
const installComponents: any = (app: App) => {
// components.forEach((comp: any) => {
// app.component(comp.name as string, comp)
// })
// app.use(ElementPlus, {
// locale // 语言设置
// // size: Cookies.get('size') || 'medium' // 设置默认尺寸
// })
for (const key in components) {
app.component(key, components[key]);
}
};
// vue插件
// - install:每个插件都有一个 install 方法
// - 参数:是通过 Vue.createApp() 创建的 app 实例
const install: any = (app: any, router?: any) => {
// !router && installRouter(app);
installComponents(app);
};
// 按需引入
export { Btn, labelInput };
/**
* @description 公共方法
*/
/* export {
throttle,
debounce,
formatNumber
} */
export default {
// 导出的对象必须具有 install,才能被 Vue.use() 方法安装
install,
};
安装npm i vite-plugin-dts -D,作用是为打包的库里加入声明文件(即生成:.d.ts文件)
修改文件如下
tsconfig.json
{
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"noImplicitAny": false, // 隐式具有“any”类型
"module": "ESNext",
"moduleResolution": "Node",
"strict": true,
"jsx": "preserve",
"types": ["vite/client"],
// 如果编译器无法根据变量的使用来判断类型时,将用 any 类型代替
// "suppressImplicitAnyIndexErrors": true,
// 允许从没有设置默认导出的模块中默认导入。这并不影响代码的输出,仅为了类型检查。
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"resolveJsonModule": true,
"isolatedModules": true,
"esModuleInterop": true,
"lib": ["ESNext", "DOM"],
// 解析非相对模块名的基准目录
"baseUrl": "./",
// 模块名到基于 baseUrl的路径映射的列表。
"paths": {
"@": ["packages"],
"@vue/shared": ["./node_modules/@vue/shared"],
"@/*": ["packages/*"]
},
"skipLibCheck": true
},
"include": ["packages/**/*.ts", "packages/**/*.d.ts", "packages/**/*.tsx", "packages/**/*.vue"],
"exclude": ["node_modules"],
"references": [
{
"path": "./tsconfig.node.json"
}
]
}
tsconfig.node.json
{
"extends": "@tsconfig/node20/tsconfig.json",
"include": [
"vite.config.*",
"vitest.config.*",
"cypress.config.*",
"nightwatch.conf.*",
"playwright.config.*"
],
"compilerOptions": {
"composite": true,
"noEmit": true,
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"module": "ESNext",
"moduleResolution": "Bundler",
"types": ["node"]
}
}
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 dts from "vite-plugin-dts";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue(), dts(), vueJsx()],
resolve: {
alias: {
"@": fileURLToPath(new URL("./src", import.meta.url)),
},
},
build: {
outDir: "lib",
rollupOptions: {
// 请确保外部化那些你的库中不需要的依赖
external: ["vue"],
output: {
// 在 UMD 构建模式下为这些外部化的依赖提供一个全局变量
globals: {
vue: "Vue",
},
},
},
lib: {
entry: "./packages/index.ts",
name: "v3-elp-ui",
},
},
});
package.json
{
"name": "v3-elp-ui",
"version": "0.0.5",
"type": "module",
"private": false,
"description": "描述",
"author": "作者",
"main": "lib/v3-elp-ui.umd.cjs",
"module": "lib/v3-elp-ui.umd.cjs",
"types": "lib/index.d.ts",
"files": [
"package.json",
"README.md",
"lib"
],
"scripts": {
"dev": "vite",
"lib": " vite build",
"build": "run-p type-check \"build-only {@}\" --",
"preview": "vite preview",
"build-only": "vite build",
"type-check": "vue-tsc --build --force",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
"format": "prettier --write src/"
},
"dependencies": {
"element-plus": "^2.7.5",
"less": "^4.2.0",
"vue": "^3.4.21"
},
"devDependencies": {
"@rushstack/eslint-patch": "^1.8.0",
"@tsconfig/node20": "^20.1.4",
"@types/node": "^20.12.5",
"@vitejs/plugin-vue": "^5.0.4",
"@vitejs/plugin-vue-jsx": "^3.1.0",
"@vue/eslint-config-prettier": "^9.0.0",
"@vue/eslint-config-typescript": "^13.0.0",
"@vue/tsconfig": "^0.5.1",
"eslint": "^8.57.0",
"eslint-plugin-vue": "^9.23.0",
"npm-run-all2": "^6.1.2",
"prettier": "^3.2.5",
"typescript": "~5.4.0",
"vite": "^5.2.8",
"vite-plugin-dts": "^3.9.1",
"vue-tsc": "^2.0.11"
}
}
经过以上操作能够正常打包,命令
npm run lib,在项目中验证正常,但是需要项目全局安装element plus支持全量引入和按需引入
需要再
main.ts中引入css文件
import 'v3-elp-ui/lib/style.css'
组件设置name属性
在编写组件的时候需要将name单独添加到一个script中,使用不方便,安装vite-plugin-vue-setup-extend可以直接在script上添加name
npm i vite-plugin-vue-setup-extend -D
在vite.config.ts中引入
import vueSetupExtend from 'vite-plugin-vue-setup-extend' // 设置neme属性
plugins: [vue(), dts(), vueJsx(), vueSetupExtend()],
集成vitepress及完善其配置
参考资料:
-
安装vitepress(也看用yarn、npm)
pnpm add vitepress -D -
在根目录创建文件夹
docs -
创建文件夹及文件,结构如下
docs ├── .vitepress │ ├── config │ │ ├── global.ts │ │ └── plugins.ts │ ├── config.ts │ ├── theme │ │ ├── index.ts │ │ └── useComponents.js │ ├── utils │ │ └── highlight.ts │ └── vitepress │ ├── components │ │ └── vp-demo │ ├── index.ts │ └── style │ ├── code.css │ ├── css-vars.scss │ ├── index.scss │ ├── mixins.scss │ └── vars.scss ├── components │ ├── button │ │ └── base.md │ └── index.md ├── demos │ └── button │ └── index.vue ├── index.md └── public ├── css │ └── index.css ├── favicon.ico └── img └── vue.jpg -
添加 scripts
"scripts": { "docs:dev": "vitepress dev docs", "docs:build": "vitepress build docs" }, -
首页配置(即:docs/index.md文件)如下修改:
--- layout: home title: vue3 + element plus 组件库 # titleTemplate: 选项卡描述 editLink: true lastUpdated: true hero: name: v3-elp-ui text: vue3基础组件 tagline: Vue3 中基于Element-plus二次封装基础组件文档 image: src: /img/vue.jpg alt: v3-elp-ui actions: - theme: brand text: 安装指南 link: /components/ - theme: brand text: 组件预览 link: /components/button/base.md features: - icon: 🔨 title: 实际项目 details: 实际项目中碰到的疑点、难点,致力于更优的自我。。 - icon: 🧩 title: 基础组件 details: 基于Element-plus二次封装;使用组件 Demo 快速体验交互细节。。 - icon: ✈️ title: Vue驱动。 details: 享受 Vue3 + vite3 的开发体验,在 Markdown 中使用 Vue 组件,同时可以使用 Vue 来开发自定义主题。 --- <p style="display: flex; justify-content: center; align-items: center; margin-top: 10px;"> <a href="https://github.com/vuejs/vue" target="_blank"> <img src="https://img.shields.io/badge/vue-3.2.36-brightgreen.svg" alt="vue3"> </a> </p> -
配置组件
在
demos目录下创建组件文件夹button,里面在创建对应的vue文件<template> <!-- 组件库中的包 --> <Btn /> </template>在
components文件夹中创建组件说明文档文件夹button,里面在创建base.md# 按钮组件 :::demo button/index :::在
components目录下创建index.md# 安装&使用 ::: tip 提示 v3ElpUi 是基于 vue3 + Element-plus 二次封装的基础组件 ::: ## 安装 ```js npm install v3-elp-ui & yarn add v3-elp-ui -S ``` ## 使用 ```js // main.js import v3ElpUi from "v3-elp-ui"; Vue.use(v3ElpUi); ``` ## 说明 需要项目全局安装`elemen-plus` -
接下来开始配置
vitepress,主要设置docs\.vitepress目录下的文件,代码较多就不写了.vitepress ├── config │ ├── global.ts # 设置文档库路径 │ └── plugins.ts # 用于扩展Markdown解析器markdown-it的功能,以便在Markdown文档中支持一种特殊的自定义容器(以demo标记),该容器可以用来展示代码示例及其描述。 ├── config.ts # vitepress配置文件 设置导航和侧边栏 ├── theme │ ├── index.ts # 安装注册组件 注册了element-plus he ziji de zuianku │ └── useComponents.js # 注册自定义组件 ├── utils │ └── highlight.ts # 实现代码高亮 └── vitepress ├── components │ └── vp-demo # 自定义组件 用来展示demo │ ├── index.vue │ ├── vp-example.vue # 注意 25行 的 demo表示组件demo文件夹 │ └── vp-source-code.vue ├── index.ts # 导出组件 └── style #代码样式 ├── code.css ├── css-vars.scss ├── index.scss ├── mixins.scss └── vars.scss-
docs\.vitepress\config\plugins.ts-
导入依赖:
- 引入了Node.js的
path和fs模块来处理文件路径和读取文件内容。 - 引入了TypeScript类型忽略注释
@ts-ignore来规避Markdown解析器和容器插件的类型检查问题,因为这些包可能缺少直接的TypeScript声明文件。 - 导入了
markdown-it库来解析Markdown文本,并且使用了markdown-it-container插件以支持自定义的容器块。 - 从本地
highlight函数和docRoot变量导入,用于代码高亮和获取文档根目录路径。
- 引入了Node.js的
-
定义类型:
ContainerOpts接口定义了传递给mdContainer插件的选项结构,包括验证函数、渲染函数和可选的标记。
-
创建Markdown解析实例:
- 创建了一个
MarkdownIt的实例localMd,用于渲染描述文本。
- 创建了一个
-
定义mdPlugin函数:
-
此函数接收一个
MarkdownIt实例作为参数,用于扩展Markdown解析功能。 -
使用
mdContainer插件定义名为"demo"的容器,该容器包含两部分逻辑:validate函数检查代码块是否以"demo"开头,并可选地捕获后续描述文本。render函数定义了如何渲染这种特殊类型的代码块。它读取指定的Vue组件文件,对组件源码进行高亮处理,然后构造一个<Demo>标签来包裹这些信息,包括组件源代码、文件路径、未经处理的源码以及可选的描述。
-
-
用途示例:
- 在Markdown文档中,用户可以通过以下方式插入组件示例:
::: demo 示例名称 src/components/Button.vue :::- 解析器会将上述Markdown转换成HTML,其中包含一个
<Demo>元素,属性包括组件的源代码(经过高亮处理)、原始文件路径、未编码的源代码以及描述(如果有的话)。
此代码片段极大地增强了Markdown文档的交互性和开发者的文档编写体验,特别是在需要频繁展示和文档化代码组件的项目中。
注意
第34行的demos代表组件demo文件夹 -
-
docs\.vitepress\utils\highlight.ts主要实现了代码高亮功能,使用了
prismjs库来对特定语言的代码进行语法高亮处理。以下是代码的关键部分和功能解释:-
导入依赖:
chalk:用于在控制台输出带有颜色的文本。escapeHtml:用于转义HTML特殊字符,防止XSS攻击。prism:代码高亮库,支持多种编程语言的语法高亮。consola:一个美观的日志记录库,常用于Node.js应用中。loadLanguages:动态加载prismjs的语言包,确保需要的语言支持已加载。
-
加载语言包:
- 使用
loadLanguages(["markup", "css", "javascript"])预先加载了一些常用的语言包,确保基本的代码高亮功能可用。
- 使用
-
wrap函数:- 接受一段代码和语言类型,如果语言类型是"text",则转义HTML特殊字符后包裹在
<pre><code>...</code></pre>标签内返回。否则,直接返回原始代码包裹在相同的标签内。
- 接受一段代码和语言类型,如果语言类型是"text",则转义HTML特殊字符后包裹在
-
highlight函数:- 是主要的代码高亮处理函数,接受要高亮的字符串和语言类型作为参数。
- 首先,如果没有指定语言类型,则默认按照纯文本处理。
- 然后,根据语言类型调整为
prismjs支持的标准语言标识符(如将vue调整为markup)。 - 接着,尝试加载对应语言的高亮规则,如果规则不存在,则尝试动态加载,并在加载失败时通过
consola.warn输出警告信息。 - 最后,如果成功加载了语言规则,使用
prism.highlight方法对代码进行高亮处理,并返回包裹好的HTML代码;否则,按纯文本处理返回。
综上所述,这段代码提供了一个灵活且健壮的代码高亮工具,能够适应多种编程语言,并且在遇到不支持的语言时提供了友好的警告提示。
-
-
-
最后安装依赖
# highlight.ts npm i chalk escape-html prismjs consola -D # plugins.ts npm i markdown-it markdown-it-container -D # demo文件 npm i @vueuse/core
说明文档添加搜索
查看代码没有找到4、7参考链接的搜索设置
经过上网搜索发现VitePress支持使用浏览器内置索引进行模糊全文搜索,查看4、7参考链接的确具有相同的设置
在.vitepress/config.ts文件中将themeConfig.search.provider选项设置为local即可
结束
最后就是对组件库进行打包上传并部署组件库文档了