话不多说,先看成品👇

@wei_design/web-vue

A Vue.js 3 UI library

vite+ts+vue3搭建组件库 - 图1
vite+ts+vue3搭建组件库 - 图2
vite+ts+vue3搭建组件库 - 图3

技术栈

关于技术选型
2022年了,相信对于vitevue3听得不能再多了,对于他们的剖析也多的不能再多了,
如果你还没用上这些,何不造个组件库,一起卷起来…


vue

https://cn.vuejs.org/
这里使用vue3去搭建,其实就是多了一些api,换了写法,选项式api和组合式api的切换了,也可以更丝滑的使用ts
要使用vue2的写法也不是不可以,但不推荐

  1. "vue": "^3.2.*"

vite

https://cn.vitejs.dev/
原生esm打包工具,没用过的刚好可以练练手

  1. "vite": "^3.0.*"

typescript

vue3用ts重写了,性能和体积都更优秀了,2202年了,ts卷起来

  1. "typescript": "^4.*.*"

vitepress

  1. "vitepress": "^1.0.0-alpha.*"

当然,组件库必须得有一个文档库了,这里使用vitepress1.0.0-alpha.*,虽然还是alpha,但看到UI相信你也会用上他的
vite官网也更新了vitepress1.0.0-alpha.*

vitejs-dev-1662039236347.png

项目搭建

Node Version:>=16.0.0
可以选择通过vite提供模板创建,也可以使用vue-cli来创建
当然,伟大的项目都是从git init开始的

1、vite模板创建

https://vitejs.dev/guide/#scaffolding-your-first-vite-project

  • npm
  1. npm init vite@latest
  • yarn
  1. yarn create vite

doc-vite-vue-ts-init.jpg
选择Vue并选择使用TypeScript

也可以直接指定对应的模板来初始化

  1. yarn create vite vite-app-vue --template vue-tsc

2、vue cli创建

https://cn.vuejs.org/guide/quick-start.html#with-build-tools

  1. npm init vue@latest

使用官方vue cli可以提供给你对于TypeScriptESLintVitest之类的可选支持

  1. Vue.js - The Progressive JavaScript Framework
  2. Project name: web-vue
  3. Add TypeScript? No / Yes
  4. Add JSX Support? No / Yes
  5. Add Vue Router for Single Page Application development? No / Yes
  6. Add Pinia for state management? No / Yes
  7. Add Vitest for Unit Testing? No / Yes
  8. Add Cypress for End-to-End testing? No / Yes
  9. Add ESLint for code quality? No / Yes
  10. Add Prettier for code formatting? No / Yes
  11. Scaffolding project in /Users/forguo/work/wei-design/web-vue...
  12. Done. Now run:
  13. cd web-vue
  14. npm install
  15. npm run lint
  16. npm run dev

如果为了省事,使用vue-cli即可,就不用后面再去配置ESLintPrettier
eslint + prettier 配置


使用vue-cli搭建之后,此时的文件夹目录是这样的
image.png

组件库搭建

关于组件库引用

首先,来说说组件库的引用,众猿周知
使用npm包有两种方式,还有cdn引入(后面会说怎么使用免费cdn)

1、全量引用

main.js

  1. import { createApp } from 'vue';
  2. import App from './App.vue';
  3. // 完整引入组件库
  4. import WeDesign from '@wei_design/web-vue';
  5. const app = createApp(App);
  6. // 全局安装
  7. app.use(WeDesign).mount('#app');

组件当中

  1. <WeButton :loading="true">按钮组件</WeButton>

2、按需引入

main.js

  1. import { createApp } from 'vue';
  2. import App from './App.vue';
  3. // 按需引入
  4. import { Button } from '@wei_design/web-vue';
  5. const app = createApp(App);
  6. app.use(Button).mount('#app');

组件当中

  1. <WeButton :loading="true">按钮组件</WeButton>

要做一个组件库,就得提供这两种引入方式

开始第一个组件

1、组件开发

需要先来添加下sass编译器

  1. pnpm install sass

添加packages/components文件夹,或mkdir packages/components,这里用来存放组件库的源码
添加button文件夹,也就是第一个组件button

组件文件夹可以这样来组织

  1. ├── src # 组件源码
  2. ├── index.scss # 样式
  3. ├── index.vue # 组件
  4. │── index.ts # 组件库导出

