手把手,如何搭建一个通用组件库?(文档+样式+按需打包

之前的文章# 手把手,如何搭建一个通用组件库,并发布到npm?搭建了一个简单的组件库框架,并发布到了npm。

在文章结果也留了几个个坑,

1.没有样式

2.文档系统也没有

3.组件也不能按需加载

我们今天来一一解决。

样式系统

搭建之前,先来看看element-plus的样式。

主要分为几个部分,公共样式,混入函数,每个组件对应的样式。

我看了其他几个库,也大概是这种模式。

先看一下var_scss文件。

通过map定义选项,然后通过map.get来获取对应的值,具体的样式,通过各种函数来进行计算。

大概思路有了,就来搭建我们自己的样式。

首先是全局样式,以及公用样式。

具体的组件样式跟函数,我放在组件同级目录中。

文档系统

文档系统用的是vitepress。

相比于老大哥vuepress。

vitepress跟vite兼容会更好一些,更轻量一些,但是毕竟比较新,可能坑也会多一些。大家可自行选择。

快速上手,我就不介绍了,官方有详细的说明。

安装好了之后,项目跑起来,就能看到一个简单的文档了。

现在我们就可以直接md在上面写vue语法了。

并不是很方便,对吧——button需要写两次

我们希望的是写一次,既有效果,又能展示代码片段。

所以,引入一个插件——vitepress-theme-demoblock。

  markdown: {
    config(md) {
      // 这里可以使用markdown-it插件
      md.use(demoBlockPlugin, {
        scriptImports: ["import * as bubuUI from '@/index'"],
        scriptReplaces: [
          {
            searchValue: /import ({.*}) from 'bubu-ui'/g,
            replaceValue: (s, s1) => `const ${s1} = bubuUI`,
          },
        ],
      });
    },
  },
复制代码

scriptImports里面的配置是将doc文档中的import引入替换成本地文件,这样打包之后就不需要做修改了。开发时请求本地文件,打包后使用npm版本。

注意:vitepress-theme-demoblock插件暂不支持vue3.2.44以后得setup写法。需要使用defineComponent写法,且引入库需要使用单引号。

参考如下。

<template>
  <bu-checkbox v-model="val" label="A"></bu-checkbox>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
export default defineComponent({
  setup() {
    const val = ref(false);
    return {
      val,
    };
  },
});
</script>
复制代码

docs的详细请求,大家可以看一下官方文档。

我当时是直接拷贝了vitepress官网上的配置,然后修改侧边栏菜单。

配置好的文档长这样。

按需打包

我们使用ui库一般有2种方式。

一种是全局引入。

import BuBuUI from "bubu-ui"

app.use(BuBuUI)

复制代码

另一种是按需引入。

我们就只管用,不需要管引入的问题,比如我用bu-button,就自动到对应的包中去拿组件。

import BuButton from "bubu-ui/components/button"

app.use(BuButton)

复制代码

所以我们需要,把组件单独打包出来。

我们自己写一个脚本,通过vite的buid方法来构建。

import { defineConfig, build } from 'vite';

build({
   build: {
       // 配置跟vite.config.ts文件基本相同
   }
})

复制代码

这个只是全局打包,还需要多走一步,就是遍历components文件夹的组件,找到index.ts入口文件,重新执行一遍build打包。

打包出来的文件如下,components中的就是单独打出来的组件包。

到这里,还有个问题,ts文件在src/components中,而打包出来的子组件,在components中。(如果打包的时候指定一样的目录,会相互覆盖)

我的解决方案就是写了个拷贝函数,直接把components下的组件,直接拷贝到src/components中。如果哪位大佬有比较优雅的方式,欢迎指正留言,感谢感谢。

  // 如果目标文件夹不存在,创建目标文件夹
  if (!fse.existsSync(destPath)) {
    fse.mkdirSync(destPath);
  }

  let files;
  // 读取源文件夹下的所有文件和子文件夹
  try {
    files = fse.readdirSync(srcPath);
  } catch (err) {
    return;
  }

  // 遍历所有文件和子文件夹
  files.forEach((file) => {
    // 拼接文件路径
    const srcFilePath = join(srcPath, file);
    const destFilePath = join(destPath, file);

    // 如果是文件夹,递归复制文件夹
    if (fse.statSync(srcFilePath).isDirectory()) {
      copyFolder(srcFilePath, destFilePath);
    } else {
      // 如果是文件,复制文件
      fse.copyFileSync(srcFilePath, destFilePath);
    }
  });
复制代码

现在单独的组件包也有了,还差最后一步。

按需引入

安装unplugin-vue-components,这也是element-plus用的方案。

配置替换规则。

    Components({
      dts: true,
      resolvers: [
        (componentName) => {
          if (componentName.startsWith('Bu')) {
            return { name: componentName, from: `bubu-ui/src/components/${componentName.slice(2)}` }
          }
        }
      ]
    })

复制代码

作用就是,如果有组件是以Bu开头的,就从ui库的src/components下引入组件。然后通过vue的components方法注册组件。

<template>
  <BuButton type="primary">nihao</BuButton>
</template>
复制代码

以上的组件使用方式,就相当于如下写法

<template>
  <BuButton type="primary">nihao</BuButton>
</template>
<script lang="ts">
import { defineComponent } from "vue"
import { BuButton } from "bubu-ui/src/components/button"
defineComponent({
  components: {
    BuButton
  }
})
</script>
复制代码

总结

到这里,一个通用的组件库基本算是搭建完成了,也能发布上线使用了。

但是要真正封装出一个好用的ui组件库,还是有很多细节需要实现。

举几个例子

1.element-plus支持手动按需导入

<template>
  <ElButton type="primary">nihao</ElButton>
</template>
<script lang="ts">
import { ElButton } from "element-plus"
</script>
复制代码

他的入口文件,并没有把每个组件都打包进去。

这个有大佬知道怎么弄的,也欢迎联系我,感谢。

2.组件开发过程中的相互引用

在组件开发过程中,如果存在组件相互引用,那么我们最好的方式是开发的时候引用本地,打包上线的时候引用的是对应的模块。

这个就涉及到包模块管理了。

3.element-plus的类型封装

element支持如下2种使用方式,又能当插件,又能当组件。

// 1
import { ElButton } from "element-plus"
app.use(ElButton)

// 2
import { ElButton } from "element-plus"
app.component(ElButton)
复制代码

在element-plus中,在组件上添加了一个install方法,导出的均为组件本身。

先到这吧。

后续如果有新的感悟,或者对架构有新的思考再分享。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,下面是从零开始封装一个基于videojs和vue的视频播放器组件的步骤。 1. 安装依赖 首先要安装video.js和vue-video-player这两个依赖: ``` npm install video.js vue-video-player --save ``` 2. 创建组件 创建一个名为VideoPlayer.vue的组件文件,并在文件中引入video.js和vue-video-player: ```html <template> <div> <video ref="videoPlayer" class="video-js"></video> </div> </template> <script> import videojs from 'video.js' import 'video.js/dist/video-js.css' import VueVideoPlayer from 'vue-video-player' export default { name: 'VideoPlayer', props: { options: { type: Object, default: () => ({}) } }, data() { return { player: null } }, mounted() { this.initPlayer() }, methods: { initPlayer() { this.player = videojs(this.$refs.videoPlayer, this.options, function onPlayerReady() { console.log('player is ready') }) } }, beforeDestroy() { if (this.player) { this.player.dispose() } } } </script> <style> /* video.js样式 */ .video-js { width: 100%; height: 100%; } </style> ``` 在组件中,我们使用了video.js创建了一个video标签,并将其挂载到组件中。同时,我们通过props传递了一些配置项,如autoplay、controls等。 3. 使用组件 使用该组件时,可以通过options属性传递一些配置项,如下所示: ```html <template> <div> <VideoPlayer :options="{ autoplay: false, controls: true, sources: [{ src: 'http://example.com/path/to/video.mp4', type: 'video/mp4' }] }" /> </div> </template> <script> import VideoPlayer from './VideoPlayer.vue' export default { name: 'App', components: { VideoPlayer } } </script> <style> /* 样式 */ </style> ``` 在使用组件时,我们只要传递一个options属性,其中包含了视频链接、视频类型、是否自动播放等配置即可。这里我们只提供了一个视频链接,实际使用时可以根据求添加更多的源。 至此,一个基于video.js和vue的视频播放器组件就完成了。要注意的是,该组件在使用时要提供video.js的样式文件,并且要在mounted生命周期函数中初始化播放器,以及在beforeDestroy生命周期函数中销毁播放器实例。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值