wp-calypso Blaze Dashboard 独立应用全指南目录架构、hashbang 路由、Gridicon 替换与构建发布实战【免费下载链接】wp-calypsoThe JavaScript and API powered WordPress.com项目地址: https://gitcode.com/gh_mirrors/wp/wp-calypsoBlaze Dashboard 是 wp-calypso 仓库中以独立应用形态存在的广告Blaze/推广面板设计目标是嵌入 Jetpack 插件、并面向未来嵌入 WooCommerce 使用。它复用 Calypso 的 React、Redux 与路由体系却以零 Calypso 外壳的轻量方式运行于wp-admin内部。本文以 apps/blaze-dashboard/README.md 为骨架结合仓库源码深入讲解其目录结构、hashbang 路由机制、Gridicon 无 Sprite 替换方案以及生产构建、本地 Jetpack 联调、沙盒同步和 CDN 发布的完整流程帮助读者理解Calypso 组件如何被拆出来做成独立插件应用这一架构模式。Blaze Dashboard 是什么Blaze Dashboard 是一个独立构建的 Web 应用standalone application当前的宿主是 Jetpack 插件未来计划嵌入 WooCommerce。Jetpack 侧对应的实现位于 Automattic 的 Jetpack 仓库projects/packages/blaze包README 原文指向 Jetpack blaze 包 可以看出它的定位描述name: automattic/blaze-dashboard, description: Blaze dashboard served within wp-admin via the Jetpack plugin., main: dist/build.min.js, private: true也就是说它被打包成dist/build.min.js提供给 Jetpack 在wp-admin中挂载而不是作为 Calypso 主站的一个路由页面存在。从源码看Blaze Dashboard 复用了大量 Calypso 基础设施automattic/calypso-config配置、automattic/calypso-routerpage.js 路由、automattic/calypso-polyfillspolyfill、Redux/Redux-Thunk 状态管理、React Query 数据请求tanstack/react-query以及calypso/my-sites/promote-post-i2下的推广后台控制器。它本质上是把 Calypso 中推广帖子功能区域整体搬进 Jetpack 的独立应用。目录结构HierarchyREADME 给出了应用自身的顶层结构. └── src/ ├── components/ ← blaze dashboard app only components. For now there is only a layout component. ├── page-middleware/ ← page.js integration with React and everything ├── app.js ← entry point └── routes.js ← page.js routes对照仓库实际目录 apps/blaze-dashboard/src结构与 README 描述一致并略有扩展components/应用自有组件目前包含layout.jsx布局外壳负责渲染primary/secondary区域、文档头与加载器见 components/layout.jsx和nothing.jsx用于 webpackNormalModuleReplacementPlugin把不需要的模块替换为空组件的占位实现。page-middleware/page.js 与 React 的桥接层包含layout.jsxmakeLayout/ProviderWrappedLayout把 Redux Provider、React Query Provider、i18n Provider 和 Calypso 路由上下文包在一起与setup-context.jsx为每个路由上下文注入store、queryClient、query、pathname、hash、previousPath与redirect能力见 page-middleware/setup-context.jsx。app.jsx应用入口负责装载全局配置、polyfill、主题变量、Redux store并触发路由注册与首屏渲染见 app.jsx。routes.jspage.js 路由定义见 routes.js。其余目录README 未单独列出但属于实现细节lib/fix-path.js路径修复、set-locale.js语言包加载、pages/setup 页面与 controller、styles/布局、排版、wp-admin 兼容样式以及themes.jsJetpack/WP.com/Woo 三套主题色变量。入口启动流程app.jsx 的AppBoot清晰展示了启动顺序根据 feature flag 选择主题is_running_in_woo_site→woois_running_in_blaze_plugin→wpcom否则jetpack并把 CSS 变量写入document.documentElement用combineReducers组合currentUser与sitesreducer创建 Redux store依次挂载thunkMiddleware、wpcomApiMiddleware、analyticsMiddleware从config( initial_state )读取当前用户store.dispatch( setSelectedSiteId( config( blog_id ) ) )设置站点上下文初始化分析仅当 Jetpack 返回用户邮箱时才视为已连接用户修正window.location.hash见下文 fix-path加载 locale 后注册路由并page.show( fixPath( window.location.hash ) )渲染首屏。一个值得注意的细节app.jsx中特意给body添加了is-section-promote-post-i2类名表明该独立应用在语义上仍隶属于 Calypso 的promote-post-i2section。路由机制hashbang#!与 page.js为什么需要 hashbangBlaze Dashboard 使用 page.js 的hashbang#!模式。原因在于它运行在 Jetpack 的wp-admin页面内无法像 Calypso 主站那样自由支配浏览器地址栏的 pathname——所有跳转都被限制在 hash 片段中。仓库中automattic/calypso-router正是对 page.js 的封装。但 hashbang 不会开箱即用Calypso 中大量链接是硬编码的普通路径如/advertising/xxx点击后浏览器会直接尝试整页导航。因此 Jetpack 侧需要拦截锚点点击把普通链接转换成 hashbangREADME 给出了这段核心代码$( #wpcom ).on( click, a, function ( e ) { const link e e.currentTarget e.currentTarget.attributes e.currentTarget.attributes.href e.currentTarget.attributes.href.value; if ( link ! link.startsWith( http ) ) { location.hash #!${ link }; return false; } } );逻辑要点监听#wpcom容器内的所有a点击读取href属性值若不存在或为http开头外部链接则放行否则把location.hash设置为#!${link}并return false阻止默认跳转从而让 page.js 接管路由。路由表实现在 routes.js 中page.base( pageBase )设定基准路径随后通过blazePage( url, ...controller )统一注册路由每个路由都会经过setupMode → 具体 controller → siteSelection → makeLayout → clientRender链路。核心路由包括blazePage( getAdvertisingDashboardPath( /setup/:site ), setup ); blazePage( getAdvertisingDashboardPath( /:site ), promotedPosts ); blazePage( getAdvertisingDashboardPath( /:tab/:site ), checkValidTabInNavigation, promotedPosts ); blazePage( getAdvertisingDashboardPath( /campaigns/:campaignId/:site ), campaignDetails ); blazePage( getAdvertisingDashboardPath( /promote/:item/:site ), promoteWidget ); blazePage( getAdvertisingDashboardPath( /:tab/promote/:item/:site ), promoteWidget ); blazePage( getAdvertisingDashboardPath( /payments/receipt/:receiptId/:site? ), promotedPosts );这些 controllerpromotedPosts、campaignDetails、promoteWidget、checkValidTabInNavigation均来自calypso/my-sites/promote-post-i2/controller印证了 Blaze Dashboard 与 Calypso 推广后台共享同一套页面实现。setupMode中间件根据blaze_setup_modefeature flag 决定是强制进入/setup/引导页还是跳回主面板最后的blazePage( *, redirectToReadyToPromote )兜底把未知路径重定向到getAdvertisingDashboardPath( / hostname )。文件末尾page( { hashbang: true } )正式开启 hashbang 模式这正是 README 所说在 Jetpack 中启用 hashbang 路由的落点。路径修复fix-path.js由于 page.js 会在 hash 上追加?pageadvertising之类的查询串且历史遗留的旧式路径前缀需要归一化lib/fix-path.js 做了两件事截断?之后的所有查询串若路径不以config( advertising_dashboard_path_prefix )默认/advertising开头则把第二段路径替换为正确前缀。app.jsx在启动时用它修正window.location.hash并注释说明URL 可能已被 page.js 添加的?pageadvertising破坏。Gridicon 替换不加载 SVG Sprite 的方案automattic/components包中的Gridicon组件通过use引用 SVG Sprite 文件。当应用从 CDN非主域加载时use跨域引用 Sprite 会出问题因此 Blaze Dashboard 换用了不加载 Sprite 文件的实现packages/components/src/gridicon/no-asset.tsx随后由 Jetpack 单独加载 Sprite。README 给出了 Jetpack 侧加载 Sprite 的代码$.get( https://widgets.wp.com/blaze-dashboard/common/gridicons-506499ddac13811fee8e.svg, function ( data ) { var div document.createElement( div ); div.innerHTML new XMLSerializer().serializeToString( data.documentElement ); div.style display: none; document.body.insertBefore( div, document.body.childNodes[ 0 ] ); } );要点把 SVG 文件内容序列化后塞进一个display: none的div并插入body最前面这样页面上存在完整的 Sprite 定义use引用即可命中。仓库侧的对应替换动作发生在 webpack.config.js// Replace the packages/components/src/gridicon/index.tsx with a replacement that does not enqueue the SVG sprite. // The sprite is loaded separately in Jetpack. new webpack.NormalModuleReplacementPlugin( /^\.\.\/gridicon$/, ../gridicon/no-asset ), new webpack.NormalModuleReplacementPlugin( /^\.\/gridicon$/, ./gridicon/no-asset ),构建时把gridicon模块整体替换为no-asset实现从而保证产物中不包含 Sprite 加载逻辑配套的src/components/nothing.jsx空组件则用于excludedPackagesexcludedPackagePlugins把确认无用的依赖模块替换为空实现进一步缩减最终产物。构建与本地开发生产构建ProductionREADME 给出的标准生产构建命令cd apps/blaze-dashboard yarn build从 package.json 的 scripts 看build实际是NODE_ENVproduction yarn dev而dev为dev: yarn run calypso-apps-builder --localPath dist --remotePath /home/wpcom/public_html/widgets.wp.com/blaze-dashboard/v1即借助automattic/calypso-apps-builder构建并把产物同步到widgets.wp.com/blaze-dashboard/v1对应的远程路径。webpack 配置中入口为src/app输出build.min.jschunk 为[name]-[contenthash].js生产模式开启bail、代码压缩与GenerateChunksMapPlugin生成dist/chunks-map.json。其余常用脚本yarn build:statscalypso-build用于产出构建统计yarn show-statsNODE_ENVproduction EMIT_STATStrue yarn build配合webpack-bundle-analyzer查看打包体积分析yarn translate使用wp-babel-makepot提取client、packages、apps下的可翻译字符串生成 POT 文件并调用build-app-languages产出语言包。与本地 Jetpack 联调开发README 给出的步骤确保本地有可用的 Jetpack 安装运行BLAZE_DASHBOARD_PACKAGE_PATH/path/to/jetpack/projects/packages/blaze yarn dev该环境变量在 webpack.config.js 中被消费const outBasePath process.env.BLAZE_DASHBOARD_PACKAGE_PATH ? process.env.BLAZE_DASHBOARD_PACKAGE_PATH : __dirname; const outputPath path.join( outBasePath, dist );也就是说不设置该变量时产物输出到apps/blaze-dashboard/dist设置后直接输出到 Jetpack 的projects/packages/blaze/dist这样yarn dev的增量构建能立刻被本地 Jetpack 读取实现边改边看。沙盒Sandbox开发README 说明确保有可用的沙盒环境且其主机名为wpcom-sandbox运行yarn dev --sync在改动文件时自动构建并同步。这里的--sync由calypso-apps-builder提供配合上面dev脚本中的--remotePath /home/wpcom/public_html/widgets.wp.com/blaze-dashboard/v1把构建产物实时同步到沙盒对应的widgets.wp.com目录便于在接近线上的环境中验证。上传到 CDNREADME 明确指出 CDN 路径为widgets.wp.com/blaze-dashboard。结合前文可知构建产物目录dist对应 CDN 上的widgets.wp.com/blaze-dashboard当前dev脚本实际同步到/v1子路径Gridicon Sprite 文件位于widgets.wp.com/blaze-dashboard/common/下如gridicons-506499ddac13811fee8e.svg语言包从widgets.wp.com/blaze-dashboard/v1/languages/${languageFileName}-v1.1.json加载见 lib/set-locale.js 中loadLanguageFile的 URL 拼接。也就是说无论 JS、CSS、SVG Sprite 还是翻译文件都从该 CDN 路径对外提供这解释了为什么 Sprite 与语言包都要显式远程加载而不能依赖 Calypso 主域。配置注入与运行环境适配Blaze Dashboard 的一大特点是通过 Jetpack 注入的window.configData完成运行时配置而不是在构建期写死环境。load-config.js 做了几件关键的事修正 Jetpack 配置响应中的拼写错误intial_state→initial_state把blog_id强制转为数字BlazePageViewTracker在 Atomic 环境遇到字符串 blog_id 会出问题依据is_woo_store/is_blaze_plugin/need_setup等运行时标志动态覆盖is_running_in_woo_site、is_running_in_blaze_plugin、blaze_setup_mode等 feature flag设置advertising_dashboard_path_prefixBlaze Ads 插件环境下为/wc-blaze并兼容旧版本插件Jetpack 环境下为/advertising关闭use-translation-chunks完整翻译文件加载方式。同时 webpack.config.js 通过自研的 filter-json-config-loader.js 只从config/production.json中抽取features、dsp_stripe_pub_key、dsp_widget_js_src、client_slug、hotjar_enabled这几个 key 打进产物避免把整个配置文件全部带进独立应用。该 loader 的实现就是解析 JSON → 按options.keys白名单过滤 → 重新序列化。主题方面themes.js 定义了 Jetpack 主题以--studio-jetpack-green系作为--color-primary的完整色阶与空的wpcom/woo主题占位默认回退到jetpack配合入口处isEnabled判断实现不同宿主下的视觉区分。小结Blaze Dashboard 是Calypso 能力外置的典型示例以page.js的 hashbang 模式解决wp-admin内嵌场景下的路由问题以NormalModuleReplacementPlugin替换掉跨域不友好的 Gridicon Sprite 实现通过BLAZE_DASHBOARD_PACKAGE_PATH、yarn dev --sync与calypso-apps-builder打通本地 Jetpack 联调、沙盒同步和 CDN 发布widgets.wp.com/blaze-dashboard全链路。理解这一应用的结构与构建方式对阅读 Jetpack 侧projects/packages/blaze的宿主逻辑、以及在未来把它扩展到 WooCommerce 场景都很有帮助。后续想深入某个环节可直接从 app.jsx 入口、routes.js 路由表、webpack.config.js 构建配置三处源码继续追踪。【免费下载链接】wp-calypsoThe JavaScript and API powered WordPress.com项目地址: https://gitcode.com/gh_mirrors/wp/wp-calypso创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
