从零开始的组件库开发之旅: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)。您的每一个建议和反馈,都将帮助这个项目变得更好。让我们一起在实践中成长!

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

相关推荐
向前看-20 分钟前
验证码机制
前端·后端
燃先生._.1 小时前
Day-03 Vue(生命周期、生命周期钩子八个函数、工程化开发和脚手架、组件化开发、根组件、局部注册和全局注册的步骤)
前端·javascript·vue.js
高山我梦口香糖2 小时前
[react]searchParams转普通对象
开发语言·前端·javascript
m0_748235242 小时前
前端实现获取后端返回的文件流并下载
前端·状态模式
m0_748240253 小时前
前端如何检测用户登录状态是否过期
前端
black^sugar3 小时前
纯前端实现更新检测
开发语言·前端·javascript
寻找沙漠的人4 小时前
前端知识补充—CSS
前端·css
GISer_Jing4 小时前
2025前端面试热门题目——计算机网络篇
前端·计算机网络·面试
m0_748245524 小时前
吉利前端、AI面试
前端·面试·职场和发展