Start Date Release Date Release Versions PR link Tracking Link Stage Teams
1/22/2024
Accepted
  • CLI
  • Data
  • Framework
  • Learning
  • Steering
  • TypeScript

Deprecate `import Ember from 'ember';

Summary

This RFC proprosing deprecating all APIs that have module-based replacements, as described in RFC #176 as well as other Ember.* apis that are no longer needed.

Motivation

The import Ember from 'ember'; set of APIs is implementn as a barrel file, and properly optimizing barrel files is a lot of work, requiring integration with build time tools.

If anyone one dependency in an app's dependency tree does import ... from 'ember', every feature of the framework is shipped to your users, without any ability for you to optimize.

By removing this set of exports, we have an opportunity to shrink some apps (as some APIs are not used), improving the load performance of ember apps -- and we removing all of these gives us a chance to have a better grasp of what we can get rid of permananently.

Many of these APIs already have alternatives, and those will be called out explicitly in the Transition Path below.

Transition Path

This list is semi-exhaustive, in that it covers every export from 'ember', but may not exhaustivily provide alternatives.

Throughout the rest of this RFC, the following key will be used:

  • ๐ŸŒ to mean "this is public API"
  • ๐Ÿ”’ to mean "this is private API"
  • ๐Ÿงท to mean "this is protected API"
  • ๐Ÿซฃ to mean "no declared access"

Testing utilities

APIs for wiring up a test framework (e.g. QUnit, etc)

| | API | Usage: EmberObserver | -- | | - | --- | ----- | -- | |๐ŸŒ | Ember.Test | A good few | | |๐ŸŒ | Ember.Test.Adapter | ember-cli-fastboot and @ember/test-helpers | currently available at @ember/test | |๐ŸŒ | Ember.Test.QUnitAdapter | ember-cli-fastboot | | |๐ŸŒ | Ember.setupForTesting | ember-cli-fastboot | |

If needed, these will need to be moved to a module such as @ember/test.

A way to communicate with the ember-inspector

The inspector will be hit especially hard by the removal of these APIs.

A good few already have available imports though.

| | API | import | | - | --- | ------ | |๐Ÿ”’| Ember.meta | import { meta } from '@ember/-internals/meta'; | |๐ŸŒ| Ember.VERSION | import { VERSION } from '@ember/version'; | |๐Ÿ”’| Ember._captureRenderTree | import { captureRenderTree } from '@ember/debug'; | |๐Ÿ”’| Ember.instrument | import { instrument } from '@ember/instrumentation'; | |๐Ÿ”’| Ember.subscribe | import { subscribe } from '@ember/instrumentation'; | |๐Ÿ”’| Ember.Instrumentation.* | import { * } from '@ember/instrumentation'; | |๐Ÿซฃ| Ember.ViewUtils | import * as viewUtils from '@ember/-internals/views';[^view-utils] | |๐Ÿ”’| Ember.ViewUtils.getChildViews | import { getChildViews } from '@ember/-internals/views'; | |๐Ÿซฃ| Ember.ViewUtils.getElementView | import { getElementView } from '@ember/-internals/views'; | |๐Ÿ”’| Ember.ViewUtils.getRootViews | import { getRootViews } from '@ember/-internals/views'; | |๐Ÿ”’| Ember.ViewUtils.getViewBounds | import { getViewBounds } from '@ember/-internals/views'; | |๐Ÿ”’| Ember.ViewUtils.getViewBoundingClientRect | import { getViewBoundingClientRect } from '@ember/-internals/views'; | |๐Ÿ”’| Ember.ViewUtils.getViewClientRects | import { getViewClientRects } from '@ember/-internals/views'; | |๐Ÿ”’| Ember.ViewUtils.getViewElement | import { getViewElement } from '@ember/-internals/views'; | |๐Ÿซฃ| Ember.ViewUtils.isSimpleClick | import { isSimpleClick } from '@ember/-internals/views'; | |๐Ÿซฃ| Ember.ViewUtils.isSerializationFirstNode | import { isSerializationFirstNode } from '@ember/-internals/glimmer'; |

[^view-utils]: Not all of these exports are used for ViewUtils.

Perhaps we can have folks add this to their apps:

import { macroCondition, isDevelopingApp, importSync } from '@embroider/macros';

if (macroCondition(isDevelopingApp())) {
  // maybe this is side-effecting and installs 
  // some functions on `globalThis` that the inspector could call
  // since the inspector can't import modules from a built app.
  importSync('@ember/inspector-support');
}

No replacements.

Applies to both the value and type exports (if applicable). All of these will not be re-exported from other @ember/* packages, but the following tables will show addon usage[^why-addon-usage] in the ecosystem and potential paths forward for library authors.

[^why-addon-usage]: Addons are notorious for doing things they shouldn't, accessing private APIs, doing crazy things so users don't have to, working around ecosystem and broader ecosystem problems etc. It's also expected that addon authors will be able to handle migrations more quickly than app devs.

| | API | Usage: EmberObserver | Migration | | - | --- | ----- | --------- | |๐Ÿซฃ | Ember._getPath | None | n/a | |๐Ÿซฃ | Ember.isNamespace | None | n/a | |๐Ÿซฃ | Ember.toString | None | n/a | |๐Ÿ”’ | Ember.Container | Many, but old or docs | n/a | |๐Ÿ”’ | Ember.Registry | Many, but old or docs | n/a |

Internal decorator utils | | API | Usage: EmberObserver | Migration | | - | --- | ----- | --------- | |๐Ÿซฃ | Ember._descriptor | EmberObserver: None | n/a | |๐Ÿ”’ | Ember._setClassicDecorator | EmberObserver: ember-concurrency | n/a |

Reactivity | | API | Usage: EmberObserver | Migration | | - | --- | ----- | --------- | |๐Ÿ”’ | Ember.beginPropertyChanges | ember-m3 + old addons | n/a | |๐Ÿ”’ | Ember.endPropertyChanges | ember-m3 + old addons | n/a | |๐Ÿ”’ | Ember.changeProperties | None | n/a |

Observable | | API | Usage: EmberObserver | Migration | | - | --- | ----- | --------- | |๐ŸŒ | Ember.hasListeners | None | n/a |

Mixins | | API | Usage: EmberObserver | Migration | | - | --- | ----- | --------- | |๐Ÿ”’ | Ember._ContainerProxyMixin | mostly old addons. Includes ember-decorators, ember-data-has-many-query, ember-graphql-adapter, ember-cli-fastboot (in tests / test-support) | n/a | |๐Ÿ”’ | Ember._RegistryProxyMixin | mostly old addons. Includes ember-decorators, ember-data-has-many-query, ember-graphql-adapter, ember-cli-fastboot (in tests / test-support) | n/a | |๐Ÿ”’ | Ember._ProxyMixin | ember-bootstrap-components, 8 years ago | n/a | |๐Ÿ”’ | Ember.ActionHandler | 'ember-error-tracker' + old addons. Many usages include pre-modules Ember usage. | n/a | |๐Ÿ”’ | Ember.Comparable | ember-data-model-fragments | n/a |

Utility | | API | Usage: EmberObserver | Migration | | - | --- | ----- | --------- | |๐Ÿซฃ | Ember.lookup | old addons, > 6 years | Use getOwner(...).lookup from @ember/owner | |๐ŸŒ | Ember.libraries | Many usages, mostly ember-data and related | This isn't a behavior that Ember needs to provide, nor should it be library authors' responsibilty to register themselves with a library listing system. App authors could choose to use any webpack or other build plugin that collections this information, such as webpack-node-modules-list or unplugin-info. | |๐Ÿซฃ | Ember._Cache | None | n/a | |๐Ÿ”’ | Ember.GUID_KEY | ember-data-save-relationships, 6 years ago | n/a | | ๐Ÿ”’ | Ember.canInvoke | @summit-electric-supply | use optional chaining, e.g.: this.foo?.method?.() | |๐Ÿ”’ | Ember.generateGuid | [ember-flexberry + old addons](https://emberobserver.com/code-search?codeQuery=Ember.generateGuid&sort=updated&sortAscending=false) | Use [guidFor](https://api.emberjs.com/ember/5.6/functions/@ember%2Fobject%2Finternals/guidFor) or [uuid](https://www.npmjs.com/package/uuid) or the browser-native [crypto.randomUUID()](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/randomUUID) | |๐ŸŒ |Ember.uuid| [3 recent addons](https://emberobserver.com/code-search?codeQuery=Ember.uuid&sort=updated&sortAscending=false) | Use [guidFor](https://api.emberjs.com/ember/5.6/functions/@ember%2Fobject%2Finternals/guidFor) or [uuid](https://www.npmjs.com/package/uuid) or the browser-native [crypto.randomUUID()](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/randomUUID) | |๐Ÿ”’ |Ember.wrap| [None](https://emberobserver.com/code-search?codeQuery=Ember.wrap&sort=updated&sortAscending=false) | n/a | |๐Ÿ”’ |Ember.inspect| [old addons](https://emberobserver.com/code-search?codeQuery=Ember.inspect&sort=updated&sortAscending=false) | n/a | |๐Ÿซฃ |Ember.Debug| [old addons](https://emberobserver.com/code-search?codeQuery=Ember.Debug&sort=updated&sortAscending=false) | use [@ember/debug](https://api.emberjs.com/ember/5.6/modules/@ember%2Fdebug) | |๐Ÿซฃ |Ember.cacheFor| [old addons](https://emberobserver.com/code-search?codeQuery=Ember.cacheFor&sort=updated&sortAscending=false) | potentially [@glimmer/tracking/primitives/cache](https://api.emberjs.com/ember/5.6/modules/@glimmer%2Ftracking%2Fprimitives%2Fcache) | |๐ŸŒ |Ember.ComputedProperty| [aside from docs, old addons](https://emberobserver.com/code-search?codeQuery=Ember.ComputedProperty&sort=updated&sortAscending=false). Most recent usage is 3 years ago inember-cli-furnance-validation| n/a | |๐Ÿซฃ |Ember.RouterDSL| [old addons](https://emberobserver.com/code-search?codeQuery=Ember.RouterDSL&sort=updated&sortAscending=false) | n/a | |๐Ÿ”’ |Ember.controllerFor| [None](https://emberobserver.com/code-search?codeQuery=Ember.controllerFor&sort=updated&sortAscending=false) | n/a | |๐Ÿ”’ |Ember.generateController| [bitbird-core-ember-routing, 5 years ago](https://emberobserver.com/code-search?codeQuery=Ember.generateController&sort=updated&sortAscending=false) | n/a | |๐Ÿ”’ |Ember.generateControllerFactory` | None | n/a |