index.scss中添加样式

  1. @import "../../../theme/color.variables";
  2. button {
  3. outline: none;
  4. }
  5. .we-button {
  6. padding: 8px 12px;
  7. overflow: hidden;
  8. border-radius: 6px;
  9. border: 0;
  10. text-align: center;
  11. display: inline-block;
  12. position: relative;
  13. outline: none;
  14. font-weight: 400;
  15. -webkit-appearance: none;
  16. user-select: none;
  17. cursor: pointer;
  18. white-space: nowrap;
  19. transition: all 0.1s linear;
  20. box-sizing: border-box;
  21. }
  22. .we-button-type-default {
  23. background: $primaryColor;
  24. color: $white;
  25. }
  26. .we-button-disabled {
  27. background-color: #f7f7fa;
  28. cursor: not-allowed;
  29. color: $black;
  30. &:focus,
  31. &:hover {
  32. background-color: #f7f7fa;
  33. outline: none;
  34. }
  35. }

index.vue中添加button组件代码
vue3ts可以提前来浅学一下

  1. <template>
  2. <button :class="[classString]" :disabled="disabled">
  3. <slot></slot>
  4. </button>
  5. </template>
  6. <script lang="ts">
  7. import { defineComponent, PropType } from 'vue'
  8. import './index.scss'
  9. const Props = {
  10. type: {
  11. type: String as PropType<string>, // 转为ts类型string
  12. default: 'default'
  13. },
  14. disabled: {
  15. type: Boolean as PropType<boolean>,
  16. default: false
  17. },
  18. }
  19. export default defineComponent({
  20. name: 'WeButton',
  21. props: Props,
  22. setup(props) {
  23. const classString = [
  24. 'we-button',
  25. `we-button-type-${props.type}`,
  26. props.disabled ? 'we-button-disabled' : ''
  27. ]
  28. return {
  29. classString
  30. }
  31. }
  32. })
  33. </script>

添加index.ts
组件注册
单个组件的使用,也有局部注册和全局注册

局部注册通过components来完成
全局注册就得通过App.component(Button.name, Button)
当然,这样页比较麻烦,可以直接提供install方法,使用的时候通过use方法来完成注册

  1. import { App } from 'vue'
  2. import Button from './src/index.vue'
  3. Button.install = function (app: App) {
  4. // 组件注册,按需引入
  5. app.component(Button.name, Button)
  6. return app
  7. }
  8. export default Button

2、组件库导出

添加component.ts,导出所有的组件

  1. /**
  2. * 导出所有组件
  3. */
  4. import Button from './components/button'
  5. export default [Button]
  6. export { Button }

添加index.ts,提供组件库全量注册引入及单个组件注册引入

  1. import { App } from 'vue'
  2. import components from './component'
  3. // 所有组件
  4. export * from './component'
  5. // 完整引入组件
  6. const install = function (app: App) {
  7. components.forEach(component => {
  8. app.use(component as unknown as { install: () => any })
  9. })
  10. }
  11. export default {
  12. install
  13. }

