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

2023-10-31

之前的文章# 手把手,如何搭建一个通用组件库,并发布到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方法,导出的均为组件本身。

先到这吧。

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

  • getScript 本地加载而不是全局加载?

    根据我的阅读 JQuery 的 getScript 函数使用名为 global eval 的函数在全局上下文中加载脚本文件 是否有特定的设置或方法可以更改此设置 以便它将改为在我调用它的函数中加载 如果我执行以下代码名称 则返回未定义 因为
  • Javascript 中的无限原型继承

    我正在学习 Javascript 中的原型继承 根据我的理解 我尝试使用它来将进程发送到无限递归链接中 我对原型继承的想法是一个对象 它是一个函数 保存原型链接 该对象的任何实例都指向它 因此 如果我说instance someproper
  • Express MongoDB find() 基于 _id 字段

    因此 在我的 Express 应用程序中 我尝试根据我的 id 字段查找 请参阅下面我的 MongoDB 记录 id oid 58c2a5bdf36d281631b3714a title EntertheBadJah subTitle Lo
  • 即使 WebPack 构建工作正常,VS Code 显示未找到模块

    我的 VS Code 说它找不到导入 即使我的 WebPack 构建仍然有效 这是进口 import as tf from tensorflow tfjs 以及来自 VS Code 的消息 找不到模块 tensorflow tfjs 您的意
  • 将对象传递给jquery中的回调函数

    我最近正在开发小型聊天模块 该模块需要不断检查服务器是否有新消息 我正在向服务器发送 ajax 请求 服务器将保持连接 直到找到新消息 长轮询 Code var chatController function other variable
  • 我可以在 Express POST 请求中进行 DOM 操作吗?

    我正在使用基本的 HTML CSS 前端 目前有一个登陆页面 上面有一个表单 可将 一些数据发送到数据库 当请求完成后 它期待某种响应 在这种情况下 我正在重新渲染页面 但是 我想用某种感谢消息替换表单 以便用户知道它已正确发送 我尝试过简
  • Ionic 和 Angular 2 - 拒绝应用“http://localhost:8100/build/main.css”中的样式,因为其 MIME 类型(“text/html”)不受支持

    My Ionic https en wikipedia org wiki Ionic mobile app framework 构建一直运行得很好 直到我想在我的 iPhone 上进行测试 所以我停止了我的服务器 做了一个ionic ser
  • 我可以检测焦点来源吗? (Javascript、jQuery)

    快速提问 是否可以检测焦点是来自鼠标单击还是来自焦点事件的选项卡 我想如果没有 我将不得不在同一元素上使用单击句柄来确定源 但我更喜欢通过焦点事件的方式 Thanks Gausie 可能无法 100 工作 但如果没有直接的方法 那么你不能直
  • JavaScript 附加和前置与 jQuery 附加和前置

    QA Style 我最近读了一篇文章 里面说JavaScript已经实现了append and prepend受 jQuery 启发的方法 这对我来说是一个新知识 因为据我所知 要附加一个元素 我必须使用element appendChil
  • 从右到左的语言和编程问题

    我正在创建一个网络文本编辑器 它使用我创建的新语言 如 BBcode 这种标记语言将采用阿拉伯语 但我面临这些问题 在所有 IDE 和编辑器中将英语和阿拉伯语文本混合在同一行中确实很困难 因为会发生奇怪的事情 单词和字符的顺序发生变化 使用
  • TypeError:React 中的循环对象值

    这是我的代码 sendMail e e preventDefault fetch https uczsieapp mailer herokuapp com var name document getElementById name var
  • JS 中的 .Jar 文件

    有谁知道如何在 JS 中访问 jar 文件 我已经用 Java 创建了类并作为 jar 文件导入 我想从 JS 文件访问该类 大家好 我感谢你们所有人 我尝试在 Firefox XUL 中使用 JS 列出文件夹中的文件 但我做不到 然后我决
  • 如何判断CKEditor是否已加载?

    如何确定 CKEditor 是否已加载 我查看了API文档 但只能找到loaded事件 我想检查 CKEditor 是否已加载 因为如果我第二次加载它 我的文本区域就会消失 The loaded活动对我不起作用 instanceReady
  • 如何从 JavaScript 中的 URL 中提取主机?

    捕获域直到结束字符 我需要一个捕获的正则表达式example com在所有这些中 example com 3000 example com pass gas example com example com 如果您确实有有效的 URL 那么这
  • 添加 sigma.js 导航按钮

    我是 javascript 和 sigma js 的新手 我试图让导航按钮在画布中向上 向下 向左 向右滚动 就像发现的那样here http jcml fr jacomyal osdc2012 demo 到目前为止 我有一个简单的例子 我
  • 为什么 useState 会导致组件在每次更新时渲染两次?

    我这里有一段简单的代码 import React useState from react import styles css export default function App const number setNumber useSta
  • 包括来自raw.github.com的js

    我有一个 github com 演示页面 链接到https raw github com master file js https raw github com master file js这样我就不需要总是复制 js文件转移到gh pag
  • Dojo require,模块加载失败时连接错误

    当我尝试加载不存在的模块时 它失败并出现 404 错误 当然 我想处理此错误 但不知道如何连接到 错误 事件 根据 Dojo 文档 我应该能够使用它的微事件 API http livedocs dojotoolkit org loader
  • RegisterClientScriptCode 在部分回发后不起作用

    以下代码行位于 SharePoint 网站的用户控件中 ScriptManager RegisterClientScriptBlock this this GetType jquery144 false ScriptManager Regi
  • 如何让JS变量在页面刷新后保留值? [复制]

    这个问题在这里已经有答案了 是否可以永久更改 JavaScript 变量 例如 如果我设置变量 X 并使其等于 1 然后按钮的 onClick 将该变量更改为 2 如何使该变量在刷新页面时保持为 2 这是可能的window localSto

