鸿蒙化改造做了一半时,团队里最容易出现的一个场景是:组件库失控。有人新写了一个按钮,有人把老按钮塞了五个可选参数,设计走查靠截图来回传阅,QA 只能在发布前凭感觉点一遍。某团队在模拟项目 X 中就是这么熬过前两个迭代的。后来把 Flutter 组件手册工具 widgetbook_cli 接进鸿蒙开发流程,组件从"内耗品"变成了"资产":UI 组件自动进入统一的预览库,构建后直接托管到云端,设计、开发、测试打开同一个 URL 就能验收。这篇文章就把整个鸿蒙化适配过程、组件自动托管机制、云端交付链路和"鸿蒙级精密组件"的验收方法完整拆一遍。适合正在做鸿蒙化迁移的 Flutter 团队,也适合想给组件库建立一套可视化、可远程协作机制的开发者。
1. 鸿蒙化项目为什么比 Flutter 原生项目更需要组件托管
1.1 三个信号:组件失控其实有迹可循
先说清楚我观察到的失控过程,它往往不是突然爆发的,而是从一个很小的细节开始。
第一个信号:新需求来时,前端喜欢在旧组件上继续加字段。某个列表项卡片经过了三个迭代,身上挂了默认态、加载态、错误态、抽奖态,代码里还有两组永远没人走的过期分支。组件能用,但没人敢动。
第二个信号:设计规范更新后,团队没法快速回答"哪些组件受影响"。设计师改了一个圆角标准,开发只能靠人肉搜索相关实现,漏掉几个页面零件是常有的事。
第三个信号:跨端验收靠截图对比。安卓、iOS、鸿蒙三个环境各自截图,再拼到一张图上人工比对。组件一多,比对就变成抽样,抽样就会漏。
这些信号在 Flutter 原生项目里靠团队纪律还能勉强压住,但在鸿蒙化阶段会被放大。因为鸿蒙版本要解决的不只是"功能能不能跑",还有"组件在鸿蒙设备上是否足够精致、是否和设计稿一致"。这时候,把组件从业务代码里抽出来,变成一套独立的、可预览的、可远程访问的组件库,就不是加分项而是刚需。
1.2 widgetbook_cli 到底帮我们做了什么:从 Dart 源码到可托管 bundle
Widgetbook 本身是一个 Flutter 组件预览应用框架。你为每个组件写若干个 use-case,描述它在不同状态下的渲染效果,Widgetbook 会生成一个独立的组件手册应用,左侧是组件目录,右侧是每个 use-case 的实时渲染效果。
widgetbook_cli 是这个体系里的命令行工具,它把"本地手工打开组件手册"升级成了三条可自动化的链路。build 命令会在非交互模式下扫描所有组件和 use-case,生成一份组件的元数据清单,方便 CI 校验;build-bundle 会把整个组件手册编译成一个自包含的前端资源包,里面有页面入口、组件渲染脚本和静态资源,可以直接丢到任意静态托管环境;bundle-upload 把这个打包结果推到对象存储或托管服务上,团队其他人拿一个链接就能访问。
用大白话讲,Widgetbook 是"组件的陈列柜",widgetbook_cli 是"把陈列柜打包快递到云端的那条流水线"。自动化之后,组件更新到仓库的同一时刻,预览库也更新了,不需要前端手工上传截图,也不需要设计追着开发要最新效果图。
注意:build-bundle 产出的预览资源本质上是 Flutter Web 构建物,运行在浏览器里。它不是鸿蒙设备的原生产物,但恰恰因为跑在浏览器里,才能被团队里的多角色轻松访问。这件事和鸿蒙化不冲突,反而是鸿蒙真机测试之外的"快速预览层"。
1.3 鸿蒙适配的两个层面:工具链层与渲染层
很多人一听到"鸿蒙化适配 widgetbook_cli",第一反应是"在鸿蒙设备上跑 widgetbook"或者"让 widgetbook 生成鸿蒙应用的预览"。这理解对了一半。
实际适配包含两个层面。第一个层面是工具链层:让 widgetbook_cli 在鸿蒙开发环境里正常工作,能扫描代码、能构建、能打包上传。这涉及 Flutter 鸿蒙版 SDK 的路径定位、环境变量、依赖替换这些问题。第二个层面是渲染层:被托管到云端的组件库必须尽量还原组件在鸿蒙真机上的视觉表现,让设计在浏览器里看组件时,看到的就是用户在鸿蒙手机上看到的。
组件在浏览器里的渲染引擎和鸿蒙真机上的渲染引擎不完全等同,因此"精密"两个字的全部工作,就在于把这种差异逐项找到、逐项校准。这也是为什么标题强调"鸿蒙级精密组件专家"——不是把组件写得好看,而是把组件的尺寸、间距、字体、圆角、交互热区做到在鸿蒙设备上经得起像素级检查。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 鸿蒙化适配第一步:依赖替换与工具链搭桥
2.1 切到鸿蒙版 SDK 后的第一个报错:定位不到 Flutter 环境
模拟项目 X 在从标准 Flutter 切换为鸿蒙版 Flutter SDK 后,我做的第一件事是在终端里直接跑 dart run widgetbook_cli build,结果没有任何输出的报错,只看到一行"Flutter SDK path not found"。
这个报错的原因要谈清楚:widgetbook_cli 启动时,会通过当前运行的 Dart 可执行文件反查 Flutter SDK 的根目录。标准 Flutter 的完整目录结构是固定的,而鸿蒙版 Flutter SDK 有时以独立发行包形式存在,目录层级里缺少一个让 CLI 识别的标记文件,或者 bin 目录结构和预期不完全一致,导致反查失败。
解决办法算不上高明但很稳:手动指定 FLUTTER_ROOT,并把这个环境变量写入开发环境的全局配置,而不是每次在终端里现敲。
bash复制export FLUTTER_ROOT="$HOME/sdk/flutter-harmonyos"
export PATH="$FLUTTER_ROOT/bin:$PATH"
flutter --version
执行完 flutter --version 能正常输出版本号,说明第一步通了。接着重新运行 CLI 命令,后续的扫描与构建流程就能正常引导。
调整完环境变量仍会遇到的另一个细节是:同一个机器上可能同时存在标准 Flutter 和鸿蒙版 Flutter。全局 PATH 指向鸿蒙版,但编辑器的 Dart 分析服务可能还指向标准版,导致命令行构建与 IDE 内调试使用两套 SDK。建议在项目根目录放一份统一的环境脚本,所有终端、CI、IDE 启动前都先加载它,保证工具链一致。
2.2 一套可复用的环境准备模板:同一台机器跑鸿蒙设备包与 web 预览包
既然鸿蒙真机调试走鸿蒙版 Flutter SDK,而 widgetbook_cli 的云端预览依赖于 Web 构建,就会遇到问题:当前的鸿蒙版 Flutter 是否保留了 Web 通道。
实测中遇到过两种情况。有的版本保留完整 Web 支持,flutter build web 一条命令直接可用;有的版本为了精简体积裁剪了 Web 通道,构建时会直接提示找不到 web 相关命令。
针对后一种情况的做法是:保留一个标准 Flutter SDK,专门用于生成 widgetbook 的 Web 预览包,鸿蒙设备包仍然走鸿蒙版 SDK。开发时通过环境变量快速切换。
bash复制# 开发环境统一入口 load-env.sh
export OHOS_HOME="$HOME/sdk/ohos-sdk"
export HARMONY_FLUTTER_ROOT="$HOME/sdk/flutter-harmonyos"
export WEB_FLUTTER_ROOT="$HOME/sdk/flutter-stable"
# 鸿蒙设备调试
alias fh='export FLUTTER_ROOT="$HARMONY_FLUTTER_ROOT"; export PATH="$HARMONY_FLUTTER_ROOT/bin:$PATH"'
# Web 预览包构建
alias fw='export FLUTTER_ROOT="$WEB_FLUTTER_ROOT"; export PATH="$WEB_FLUTTER_ROOT/bin:$PATH"'
这个模板看起来简单,但解决了实际工作中最容易踩的一个坑:工具链串版本。在两个 SDK 之间反复横跳时,如果忘记重置 FLUTTER_ROOT,打包产物会由错误的 SDK 生成,轻则版本号对不上,重则出现仲裁冲突导致构建失败。
对已经跑起来的老项目,我建议把版本号固定住,不要每次拉最新。某次 SDK 升级后强制要求新的编译器版本,间接把 CLI 的构建链路打断过,排查花了整个下午。固定的版本组合至少保证"昨天能构建的,今天还能构建"。
2.3 把 widgetbook_cli 正式接入构建脚本
工具链就绪后,需要把 CLI 的调用逻辑固化到构建脚本里,让团队成员不记命令也能跑完整流程。这里给一个可复用的 Makefile 片段:
makefile复制.PHONY: widgetbook-build widgetbook-bundle widgetbook-upload
WCLI := dart run widgetbook_cli
widgetbook-build:
$(WCLI) build
widgetbook-bundle:
$(WCLI) build-bundle
widgetbook-upload:
$(WCLI) bundle-upload --api-key $$WIDGETBOOK_API_KEY
命令拆成三段的好处是:开发提交代码后只跑 build,确认 use-case 没有遗漏;发预览版时跑 bundle;确认产物 OK 再跑 upload。三步分开,每一步的产物都能单独检查,出问题时不至于全链重来。
配置文件方面,widgetbook_cli 支持在项目根目录放一份配置来指定输出目录、并发数和网络重试参数。我建议显式锁定输出目录:
yaml复制networking:
timeout: 60
retries: 3
output:
directory: .dart_tool/widgetbook
一个容易忽略的注意点是:.dart_tool 目录通常被版本控制忽略,本地构建与 CI 构建会各自生成新的编译缓存,这没问题。但 bundle 产物如果也需要提交到仓库或者被自动化发布工具读取,建议把输出目录调整到项目内的 build/widgetbook,同时在版本控制规则里显式放行。
3. 组件自动托管的工程化落地:目录约定、use-case 策略与 addons 取舍
3.1 目录约定:把 Widgetbook 入口从业务代码里隔离出来
widgetbook_cli 能不能自动扫描到组件,关键不在于工具本身,而在于项目结构是否足够规整。我见过最混乱的情况是:业务组件、页面局部组件、第三方组件二次封装全部混在同一个目录里,CLI 扫描时把大量无关文件也编进了 use-case 清单,构建产物膨胀得厉害。
在模拟项目 X 里我们制定了一套简单的规则,现在看基本成了团队约定:
text复制lib/
components/
button/
button.dart
button_params.dart
button.usecase.dart
card/
card.dart
card.usecase.dart
pages/
tool/
widgetbook/
widgetbook.dart
widgetbook_use_cases.dart
业务组件放在 lib/components 下,每个组件一个目录,组件本体与 use-case 描述文件放在一起。Widgetbook 的启动入口放在 tool/widgetbook 下,不参与线上业务包的编译。这套结构有三个好处:
第一,组件与用例的关联关系在文件系统层面就建立起来了,新增组件时不会忘记补 use-case。第二,widgetbook.dart 作为独立入口不会把业务启动逻辑污染进来。第三,扫描范围可控,CLI 构建元数据时定位清晰,新组件没进预览库的问题能直接从目录结构找到原因。
3.2 use-case 组织策略:一个组件一个用例文件,状态拆到不可再拆
组件预览的价值上限,取决于 use-case 写得有多认真。最偷懒的写法是一个组件只登记一个"默认状态",那这个预览库本质上就是个静态截图,没法覆盖组件的关键状态。
我们的策略是"一个组件一个用例文件,状态拆到不可再拆"。每个组件文件夹下都放一个 *.usecase.dart,里面注册若干 WidgetbookUseCase。像按钮这种组件,至少要覆盖:默认态、悬停态、按压态、禁用态、加载态,如果支持图标,还要把图标+文字的组合拆出来。
use-case 里尽量使用可交互参数来暴露输入能力,而不是写死成若干个静态实例。文本内容、尺寸、颜色这些用参数暴露出来,设计验收时可以直接在浏览器里拉数值,不用每次发需求让前端调整。
还有一个容易在鸿蒙化过程中翻车的点:use-case 里渲染组件时用的是构造参数直传,但真实业务里组件可能要读取服务端数据。团队内部定了一条硬规则:use-case 只允许传静态数据或本地模拟数据,任何网络请求都禁止出现在用例中。原因后面踩坑实录里会细说。
3.3 addons 在鸿蒙真机与 web 预览下的取舍清单
Widgetbook 的 addons 提供了很多增强能力,比如主题切换、设备边框模拟、文字缩放、性能面板。但并不是越多越好,鸿蒙化适配过程中我对 addons 做了一次减仓,原则是"预览加载速度优先,增强功能能砍就砍"。
主题切换 addon 建议保留。鸿蒙系统对深色模式的支持比较完整,设计验收经常需要同时看深浅两套配色。设备边框模拟 addon 建议禁用。在 Web 预览环境下它无法准确读取鸿蒙设备信息,渲染出来的边框经常错位,反而干扰判断。文字缩放 addon 在鸿蒙字体栈下表现不稳定,对高缩放倍率的支持有明显偏差,更可靠的做法是在 use-case 里通过固定字号参数模拟大字号场景。
注意:每一个 addon 最终都会被编译进 Web bundle,直接影响设计师打开预览 URL 的加载速度。从实测看,addon 数量翻一倍,起始加载时间可能会有 30% 左右的增长。对组件手册这种高频访问页面来说,体感差距很明显,所以控制 addon 数量本身就是性能优化。
4. 云端交付实战:build-bundle、存储选型与团队访问控制
4.1 build、build-bundle 与 bundle-upload:三条命令如何拼出交付流水线
把组件手册变成"团队所有人可访问"的产物,完整链路是三条命令的接力。先在项目根目录执行:
bash复制dart run widgetbook_cli build
dart run widgetbook_cli build-bundle
build 生成的是 use-case 元数据清单,构建速度快,常用于提交代码后的快速校验,确认"所有组件都登记上了"。build-bundle 才真正产出可托管的完整资源,包含页面入口、组件渲染代码、字体与图片资源。产物在配置文件指定的目录里,结构大致是:
text复制build/widgetbook/
index.html
main.dart.js
assets/
...
拿到这组资源后,我习惯先在本地起一个静态服务快速验证,再决定是否上传,避免把坏包传到云端影响团队其他人。
bash复制cd build/widgetbook
python3 -m http.server 8080
浏览器打开 http://localhost:8080,确认组件目录能正常加载、use-case 切换没有报错,然后调用上传命令:
bash复制dart run widgetbook_cli bundle-upload --api-key ${WIDGETBOOK_API_KEY}
如果不想用官方上传通道,也可以直接写脚本把 build/widgetbook 目录同步到自己的存储服务。两种方式对比下来,官方通道胜在命令简单、自动处理版本标识,自建通道胜在存储位置可控、便于和公司内部权限体系打通。项目处于早期探索阶段时用官方通道,稳定后切自建通道,体验更顺畅。
4.2 存储选型:对象存储、静态托管与 CDN 怎么选
组件手册的访问场景和普通网页不一样。团队成员(设计、开发、QA 大约十到二十人)会在工作日频繁打开、刷新,组件更新后所有旧缓存需要尽快失效。候选方案有三个,我分别试过。
静态托管平台最简单,提供固定 URL,但不少平台对刷新策略支持较弱,组件更新后用户容易看到旧版本,需要手工强制刷新。对象存储服务加 CDN 是我们最终采用的方案:对象存储放原始产物,CDN 负责加速分发和缓存控制,组件更新时主动刷新 CDN 缓存路径,团队成员刷新页面即可看到最新版本。私有对象存储配合临时签名 URL 适合保密要求高的场景,但每次访问都要带签名参数,设计师的浏览器体验会被打断,不适合高频访问的组件库。
| 方案 | 更新速度 | 访问体验 | 适用阶段 |
|---|---|---|---|
| 静态托管平台 | 较慢,依赖缓存策略 | 简单直接 | 个人验证、原型演示 |
| 对象存储 + CDN | 快,可主动刷新 | 稳定 | 团队正式使用 |
| 私有对象存储 + 签名 URL | 快 | 有跳转成本 | 强保密内部项目 |
选型时要预留一个判断点:组件更新频率远高于传统页面发版频率。如果 CDN 刷新能力弱,每周三四十次组件更新会让团队成员反复看到过期预览,信任度直线下降。所以我不建议在组件托管上用"省事但缓存难清"的方案。
4.3 版本化发布与回滚:让组件更新像发版一样可控
组件库托管之后,最怕的是"不知道线上是哪一版"。团队第一次把 widgetbook 推到云端时,由于产物目录固定,第二次上传直接覆盖了第一次,结果回看历史效果时完全找不到旧版快照。
后来引入的机制很简单:每次上传的产物目录带上版本标识,来源用 Git 短提交号。对象存储里的路径结构如下:
text复制widgetbook/
latest/
archive/20240601-a1b2c3/
archive/20240608-d4e5f6/
latest 永远是当前团队访问的地址,archive 保留历史版本。组件更新后先上传到 archive 目录验证无误,再把 latest 切换为新版本。一旦某个组件在鸿蒙真机上出现异常,把 latest 指回上一个归档目录即可完成秒级回滚。
访问控制方面,内部评审阶段打开预览 URL 不做鉴权,纯靠私密链接控制范围;组件库推给合作方时,在存储服务前加一层白名单策略,只有登记过的账号可以访问。按角色建议的权限分别是:设计只读,QA 只读,开发可读可更新。这样既能避免组件被误改,也保障了团队协作效率。
5. "鸿蒙级精密组件"到底验收什么:真机实测与自动化检查
5.1 精密组件验收清单:从尺寸、字体到触摸热区
标题里的"鸿蒙级精密组件"不是宣传口号,落到工程上就是一套验收维度。我整理了五类检查项,覆盖了实践中最容易被漏掉的部分。
尺寸检查:组件在不同屏幕密度下,宽度、高度、内边距必须符合设计规范。鸿蒙设备的高分辨率屏幕占比高,容易出现非整数像素渲染导致的模糊。
字体检查:中文字体在鸿蒙系统与其它系统上的字体回退机制不同,同一字号下实际渲染高度可能相差 1 到 2 像素,行高、字间距都要逐一核对。
色彩检查:深浅色模式下组件配色都要通过对比度检查,尤其注意透明遮罩在两种模式下的叠加效果差异明显。
交互检查:触摸热区是否达到鸿蒙交互规范要求的最小尺寸,点击态、按压态的视觉反馈是否完整。
边界检查:长文本、极端数字、空数据、超长标题四类边界输入下组件是否依然稳定,不破碎、不溢出、不遮挡。
这张清单听上去普通,但组件一旦达到几十个上百个,手工执行就是灾难。能在工具层面自动化的部分尽量自动化,剩下的人工项也要用组件预览库集中验收,不要散落在各个业务页面里。
5.2 真机实测发现的三类渲染偏差
在模拟项目 X 的鸿蒙真机上跑完一轮后,我们发现了三类浏览器预览里看不出来、必须真机才能暴露的偏差。每一类都花了不少时间去定位,这里直接给结论。
第一类是字体高度差异。鸿蒙系统的中文字体在某些字号下,实际占用的行高比设计稿预估的高度更大,导致固定高度的文本容器出现 1 到 2 像素的裁切。解决办法不是调小字号,而是给文本容器设置 minHeight 并适度放宽行高到 1.5 倍,给字体渲染留出余量。
第二类是模糊效果的性能问题。组件里使用的高斯模糊背景,在鸿蒙真机首次渲染时经常出现一帧的白屏闪烁。问题出在 GPU 加载着色器的时机,规避方案是放弃大面积模糊,用渐变半透明遮罩替代;实在需要模糊的地方,前置加载模糊图层,避免在组件挂载瞬间实时计算。
第三类是 0.5 像素细线的消失。组件里用 border 画的分割线,在部分鸿蒙屏幕密度下渲染不出来。这个问题在浏览器预览里不会出现,真机上却很常见。规避方案是细线不依赖 border,改用 1 像素圆角矩形组件,确保任何密度下都有物理像素兜底。
5.3 把"精密"变成自动化:golden 测试与跨端对比
前面说的偏差,第一次发现靠人眼,第二次就不应该再靠人眼。自动化验证我们用了两层方案,一层是 golden 测试,一层是利用 widgetbook 的用例做跨端对比。
golden 测试的本质是"对渲染结果拍基准图,之后每次渲染都和基准图做像素对比"。流程是:先在鸿蒙模拟器上把组件关键 use-case 渲染成基准快照,提交到仓库;后续每次修改组件代码,CI 里重新渲染同一组 use-case,和基准图做 diff。差异超过阈值就构建失败,强制开发者说明改动原因。
跨端对比利用 widgetbook 的同一套 use-case 在浏览器和鸿蒙设备上分别渲染,再对比两侧截图。这个方法能快速圈出"只在一个平台存在的渲染偏差"。实践里比较有效的使用节奏是:每周抽一天对新增和修改过的组件做全量跨端对比,其余时间靠 golden 测试兜底。
逻辑上,golden 测试解决的是"组件修改后有没有意外变化",跨端对比解决的是"同一组件在不同平台是否保持一致",两者配合才构成了"鸿蒙级精密组件"的自动化检查闭环。
6. 踩坑实录:三个最隐蔽的鸿蒙适配问题
6.1 坑一:新登记的 use-case 在路由表里消失
现象:开发新增了一个组件,也写了 use-case 文件,但打开云端组件手册,目录里死活看不到新登记的用例。本地构建 build 命令跑得很顺利,没有报任何错。
排查链路是这样的:先看入口文件 widgetbook_use_cases.dart 有没有 import 新写的用例文件,结果显示 import 被注释掉了,推测是某次合并冲突留下的。改成主动 import 之后重新 build,元数据清单里仍然没有出现新组件。继续下钻到 build-bundle 产物里的 use-case 信息文件,发现连组件目录的登记都没有。
最终定位根因:组件目录虽然新增了文件,但入口文件在编译时没有把它加入组件列表,CLI 只能扫描到已经被引用的用例。这类问题光靠工具链报错是查不出来的,因为构建流程本身没有失败。解决动作除了修正 import,更关键的是在 CI 里加了一道自动化检查:比较 Git 分支新增的 .usecase.dart 文件数量和产物元数据里的 use-case 数量,两者不一致就快速失败。
6.2 坑二:bundle 体积异常膨胀,网络库被意外编进去了
现象:某次 build-bundle 之后,产物从十几兆涨到了四十多兆,加载速度明显下降,还出现了"找不到资源路径"的报错。
排查链路从产物目录下手。把生成的前端资源列表按体积排序,发现里面多了不少网络库相关的文件。一个组件预览应用为什么要打包网络库?因为某个组件的 use-case 文件在初始化组件时,无意间 import 了页面服务层文件,而服务层文件又链式引用了业务网络客户端。widgetbook 构建会完整追踪整个 import 链,所以网络库连同它的依赖都被编译了进来。
这个问题在原始代码里其实埋了很久,只是组件少时体积不大没有暴露。解决思路有两层:第一层是严格按 3.2 里那条规则执行,use-case 只操作组件的展示参数,绝不调用任何服务层代码;第二层是用 kIsWeb 或抽象接口强行隔离,在预览入口注入一份固定的本地数据源,阻断网络库的 import 链。那次之后,我再写 use-case 时默认不 import use-case 文件外部的东西。
6.3 坑三:热重载后组件状态回退,多改两轮就乱
现象:在鸿蒙适配开发过程中,经常修改 use-case 里的参数后保存,页面自动热重载,看起来没问题,但多改两轮之后组件回退到默认状态,且控制台有序列化相关的报错。
定位发现,问题出在 widgetbook 的热重载与鸿蒙版 Flutter 插件的配合上。热重载过程需要把当前组件状态序列化后注入到新构建产物中,鸿蒙版容器在这个环节的状态保存并不完整,导致部分状态丢失,界面回到初始形态。
实测后确定的规避方式是:开发阶段把 widgetbook 的调试入口改成 hot restart 而不是 hot reload,每次改 use-case 后整体重启预览应用,虽然稍微慢一点但状态可靠。团队预览用的构建流程本来就走独立 bundle,并不依赖开发期的热重载,所以影响面被控制住了。这个坑给我最大的教训是:在跨平台适配阶段不要过度依赖某一种编译模式的便利性,工具链不完整时要敢于用更保守的调试方式。
把 widgetbook_cli 的鸿蒙化适配完整跑通之后,我最大的体会是:组件托管这件事的价值,不在于"有一个页面能看组件",而在于它让团队对"组件到底长什么样"有了共同的定义。设计师不再需要从开发手里要截图,开发不再需要逐条解释交互状态,QA 也不再靠发布前的人肉盘点。整个链路最花时间的部分不是 CLI 配不好,而是团队愿不愿意把组件登记的规范性当成工程纪律来执行。如果你也在做鸿蒙化,建议第一步先别追求全量组件迁移,挑三五个核心组件把目录规则、use-case 规范和云端发布流程跑通,再逐步扩大范围。另外一个小技巧:每周固定时间重新生成一次预览包并通知全组,让组件库更新节奏和发版节奏一样清晰,团队对这个工具的信心会很快建立起来。
