news 2026/9/28 7:25:24

构建 Dendron Design System:基于 TSDX 的设计系统开发、字体集成与发布实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
构建 Dendron Design System:基于 TSDX 的设计系统开发、字体集成与发布实战指南
  • 知识管理
  • 知识库

【免费下载链接】dendron

The personal knowledge management (PKM) tool that grows as you do!

项目地址:https://gitcode.com/gh_mirrors/de/dendron
点击查看免费下载

Dendron 是面向个人知识管理(PKM)的开源工具,其前端生态由多个 npm 包构成。dendron-design-system是其中负责统一视觉规范与共享 UI 组件的基础包:它基于 TSDX 脚手架搭建,内置 Chakra UI 主题(字体、品牌色)与 Logo 组件,并通过 Storybook、Example Playground 与 size-limit 建立了一套"开发—预览—体积管控—发布"的完整工作流。阅读本文后,你将掌握该设计系统的目录结构、字体与主题集成方式、TSDX 开发命令、组件测试与体积分析,以及在 Lerna 单仓中运行 Example 与发布到 Netlify 的完整实操方案。

设计系统概览:包结构与工程定位

dendron-design-system位于 packages/dendron-design-system,是一个以 React 为基础、通过 TSDX 可以确认它的工程定位:

  • 包名与产物:name为dendron-design-system,main指向dist/index.js(CJS 产物),module指向dist/dendron-design-system.esm.js(ESM 产物),typings指向dist/index.d.ts,发布时仅打包dist与src两个目录;
  • 运行时依赖:@chakra-ui/react(组件与主题体系)、@emotion/react/@emotion/styled(样式引擎)、@fontsource/montserrat与@fontsource/roboto(自托管字体)、framer-motion(动画);
  • 对宿主的要求:peerDependencies声明react >= 16,即宿主项目只需保证 React 版本不低于 16 即可引入本设计系统。

目录结构分为五大部分:src/(组件与主题源码)、example/(Parcel 驱动的示例 Playground)、stories/(Storybook 故事)、test/(单元测试)与public/(静态资源,如 dendron-vector.svg Logo 矢量图)。

字体策略:Montserrat + Roboto 双字体方案

设计系统在字体上采用了明确的"标题/正文"双字体搭配:Montserrat作为标题字体(header font),Roboto作为正文字体(body font)。之所以选择 Montserrat,是因为它已在当时的 dendron.so 官网上投入使用,属于延续既有品牌视觉;Roboto 则来自 Google Fonts 的推荐搭配,用于保证正文的长文可读性。

通过 Fontsource 自托管,而非 CDN 加载

按 README 的说明,字体引入方式采用了 Chakra UI 官方指南中推荐的Fontsource 方案(自托管字体包)。与依赖 Google Fonts CDN 不同,Fontsource 将字体文件打包进 npm 依赖,随设计系统一起分发,宿主项目无需联网请求外部字体服务,加载更稳定、隐私更友好。

在 package.json 中可以看到两个字体依赖:

"@fontsource/montserrat": "^4.2.2", "@fontsource/roboto": "^4.2.2"

宿主项目只需两行 import

字体将随设计系统一起被打包分发,宿主项目唯一需要做的,是在应用最底层引入字体样式:

import '@fontsource/montserrat'; import '@fontsource/roboto';

对于 Next.js 项目,这个位置就是_app.tsx(应用入口组件)。README 注明该导入方式已在本仓库的preview.tsx中完成过。需要注意:这只是一种"接入约定"——字体样式导入必须发生在任何组件渲染之前,因此 README 特别强调"at the lowest app level"。

主题层:字体与品牌色如何注入 Chakra UI

字体导入解决的是"字体文件可用"的问题,而"哪些场景用哪种字体"则由主题配置决定。看 src/theme/fonts.ts:

export const fonts = { heading: "montserrat", body: "roboto", };

heading对应标题类组件(如Heading),body对应正文类组件(如Text),两者恰好与 README 中的设计决策一一对应。

与之配套的是品牌色板 src/theme/colors.ts:

