Since we always have a DOM and modifiers always run, the entire
isInteractive/hasDOM split is dead weight. Tear it out.
Glimmer-vm:
- @glimmer/runtime/lib/environment.ts: drop the isInteractive field on
EnvironmentImpl and EnvironmentDelegate. scheduleInstallModifier and
scheduleUpdateModifier always schedule.
- @glimmer/runtime/lib/compiled/opcodes/dom.ts: drop the early-returns
in VM_MODIFIER_OP and VM_DYNAMIC_MODIFIER_OP. Modifiers always run.
- @glimmer/interfaces: drop isInteractive from the Environment interface.
Ember component layer:
- curly + root component managers: lifecycle hooks (willRender,
willInsertElement, didInsertElement, willUpdate, didUpdate, didRender,
willDestroyElement, willClearRender) always fire.
- ComponentStateBucket no longer carries isInteractive.
- BootEnvironment loses both fields.
Renderer:
- BaseRenderer / Renderer / renderComponent no longer take isInteractive
or hasDOM env config.
- Renderer.getElement always returns the element (no more "not allowed in
non-interactive environments" throw).
- Renderer.remove always triggers didDestroyElement.
- Drop the _isInteractive getter and the debug.isInteractive field.
- EmberEnvironmentDelegate has no constructor args.
Application/engine boot:
- BootOptions drops isInteractive and isBrowser.
- _BootOptions no longer threads isInteractive through isBrowser /
shouldRender / option override; just _renderMode, location,
shouldRender, document, rootElement.
- ApplicationInstance always calls setupEventDispatcher.
- EngineInstance's singleton list always includes event_dispatcher:main.
- EventDispatcher.setup drops the "should never be setup in fastboot"
assertion.
- @ember/-internals/views/lib/system/event_dispatcher.ts no longer
imports from @ember/-internals/glimmer.
Component:
- The DEBUG tagless event-handler check no longer needs renderer._isInteractive.
- _dispatcher always looks up event_dispatcher:main.
- appendTo always uses document.querySelector for string selectors;
the "no DOM" branch is gone. matches() drops its fastboot guard.
@ember/-internals/browser-environment package: deleted entirely.
- isChrome/isFirefox were the only remaining consumers (in @ember/debug);
inlined there with `typeof window !== 'undefined'` guards.
- self/location/history/window references were the only hasDOM users.
- Removed from @ember/-internals package exports, root package.json
embedded-package map, types/stable manifest, and lib/index.js
implicit-modules list.
- Test files that imported `window`/`isChrome`/`isFirefox` from
browser-environment now use globals directly.
<Input> lazily initializes its INPUT_ELEMENT probe (instead of at module
-load time) so node-side build tooling that imports the package without
a DOM in scope still loads. The DOM is required at render time, which
is the contract.
Tests:
- Drop the non-interactive variants of the lifecycle, custom-modifier,
and on-modifier integration tests. Drop the lifecycle test's
isInteractive/nonInteractive split — assertHooks always uses the
interactive expectations.
- Drop the visit_test that checked event_dispatcher:main wasn't created
for isInteractive: false.
- OutletView render-queue test now appends to a real DOM element rather
than a CSS-selector string.
- type-tests for BootOptions no longer mention isBrowser.
Smoke tests:
- Delete app-boot, component-rendering, fastboot-sandbox, and visit
tests in node-template, plus their setup-app/setup-component/
build-owner/assert-html-matches helpers. They were FastBoot-only —
every one of them used SimpleDOM as a stand-in for document.
tests/docs/expected.js: drop the isBrowser, isInteractive, and matches
entries (the public surfaces that have been removed).
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
RFC: emberjs/rfcs#1178
Drop isInteractive and hasDOM; remove FastBoot codepaths.
the limitations fastboot placed on us for SSR are no longer needed, I think we can drop this stuff in a non-major release (especially so since fastboot is not compatible with vite, and... i don't know if fastboot works with latest ember even in classic, tbh -- it also is built on private apis so while we normally don't care about private api breakage, the SSR use case is important enough that it'd be in bad taste to drop to 0 SSR solutions... which brings us to the next point)
vite-ember-ssr proves that we can not only render in interactive mode, but we can await settled() if we want until rendering is finished, which gives us a lot of flexibility, and frees us from having to maintain all this cruft.
@evoactivity made vite-ember-ssr (and it's awesome)
I have a demo of it here, running modifiers: https://limber.glimdown.com/docs/embedding