Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 5 additions & 12 deletions packages/@ember/-internals/glimmer/lib/base-renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,12 @@ import type {

import { artifacts } from '@glimmer/program/lib/helpers';
import { RuntimeOpImpl } from '@glimmer/program/lib/opcode';
import { liveParent } from '@glimmer/runtime/lib/bounds';
import { clientBuilder } from '@glimmer/runtime/lib/vm/element-builder';
import { inTransaction, runtimeOptions } from '@glimmer/runtime/lib/environment';
import { renderComponent as glimmerRenderComponent } from '@glimmer/runtime/lib/render';
import { CURRENT_TAG, validateTag, valueForTag } from '@glimmer/validator/lib/validators';
import type { SimpleDocument, SimpleElement } from '@simple-dom/interface';
import type { SimpleDocument, SimpleDocumentFragment, SimpleElement } from '@simple-dom/interface';
import { hasDOM } from '../../browser-environment';
import { EmberEnvironmentDelegate } from './environment';
import ResolverImpl from './resolver';
Expand Down Expand Up @@ -402,7 +403,7 @@ export class RendererState {
}
}

type IntoTarget = Cursor | Element | SimpleElement;
type IntoTarget = Cursor | Element | SimpleElement | DocumentFragment | SimpleDocumentFragment;

/**
* The returned object from `renderComponent`
Expand Down Expand Up @@ -462,18 +463,12 @@ export function renderComponent(
env,
into,
args,
appendIntoTarget = false,
}: {
/**
* The element to render the component in to.
*/
into: IntoTarget;

/**
* Appends `into` without clearing the target first. Mimics the `appendTo` behavior for classic components.
*/
appendIntoTarget?: boolean;

/**
* Optional owner. Defaults to `{}`, can be any object, but will need to implement the [Owner](https://api.emberjs.com/ember/release/classes/Owner) API for components within this render tree to access services.
*/
Expand Down Expand Up @@ -540,7 +535,7 @@ export function renderComponent(
* Because destruction is async, it won't be safe to
* do this again, and we'll have to rely on the above destroy.
*/
if (!(appendIntoTarget || existing) && into instanceof Element) {
if (!existing && typeof Element !== 'undefined' && into instanceof Element) {
into.innerHTML = '';
}

Expand All @@ -558,10 +553,8 @@ 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: liveParent(existing.glimmerResult), nextSibling: firstNode };
}

let innerResult = renderer.render(component, { into: renderTarget, args }).result;
Expand Down
11 changes: 8 additions & 3 deletions packages/@ember/-internals/glimmer/lib/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,12 @@ import { curry } from '@glimmer/runtime/lib/curried-value';
import { inTransaction } from '@glimmer/runtime/lib/environment';
import { renderMain } from '@glimmer/runtime/lib/render';
import { unwrapTemplate } from './component-managers/unwrap-template';
import type { SimpleDocument, SimpleElement, SimpleNode } from '@simple-dom/interface';
import type {
SimpleDocument,
SimpleDocumentFragment,
SimpleElement,
SimpleNode,
} from '@simple-dom/interface';
import type Component from './component';
import type ClassicComponent from './component';
import { BOUNDS } from './component-managers/curly';
Expand Down Expand Up @@ -309,15 +314,15 @@ export class Renderer extends BaseRenderer {
}

getBounds(component: View): {
parentElement: SimpleElement;
parentElement: SimpleElement | SimpleDocumentFragment;
firstNode: SimpleNode;
lastNode: SimpleNode;
} {
let bounds: Bounds | null = component[BOUNDS];

assert('object passed to getBounds must have the BOUNDS symbol as a property', bounds);

let parentElement = bounds.parentElement();
let parentElement = bounds.parentNode();
let firstNode = bounds.firstNode();
let lastNode = bounds.lastNode();

Expand Down
18 changes: 16 additions & 2 deletions packages/@ember/application/instance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { assert } from '@ember/debug';
import Router from '@ember/routing/router';
import EventDispatcher from '@ember/-internals/views/lib/system/event_dispatcher';
import type Registry from '@ember/-internals/container/lib/registry';
import type { SimpleElement } from '@simple-dom/interface';
import type { SimpleDocumentFragment, SimpleElement } from '@simple-dom/interface';

/**
The `ApplicationInstance` encapsulates all of the stateful aspects of a
Expand Down Expand Up @@ -142,9 +142,23 @@ class ApplicationInstance extends EngineInstance {
return this._router;
}

#rootFragment?: DocumentFragment | SimpleDocumentFragment;

renderRootComponent(component: object) {
setRenderer(this, this.lookup('renderer:-dom') as BaseRenderer);
renderComponent(component, { into: this.rootElement!, owner: this, appendIntoTarget: true });
let env = this.lookup('-environment:main') as { _renderMode?: string };

if (env._renderMode === 'rehydrate') {
// Cursor form avoids clearing rootElement
renderComponent(component, {
into: { element: this.rootElement as SimpleElement, nextSibling: null },
owner: this,
});
} else {
this.#rootFragment ??= this.rootElement!.ownerDocument.createDocumentFragment();
renderComponent(component, { into: this.#rootFragment, owner: this });
(this.rootElement as Element).appendChild(this.#rootFragment as DocumentFragment);
}
}

/**
Expand Down
Loading
Loading