随机推荐

  • File类读取文件---本地文件和网络文件

    读取本地文件 File file new File resource audio 5 mp3 InputStream in null try 一次读多个字节 byte tempbytes new byte 100 int byteread
  • Vue项目开发环境安装、项目构建运行、打包部署详解

    Vue项目开发环境安装 项目构建运行 打包部署详解 背景 Vue工程化项目环境配置还是比较麻烦的 本篇来详细的记录下从0开始的安装 构建 打包 运行全过程 整体步骤 第一 安装Node js 这个是前端工程化项目运行的基础环境 第二 安装V
  • Java 网络编程 —— RMI 框架

    概述 RMI 是 Java 提供的一个完善的简单易用的远程方法调用框架 采用客户 服务器通信方式 在服务器上部署了提供各种服务的远程对象 客户端请求访问服务器上远程对象的方法 它要求客户端与服务器端都是 Java 程序 RMI 框架采用代理
  • 【程序员面试系列】算法题练习-汇总(含华为OD机试题目)

    做个4月算法刷题集合 方便复习巩固 欢迎交流探讨 题库源于牛客网 ACM模式 语言 Java Python 题库链接 HJ1 字符串最后一个单词的长度 描述 计算字符串最后一个单词的长度 单词以空格隔开 字符串长度小于5000 注 字符串末
  • 如何修复损坏的word

    Word是许多人在日常工作中经常使用的软件 但有时它可能会出现意外的崩溃或文档损坏 这对于你正在编辑的文件和工作的进展都会产生重大影响 但是 你不需要过于担心 因为还是有一些方法可以通过修复Word文档中的损坏来解决这个问题 那么如何修复损
  • TCP三次握手,两次可以吗?

    这个问题网络上的回答超级多 众说纷纭 以 RFC 793 来回答这个问题可能更加准确 Reliability The TCP must recover from data that is damaged lost duplicated or
  • C语言——qsort()函数用法

    qsort函数简介及用法 一 qsort 函数的简介 二 qsort 函数实例 1 排序整形数组 2 排序double型数组 3 排序字符型数据 4 结构体类型数据排序 三 使用冒泡排序模拟qsort 函数 一 qsort 函数的简介 qs
  • ' requires string as left operand, not int' aria-label='TypeError: 'in ' requires string as left operand, not int'> TypeError: 'in ' requires string as left operand, not int

    报错 Traceback most recent call last File D PyCharm 5 0 3 WorkSpace 2 NLP 9 DL在NLP中的应用 4 VectorizerVisualization py line 4
  • docker和k8s的关系

    docker和k8s的关系 过去十年间 云计算的技术得到了长足的发展 越来越多的人开始了解 云原生 技术 以著名的云原生计算基金会 CNCF Cloud Native Computing Foundation 为首 各大企业和社区都开始发展
  • javascript:;与javascript:void(0)使用介绍

    最近看了好几个关于 a 标签和javascript void 0 的帖子 谨记于此 以资查阅 注 以下代码未经全面测试 但每一种方法可能会出现的情况都基本做了说明 在做页面时 如果想做一个链接点击后不做任何事情 或者响应点击而完成其他事情
  • 一文读懂CAN总线及通信协议

    CAN总线的汽车 CAN概念 CAN是控制器域网 Controller Area Network CAN 的简称 是由研发和生产汽车电子产品著称的德国BOSCH公司开发了的 并最终成为国际标准 ISO11898 是ISO国际标准化的串行通信
  • CTFSHOW web入门——web171

    首先查询有多少列 1 order by 3 然后查询库名 1 union select 1 2 database 查看ctfshow web库的表 1 union select 1 2 table name from information
  • AtomicInteger如何保证线程安全?

    1 AtomicInteger不是final类型 如何保证线程安全 先看一下AtomicInteger类局部源码 关注两个字段 U以及value public class AtomicInteger extends Number imple
  • 使用Kalibr工具线对相机+IMU离线标定

    传感器标定的准确后面做算法才会更准确 所以对Kalibr进行学习 一 Kalibr编译 1 下载kalibr包 GitHub下载地址 2 解压后放到 catkin ws src文件夹下 重新命令文件夹为kalibr 3 安装依赖库 sudo
  • wireshark抓包tcp为何没有四次挥手 而是三次挥手

    在wireshark上抓包 使用telnet直接连接baidu的ip 端口使用www p4 u1804 ping www baidu com PING www a shifen com 183 232 231 174 56 84 bytes
  • LDA(latent dirichlet allocation)的应用

    主题模型LDA latent dirichlet allocation 的应用还是很广泛的 之前我自己在检索 图像分类 文本分类 用户评论的主题词抽取等都用过 做feature 降维等 例如可以用主题维度来表示原来的字典维度 大大的降低了文
  • 最新骗局:利用支付宝快捷支付 套取手机验证码转账

    最新骗局 利用支付宝快捷支付 套取手机验证码转账 小心 骗子在你不知情的情况下 也能帮你开通支付宝快捷支付 昨天 市民王先生向媒体反映 骗子通过QQ知道他的银行账号等信息后 又通过花言巧语骗取他的手机验证码 替他开通支付宝快捷支付功能 并转
  • LeetCode-1237. 找出给定方程的正整数解【双指针,二分查找】

    LeetCode 1237 找出给定方程的正整数解 双指针 二分查找 题目描述 解题思路一 双指针 首先我们不管f是什么 即function id等于什么不管 但是我们可以调用customfunction中的f函数 然后我们遍历x y 1
  • 如何在Idea打开一个本地项目(超详细版)

    背景 网上关于Idea的介绍和使用其实很多了 但是答应了某人还是要写一个打开项目的详细教程 下载项目压缩包 从本地打开 比如说我下载一个海大校园通的项目到本地 解压后 打开Idea 在左上角点击File gt New gt Project
  • 手把手,如何搭建一个通用组件库?(文档+样式+按需打包

    之前的文章 手把手 如何搭建一个通用组件库 并发布到npm 搭建了一个简单的组件库框架 并发布到了npm 在文章结果也留了几个个坑 1 没有样式 2 文档系统也没有 3 组件也不能按需加载 我们今天来一一解决 样式系统 搭建之前 先来看看e