如何在被外部库调用的Ember工具函数中使用Ember服务?
Great question! The issue with your current code is that Ember's service() injection helper only works within Ember class definitions (like components, routes, or services themselves). When you call it in a plain standalone function, it doesn't resolve to an actual service instance—instead, it returns a descriptor object that Ember's dependency injection (DI) system would normally process in a class context. That's why your get(bar, "name") call isn't returning the expected value.
To fix this, you need to access your Ember application instance directly, since it's the entry point for looking up service instances via Ember's DI system. Here are two clean ways to do this:
Option 1: Use a Module to Store the App Instance (Recommended)
This avoids polluting the global namespace and keeps your code organized:
- Create a utility module to hold the app instance:
// app/utils/app-context.js let appInstance; export function setAppInstance(instance) { appInstance = instance; } export function getAppInstance() { return appInstance; }
- Update your app's main class to save the instance on initialization:
// app/app.js import Application from '@ember/application'; import Resolver from 'ember-resolver'; import loadInitializers from 'ember-load-initializers'; import config from './config/environment'; import { setAppInstance } from './utils/app-context'; export default class App extends Application { modulePrefix = config.modulePrefix; podModulePrefix = config.podModulePrefix; Resolver = Resolver; init() { super.init(...arguments); // Save the app instance when the app initializes setAppInstance(this); } }
- Modify your standalone function to use the stored app instance to lookup the service:
// Your utility function file import { getAppInstance } from '../utils/app-context'; import Ember from 'ember'; const { get } = Ember; export default function(foo) { const appInstance = getAppInstance(); // Look up the actual service instance using the app instance const bar = appInstance.lookup('service:bar'); console.log('bar', bar); console.log('get(bar, "name")', get(bar, 'name')); // Now returns "TheSpot" return [foo, bar]; }
Option 2: Mount the App Instance to the Global Window (Quick Fix)
If you need a simpler, temporary solution, you can attach the app instance to the global window object:
- Update your app's main class:
// app/app.js import Application from '@ember/application'; import Resolver from 'ember-resolver'; import loadInitializers from 'ember-load-initializers'; import config from './config/environment'; export default class App extends Application { modulePrefix = config.modulePrefix; podModulePrefix = config.podModulePrefix; Resolver = Resolver; init() { super.init(...arguments); // Attach app instance to global window window.EmberAppInstance = this; } }
- Update your utility function:
// Your utility function file import Ember from 'ember'; const { get } = Ember; export default function(foo) { const appInstance = window.EmberAppInstance; const bar = appInstance.lookup('service:bar'); console.log('bar', bar); console.log('get(bar, "name")', get(bar, 'name')); return [foo, bar]; }
Important Notes
- Make sure your external library calls the utility function after the Ember app has finished initializing. If the library might run earlier, you can wait for Ember's
didTransitionevent or theapplication:initializedevent to ensure the app instance is available. - Using
lookup('service:bar')gives you the singleton instance of the service, just like using theservice()injection helper in a class—so you'll get consistent state across your app.
内容的提问来源于stack exchange,提问作者Devin Rhode

