diff --git a/.gitignore b/.gitignore index 9bf32df156f..86bbbbb3da9 100644 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,7 @@ test/version_tmp test_*.html /tests/ember-tests.js /smoke-tests/scenarios/output/ +/smoke-tests/scenarios/output-*/ tmp tmp*.gem tmp.bpm diff --git a/package.json b/package.json index 52ed8c88fb0..aca8bb519c9 100644 --- a/package.json +++ b/package.json @@ -205,6 +205,16 @@ "@ember/-internals/metal/index.js": "ember-source/@ember/-internals/metal/index.js", "@ember/-internals/owner/index.js": "ember-source/@ember/-internals/owner/index.js", "@ember/-internals/routing/index.js": "ember-source/@ember/-internals/routing/index.js", + "@ember/-internals/routing/route-managers/api.js": "ember-source/@ember/-internals/routing/route-managers/api.js", + "@ember/-internals/routing/route-managers/classic/bucket.js": "ember-source/@ember/-internals/routing/route-managers/classic/bucket.js", + "@ember/-internals/routing/route-managers/classic/manager.js": "ember-source/@ember/-internals/routing/route-managers/classic/manager.js", + "@ember/-internals/routing/route-managers/classic/outlet-component.js": "ember-source/@ember/-internals/routing/route-managers/classic/outlet-component.js", + "@ember/-internals/routing/route-managers/classic/query-params.js": "ember-source/@ember/-internals/routing/route-managers/classic/query-params.js", + "@ember/-internals/routing/route-managers/classic/substates.js": "ember-source/@ember/-internals/routing/route-managers/classic/substates.js", + "@ember/-internals/routing/route-managers/management.js": "ember-source/@ember/-internals/routing/route-managers/management.js", + "@ember/-internals/routing/route-managers/outlet-state.js": "ember-source/@ember/-internals/routing/route-managers/outlet-state.js", + "@ember/-internals/routing/route-managers/registry.js": "ember-source/@ember/-internals/routing/route-managers/registry.js", + "@ember/-internals/routing/route-managers/root-outlet.js": "ember-source/@ember/-internals/routing/route-managers/root-outlet.js", "@ember/-internals/runtime/index.js": "ember-source/@ember/-internals/runtime/index.js", "@ember/-internals/runtime/lib/ext/rsvp.js": "ember-source/@ember/-internals/runtime/lib/ext/rsvp.js", "@ember/-internals/runtime/lib/mixins/-proxy.js": "ember-source/@ember/-internals/runtime/lib/mixins/-proxy.js", diff --git a/packages/@ember/-internals/glimmer/index.ts b/packages/@ember/-internals/glimmer/index.ts index 4559c0ce317..a11e878d169 100644 --- a/packages/@ember/-internals/glimmer/index.ts +++ b/packages/@ember/-internals/glimmer/index.ts @@ -17,7 +17,7 @@ The documentation for `@ember/component` still refers to the older authoring format. To read about the new authoring format, see the [Glimmer Component API documentation](/ember/release/modules/@glimmer%2Fcomponent). - + ### Showing a property Templates manage the flow of an application's UI, and display state (through @@ -118,6 +118,7 @@ export { default as Input } from './lib/components/input'; export { default as LinkTo } from './lib/components/link-to'; export { default as Textarea } from './lib/components/textarea'; export { default as Component } from './lib/component'; +export { makeRouteTemplate } from './lib/component-managers/route-template'; export { default as Helper, helper, @@ -139,6 +140,7 @@ export { _resetRenderers, renderSettled, renderComponent, + setRenderer, type View, } from './lib/renderer'; export { @@ -156,8 +158,7 @@ export { DOMChanges, NodeDOMTreeConstruction, DOMTreeConstruction } from './lib/ // TODO just test these through public API // a lot of these are testing how a problem was solved // rather than the problem was solved -export { default as OutletView, type BootEnvironment } from './lib/views/outlet'; -export type { OutletState, RenderState } from './lib/utils/outlet'; +export type { BootEnvironment } from '@ember/engine/instance'; export { componentCapabilities, modifierCapabilities, diff --git a/packages/@ember/-internals/glimmer/lib/base-renderer.ts b/packages/@ember/-internals/glimmer/lib/base-renderer.ts index 955511c4389..d604056fb05 100644 --- a/packages/@ember/-internals/glimmer/lib/base-renderer.ts +++ b/packages/@ember/-internals/glimmer/lib/base-renderer.ts @@ -426,6 +426,15 @@ interface RenderCacheEntry { glimmerResult: GlimmerRenderResult | undefined; } +// Cursor descriptor isn't a stable enough reference. +// Cursor fails during application teardown +type RendererCacheKey = Element | SimpleElement; + +const isDOMElement = (into: IntoTarget): into is Element => 'innerHTML' in into; + +const cacheKey = (into: IntoTarget): RendererCacheKey => + 'element' in into ? (into as Cursor).element : (into as RendererCacheKey); + function intoTarget(into: IntoTarget): Cursor { if ('element' in into) { return into; @@ -527,14 +536,15 @@ export function renderComponent( * * NOTE: destruction is async */ - let existing = RENDER_CACHE.get(into); + let key = cacheKey(into); + let existing = RENDER_CACHE.get(key); existing?.result.destroy(); /** * We can only replace the inner HTML the first time. * Because destruction is async, it won't be safe to * do this again, and we'll have to rely on the above destroy. */ - if (!existing && into instanceof Element) { + if (!existing && isDOMElement(into)) { into.innerHTML = ''; } @@ -552,16 +562,19 @@ export function renderComponent( */ let renderTarget: IntoTarget = into; if (existing?.glimmerResult) { - let parentElement = - into instanceof Element ? (into as unknown as SimpleElement) : (into as Cursor).element; let firstNode = existing.glimmerResult.firstNode(); - renderTarget = { element: parentElement, nextSibling: firstNode }; + renderTarget = { element: key as SimpleElement, nextSibling: firstNode }; } let innerResult = renderer.render(component, { into: renderTarget, args }).result; if (innerResult) { associateDestroyableChild(owner, innerResult); + registerDestructor(innerResult, () => { + if (RENDER_CACHE.get(key)?.glimmerResult === innerResult) { + RENDER_CACHE.delete(key); + } + }); } let result: RenderResult = { @@ -572,14 +585,22 @@ export function renderComponent( }, }; - RENDER_CACHE.set(into, { result, glimmerResult: innerResult }); + RENDER_CACHE.set(key, { result, glimmerResult: innerResult }); return result; } -const RENDER_CACHE = new WeakMap(); +const RENDER_CACHE = new WeakMap(); const RENDERER_CACHE = new WeakMap(); +/** + * The application seeds its `renderer:-dom` service which allows for + * router-aware resolver to resolve {{mount}} + */ +export function setRenderer(owner: object, renderer: BaseRenderer): void { + RENDERER_CACHE.set(owner, renderer); +} + export class BaseRenderer { static strict( owner: object, diff --git a/packages/@ember/-internals/glimmer/lib/component-managers/outlet.ts b/packages/@ember/-internals/glimmer/lib/component-managers/outlet.ts deleted file mode 100644 index aba8e2e979d..00000000000 --- a/packages/@ember/-internals/glimmer/lib/component-managers/outlet.ts +++ /dev/null @@ -1,201 +0,0 @@ -import type { InternalOwner } from '@ember/-internals/owner'; -import type { Nullable } from '@ember/-internals/utility-types'; -import { assert } from '@ember/debug'; -import type EngineInstance from '@ember/engine/instance'; -import { _instrumentStart } from '@ember/instrumentation'; -import { precompileTemplate } from '@ember/template-compilation'; -import type { - CompilableProgram, - ComponentDefinition, - CustomRenderNode, - Destroyable, - Environment, - InternalComponentCapabilities, - VMArguments, - WithCreateInstance, - WithCustomDebugRenderTree, -} from '@glimmer/interfaces'; -import { capabilityFlagsFrom } from '@glimmer/manager/lib/util/capabilities'; -import type { Reference } from '@glimmer/reference/lib/reference'; -import { UNDEFINED_REFERENCE, valueForRef } from '@glimmer/reference/lib/reference'; -import { EMPTY_ARGS } from '@glimmer/runtime/lib/vm/arguments'; -import { unwrapTemplate } from './unwrap-template'; - -import type { DynamicScope } from '../renderer'; -import type { OutletState } from '../utils/outlet'; -import type OutletView from '../views/outlet'; - -function instrumentationPayload(def: OutletDefinitionState) { - // "main" used to be the outlet name, keeping it around for compatibility - return { object: `${def.name}:main` }; -} - -interface OutletInstanceState { - engine?: { - instance: EngineInstance; - mountPoint: string; - }; - finalize: () => void; -} - -export interface OutletDefinitionState { - ref: Reference; - name: string; - template: object; - controller: unknown; -} - -const CAPABILITIES: InternalComponentCapabilities = { - dynamicLayout: false, - dynamicTag: false, - prepareArgs: false, - createArgs: false, - attributeHook: false, - elementHook: false, - createCaller: false, - dynamicScope: true, - updateHook: false, - createInstance: true, - wrapped: false, - willDestroy: false, - hasSubOwner: false, -}; - -const CAPABILITIES_MASK = /*@__PURE__*/ capabilityFlagsFrom(CAPABILITIES); - -class OutletComponentManager - implements - WithCreateInstance, - WithCustomDebugRenderTree -{ - create( - _owner: InternalOwner, - definition: OutletDefinitionState, - _args: VMArguments, - env: Environment, - dynamicScope: DynamicScope - ): OutletInstanceState { - let parentStateRef = dynamicScope.get('outletState'); - let currentStateRef = definition.ref; - - // This is the actual primary responsibility of the outlet component – - // it represents the switching from one route component/template into - // the next. The rest only exists to support the debug render tree and - // the old-school (and unreliable) instrumentation. - dynamicScope.set('outletState', currentStateRef); - - let state: OutletInstanceState = { - finalize: _instrumentStart('render.outlet', instrumentationPayload, definition), - }; - - if (env.debugRenderTree !== undefined) { - let parentState = valueForRef(parentStateRef); - let parentOwner = parentState?.render?.owner; - let currentState = valueForRef(currentStateRef); - let currentOwner = currentState?.render?.owner; - - if (parentOwner && parentOwner !== currentOwner) { - assert( - 'Expected currentOwner to be an EngineInstance', - currentOwner != null && 'buildChildEngineInstance' in currentOwner - ); - - let engineInstance = currentOwner as EngineInstance; - let { mountPoint } = engineInstance; - - if (mountPoint) { - state.engine = { - mountPoint, - instance: engineInstance, - }; - } - } - } - - return state; - } - - getDebugName({ name }: OutletDefinitionState): string { - return `{{outlet}} for ${name}`; - } - - getDebugCustomRenderTree( - _definition: OutletDefinitionState, - state: OutletInstanceState - ): CustomRenderNode[] { - let nodes: CustomRenderNode[] = []; - - nodes.push({ - bucket: state, - type: 'outlet', - // "main" used to be the outlet name, keeping it around for compatibility - name: 'main', - args: EMPTY_ARGS, - instance: undefined, - }); - - if (state.engine) { - nodes.push({ - bucket: state.engine, - type: 'engine', - name: state.engine.mountPoint, - args: EMPTY_ARGS, - instance: state.engine.instance, - }); - } - - return nodes; - } - - getCapabilities(): InternalComponentCapabilities { - return CAPABILITIES; - } - - getSelf() { - return UNDEFINED_REFERENCE; - } - - didCreate() {} - didUpdate() {} - - didRenderLayout(state: OutletInstanceState): void { - state.finalize(); - } - - didUpdateLayout() {} - - getDestroyable(): Nullable { - return null; - } -} - -const OUTLET_MANAGER = /*@__PURE__*/ new OutletComponentManager(); - -const OUTLET_COMPONENT_TEMPLATE = precompileTemplate( - '<@Component @controller={{@controller}} @model={{@model}} />', - { strictMode: true } -); - -export class OutletComponent implements ComponentDefinition< - OutletDefinitionState, - OutletInstanceState, - OutletComponentManager -> { - // handle is not used by this custom definition - public handle = -1; - public resolvedName = null; - public manager = OUTLET_MANAGER; - public capabilities = CAPABILITIES_MASK; - public compilable: CompilableProgram; - - constructor( - owner: InternalOwner, - public state: OutletDefinitionState - ) { - this.compilable = unwrapTemplate(OUTLET_COMPONENT_TEMPLATE(owner)).asLayout(); - } -} - -export function createRootOutlet(outletView: OutletView): OutletComponent { - return new OutletComponent(outletView.owner, outletView.state); -} diff --git a/packages/@ember/-internals/glimmer/lib/component-managers/route-template.ts b/packages/@ember/-internals/glimmer/lib/component-managers/route-template.ts index c1cba0428ef..881fa87c64d 100644 --- a/packages/@ember/-internals/glimmer/lib/component-managers/route-template.ts +++ b/packages/@ember/-internals/glimmer/lib/component-managers/route-template.ts @@ -1,10 +1,6 @@ import type { InternalOwner } from '@ember/-internals/owner'; -import { _instrumentStart } from '@ember/instrumentation'; import type { CapturedArguments, - CompilableProgram, - ComponentDefinition, - CurriedComponent, CustomRenderNode, Destroyable, InternalComponentCapabilities, @@ -14,20 +10,13 @@ import type { WithCustomDebugRenderTree, } from '@glimmer/interfaces'; import type { Nullable } from '@ember/-internals/utility-types'; -import { DEBUG } from '@glimmer/env'; -import { capabilityFlagsFrom } from '@glimmer/manager/lib/util/capabilities'; +import { setInternalComponentManager } from '@glimmer/manager/lib/internal/api'; +import { setComponentTemplate } from '@glimmer/manager/lib/public/template'; import type { Reference } from '@glimmer/reference/lib/reference'; -import { createDebugAliasRef, valueForRef } from '@glimmer/reference/lib/reference'; -import { curry, type CurriedValue } from '@glimmer/runtime/lib/curried-value'; -import { unwrapTemplate } from './unwrap-template'; +import { UNDEFINED_REFERENCE, valueForRef } from '@glimmer/reference/lib/reference'; interface RouteTemplateInstanceState { self: Reference; - controller: unknown; -} - -export interface RouteTemplateDefinitionState { - name: string; } const CAPABILITIES: InternalComponentCapabilities = { @@ -46,39 +35,31 @@ const CAPABILITIES: InternalComponentCapabilities = { hasSubOwner: false, }; -const CAPABILITIES_MASK = /*@__PURE__*/ capabilityFlagsFrom(CAPABILITIES); - class RouteTemplateManager implements - WithCreateInstance, - WithCustomDebugRenderTree + WithCreateInstance, + WithCustomDebugRenderTree { create( _owner: InternalOwner, - _definition: RouteTemplateDefinitionState, - args: VMArguments + definition: RouteTemplate, + _args: VMArguments ): RouteTemplateInstanceState { - let self = args.named.get('controller'); - - if (DEBUG) { - self = createDebugAliasRef!('this', self); - } - - let controller = valueForRef(self); - - return { self, controller }; + return { + self: definition.self, + }; } getSelf({ self }: RouteTemplateInstanceState): Reference { return self; } - getDebugName({ name }: RouteTemplateDefinitionState) { + getDebugName({ name }: RouteTemplate) { return `route-template (${name})`; } getDebugCustomRenderTree( - { name }: RouteTemplateDefinitionState, + { name }: RouteTemplate, state: RouteTemplateInstanceState, args: CapturedArguments ): CustomRenderNode[] { @@ -88,7 +69,7 @@ class RouteTemplateManager type: 'route-template', name, args, - instance: state.controller, + instance: valueForRef(state.self), }, ]; } @@ -111,47 +92,31 @@ class RouteTemplateManager const ROUTE_TEMPLATE_MANAGER = /*@__PURE__*/ new RouteTemplateManager(); /** - * This "upgrades" a route template into a invocable component. Conceptually - * it can be 1:1 for each unique `Template`, but it's also cheap to construct, - * so unless the stability is desirable for other reasons, it's probably not - * worth caching this. + * This "upgrades" a route template into an invokable component. A + * `RouteTemplate` *is* its own definition state; the VM turns it into a + * `ComponentDefinition` via the manager on the prototype below. + * + * Conceptually it can be 1:1 for each unique `Template`, but it's also cheap + * to construct, so unless the stability is desirable for other reasons, it's + * probably not worth caching this. */ -export class RouteTemplate implements ComponentDefinition< - RouteTemplateDefinitionState, - RouteTemplateInstanceState, - RouteTemplateManager -> { - // handle is not used by this custom definition - public handle = -1; - public resolvedName: string; - public state: RouteTemplateDefinitionState; - public manager = ROUTE_TEMPLATE_MANAGER; - public capabilities = CAPABILITIES_MASK; - public compilable: CompilableProgram; - - constructor(name: string, template: Template) { - let unwrapped = unwrapTemplate(template); - // TODO This actually seems inaccurate – it ultimately came from the - // outlet's name. Also, setting this overrides `getDebugName()` in that - // message. Is that desirable? - this.resolvedName = name; - this.state = { name }; - this.compilable = unwrapped.asLayout(); - } +export class RouteTemplate { + constructor( + readonly name: string, + readonly self: Reference + ) {} } -// TODO a lot these fields are copied from the adjacent existing components -// implementation, haven't looked into who cares about `ComponentDefinition` -// and if it is appropriate here. It seems like this version is intended to -// be used with `curry` which probably isn't necessary here. It could be the -// case that we just want to do something more similar to `InternalComponent` -// (the one we used to implement `Input` and `LinkTo`). For now it follows -// the same pattern to get things going. +setInternalComponentManager(ROUTE_TEMPLATE_MANAGER, RouteTemplate.prototype); + export function makeRouteTemplate( - owner: InternalOwner, name: string, - template: Template -): CurriedValue { - let routeTemplate = new RouteTemplate(name, template); - return curry(0 as CurriedComponent, routeTemplate, owner, null, true); + template: Template, + self: Reference = UNDEFINED_REFERENCE +): RouteTemplate { + let routeTemplate = new RouteTemplate(name, self); + + setComponentTemplate(() => template, routeTemplate); + + return routeTemplate; } diff --git a/packages/@ember/-internals/glimmer/lib/renderer.ts b/packages/@ember/-internals/glimmer/lib/renderer.ts index c404404ecd9..88166168d10 100644 --- a/packages/@ember/-internals/glimmer/lib/renderer.ts +++ b/packages/@ember/-internals/glimmer/lib/renderer.ts @@ -1,7 +1,6 @@ import { privatize as P } from '@ember/-internals/container/lib/registry'; import type { InternalOwner } from '@ember/-internals/owner'; import { getOwner } from '@ember/-internals/owner'; -import { guidFor } from '@ember/-internals/utils/lib/guid'; import { getViewElement, getViewId } from '@ember/-internals/views/lib/system/utils'; import { sendCoreViewEvent } from '@ember/-internals/views/lib/views/core-view-utils'; import { assert } from '@ember/debug'; @@ -27,22 +26,17 @@ import type { Reference } from '@glimmer/reference/lib/reference'; import { createConstRef, UNDEFINED_REFERENCE, valueForRef } from '@glimmer/reference/lib/reference'; import type { CurriedValue } from '@glimmer/runtime/lib/curried-value'; import { clientBuilder } from '@glimmer/runtime/lib/vm/element-builder'; -import { createCapturedArgs, EMPTY_POSITIONAL } from '@glimmer/runtime/lib/vm/arguments'; import { curry } from '@glimmer/runtime/lib/curried-value'; import { inTransaction } from '@glimmer/runtime/lib/environment'; import { renderMain } from '@glimmer/runtime/lib/render'; -import { dict } from '@glimmer/util/lib/collections'; import { unwrapTemplate } from './component-managers/unwrap-template'; import type { SimpleDocument, SimpleElement, SimpleNode } from '@simple-dom/interface'; import type Component from './component'; import type ClassicComponent from './component'; import { BOUNDS } from './component-managers/curly'; -import { createRootOutlet } from './component-managers/outlet'; import { RootComponentDefinition } from './component-managers/root'; import RouterResolver from './router-resolver'; -import type { OutletState } from './utils/outlet'; -import OutletView from './views/outlet'; -import { makeRouteTemplate } from './component-managers/route-template'; +import type { OutletState } from '../../routing/route-managers/outlet-state'; import type { IBuilder, RendererRoot } from './base-renderer'; import { BaseRenderer, errorLoopTransaction } from './base-renderer'; @@ -55,6 +49,7 @@ export { errorLoopTransaction, renderComponent, renderSettled, + setRenderer, _resetRenderers, } from './base-renderer'; @@ -105,7 +100,7 @@ class ClassicRootState implements RendererRoot { readonly env: Environment; constructor( - public root: Component | OutletView, + public root: Component, context: EvaluationContext, owner: object, template: Template, @@ -119,7 +114,7 @@ class ClassicRootState implements RendererRoot { template !== undefined ); - this.id = root instanceof OutletView ? guidFor(root) : getViewId(root); + this.id = getViewId(root); this.result = undefined; this.destroyed = false; this.env = context.env; @@ -218,42 +213,6 @@ export class Renderer extends BaseRenderer { // renderer HOOKS - appendOutletView(view: OutletView, target: SimpleElement): void { - // TODO: This bypasses the {{outlet}} syntax so logically duplicates - // some of the set up code. Since this is all internal (or is it?), - // we can refactor this to do something more direct/less convoluted - // and with less setup, but get it working first - let outlet = createRootOutlet(view); - let { name, /* controller, */ template } = view.state; - - let named = dict(); - - named['Component'] = createConstRef( - makeRouteTemplate(view.owner, name, template as Template), - '@Component' - ); - - // TODO: is this guaranteed to be undefined? It seems to be the - // case in the `OutletView` class. Investigate how much that class - // exists as an internal implementation detail only, or if it was - // used outside of core. As far as I can tell, test-helpers uses - // it but only for `setOutletState`. - // named['controller'] = createConstRef(controller, '@controller'); - // Update: at least according to the debug render tree tests, we - // appear to always expect this to be undefined. Not a definitive - // source by any means, but is useful evidence - named['controller'] = UNDEFINED_REFERENCE; - named['model'] = UNDEFINED_REFERENCE; - - let args = createCapturedArgs(named, EMPTY_POSITIONAL); - - this._appendDefinition( - view, - curry(0 as CurriedComponent, outlet, view.owner, args, true), - target - ); - } - appendTo(view: ClassicComponent, target: SimpleElement): void { let definition = new RootComponentDefinition(view); this._appendDefinition( @@ -263,11 +222,7 @@ export class Renderer extends BaseRenderer { ); } - _appendDefinition( - root: OutletView | ClassicComponent, - definition: CurriedValue, - target: SimpleElement - ): void { + _appendDefinition(root: ClassicComponent, definition: CurriedValue, target: SimpleElement): void { let self = createConstRef(definition, 'this'); let dynamicScope = new DynamicScope(null, UNDEFINED_REFERENCE); let rootState = new ClassicRootState( diff --git a/packages/@ember/-internals/glimmer/lib/resolver.ts b/packages/@ember/-internals/glimmer/lib/resolver.ts index 4f12df139dd..2583ba88ba7 100644 --- a/packages/@ember/-internals/glimmer/lib/resolver.ts +++ b/packages/@ember/-internals/glimmer/lib/resolver.ts @@ -189,7 +189,7 @@ export default class ResolverImpl implements ClassicResolver { assert( `The \`{{${name.slice(1)}}}\` keyword requires the router, which is not available here. ` + `It is only supported in templates rendered by an Ember application (e.g. not via \`renderComponent\`).`, - name !== '-outlet' && name !== '-mount' + name !== '-mount' ); return BUILTIN_KEYWORD_HELPERS[name] ?? null; diff --git a/packages/@ember/-internals/glimmer/lib/router-resolver.ts b/packages/@ember/-internals/glimmer/lib/router-resolver.ts index acc2c8230ef..e555bee3da6 100644 --- a/packages/@ember/-internals/glimmer/lib/router-resolver.ts +++ b/packages/@ember/-internals/glimmer/lib/router-resolver.ts @@ -3,11 +3,8 @@ import type { InternalOwner } from '@ember/-internals/owner'; import type { Nullable } from '@ember/-internals/utility-types'; import ResolverImpl from './resolver'; import { mountHelper } from './syntax/mount'; -import { outletHelper } from './syntax/outlet'; - const ROUTER_KEYWORD_HELPERS: Record = { '-mount': mountHelper, - '-outlet': outletHelper, }; /** diff --git a/packages/@ember/-internals/glimmer/lib/setup-registry.ts b/packages/@ember/-internals/glimmer/lib/setup-registry.ts index 75fb2760855..19e6ac676ef 100644 --- a/packages/@ember/-internals/glimmer/lib/setup-registry.ts +++ b/packages/@ember/-internals/glimmer/lib/setup-registry.ts @@ -7,9 +7,7 @@ import LinkTo from './components/link-to'; import Textarea from './components/textarea'; import { clientBuilder, rehydrationBuilder, serializeBuilder } from './dom'; import { Renderer } from './renderer'; -import OutletTemplate from './templates/outlet'; import RootTemplate from './templates/root'; -import OutletView from './views/outlet'; export function setupApplicationRegistry(registry: Registry): void { // because we are using injections we can't use instantiate false @@ -42,9 +40,6 @@ export function setupApplicationRegistry(registry: Registry): void { export function setupEngineRegistry(registry: Registry): void { registry.optionsForType('template', { instantiate: false }); - registry.register('view:-outlet', OutletView); - registry.register('template:-outlet', OutletTemplate as any); - registry.optionsForType('helper', { instantiate: false }); registry.register('component:input', Input); diff --git a/packages/@ember/-internals/glimmer/lib/syntax/outlet.ts b/packages/@ember/-internals/glimmer/lib/syntax/outlet.ts deleted file mode 100644 index e0a09cabe41..00000000000 --- a/packages/@ember/-internals/glimmer/lib/syntax/outlet.ts +++ /dev/null @@ -1,248 +0,0 @@ -import type { InternalOwner } from '@ember/-internals/owner'; -import { assert } from '@ember/debug'; -import { DEBUG } from '@glimmer/env'; -import type { - CapturedArguments, - CurriedComponent, - DynamicScope, - Template, -} from '@glimmer/interfaces'; -import type { Reference } from '@glimmer/reference/lib/reference'; -import { - childRefFromParts, - createComputeRef, - createConstRef, - createDebugAliasRef, - valueForRef, -} from '@glimmer/reference/lib/reference'; -import type { CurriedValue } from '@glimmer/runtime/lib/curried-value'; -import { createCapturedArgs, EMPTY_POSITIONAL } from '@glimmer/runtime/lib/vm/arguments'; -import { curry } from '@glimmer/runtime/lib/curried-value'; -import { dict } from '@glimmer/util/lib/collections'; -import { hasInternalComponentManager } from '@glimmer/manager/lib/internal/api'; -import { OutletComponent, type OutletDefinitionState } from '../component-managers/outlet'; -import { makeRouteTemplate } from '../component-managers/route-template'; -import { internalHelper } from '../helpers/internal-helper'; -import type { OutletState } from '../utils/outlet'; - -/** - @module @ember/helper - */ - -/** - The `{{outlet}}` helper lets you specify where a child route will render in - your template. An important use of the `{{outlet}}` helper is in your - application's `application.gjs` file: - - ```gjs {data-filename="app/templates/application.gjs"} - import MyHeader from '../components/my-header'; - import MyFooter from '../components/my-footer'; - - - ``` - - See the [routing guide](https://guides.emberjs.com/release/routing/rendering-a-template/) for more - information on how your `route` interacts with the `{{outlet}}` helper. - Note: Your content __will not render__ if there isn't an `{{outlet}}` for it. - - `outlet` is built-in and does not need to be imported. - - @method outlet - @for Keywords - @static - @noimport - @public -*/ -export const outletHelper = /*@__PURE__*/ internalHelper( - (_args: CapturedArguments, owner?: InternalOwner, scope?: DynamicScope) => { - assert('Expected owner to be present, {{outlet}} requires an owner', owner); - assert( - 'Expected dynamic scope to be present. You may have attempted to use the {{outlet}} keyword dynamically. This keyword cannot be used dynamically.', - scope - ); - - let outletRef = createComputeRef(() => { - let state = valueForRef(scope.get('outletState') as Reference); - return state?.outlets?.main; - }); - - let lastState: OutletDefinitionState | null = null; - let outlet: CurriedValue | null = null; - - return createComputeRef(() => { - let outletState = valueForRef(outletRef); - let state = stateFor(outletRef, outletState); - - // This code is deliberately using the behavior in glimmer-vm where in - // <@Component />, the component is considered stabled via `===`, and - // will continue to re-render in-place as long as the `===` holds, but - // when it changes to a different object, it teardown the old component - // (running destructors, etc), and render the component in its place (or - // nothing if the new value is nullish. Here we are carefully exploiting - // that fact, and returns the same stable object so long as it is the - // same route, but return a different one when the route changes. On the - // other hand, changing the model only intentionally do not teardown the - // component and instead re-render in-place. - if (!isStable(state, lastState)) { - lastState = state; - - if (state !== null) { - // If we are crossing an engine mount point, this is how the owner - // gets switched. - let outletOwner = outletState?.render?.owner ?? owner; - - let named = dict(); - - // Here we either have a raw template that needs to be normalized, - // or a component that we can render as-is. `RouteTemplate` upgrades - // the template into a component so we can have a unified code path. - // We still store the original `template` value, because we rely on - // its identity for the stability check, and the `RouteTemplate` - // wrapper doesn't dedup for us. - let template = state.template; - let component: object; - - if (hasInternalComponentManager(template)) { - component = template; - } else { - if (DEBUG) { - // We don't appear to have a standard way or a brand to check, but for the - // purpose of avoiding obvious user errors, this probably gets you close - // enough. - let isTemplate = (template: unknown): template is Template => { - if (template === null || typeof template !== 'object') { - return false; - } else { - let t = template as Partial