| | API | Usage: EmberObserver | Migration | | - | --- | ----- | --------- | |๐ŸŒ | Ember.VERSION | EmberObserver: Not many usages. | This has the ember version in it, but it could be converted to a virtual module to import from somewhere, such as @ember/version | |๐Ÿ”’ | Ember._Backburner | EmberObserver: None | n/a | |๐ŸŒ | Ember.inject | EmberObserver: Many, all using classic classes. A lot of results are also classic-class docs. | Use @service |

Any projects using these are already not safe for embroider and won't work with Vite | | API | Usage: EmberObserver | Migration | | - | --- | ----- | --------- | |๐Ÿซฃ | Ember.__loader | 159 addons. Some experimental. Most from @ascua | n/a | | ๐Ÿซฃ | Ember.__loader.require | same as Ember.__loader | n/a | | ๐Ÿซฃ | Ember.__loader.define | 5 addons, ~2 recent. One is ember-cli-fastboot (tests, test-support). | n/a | |๐Ÿซฃ | Ember.__loader.registry | 13 addons, ~5 recent. One is ember-cli-fastboot (tests, test-support). | n/a | |๐Ÿ”’ | Ember.BOOTED | None | n/a |

Replaced by RFC #931. For scenarios where folks would like to compile templates at runtime, see RFC #931 or the code of ember-repl. | | API | Usage: EmberObserver | Migration | | - | --- | ----- | --------- | |๐Ÿ”’ | Ember.TEMPLATES | ember-resolver | n/a | |๐Ÿซฃ | Ember.HTMLBars | Lots of usage (encompasses the below APIs) | n/a | |๐Ÿซฃ | Ember.HTMLBars.DOMHelper | ember-cli-fastboot uses protocolForURL, parseHTML | n/a | |๐Ÿซฃ | Ember.HTMLBars.template | ember-cli-fastboot (and ember-ast-hot-load) | n/a | |๐Ÿซฃ | Ember.HTMLBars.compile | old addons | n/a | |๐Ÿซฃ | Ember.HTMLBars.precomple | ember-ast-hot-load | n/a | |๐Ÿซฃ | Ember.Handlebars | 174 addons, mostly @ascua and also a lot of mentions in docs. | n/a | |๐Ÿซฃ | Ember.Handlebars.template | None | n/a | |๐Ÿซฃ | Ember.Handlebars.Utils.escapeExpression | 100 addons, mostly @ascua | Removed in ember.js PR#20360 as it is not public API. | |๐Ÿซฃ | Ember.Handlebars.compile | ember-cli-fastboot and ember-collection | n/a | |๐Ÿซฃ | Ember.Handlebars.precomple | None | n/a |

