
MetaMask Extension 的 Storybook 组件开发指南启动、配置与 UI 组件测试实战【免费下载链接】metamask-extension:globe_with_meridians: :electric_plug: The MetaMask browser extension enables browsing Ethereum blockchain enabled websites项目地址: https://gitcode.com/GitHub_Trending/me/metamask-extensionMetaMask 浏览器扩展仓库metamask-extension将 Storybook 作为其设计系统Design System的核心组成部分用于在隔离环境中浏览、调试和交互式验证 UI 组件。本指南将带你完成从克隆仓库、安装依赖到启动 Storybook 的完整流程并结合仓库中的 .storybook/main.js、.storybook/preview.js 等配置文件深入解析 MetaMask 如何定制 Storybook 的 Webpack 构建、国际化、Redux 状态与主题切换帮助你在本地高效地开发与测试 MetaMask 的组件和页面。一、Storybook 在 MetaMask 项目中的角色MetaMask 的界面由数千个 React 组件构成仓库中 ui/components 与 ui/pages 目录下共有上千个组件与页面文件它们彼此依赖 Redux 状态、后台连接background connection与国际化消息。若直接在完整扩展环境中调试单个组件需要处理大量环境依赖。Storybook 正是为解决这一问题而引入的它把每个组件当作一个独立的故事story渲染在浏览器中让开发者无需启动完整的扩展即可快速浏览组件的不同视觉状态通过 Controls 面板实时修改组件属性props以亮色 / 暗色主题、多种语言环境预览效果配合 a11y 与 docs 插件检查可访问性并生成组件文档。从仓库的 package.json 可以看到MetaMask 将 Storybook 与其设计系统深度绑定并配套了构建、部署与自动化测试脚本下文会逐一说明。二、快速开始克隆仓库并启动 Storybook官方在 .storybook/README.md 中给出了最小启动路径。MetaMask 使用 Yarn 作为包管理器仓库根目录存在 yarn.lock因此不要使用npm install否则可能因依赖版本不一致而失败。# 1. 克隆仓库或使用你已有的本地副本 git clone https://gitcode.com/GitHub_Trending/me/metamask-extension # 2. 进入仓库根目录并安装依赖 cd metamask-extension yarn # 3. 启动 Storybook 开发服务器 yarn storybook启动成功后终端会输出类似下面的信息info Storybook started on http://localhost:6006/在浏览器中打开 http://localhost:6006/ 即可看到 Storybook 界面。从此处你可以浏览项目中的各类组件并直接在右侧面板修改组件的部分属性实时观察渲染变化。yarn storybook对应的脚本定义在 package.jsonstorybook: storybook dev -p 6006 -c .storybook它等价于执行 Storybook CLI 的dev命令指定端口6006、配置文件目录.storybook。提示MetaMask 是一个包含大量依赖的大型仓库首次yarn安装耗时较长。如果启动时出现依赖解析或兼容性问题建议确认 Node.js 版本与仓库要求一致并优先清空本地 node_modules 后重新安装。三、常用 Storybook 相关脚本一览除开发启动外package.json 中还定义了多个与 Storybook 生命周期相关的脚本脚本命令用途storybookstorybook dev -p 6006 -c .storybook启动本地开发服务器默认 6006 端口storybook:buildstorybook build -c .storybook -o storybook-build构建静态站点到storybook-build/目录storybook:deploystorybook-to-ghpages --existing-output-dir storybook-build --remote storybook --branch main将静态构建结果发布到 GitHub Pagestest-storybooktest-storybook -c .storybook运行 Storybook 交互测试基于 storybook/test-runnertest-storybook:ci先构建并用http-server服务 6006 端口wait-on就绪后运行test-storybook在 CI 中端到端执行 Storybook 测试配套依赖方面仓库固定使用 Storybook9.1.20版本见 package.json并安装了storybook/react-webpack5、storybook/addon-a11y、storybook/addon-docs、storybook/addon-webpack5-compiler-babel、storybook/storybook-deployer与storybook/test-runner等插件package.json。四、深入 .storybook 配置目录.storybook目录是整个 Storybook 实例的中枢包含以下关键文件.storybook/ ├── README.md # 官方使用说明 ├── main.js # 主配置stories 路径、addons、Webpack ├── preview.js # 全局参数、装饰器、工具栏、Redux 集成 ├── i18n.js / locales.js # 国际化 Provider 与 40 语言消息 ├── test-data.js # 注入 Storybook 的 Redux 初始状态 ├── metamask-storybook-theme.js # Storybook 品牌主题 ├── metametrics.js # MetaMetrics 埋点 Provider 包装 ├── preview-body.html # 自定义预览 HTML挂载根节点 ├── index.css # 全局样式 ├── actions/sb-send-action.js # send 流程的 action mock ├── initial-states/ # 各审批页面的初始状态 fixture ├── reducers/sb-history-reducer.js ├── shims/scure-bip39-english.js # 助记词库浏览器端 shim └── images/ # 演示用 token / 图标资源4.1 主配置 main.jsstories、addons 与 Webpack 定制.storybook/main.js 是 Storybook 的入口配置核心内容包括1扫描范围与插件stories: [../ui/**/*.stories.js, ../ui/**/*.stories.tsx], addons: [ storybook/addon-a11y, storybook/addon-docs, storybook/addon-webpack5-compiler-babel, ],Storybook 会递归扫描ui目录下所有*.stories.js与*.stories.tsx文件。经检索当前仓库中存在 300 个 stories 文件如ui/components/app/alert-system/general-alert/general-alert.stories.tsx分布在ui/components与ui/pages各处。2静态资源与环境变量staticDirs: [../app, ./images], env: (config) ({ ...config, INFURA_PROJECT_ID: process.env.INFURA_STORYBOOK_PROJECT_ID || , ENABLE_ENFORCED_SIMULATIONS: process.env.ENABLE_ENFORCED_SIMULATIONS || , }),staticDirs将app/与.storybook/images/暴露为静态资源目录故事中可直接引用其中的图标、字体等env从.metamaskrc文件见dotenv.config读取INFURA_STORYBOOK_PROJECT_ID等变量注入构建环境避免将真实密钥带入 Storybook。3Webpack 定制webpackFinal是配置中最复杂的部分其作用可归纳为四类模块别名替换mock将webextension-polyfill替换为 ui/mocks/webextension-polyfill.js把多层store/actions与hooks/useAnalytics替换为对应 mockmetamask/scure-bip39的英文词表也替换为 .storybook/shims/scure-bip39-english.js。Node polyfill / fallback对child_process、fs、crypto等 Node 内置模块设置false或浏览器替代实现如process/browser、stream-browserify使扩展代码可在浏览器中运行。SCSS 处理链路为*.scss追加style-loader → css-loader → postcss-loadertailwindcss autoprefixer→ sass-loadersass-embeddedmodern-compiler API的完整加载链loadPaths包含ui/css与node_modules保证 MetaMask 的 Tailwind 样式体系在 Storybook 中生效。字体与全局变量通过CopyWebpackPlugin复制ui/css/utilities/fonts/与 FontAwesome webfonts 到输出目录并通过ProvidePlugin注入Buffer与process全局变量。框架方面配置为storybook/react-webpack5并关闭了reactDocgen与 TS 类型检查typescript: { reactDocgen: false, check: false }以加速构建。4.2 全局预览 preview.js装饰器、工具栏与状态注入.storybook/preview.js 负责 Storybook 的全局渲染环境主要包含1全局参数parametersparameters: { backgrounds: { options: { default: { name: default, value: var(--color-background-default) }, alternative: { name: alternative, value: var(--color-background-alternative) }, }, }, options: { storySort: { order: [Getting Started, Foundations, Components, Pages], }, }, controls: { expanded: true }, }背景色直接复用设计 token 的 CSS 变量--color-background-default/--color-background-alternative并配置了故事排序规则与默认展开的 Controls 面板。2全局工具栏globalTypesglobalTypes: { locale: { /* 语言切换遍历 app/_locales/index.json 生成语言列表 */ }, theme: { name: Color Theme, defaultValue: both, toolbar: { items: [ { value: light, title: Light, icon: sun }, { value: dark, title: Dark, icon: moon }, { value: both, title: Light/Dark, icon: paintbrush }, ], dynamicTitle: true, }, }, }工具栏提供Locale国际化语言与Color Theme亮 / 暗 / 双主题两个切换器。主题逻辑会读取prefers-color-scheme系统偏好并通过设置document.documentElement的data-theme属性来切换设计 token 变量。3Redux Store 与后台连接 mockexport const store configureStore(testData); const proxiedBackground new Proxy({}, { get(_, method) { return function () { return new Promise(() {}); }; }, }); setBackgroundConnection(proxiedBackground);Store 由 ui/store/store.js 的configureStore基于 .storybook/test-data.js 中的测试状态创建。这份状态包含账户、交易记录、token 缓存、Snap 列表、市场数据等完整的 Redux 切片保证组件看起来像在真实扩展中运行后台连接通过一个 Proxy 对象 mock任何对 background 方法的调用都会返回一个永不 resolve 的 Promise从而避免真实的后台通信。4全局装饰器decoratorsmetamaskDecorator将每个故事包裹在Provider(store) → QueryClientProvider → MemoryRouter → AlertMetricsProvider → I18nProvider → Routes的层级中其中路由支持通过故事参数parameters.initialEntries与parameters.path自定义默认路径为*、入口为/I18nProvider负责将当前语言的消息字典通过I18nContext提供给组件详见下文withColorScheme装饰器负责按工具栏主题渲染浅色 / 深色包裹层。5预览 HTML.storybook/preview-body.html 预置了#custom-root与#popover-content两个挂载节点供弹层类组件Popover、Tooltip 等渲染使用。五、国际化与多语言支持MetaMask 支持 40 种语言app/_locales 目录下每种语言一个messages.json。Storybook 环境通过两处实现语言切换.storybook/locales.js 静态导入所有语言包am、ar、de、en、zh_CN、zh_TW等导出为按 locale code 索引的字典.storybook/i18n.js 实现I18nProvider其t函数优先从当前语言字典取消息取不到时回退到英文en底层复用 ui/helpers/utils/i18n-helper 的getMessage。语言列表本身来自 app/_locales/index.json在preview.js中生成工具栏下拉项。六、编写一个真实的故事StoryMetaMask 的故事采用 Component Story FormatCSF。以 ui/components/app/alert-system/general-alert/general-alert.stories.tsx 为例import { Severity } from ../../../../helpers/constants/design-system; import { SecurityProvider } from ../../../../../shared/constants/security-provider; import GeneralAlert from ./general-alert; export default { title: Confirmations/Components/GeneralAlert, component: GeneralAlert, argTypes: { description: { control: text, defaultValue: mockPlainText }, provider: { control: { type: select }, options: [none, ...Object.values(SecurityProvider)], mapping: { none: null }, }, severity: { control: { type: select }, options: [Severity.Danger, Severity.Info, Severity.Warning], }, onClickSupportLink: { action: onClickSupportLink }, }, };写作要点title决定故事在侧边栏中的分组层级Confirmations/Components/...argTypes定义 Controls 面板的可调参数select类型配合options与mapping可在下拉中映射真实对象如SecurityProvideraction类型的控制项会把组件回调事件打印到 Actions 面板便于交互验证。除组件故事外仓库还提供了审批类页面的初始状态 fixture.storybook/initial-states/approval-screens 下包含add-token.js、add-suggested-token.js、token-approval.js以及 send 流程的 action mock.storybook/actions/sb-send-action.js方便直接以真实状态预览复杂页面。七、用 test-runner 自动化测试故事MetaMask 使用storybook/test-runner对故事进行自动化冒烟测试yarn test-storybook会启动本地 Storybook 并逐一渲染所有故事捕获渲染错误与控制台异常。CI 场景下可使用 package.json 中的test-storybook:ci先用yarn storybook:build构建静态站点再用http-server在 6006 端口提供静态服务wait-on等待端口就绪后运行测试整个过程由concurrently并行编排保证测试环境与真实构建产物一致。八、常见问题与注意事项端口占用默认端口为 6006若被占用可通过yarn storybook --port port指定新端口等价于修改-p参数。密钥安全Storybook 环境中的 Infura 项目 ID 默认读取.metamaskrc中的INFURA_STORYBOOK_PROJECT_ID未配置时为空字符串切勿将生产密钥硬编码进故事或配置。遥测main.js中通过core.disableTelemetry: true关闭了 Storybook 遥测上报。首次构建较慢仓库规模大、SCSS 链路长首次构建需要较长时间属正常现象storybook:build产出的静态站点可直接用于分享组件库快照或部署到 GitHub Pagesstorybook:deploy。新组件如何接入在组件同级目录新建组件名.stories.tsx并遵循 CSF 规范导出默认元数据即可无需修改任何全局配置Stories 扫描../ui/**/*.stories.tsx会自动发现它。通过以上配置与流程你可以在 MetaMask 扩展仓库中独立、高效地开发与验证 UI 组件并借助主题切换、多语言与自动化测试确保组件在真实产品环境中的表现一致可靠。【免费下载链接】metamask-extension:globe_with_meridians: :electric_plug: The MetaMask browser extension enables browsing Ethereum blockchain enabled websites项目地址: https://gitcode.com/GitHub_Trending/me/metamask-extension创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考