在Ember中如何消费single-spa共享Utility模块?
解决方案:Ember微前端消费single-spa Utility模块实现跨应用数据共享
明确说:不需要必须发布到npm,也不是只能通过props传值,Ember可以直接消费single-spa的Utility模块,以下是两种可行方案:
方案一:模拟Webpack externals效果(Ember构建配置实现)
Ember基于Broccoli构建,可通过ember-auto-import实现类似Webpack externals的全局模块映射:
确保Utility模块已在single-spa根配置中加载(作为utility模块注册,或通过script标签引入index.html),此时它会挂载到
window对象,比如window['@company/utility']。若项目未安装
ember-auto-import,先执行安装:npm install ember-auto-import --save-dev修改
ember-cli-build.js,添加externals映射:const EmberApp = require('ember-cli/lib/broccoli/ember-app'); module.exports = function(defaults) { let app = new EmberApp(defaults, { autoImport: { externals: { '@company/utility': 'window["@company/utility"]' } } }); return app.toTree(); };在Ember组件/服务中直接导入使用:
import Utility from '@company/utility'; // 调用Utility中的方法或访问可观测数据
方案二:通过single-spa注册时的props传递
这种方式无需修改构建配置,实现更直接:
在root-config中加载Utility模块,并作为props传入Ember应用:
registerApplication( "ember", async () => { const appName = "ember"; const appUrl = `${domain}/ember/assets/ember.js`; const vendorUrl = `${domain}/ember/assets/vendor.js`; // 预加载Utility模块 const utility = await System.import('@company/utility'); const emberApp = await loadEmberApp(appName, appUrl, vendorUrl); // 返回接收props的初始化函数 return (props) => emberApp(props); }, (location) => location.pathname.startsWith("/ember"), { utility: await System.import('@company/utility') } );修改Ember的single-spa适配代码(通常是
app/single-spa-adapter.js),将props注入Ember依赖系统:import Application from '@ember/application'; import Resolver from 'ember-resolver'; import loadInitializers from 'ember-load-initializers'; import config from './config/environment'; export default function(props) { const App = Application.extend({ modulePrefix: config.modulePrefix, podModulePrefix: config.podModulePrefix, Resolver }); // 注册Utility并注入到所有服务/组件 App.register('utility:main', props.utility, { instantiate: false }); App.inject('service', 'utility', 'utility:main'); App.inject('component', 'utility', 'utility:main'); loadInitializers(App, config.modulePrefix); return App.create({ autoboot: false }).boot(); }在Ember组件中直接使用注入的Utility:
import Component from '@glimmer/component'; import { inject } from '@ember/service'; export default class MyComponent extends Component { @inject utility; someAction() { // 访问共享数据或调用方法 console.log(this.utility.sharedData); } }
方案对比
- 方案一:更贴近React的externals用法,适合需要在Ember多处直接导入的场景,代码更简洁。
- 方案二:无需修改构建配置,灵活度高,适合快速验证或Utility模块需动态传入的场景。
两种方案都不需要将Utility模块发布到npm,完全基于single-spa生态实现跨框架数据共享。
内容的提问来源于stack exchange,提问作者Tautvydas Būda
相关产品推荐
相关产品推荐