Other APIs

  • ๐Ÿซฃ Ember.testing
    Instead, use
  import { macroCondition, isTesting } from '@embroider/macros';

  // ...

  if (macroCondition(isTesting())) {
    // test only code here
  }
  • ๐ŸŒ Ember.onerror Instead you may be able to use an event listener for the error event on window.
  window.addEventListener('error', /* ... event handler ... */);

For promise rejections, you'll want to use the unhandledrejection event.

  window.addEventListener('unhandledrejection', /* ... event handler ... */);

If you really need the original behavior:

  import { getOnerror, setOnerror } from '@ember/-internals/error-handling';

But this should not be needed.

Imports Available

Most of this is covered in RFC #176

Unless otherwise stated, there will not be usage-based decision on these, as they all exist under available imports today.

| | Ember. API | Use this instead | | - | ------------ | ---------------- | |๐ŸŒ | Ember.FEATURES | import { isEnabled, FEATURES } from '@ember/canary-features'; | |๐ŸŒ | Ember._setComponentManager | import { setComponentManager } from '@ember/component'; | |๐ŸŒ | Ember._componentManagerCapabilities | import { capabilities } from '@ember/component'; | |๐ŸŒ | Ember._modifierManagerCapabilities | import { capabilities } from '@ember/modifier'; | |๐ŸŒ | Ember._createCache | import { createCache } from '@glimmer/tracking/primitives/cache'; RFC #615 | |๐ŸŒ | Ember._cacheGetValue | import { getValue } from '@glimmer/tracking/primitives/cache'; RFC #615 | |๐ŸŒ | Ember._cacheIsConst | import { isConst } from '@glimmer/tracking/primitives/cache'; RFC #615 | |๐ŸŒ | Ember._tracked | import { tracked } from '@glimmer/tracking'; | |๐ŸŒ | Ember.RSVP | import RSVP from 'rsvp'; | |๐ŸŒ | Ember.guidFor | import { guidFor } from '@ember/object/internals'; | |๐ŸŒ | Ember.getOwner | import { getOwner } from '@ember/owner'; | |๐ŸŒ | Ember.setOwner | import { setOwner } from '@ember/owner'; | |๐ŸŒ | Ember.onLoad | import { onLoad } from '@ember/application'; | |๐ŸŒ | Ember.runLoadHooks | import { runLoadHooks } from '@ember/application'; | |๐ŸŒ | Ember.Application | import Application from '@ember/application'; | |๐ŸŒ | Ember.ApplicationInstance | import ApplicationInstance from '@ember/application/instance'; | |๐ŸŒ | Ember.Namespace | import Namespace from '@ember/application/namespace'; | |๐ŸŒ | Ember.A | import { A } from '@ember/array'; | |๐ŸŒ | Ember.Array | import Array from '@ember/array'; | |๐ŸŒ | Ember.NativeArray | import { NativeArray } from '@ember/array'; | |๐ŸŒ | Ember.isArray | import { isArray } from '@ember/array'; | |๐Ÿ”’ | Ember.makeArray | import { makeArray } from '@ember/array'; | |๐ŸŒ | Ember.MutableArray | import MutableArray from '@ember/array/mutable'; | |๐ŸŒ | Ember.ArrayProxy | import ArrayProxy from '@ember/array/proxy'; | |๐ŸŒ | Ember._Input | import { Input } from '@ember/component'; | |๐ŸŒ | Ember.Component | import Component from '@ember/component'; | |๐ŸŒ | Ember.Helper | import Helper from '@ember/component/helper'; | |๐ŸŒ | Ember.Controller | import Controller from '@ember/controller'; | |๐Ÿ”’ | Ember.ControllerMixin | import { ControllerMixin } from '@ember/controller'; | |๐ŸŒ | Ember.assert | import { assert } from '@ember/debug'; | |๐ŸŒ | Ember.warn | import { warn } from '@ember/debug'; | |๐ŸŒ | Ember.debug | import { debug } from '@ember/debug'; | |๐ŸŒ | Ember.deprecate | import { deprecate } from '@ember/debug'; | |๐Ÿซฃ | Ember.deprecateFunc | import { deprecateFunc } from '@ember/debug'; | |๐ŸŒ | Ember.runInDebug | import { runInDebug } from '@ember/debug'; | |๐ŸŒ | Ember.Debug.registerDeprecationHandler | import { registerDeprecationHandler } from '@ember/debug'; | |๐ŸŒ | Ember.ContainerDebugAdapter | import ContainerDebugAdapter from '@ember/debug/container-debug-adapter'; | |๐ŸŒ | Ember.DataAdapter | import DataAdapter from '@ember/debug/data-adapter'; | |๐ŸŒ | Ember._assertDestroyablesDestroyed | import { assertDestroyablesDestroyed } from '@ember/destroyable'; | |๐ŸŒ | Ember._associateDestroyableChild | import { associateDestroyableChild } from '@ember/destroyable'; | |๐ŸŒ | Ember._enableDestroyableTracking | import { enableDestroyableTracking } from '@ember/destroyable'; | |๐ŸŒ | Ember._isDestroying | import { isDestroying } from '@ember/destroyable'; | |๐ŸŒ | Ember._isDestroyed | import { isDestroyed } from '@ember/destroyable'; | |๐ŸŒ | Ember._registerDestructor | import { registerDestructor } from '@ember/destroyable'; | |๐ŸŒ | Ember._unregisterDestructor | import { unregisterDestructor } from '@ember/destroyable'; | |๐ŸŒ | Ember.destroy | import { destroy } from '@ember/destroyable'; | |๐ŸŒ | Ember.Engine | import Engine from '@ember/engine'; | |๐ŸŒ | Ember.EngineInstance | import Engine from '@ember/engine/instance'; | |๐Ÿ”’ | Ember.Enumerable | import Enumerable from '@ember/enumerable'; | |๐Ÿ”’ | Ember.MutableEnumerable | import MutableEnumerable from '@ember/enumerable/mutable'; | |๐ŸŒ | Ember.Object | import Object from '@ember/object'; | |๐ŸŒ | Ember._action | import { action } from '@ember/object'; | |๐ŸŒ | Ember.computed | import { computed } from '@ember/object'; | |๐ŸŒ | Ember.defineProperty | import { defineProperty } from '@ember/object'; | |๐ŸŒ | Ember.get | import { get } from '@ember/object'; | |๐ŸŒ | Ember.getProperties | import { getProperties } from '@ember/object'; | |๐ŸŒ | Ember.notifyPropertyChange | import { notifyPropertyChange } from '@ember/object'; | |๐ŸŒ | Ember.observer | import { observer } from '@ember/object'; | |๐ŸŒ | Ember.set | import { set } from '@ember/object'; | |๐ŸŒ | Ember.trySet | import { trySet } from '@ember/object'; | |๐ŸŒ | Ember.setProperties | import { setProperties } from '@ember/object'; | |๐ŸŒ | Ember._dependentKeyCompat | import { dependentKeyCompat } from '@ember/object/compat'; | |๐ŸŒ | Ember.expandProperties | import { expandProperties } from '@ember/object/computed'; | |๐ŸŒ | Ember.CoreObject | import EmberObject from '@ember/object'; | |๐ŸŒ | Ember.Evented | import Evented from '@ember/object/evented'; | |๐ŸŒ | Ember.on | import { on } from '@ember/object/evented'; | |๐ŸŒ | Ember.addListener | import { addListener } from '@ember/object/events'; | |๐ŸŒ | Ember.removeListener | import { removeListener } from '@ember/object/events'; | |๐ŸŒ | Ember.sendEvent | import { sendEvent } from '@ember/object/events'; | |๐ŸŒ | Ember.Mixin | import Mixin from '@ember/object/mixin'; | |๐Ÿ”’ | Ember.mixin | import { mixin } from '@ember/object/mixin'; | |๐ŸŒ | Ember.Observable | import Observable from '@ember/object/observable'; | |๐ŸŒ |Ember.addObserver | import { addObserver } from '@ember/object/observers'; | |๐ŸŒ | Ember.removeObserver | import { removeObserver } from '@ember/object/observers'; | |๐ŸŒ | Ember.PromiseProxyMixin | import EmberPromiseProxyMixin from '@ember/object/promise-proxy-mixin'; | |๐ŸŒ | Ember.ObjectProxy | import ObjectProxy from '@ember/object/proxy'; | |๐Ÿงท | Ember.HistoryLocation | import HistoryLocation from '@ember/routing/history-location'; | |๐Ÿงท | Ember.HashLocation | import HashLocation from '@ember/routing/hash-location'; | |๐Ÿงท | Ember.NoneLocation | import NoneLocation from '@ember/routing/none-location'; | |๐ŸŒ | Ember.Route | import Route from '@ember/routing/route'; | |๐ŸŒ | Ember.run | import { run } from '@ember/runloop'; | |๐ŸŒ | Ember.Service | import Service from '@ember/service'; | |๐ŸŒ | Ember.compare | import { compare } from '@ember/utils'; | |๐ŸŒ | Ember.isBlank | import { isBlank } from '@ember/utils'; | |๐ŸŒ | Ember.isEmpty | import { isEmpty } from '@ember/utils'; | |๐ŸŒ | Ember.isEqual | import { isEqual } from '@ember/utils'; | |๐ŸŒ | Ember.isPresent | import { isPresent } from '@ember/utils'; | |๐ŸŒ | Ember.typeOf | import { typeOf } from '@ember/utils'; | |๐ŸŒ | Ember._getComponentTemplate | import { getComponentTemplate } from '@ember/component'; | |๐ŸŒ | Ember._setComponentTemplate | import { setComponentTemplate } from '@ember/component'; | |๐ŸŒ | Ember._helperManagerCapabilities | import { capabilities } from '@ember/helper'; | |๐ŸŒ | Ember._setHelperManager | import { setHelperManager } from '@ember/helper'; | |๐ŸŒ | Ember._setModifierManager | import { setModifierManager } from '@ember/modifier'; | |๐ŸŒ | Ember._templateOnlyComponent | import templateOnly from '@ember/component/template-only'; | |๐ŸŒ | Ember._invokeHelper | import { invokeHelper } from '@ember/helper'; | |๐ŸŒ | Ember._hash | import { hash } from '@ember/helper'; | |๐ŸŒ | Ember._array | import { array } from '@ember/helper'; | |๐ŸŒ | Ember._concat | import { concat } from '@ember/helper'; | |๐ŸŒ | Ember._get | import { get } from '@ember/helper'; | |๐ŸŒ | Ember._on | import { on } from '@ember/modifier'; | |๐ŸŒ | Ember._fn | import { fn } from '@ember/helper'; | |๐ŸŒ | Ember.ENV | import MyEnv from '<my-app>/config/environment'; (for apps) or owner.resolveRegistration('config:environment') for addons|