export const colors = { brand: { lightGreen: "#43B02A", darkGreen: "#154734", neutralBlack: "#232222", }, };

lightGreen(亮绿)与darkGreen(深绿)构成品牌主色系,neutralBlack作为中性色基准。最终在 src/theme/index.ts 中通过 Chakra UI 的extendTheme合并为完整的主题对象并导出:

import { extendTheme } from "@chakra-ui/react"; import { colors } from "./colors"; import { fonts } from "./fonts"; export const theme = extendTheme({ colors, fonts, });

extendTheme是 Chakra UI 提供的主题扩展入口,它会在保留 Chakra 默认设计令牌的基础上,用本设计系统自定义的colors与fonts覆盖同名令牌。宿主项目引入该主题后,所有 Chakra 组件的字体与配色即自动对齐品牌规范。

开发工作流:TSDX 构建 + Storybook + Example Playground

本设计系统基于 TSDX 搭建,TSDX 会在/src下初始化库代码,并在/example下创建基于 Parcel 的 Playground 演示应用。从 package.json 的scripts可以看到完整命令映射:

"start": "tsdx watch", "build": "tsdx build", "test": "tsdx test --passWithNoTests", "lint": "tsdx lint", "storybook": "start-storybook -s ./public -p 6006", "build-storybook": "build-storybook -s ./public", "size": "size-limit", "analyze": "size-limit --why"

推荐的开发三终端工作流

README 给出的推荐流程是同时开三个终端:

终端一:启动 TSDX 监听构建

npm start # 或 yarn start

对应tsdx watch:编译输出到/dist并以监听模式运行——每次保存src下的改动,都会自动重建到/dist。这是整个工作流的核心,因为下游的 Storybook 与 Example 都消费/dist产物。

终端二:运行 Storybook

yarn storybook

加载./stories目录下的故事文件,启动时通过-s ./public指定静态资源目录(Logo 组件依赖其中的 dendron-vector.svg)。

注意:README 特别强调,Stories 中引用组件时应像使用库一样从项目根目录导入(例如import { Logo } from "../src/components"),这个根目录别名已在 tsconfig 与 Storybook 的 webpack 配置中预先配置。

终端三:启动 Example Playground

cd example npm i # 或 yarn 安装依赖 npm start # 或 yarn start

Example 是 example/package.json 定义的 Parcel 应用(parcel index.html)。它默认导入并热重载/dist中的产物,因此如果看到组件没有更新,请先确认终端一中的 TSDX 是否在监听模式运行。全程无需 symlink——组件复用依赖 Parcel 的模块别名(alias)机制,而非软链接。

Example 的入口 example/index.tsx 展示了最小用法:

import "react-app-polyfill/ie11"; import * as React from "react"; import * as ReactDOM from "react-dom"; import { Logo } from "../src/components/Logo"; const App = () => ( <div> <Logo /> </div> ); ReactDOM.render(<App />, document.getElementById("root"));

一次性构建与测试

  • 一次性构建:npm run build(或yarn build),对应tsdx build;
  • 运行测试:npm test(或yarn test),对应tsdx test --passWithNoTests,即无测试时也不会因退出码失败而中断。

组件示例:Logo 与 Storybook 交互式调试

以仓库中唯一的核心组件Logo为例,它的实现位于 src/components/Logo/index.tsx:

import { ImgProps } from "@chakra-ui/image"; import { chakra } from "@chakra-ui/system"; import * as React from "react"; export const Logo: React.FC<ImgProps> = ({ boxSize, ...rest }) => ( <chakra.img src={"/dendron-vector.svg"} boxSize={boxSize} {...rest} /> );

Logo是一个泛型组件,直接透传 Chakra UI 图片组件的全部属性(ImgProps),并暴露boxSize控制尺寸,默认渲染public/dendron-vector.svg。它从 src/components/index.ts 统一导出:

export { Logo } from "./Logo";

对应地在 stories/Logo.stories.tsx 中,Storybook 为它配置了交互式控制项,方便在设计阶段直观调节尺寸:

