从零搭建vuepress2 + vue3 +element-plus 的组件库(一)

1,790 阅读5分钟

前言

每个前端都一定积累了很多常用的组件,每次开新的项目都需要从旧的项目中拷贝一份通用组件,这时候你会发现cv大法好,但是每个组件都在不断的使用中慢慢演进和完善,新项目更新了组件的新属性,新方法,但是有一天旧项目又开始了新的迭代,原来别的项目新增的属性又要照搬过来,一个组件的更新就如此反复下去。。。

一旦有新人接手了这样的组件,他可能并不熟悉组件有哪些功能,也无法准确掌握哪个项目用的这个祖件是哪个版本;如果这样的基础组件有个十个八个的,那简直就是灾难。

相信深受其害的人一定不少,那就话不多说,组件库安排!

根据这一系列的文章,我会带你从头到脚实现一个代码库,从文档库的搭建,到使用npm发包,以及使用Lerna实现分包管理分包发布,让你的组件库支持按需引入,也支持分包安装。

选型

vuepress2.x: 以markdown形式的来书写组件库文档,并生成一个静态网站,支持vue3

element-plus: 第三方组件库,全面拥抱vue3,我们的宗旨是能复用就复用,绝不造第二遍轮子,组件库大多数都是基于element-plus的二次封装。

vuepress-plugin-demoblock-plus: demo代码块插件,用于实现像element-plus那样的demo示例文档,做到示例和代码块只写一次,做到所见即所得。

一、组件库搭建+页面布局

这部分就是傻瓜式安装,照着官方文档简单配置就可得到一套模版,链接戳此:快速开始

配置顶部导航+侧边导航

const { defaultTheme } = require('@vuepress/theme-default')
module.exports = {
  lang: 'zh-CN',
  title: '组件库',
  description: '基于vue3 + element plus的UI组件库',
  theme: defaultTheme({
    // 导航栏配置
    navbar: [
      { text: '组件', link: '/components/button.html' },
      {
        text: '更新日志',
        link:'https://gitee.com/NewCoderMCL/vuepress-ui'
      }
    ],
    // 侧边栏数组
    // 所有页面会使用相同的侧边栏
    sidebar: {
      // 侧边栏
      "/": [
        {
          text: "介绍",
          children: [
            { text: "项目简介", link: "/guide/intro" },
            { text: "快速上手", link: "/components/installation" },
          ],
        },
        {
          text: "组件",
          children: [
            { text: "Layout 布局", link: "/components/layout" },
            { text: "Table 表格", link: "/components/table.md" }
          ],
        },
      ],
    },
  }),
}

使用vuepress-plugin-demoblock-plus插件实现demo-block文档渲染

同样是傻瓜式安装:戳此👇

怎么说呢,作者也在不断的更新维护,我在使用的时候插件还未全面支持最新版的vuepress,需要更换为新版require()的形式引入插件,不过作者也针对我的问题,给出了正解,在这里跪谢作者🙏。

如果你按着文档进行了安装和使用之后,仍然不生效,那么可以参考解决方案:解决vuepress2.0.0-beta.43版本使用不生效的问题,附上链接供大家参考。

二、注册封装组件以及引入第三方库

安装element-plus

yarn add element-plus -D

手动引入封装的组件,在docs/.vuepress/client.js文件配置如下,并引入第三方组件库

import { defineClientConfig } from '@vuepress/client'
// 全量引入element-plus
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'

// 手动引入自己封装好的组件
import BaseTable from '../../packages/table/src/index.vue'
import '../../src/styles/index.css'
import './styles/index.less'

export default defineClientConfig({
  enhance({ app }) {
    // 注册element-plus
    app.use(ElementPlus)
    // 注册组件
    app.component('BaseTable', BaseTable)
  },
})

此时就可以在docs/components/ 文件夹下书写组件文档,以及示例,如下是table.md的内容:

    :::demo

    ```vue
    <template>
      <base-table :tableData="tableData" :columns="columns"></base-table>
    </template>
    <script lang="ts" setup>
    const columns = [
      {
        label: '编号',
        type: 'index',
        width: '80px'
      },
      {
        label: '姓名',
        value: 'name',
        minWidth: '120px'
      },
      {
        label: '年龄',
        value: 'age',
        minWidth: '120px'
      }
    ]
    const tableData = [
      {
        name: '张三',
        age: '20',
      }
    ]
    </script>

    ```
    :::

浏览器访问/components/table.html,效果如下:

