从零开始的组件库开发之旅:Onionl-UI 的诞生🚀

引言

Hey,大家好!今天想和大家分享一个特别的项目 ------ Onionl-UI,这是我最近在开发的一个组件库。为什么叫 Onionl-UI?因为像洋葱一样,要一层层剥开才能看到其中的奥秘(其实是因为我的Github网名叫 Onion-L 啦 😆)。

为什么要开发这个组件库?

相信很多人看到这篇文章都会向我发出灵魂拷问:"市面上已经有那么多成熟的组件库了,为什么还要重复造轮子?"说得对,但我的目标并不是造轮子,而是通过这个项目来学习开发的流程,深入探索前端工程化的实践。

项目现状

目前 Onionl-UI 还处于萌芽阶段。作为前端行业的一名小学生,我深知项目中还存在诸多不完善之处。但我始终认为:"实践是检验真理的唯一标准。"因此我希望通过项目得到成长,并且我也会尽自己的努力让项目不烂尾。

接下来,就让我向大家汇报一下,我是如何开发的。

💡 特别提醒:本项目还在十分早期的开发阶段,功能并不完善,如果您发现任何问题或有任何建议,都欢迎在 GitHub 上提出 issue 或 PR。感谢您的每一个建议!

技术选型:Vue 3 + Vite 的黄金搭档 🤔

作为一名 Vue 开发者,选择 Vue 3 作为基础框架是一个自然而然的决定。这里也就不过多赘述。在构建工具的选择上,我最终选择了 Vite。说实话,这个决定做出得很快,因为 Vite 实在是太香了!但说到库的打包,很多人可能会想到 Rollup,它确实是一个非常优秀的打包工具。但在项目初期,考虑到开发效率和上手难度,我选择了更加简单直接的 Vite。并且 Vite 底层用的就是 Rollup,这就意味着如果未来需要更细粒度的打包控制,我随时可以平滑迁移到 Rollup。

UnoCSS:原子化 CSS 的探索

在样式解决方案上,我选择了 UnoCSS 这个新兴的原子化 CSS 引擎。为什么是 UnoCSS 而不是 Tailwind CSS?因为 UnoCSS 更加轻量和灵活,它的按需生成特性让最终的样式文件体积小得惊人。具体可以看看Anthony Fu 大佬的文章:重新构想原子化 CSS,详细讲解了关于UnoCSS的功能,我个人认为是很酷的。

目录结构

python 复制代码
onionl-ui/
├── packages/                # 组件源码目录
│   ├── components/         # 基础组件
│   │   ├── button/
│   │   ├── input/
│   │   └── ...
│   ├── hooks/             # 通用 hooks
│   ├── utils/             # 工具函数
│   └── onionl-ui/         # 组件入口文件夹
├── docs/                  # 文档站点
├── play/                  # 组件测试预览
├── preset/                # UnoCSS预设
└── scripts/              # 构建脚本

组件库打包

组件库的打包是一个非常关键的环节,它决定了组件如何被其他开发者使用。让我来详细解释一下 Onionl-UI 的打包策略。

打包配置的核心思路

打包脚本主要完成三个核心任务:收集源文件、构建不同格式的输出、复制必要的文档文件。来看看具体实现:

ts 复制代码
async function buildAll() {
  // 1. 收集所有需要打包的源文件
  const input = excludeFiles(await glob('**/*.{js,ts,vue}', {
    cwd: pkgPath,
    absolute: true,
    onlyFiles: true,
  }))

  // 2. 针对不同的输出格式进行构建
  buildConfig.forEach(async ({ outPath, format, extend }) => {
    await build({
      build: {
        rollupOptions,
        minify: false,  // 保持代码可读性,方便调试
        sourcemap: true,  // 支持源码映射
        outDir: resolve(rootPath, outPath),
        lib: {
          entry: input,
          formats: [format],
          fileName: () => `[name].${extend}`
        }
      },
      plugins: [
        vue(),
        vueJsx(),
        UnoCSS(),
        dts({  // 生成类型声明文件
          include: ['packages/**/**/*.{vue,ts,tsx}'],
          exclude: ['packages/**/test/**'],
          outDir: 'dist/es',
          staticImport: true,
          insertTypesEntry: true,
        })
      ]
    })
  })

  // 3. 复制必要的文档文件
  await copyFiles()
}