argTypes: { boxSize: { control: { type: "range", min: 8, max: 80, step: 8 }, }, },

而 test/logo.test.tsx 提供了一个"渲染不崩溃"的最小冒烟测试,验证组件可被挂载与卸载:

it("renders without crashing", () => { const div = document.createElement("div"); ReactDOM.render(<Logo />, div); ReactDOM.unmountComponentAtNode(div); });

工程配置解析:代码质量、体积与类型

README 的 Configuration 一节覆盖了工程质量相关的四项配置,均可对照仓库实际文件逐一验证。

代码质量:Prettier + Husky + lint-staged

代码质量由prettier、husky、lint-staged兜底。本仓库中 Husky 钩子配置为提交前执行tsdx lint(见 package.json 的husky.hooks.pre-commit),Prettier 则采用printWidth: 80、semi: true、singleQuote: true、trailingComma: "es5"的规范。各宿主项目可按需调整package.json中对应字段。

Jest 测试

Jest 已预先配置好,执行npm test或yarn test即可运行 test 目录下的测试。

体积分析:size-limit

size-limit用于计算库的真实体积成本:

npm run size # 输出各产物实际体积与预算对比 npm run analyze # size-limit --why,可视化各依赖的体积构成

体积预算在 package.json 的size-limit字段中声明,两个产物分别限定在10 KB以内:

"size-limit": [ { "path": "dist/dendron-design-system.cjs.production.min.js", "limit": "10 KB" }, { "path": "dist/dendron-design-system.esm.js", "limit": "10 KB" } ]

这对于组件库至关重要——体积直接决定宿主应用的首屏加载成本,超限会直接让 CI 失败。

目录骨架(Setup Files)

TSDX 初始化时生成的标准结构如下,其中标注EDIT THIS的文件是需要开发者修改的:

/example index.html index.tsx # test your component here in a demo app package.json tsconfig.json /src index.tsx # EDIT THIS /test blah.test.tsx # EDIT THIS /stories Thing.stories.tsx # EDIT THIS /.storybook main.js preview.js .gitignore package.json README.md # EDIT THIS tsconfig.json

打包器:Rollup

TSDX 底层使用 Rollup 作为打包器,为不同模块格式与构建场景生成多份 Rollup 配置。本仓库还通过 tsdx.config.js 向 Rollup 管线注入了图片插件:

import image from "@rollup/plugin-image"; module.exports = { rollup(config) { config.plugins.push(image()); return config; }, };

该插件允许在源码中直接import图片资源并内联为 base64 或独立文件,是组件库处理 SVG/PNG 等静态资源的标配能力。

TypeScript 严格模式

tsconfig.json 配置了dom、esnext类型环境与react的 JSX 转换,并开启strict、noImplicitReturns、noUnusedLocals、noUnusedParameters等严格检查;declaration: true与sourceMap: true保证消费者获得.d.ts声明与源码映射,moduleResolution: "node"+esModuleInterop则保证 ESM/CJS 互操作与 Node 式模块解析。宿主项目可按自身需求调整。

部署 Example Playground 到 Netlify

Example 只是一个简单的 Parcel 应用,可以像部署任何静态站点一样部署到任意平台。README 给出了使用 Netlify CLI 的手动部署流程:

npm i -g netlify-cli # 先安装 Netlify CLI cd example # 若尚未进入 example 目录 npm run build # 构建到 dist netlify deploy # 部署 dist 目录

若已将 git 仓库接入 Netlify,也可以配置持续部署(CD):

netlify init # build command: yarn build && cd example && yarn && yarn build # directory to deploy: example/dist # pick yes for netlify.toml

即先构建设计系统本身(yarn build),再进入example安装依赖并构建 Playground,最终部署example/dist目录。

Lerna 单仓中的依赖解析问题与修复

当在 Lerna 管理的 monorepo 中新建 TSDX 包时,运行example项目可能会遇到Cannot resolve dependency错误。README 指出了根因:Lerna 项目依赖安装方式特殊,example 项目package.json中的alias 可能指向错误位置——这些依赖实际安装在了 Lerna 项目的根node_modules,而非 example 本地。