Implementation Plan

These can happen in any order

  • Add deprecations to each Ember.* access

  • Add the Testing utilities to @ember/test, if needed.

  • Add an @ember/version package to ember-source

  • Add re-exports of private APIs, ComputedProperty, and _setClassicDecorator These will still be deprecated on Ember., and will be deprecated themselves as we progress through deprecating Ember Classic.

  • Update ember-inspector to use imports for the internals and instrumentation APIs

  • Add @ember/inspector-support to ember-source to manage things like LIBRARIES.

    import { libraries } from '@ember/inspector-support';
    
    libraries.add('ember-data', '5.3.1');
    // and/or
    libraries.addAll(depInfoFromPlugin);
    
  • Add deprecation guide entries for each API

How We Teach This

While @ember/-internals were created to be internal, introducing new names for them would create churn and would make it harder for addon authors to support a wide range of versions. The internals paths all work today on supported releases, so dropping the deprecated usage doesn't reduce your support matrix, whereas using a newly-introduced import path would.

All @ember/-internals(/*)? APIs mentioned above are now public API, and to remove any of those APIs, they will need to go through the deprecation process.


The guides already use the modern imports where available.

There is a place that needs updating, around advanced debugging, where folks configure Backburner to be in debug mode.

  • https://guides.emberjs.com/release/applications/run-loop/#toc_where-can-i-find-more-information
  • https://guides.emberjs.com/release/configuring-ember/debugging/#toc_errors-within-emberrunlater-backburner
  • Access to backburner here isn't relevant though because it's accessed from the run import from @ember/runloop

When using embroider and staticEmberSource: true, the benefits of not having this file can be realized in apps (as long as the app and all consumed addons do not import from 'ember')

Available Codemods

  • https://github.com/ember-codemods/ember-modules-codemod (from the work of RFC 176)

Deprecation Guide

  • Separate ids for each API so that folks don't have to scroll too far to get to their migration path (if a migration path exists).
  • Mostly using the above tables, but without the Usage: EmberObserver column.

Drawbacks

n/a, to be more module-friendly, we must get rid of the 'ember' import.

Alternatives

Don't use @ember/-internals and create new public APIs for all of the things currently under @ember/-internals. This would create a lot of churn in the ecosystem, when we want to get rid of some of these APIs anyway.

Unresolved questions

n/a

Q: Do our instrumentation and internals sub-packages have any SemVer guarantees? Or are we allowed to "do what we need to" and not care about public-facing SemVer? A: If something is privately but heavily used, we will try to deprecate before removing the API and make sure the deprecation makes it in to an LTS before that removal.