接下来关于组件的写法就不过多赘述了,简单讲一下就是组件可以写成我们平时开发时那样的 vue 文件,同样可以使用 defineComponent结合 TSX/JSX 语法来实现更加高自由度高性能的复杂组件。

组件库单元测试:从 Button 组件说起 🧪

Button组件是最简单的,同时也是当前组件库第一个实现的组件(虽然目前为止也只写了两个😅),在众多测试框架中,我选择了 Vitest 作为测试框架。因为它完美集成了 Vite 生态。

安装必要的依赖:

css 复制代码
pnpm i -D vitest happy-dom @vue/test-utils

测试这一方面我之前不太了解,只知道单元测试可以用来测函数的输入与输出,但是组件是跑在浏览器上的,显然nodejs环境无法完成,这时就需要 happy-dom 在nodejs环境来模拟DOM。而@vue/test-utils 则是 Vue 官方的测试工具集,能更方便地测试 Vue 组件。

配置Vitest:

ts 复制代码
import vue from '@vitejs/plugin-vue'
import { defineConfig } from 'vitest/config'
  
export default defineConfig({
  plugins: [vue()],
  test: {
    environment: 'happy-dom',
    globals: true,
    testTimeout: 10000,
    coverage: {
      reporter: ['text', 'json', 'html'],
      exclude: ['play/**'],
    },
  },
})

之后就可以编写测试用例了,这里先给出一个最简单的测试,测试了按钮组件的一些默认的内容:

ts 复制代码
describe('button Component', () => {
  it('renders default button correctly', () => {
    const wrapper = mount(Button, {
      slots: {
        default: 'Button Text',
      },
    })

    expect(wrapper.classes()).toContain('ol-button')
    expect(wrapper.text()).toBe('Button Text')
    expect(wrapper.classes()).toContain('ol-button__size-sm')
    expect(wrapper.classes()).toContain('ol-button__type-primary')
  })
})

总结

开发这个组件库的初衷,并不是为了重复造轮子,而是希望通过实践来深入学习前端工程化的流程。作为一名前端新人,我深知项目中还有很多不完善之处,但正是这种不完美才给了我改进的空间和学习的机会。

如果您觉得这个项目有价值,欢迎给我一个 star ⭐️(项目地址:Onionl-UI)。您的每一个建议和反馈,都将帮助这个项目变得更好。让我们一起在实践中成长!

道阻且长,行则将至。与诸君共勉。

相关推荐
憧憬成为web高手2 小时前
ACTF 12307复现
前端·bootstrap·html
wordbaby3 小时前
Axios 上传大文件崩溃:鸿蒙 RNOH 下 XHR 返回空响应头引发的"假失败"
前端·react native
wordbaby3 小时前
React Native 列表分页实战:下拉刷新与上拉加载的工程化方案
前端·react native
wordbaby4 小时前
脱离 Tab 栏的艺术:React Native 全屏子页面的导航架构实践
前端·react native·harmonyos
陈随易4 小时前
Redis 8.8发布,一定要更新
前端·后端·程序员
wordbaby4 小时前
React Native 新架构落地鸿蒙:跨三端政务级应用的工程实践与深度复盘
前端·react native·harmonyos
excel6 小时前
为什么我推荐使用 Termius:现代 SSH 工具的完整体验
前端·后端
ZC跨境爬虫6 小时前
模块化烹饪小程序开发日记 Day7:(菜谱详情接口开发与JSON数据读取全流程)
前端·javascript·css·ui·微信小程序·json
এ慕ོ冬℘゜6 小时前
JS 前端基础面试题
开发语言·前端·javascript
LaughingZhu6 小时前
Product Hunt 每日热榜 | 2026-05-25
前端·人工智能·经验分享·chatgpt·html