修复方法是调整 example 内部package.json的alias指向实际安装位置(实际路径取决于 Lerna 目录结构):

"alias": { - "react": "../node_modules/react", - "react-dom": "../node_modules/react-dom" + "react": "../../../node_modules/react", + "react-dom": "../../../node_modules/react-dom" },

对照本仓库 example/package.json,其 alias 正是这个模式:

"alias": { "react": "../node_modules/react", "react-dom": "../node_modules/react-dom/profiling", "scheduler/tracing": "../node_modules/scheduler/tracing-profiling" }

另一种替代方案是彻底移除 alias,把被 alias 的依赖改为 devDependencies 直接声明——但这种方式可能引入其他问题(README 对此给出了警示)。实际采用哪种方式,取决于组件库对 React 版本的复用要求与 monorepo 的目录深度。

小结

dendron-design-system是一份结构清晰、工程化完备的组件库样例:字体通过 Fontsource 自托管并由 Chakra UI 主题统一注入,开发期借助 TSDX 监听构建串联 Storybook 与 Parcel Playground,发布前用 size-limit 把两个产物控制在 10 KB 预算内,并给出了 Netlify 部署与 Lerna 单仓踩坑的完整解法。无论是要为 Dendron 生态贡献组件,还是在自己的项目中搭建类似的 React 组件库,上述配置与工作流都可以直接复用。后续需要扩展组件时,只需在 src/components 新增组件、在 stories 补充 Story、并在 test 添加测试,即可无缝接入整套既有流程。

  • 知识管理
  • 知识库

【免费下载链接】dendron

The personal knowledge management (PKM) tool that grows as you do!

项目地址:https://gitcode.com/gh_mirrors/de/dendron
点击查看免费下载

相关推荐

上一篇:CodeLlama模型量化终极指南:INT4/INT8压缩技术实践与性能对比
下一篇:在 Docker 中以 Library 模式运行 PostGraphile V5:构建 Node.js 驱动的 GraphQL 容器

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/28 7:25:18

Claude Code命令速查大全:TaoToken统一Key接入CLI斜杠命令与终端配置

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/28 7:24:06

YOLOv8频射信号检测实战:时频图生成、数据集标注与94.3%识别率

简介&#xff1a;无人机频射信号检测数据集&#xff0c;面向无人机目标检测与射频信号识别场景&#xff0c;适合深度学习入门者或安全巡检、低空安防方向的开发人员使用。数据集中对无人机频射图像进行了精细标注&#xff0c;平均正确识别率达94.3%&#xff0c;并已转换为YOLOv…

作者头像 李华
网站建设 2026/9/28 7:23:07

ZCode静默上传机制深度解析:Git集成与数据安全风险

1. 事件还原&#xff1a;从一条异常 Git 提交记录开始的 48 小时事情是从一个开发者的日常操作开始的——他刚在本地完成一段核心业务逻辑的调试&#xff0c;执行git add . && git commit -m "feat: order refund logic v2"&#xff0c;然后习惯性地敲下git …

作者头像 李华
网站建设 2026/9/28 7:22:56

Cesium地球场景初始化与视角控制实战:从相机模型到动态漫游

1. 项目概述与核心场景拆解1.1 Cesium到底是什么&#xff0c;为什么绕不开它做三维GIS开发的朋友应该都有同感&#xff0c;Web端三维地球方案里&#xff0c;Cesium基本是绕不开的那一个。它本身是一个开源的JavaScript库&#xff0c;基于WebGL渲染&#xff0c;直接跑在浏览器里…

作者头像 李华
网站建设 2026/9/28 7:22:53

Cesium三维地球场景初始化与相机视角控制实战指南

说到三维地球可视化&#xff0c;Cesium 是国内 GIS 前端绕不开的名字。不管是智慧城市、数字孪生还是军工仿真项目&#xff0c;打开网页先看到一个能转、能飞、能拖拽的地球&#xff0c;第一眼的效果基本就定下了客户对整系统的印象。而我这次要讲的&#xff0c;正是这个“第一…

作者头像 李华