也可以添加一些公共的工具及插件到packages文件夹下
最终的packages是这样的

  1. ├── components/* # 组件源码
  2. │── theme # 样式及主题文件
  3. │── utils # 工具及插件
  4. │── component.ts # 所有的组件都在这里来管理
  5. │── index.ts # 导出单个组件或者整个组件库

3、调试

src/main.js中引入组件库来测试组件的效果

  1. import { createApp } from 'vue'
  2. import App from './App.vue'
  3. // 完整引入组件库
  4. import WeDesign from '../packages/index' // 可以配置alias
  5. const app = createApp(App)
  6. app.use(WeDesign).mount('#app')

app.vue当中使用

  1. <template>
  2. <div class="wei-app">
  3. <h1>wei-design</h1>
  4. <hr>
  5. <div>
  6. <we-button>按钮组件</we-button>
  7. <we-button style="margin-left: 12px" disabled>按钮组件</we-button>
  8. </div>
  9. </div>
  10. </template>

run一下,看下效果,组件库的雏形就好了image.png


packages最终是这样的
image.png

规范化

可以提前配置好,开发体验会更好,就不具体讲了

Git提交规范

组件库发布

组件库开发好了,就得发布npm,别人就可以来安装使用了
创建并发布一个npm包

1、打包配置

vite库模式配置
编辑vite.config.ts

  1. // [vite库模式配置](https://cn.vitejs.dev/guide/build.html#library-mode)
  2. build: {
  3. outDir: 'lib',
  4. lib: {
  5. entry: resolve(__dirname, './packages/index.ts'),
  6. name: 'WebVue',
  7. fileName: 'web-vue'
  8. },
  9. rollupOptions: {
  10. // 确保外部化处理那些你不想打包进库的依赖
  11. external: ['vue'],
  12. output: {
  13. // 在 UMD 构建模式下为这些外部化的依赖提供一个全局变量
  14. globals: {
  15. vue: 'Vue'
  16. }
  17. }
  18. }
  19. },

配置好之后,执行npm run build完成打包
image.png

2、package配置

主要需要修改以下几点
package.json中的browser,module,main解析

  1. {
  2. "name": "@wei_design/web-vue", // 包名,可以直接是包名,也可以@wei_design[组织]/web-vue[包名]
  3. "private": false, // 是否私有包,发布公共的需要设置false
  4. "version": "1.0.0", // 版本,每次发布都需要修改
  5. "author": "wforguo@qq.com",
  6. "description": "Wei Design - A Vue.js 3 UI library, @wei_design/web-vue", // 包的简述
  7. "keywords": [
  8. "@wei_design/web-vue" // 关键词
  9. ],
  10. "homepage": "https://wei-design.github.io/web-vue/",
  11. "repository": {
  12. "type": "git",
  13. "url": "https://github.com/wei-design/web-vue.git"
  14. },
  15. // 主要上传哪些文件或者文件夹到npm
  16. "files": [
  17. "lib/*",
  18. "packages/*",
  19. "Readme.md",
  20. "package.json"
  21. ],
  22. // 入口文件【注意文件后缀】
  23. "main": "./lib/web-vue.umd.js",
  24. "module": "./lib/web-vue.mjs",
  25. "exports": {
  26. ".": {
  27. "import": "./lib/web-vue.mjs",
  28. "require": "./lib/web-vue.umd.js"
  29. },
  30. // 这里css页需要导出,否则导入css会报错
  31. "./lib/style.css": "./lib/style.css"
  32. },
  33. "engines": {
  34. "node": ">=16.0.0"
  35. }
  36. }

3、npm发布

如何发布自己的 npm 包
首先去注册一个npm账号
在电脑terminal中登录npm,可以使用npm whoami先来查看npm登录状态

  1. npm login
  • 私有发布

npm publish 命令执行,默认是进行私有发布
scoped的包私有发布时需要收费

  • 公共发布
    1. npm publish --access public
    发布成功之后,邮箱也会收到提醒

好了,到这里,你的组件库就已经成功上线了
接下来就是去使用看看有没有什么问题

  1. import { createApp } from 'vue';
  2. import App from './App.vue';
  3. // 完整引入组件库
  4. import WeDesign from '@wei_design/web-vue';
  5. const app = createApp(App);
  6. // 全局安装
  7. app.use(WeDesign).mount('#app');

使用CDN

Free CDN for Open Source
两个都是开源免费的CDN,只要你发布了npm,替换下面包名为就可以去使用了

1、unpkg

资源浏览 https://unpkg.com/@wei_design/web-vue/

  1. <link
  2. rel="stylesheet"
  3. href="//unpkg.com/@wei_design/web-vue/lib/style.css"
  4. />
  5. <script src="//unpkg.com/@wei_design/web-vue"></script>

2、jsdelivr

资源浏览 https://cdn.jsdelivr.net/npm/@wei_design/web-vue/

  1. <link
  2. rel="stylesheet"
  3. href="//cdn.jsdelivr.net/npm/@wei_design/web-vue/lib/style.css"
  4. />
  5. <script src="//cdn.jsdelivr.net/npm/@wei_design/web-vue"></script>

问题及解决

列举了一些自己遇到的问题,希望不会帮到你
如果有遇到问题,不知道怎么解决,可以到github上@wei_design/web-vue对比代码看下是否哪里有不对的地方

  • 【组件库发布】npm publish 时提示需要升级TLS 1.2的解决方案

看看registry是否是https的,否则需要切换到https

  1. npm config set registry https://registry.npmjs.org
  • 【组件库npm使用】副作用导致打包后引入npm中的css报错

sideEffects

  • 【文档库】运行报错报错:TypeError: Invalid value used as weak map key

md中有无法解析的标签导致

  • 【组件库npm使用】引入lib/style.css导致ModuleNotFound错误

image.png
修改exports导出条件语法,新增./lib/style.css

  1. "exports": {
  2. ".": {
  3. "import": "./lib/web-vue.es.js",
  4. "require": "./lib/web-vue.umd.js"
  5. },
  6. "./lib/style.css": "./lib/style.css"
  7. }
  • 【文档库】vitepress打包报错

To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
image.png

解决办法,修改vite.config.ts中lib配置

  1. build {
  2. lib: {
  3. entry: resolve(__dirname, './packages/index.ts'),
  4. name: 'WebVue',
  5. fileName: 'web-vue'
  6. },
  7. }

修改package.json

  1. "main": "./lib/web-vue.umd.js",
  2. "module": "./lib/web-vue.mjs",
  3. "exports": {
  4. ".": {
  5. "import": "./lib/web-vue.mjs",
  6. "require": "./lib/web-vue.umd.js"
  7. },
  8. "./lib/style.css": "./lib/style.css"
  9. },

文档库搭建

04F5F5DD.jpg
正在努力加载中….


都到这了,点个赞再走吧
GitHub奉上…