image.png 查看代码示例:

image.png

⚠️注意:每次开发新的组件都需要在docs/.vuepress/client.js中手动引入并注册组件,如果组件过多的话,这又是一些工作量,我们这种“懒蛋”当然要找轮子帮我们做这些工作啦,那就继续往下看吧。

自动注册组件

使用官方的插件register-components根据组件文件或目录自动注册 Vue 组件。

参考链接:v2.vuepress.vuejs.org/zh/referenc…

安装

yarn add -D @vuepress/plugin-register-components@next

.vuepress/config.js配置如下:

const { path } = require('@vuepress/utils')
const { registerComponentsPlugin } = require('@vuepress/plugin-register-components')

module.exports = {
   ...
  plugins: [
    registerComponentsPlugin({
      componentsDir: path.resolve(__dirname, '../../packages'), // 需要自动引入的组件所在的文件夹
      componentsPatterns:['**/*.vue'], // 组件格式为.vue结尾的文件
      // 注册组件的名称,这里因人而异,我在注册组件时,都统一加了`base`前缀,
      getComponentName:(filename) =>{
        let compName = filename.split('/')[0].toLowerCase()
        compName = compName.charAt(0).toUpperCase() + compName.slice(1)
        return `base${compName}`
      }
    }),
  ]
}

按照此方式注册组件,会加一个base-的前缀,如组件目录为packages/table/src/index.vue,用自动注册baseTable组件,使用时可以用<base-table></base-table>

三、Q&A

1、vuepress不能热更新

package.jsondocs:devvuepress dev docs改为 vuepress dev docs --temp .temp

"scripts": {
    "docs:dev": "vuepress dev docs --temp .temp",
    "docs:build": "vuepress build docs"
  },

2、其他demo代码块的使用,(这个有点难,没搞懂,后来放弃了,下面列了一些心路历程仅供参考)

参考:v2.vuepress.vuejs.org/zh/referenc…

1、安装插件@vuepress/plugin-container@next

yarn add -D @vuepress/plugin-container@next

.vuepress/config.js添加如下配置:

const { containerPlugin } = require('@vuepress/plugin-container')

module.exports = {
  plugins: [
    containerPlugin({
      // 配置项
      type: 'demo',
      validate(params) {
        //函数在开始标记后验证尾部,成功时返回true
        return params.trim().match(/^demo\s*(.*)$/);
      },
      render(tokens, idx) {
        //渲染器函数
        const m = tokens[idx].info.trim().match(/^demo\s*(.*)$/);
        if (tokens[idx].nesting === 1) {
          const description = m && m.length > 1 ? m[1] : '';
          // opening tag
          return `<demo-block>
                    <div slot="demo">组件demo</div>
                    <div slot="description">${description}</div>
                    <div slot="source">代码块</div>`;
        } else {
          // closing tag
          return `</demo-block>`;
        }
      }
    }),
    .....
  ],
}

2、注册 demoBlock组件

新建组件:.vuepress/components/demoBlock.vue

<template>
  <div class="block">
    <div class="demo-content">
      <!-- 插入组件 -->
      <slot name="demo"></slot>
    </div>
    <div class="meta" ref="meta">
      <div class="description">
        <!-- 插入描述信息 -->
        <slot name="description"></slot>
      </div>
      <div class="code-content">
        <!-- 插入代码块 -->
        <slot name="source"></slot>
      </div>
    </div>
  </div>
</template>

注册组件:v2.vuepress.vuejs.org/zh/guide/mi…,文档给出两种方式注册vue组件,本文使用在 .vuepress/client.{js,ts} 中手动注册组件。

// .vuepress/client.js
import { defineClientConfig } from '@vuepress/client'
import demoBlock from './components/demoBlock.vue'

export default defineClientConfig({
  enhance({ app }) {
    // 注册组件
    app.component('demoBlock', demoBlock)
  },
})

此时在md文件中使用后效果如下:

image.png

3、从入门到放弃,走到这里,真的走不下去了,参考了各种开放的第三方组件库的demoBlock配置,发现太难了,不是报一堆错就是搞不明白,大家感兴趣的话可以试着实现实现,如果成功了希望能戳我下,跪谢🙏🙏🙏。

四、结语

后续内容:

  • 使用npm发包
  • 使用Lerna实现monorepo的单一代码块,实现组件库的分包管理分包发布

如果到目前为止,您还对我后续的文章感兴趣的话,那就持续关注吧~