
GDevelop 新 IDE 的 Storybook 配置实战.babelrc规避大文件、preview-head.html注入 libGD.js 与全局装饰器体系【免费下载链接】GDevelop Open-source, cross-platform 2D/3D/multiplayer game engine designed for everyone.项目地址: https://gitcode.com/GitHub_Trending/gd/GDevelop本篇技术指南以 newIDE/app/.storybook/README.md 为骨架深入解析 GDevelop 5 桌面/网页版编辑器基于 React Material-UI内部 Storybook 的专属配置。你将掌握为什么 Storybook 需要一份与 create-react-app 不同的.babelrc、如何通过preview-head.html把 C 编译成的 libGD.js 注入组件预览环境以及preview.js中主题切换工具栏与四层全局装饰器的工作原理并学会在本地启动、构建 Storybook 用于 UI 组件快速开发与回归测试。1. 背景GDevelop 编辑器为什么需要一套特制的 StorybookGDevelop 编辑器newIDE/README.md是一个大型 React 单页应用UI 层由 Material-UI 构建并通过 GDevelop.jsC 核心编译为 JavaScript 的libGD.js完成对游戏项目的解析、序列化与代码生成。为了让 UI 开发者能脱离完整项目、在隔离环境中快速迭代和测试单个组件项目引入了 Storybook 作为组件开发 playground。.storybook 目录 存放的就是这套为 GDevelop 定制的 Storybook 配置。其官方说明非常简短只写了两个关键点.babelrc是必需的——因为src/locales文件夹里含有体积巨大的.js翻译文件如果让 Babel 去编译它们会导致 babel 挂起/冻结/崩溃hang/freeze/crash。preview-head.html会向 Storybook 注入与主应用相同的 HTML script 导入即libGD.js。看似只有两条但这两条背后分别对应着 GDevelop 独有的两大工程约束超大的本地化资源与必须同步初始化到浏览器全局的 WASM/JS 游戏引擎核心。下面逐项展开。2. 如何启动与构建 StorybookGDevelop 将 Storybook 脚本封装在 newIDE/app/package.json 中storybook: storybook dev -p 9009, build-storybook: storybook build -o build-storybook启动开发模式默认端口 9009cd newIDE/app npm run storybook # 或 yarn storybook构建静态产物输出到build-storybook目录可用于 CI 托管与在浏览器中直接测试组件cd newIDE/app npm run build-storybook补充说明据 newIDE/README.md 所述当开发者提交 PR 时CI 会自动构建 Storybook 并在云端临时托管方便直接在浏览器中验证组件本地开发则只需上述npm run storybook一条命令。3..babelrc用ignore让 Babel 跳过src/locales巨型翻译文件3.1 问题根源locales 目录里的巨型 JSGDevelop 通过 lingui-js 做国际化翻译编译产物以 JS 文件形式存放在 newIDE/app/src/locales 中。翻译文件经过编译后会变成非常庞大的 JavaScript 文件若 Babel 逐一对它们做转换会出现内存占用激增甚至进程无响应挂起/冻结/崩溃的问题。3.2 解决方案一份和 create-react-app 同预设但排除 locales的.babelrcnewIDE/app/.storybook/.babelrc 完整内容如下{ presets: [react-app], ignore: [src/locales/**/*.js] }要点拆解presets: [react-app]直接复用 create-react-app 的 Babel 预设保证 Storybook 的转译行为与主应用保持一致避免出现同一份代码在应用与 Storybook 中编译结果不一致的问题。ignore: [src/locales/**/*.js]通过 glob 模式把整个 locales 目录下的 JS 文件从 Babel 编译中排除从而避免编译巨型翻译文件导致 babel 挂起/冻结/崩溃。由于这些 locales 文件只是静态的翻译映射数据不需要经过 JSX/Flow 等转换即可被浏览器直接加载因此跳过它们不会影响 Storybook 渲染翻译文本的能力翻译数据由I18nProviderDecorator另行注入见第 6 节。3.3 维护注意点原文档特别提醒维护者未来升级 create-react-app、lingui-js 或 Storybook 时需要重新检查这份.babelrc是否仍然必要同时检查package.json中的 babel 相关依赖如babel-core等是否仍然需要显式声明——它们本应由 create-react-app 提供但因为 lingui-js 会显式请求这些包所以项目选择在依赖中保留它们。4.main.jsStorybook 7 Webpack 构建配置解析newIDE/app/.storybook/main.js 是 Storybook 的入口配置完整内容如下module.exports { env: config ({ REACT_APP_ENV: , ...config }), framework: { name: storybook/react-webpack5, }, features: { storyStoreV7: false, }, stories: [../src/stories/**/*.stories.js], staticDirs: [../public], addons: [ { name: storybook/addon-essentials, options: { docs: false, }, }, storybook/preset-create-react-app, ], };逐项说明env: config ({ REACT_APP_ENV: , ...config })为 Storybook 的编译环境注入REACT_APP_ENV变量并置为空字符串确保构建过程中读取该环境变量的代码如按环境区分功能的模块在 Storybook 中拿到的是一个空环境避免误触发线上/生产分支逻辑。framework: { name: storybook/react-webpack5 }使用 React Webpack 5 框架与项目当前使用的 Storybook 7.4.6 配套。features: { storyStoreV7: false }关闭 Storybook 7 的 V7 存储特性即回退到传统 story store。从源码结构看GDevelop 的 stories 大量依赖模块加载顺序与全局副作用尤其是global.gd的初始化见第 6 节关闭 V7 store 可以维持旧的模块求值时机保证GDevelopJsInitializerDecorator在正确时机执行。stories: [../src/stories/**/*.stories.js]约定所有组件故事统一放在 newIDE/app/src/stories 目录下含componentStories/子目录并遵循*.stories.js命名规范另外目录中还有everything-else.stories.js这类聚合故事文件。staticDirs: [../public]将 newIDE/app/public 作为静态资源目录使页面能直接以相对路径引用公共资源这也是preview-head.html中script src./libGD.js能被正确加载的前提之一。addons启用storybook/addon-essentials并显式关闭docs面板因为项目不使用它外加storybook/preset-create-react-app以复用 CRA 的 Webpack 配置生态。5.preview-head.html把 libGD.js 同步注入 Storybook 页面newIDE/app/.storybook/preview-head.html 会在 Storybook 预览 iframe 的head中注入与主应用一致的脚本导入!-- Log the time of start -- script window[GD_STARTUP_TIMES] [ [previewHeadHtmlFirstScriptStarted, performance.now()], ]; /script !-- GDevelop.js core -- script src./libGD.js/script其作用是记录启动时间window.GD_STARTUP_TIMES数组在页面加载最早阶段被初始化配合 newIDE/app/src/stories/GDevelopJsInitializerDecorator.js 中initializeGDevelopJsCall、initializeGDevelopJsDone等时间点构成完整的引擎加载耗时链路最终可通过getStartupTimesSummary()输出摘要。加载引擎核心通过script src./libGD.js同步加载 GDevelop 的 C 核心编译产物。这与主应用在public/index.html中的做法保持一致保证 Storybook 中global.initializeGDevelopJs可用从而让每个 story 都能在真实引擎之上运行。6.preview.js主题切换工具栏与四层全局装饰器newIDE/app/.storybook/preview.js 负责全局级别的 Storybook 行为包含全局类型globalTypes、参数parameters与装饰器decorators。6.1 全局工具栏一键切换 GDevelop 主题export const globalTypes { themeName: { name: Theme, description: Global theme for components, defaultValue: GDevelop default Dark, toolbar: { icon: circlehollow, // See theme names in ThemeRegistry.js items: [ GDevelop default Dark, GDevelop default Light, Blue Dark, Nord, Solarized Dark, One Dark, Rosé Pine, ], showName: true, }, }, };该配置在 Storybook 工具栏中创建一个名为Theme的下拉切换器默认值为GDevelop default Dark并列出全部 7 个内置主题GDevelop default Dark、GDevelop default Light、Blue Dark、Nord、Solarized Dark、One Dark、Rosé Pine。主题名与 newIDE/app/src/UI/Theme/ThemeRegistry.js 中注册的名称一一对应方便组件作者在多种主题下快速验证视觉效果。6.2 parameters关闭不用的控件export const parameters { controls: { hideNoControlsWarning: true }, docs: { disable: true }, };controls的hideNoControlsWarning用于隐藏该 story 没有控件的警告docs: { disable: true }与main.js中 addon-essentials 的docs: false相互呼应整体关闭不需要的 docs 文档面板。6.3 decorators按顺序执行的四层全局装饰器export const decorators [ themeDecorator, GDevelopJsInitializerDecorator, i18nProviderDecorator, BrowserDropDownMenuDisablerDecorator, ];四层装饰器分别位于 newIDE/app/src/stories 目录themeDecoratorThemeDecorator.js读取context.globals.themeName通过FullThemeProvider的forcedThemeName把选中主题强制应用到每个 story实现一个组件、七套主题的即时预览。GDevelopJsInitializerDecoratorGDevelopJsInitializerDecorator.js这是 GDevelop Storybook 最核心的装饰器。由于编辑器源码在模块顶层import 之后就使用global.gd它必须在任何组件之前被导入因此文件先创建一个占位对象global.gd { I_AM_NOT_YET_INITIALIZED_YOU_MUST_USE_GD_INSIDE_A_STORY_ONLY: true, };随后在 React 组件挂载时调用initializeGDevelopJs()异步加载引擎加载完成后通过delete 逐 key 拷贝的方式原地更新同一个global.gd对象而非重新赋值确保那些已经持有该引用的模块代码无需重载即可拿到真实引擎。之后调用makeTestExtensions(gd)注册测试扩展并用makeTestProject(gd)构建一个测试工程对象同样原地更新导出的testProject。在isReady之前页面显示 Loading GDevelop.js, test extensions and test project...。这套设计让所有 story 都能基于真实的 GDevelop 引擎 测试扩展 测试工程渲染而不是 mock 出来的空壳。i18nProviderDecoratorI18nProviderDecorator.js提供国际化上下文使组件中的翻译函数能正常取到文案。BrowserDropDownMenuDisablerDecoratorBrowserDropDownMenuDisablerDecorator.js禁用浏览器原生的下拉菜单行为规避 Storybook 预览 iframe 中与自定义菜单组件冲突的问题。此外preview.js还引入了 icomoon 字体样式 与 app-level-styling.css后者定义了text-focus-in等在主应用打包之外使用到的关键帧动画例如 newIDE/app/public/index.html 中会用到的动画。7. 组件故事的编写约定与配套设施从main.js的stories配置可以看出GDevelop 的所有组件故事都集中在 newIDE/app/src/stories含componentStories/子目录。该目录还提供了大量story 专用工具帮助作者模拟真实编辑器环境FakeResourceManagement.js、FakeResourceExternalEditors.js模拟资源管理上下文FakeEventsFunctionsExtensionsContext.js伪造事件函数扩展上下文DragAndDropTestBed.js、EditorMosaicPlayground.js专门的交互测试场景SerializedObjectDisplay.js直观展示对象的序列化结果AlertDecorator.js、PaperDecorator.js、InAppTutorialDecorator.js、MockLeaderboardProvider.js、MockTeamProvider.js各类局部装饰器与 Mock Provider。这些设施与全局装饰器配合使开发者可以在接近真实的编辑器运行时环境中快速搭建组件 demo这也是 GDevelop 团队将 Storybook 定位为UI 组件快速开发与测试 playground的落地方式。8. 配置要点速查表配置文件相对路径核心职责.babelrcnewIDE/app/.storybook/.babelrc复用react-app预设并通过ignore: [src/locales/**/*.js]规避编译巨型翻译文件导致的 babel 挂起/冻结/崩溃main.jsnewIDE/app/.storybook/main.js框架选择react-webpack5、story 目录约定、静态资源目录、addon 装配、注入REACT_APP_ENVpreview-head.htmlnewIDE/app/.storybook/preview-head.html记录启动时间并注入script src./libGD.js与主应用加载方式保持一致preview.jsnewIDE/app/.storybook/preview.js定义 7 主题切换工具栏、关闭 docs/controls 冗余能力、装配四层全局装饰器app-level-styling.cssnewIDE/app/.storybook/app-level-styling.css提供应用打包之外使用的全局关键帧动画9. 升级与维护清单根据原文档的提醒以下场景需要重新评估这套配置是否仍然成立升级 create-react-appreact-app预设的路径与行为可能变化需确认.babelrc是否仍需显式存在升级 lingui-js翻译文件的编译产物形态可能改变若体积问题消失ignore规则可酌情移除升级 StorybookstoryStoreV7: false是否为必要回退、addon 版本是否匹配需要结合global.gd的初始化时序重新验证升级/清理 babel 依赖package.json中显式声明的babel-core等包本应由 create-react-app 提供但因 lingui-js 会显式请求它们而保留升级时应检查是否仍需要。只要守住两条主线——Babel 不碰 locales 巨型文件、libGD.js 与全局 gd 对象按正确时序初始化——GDevelop 的 Storybook 就能稳定地作为 UI 组件开发、主题验证与回归测试的可靠平台。【免费下载链接】GDevelop Open-source, cross-platform 2D/3D/multiplayer game engine designed for everyone.项目地址: https://gitcode.com/GitHub_Trending/gd/GDevelop创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考