
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),僅供參考