diff --git a/FEATURES.md b/FEATURES.md
index 3b2356e0f8f..7f8b5ed0027 100644
--- a/FEATURES.md
+++ b/FEATURES.md
@@ -32,6 +32,11 @@ for a detailed explanation.
Add `{{@foo}}` syntax to access named arguments in component templates per
[RFC](https://github.com/emberjs/rfcs/pull/276).
+* `ember-glimmer-remove-application-template-wrapper`
+
+ Remove the `
` wrapper around the application template per
+ [RFC](https://github.com/emberjs/rfcs/pull/280).
+
* `ember-glimmer-template-only-components`
Use Glimmer Components semantics for template-only components per
diff --git a/features.json b/features.json
index 7912a91f9ce..9507641ea05 100644
--- a/features.json
+++ b/features.json
@@ -4,6 +4,7 @@
"ember-libraries-isregistered": null,
"ember-improved-instrumentation": null,
"ember-glimmer-named-arguments": null,
+ "ember-glimmer-remove-application-template-wrapper": null,
"ember-glimmer-template-only-components": null,
"ember-routing-router-service": true,
"ember-engines-mount-params": true,
diff --git a/packages/ember-application/tests/system/application_test.js b/packages/ember-application/tests/system/application_test.js
index 3437abb871b..ce831e6f0aa 100644
--- a/packages/ember-application/tests/system/application_test.js
+++ b/packages/ember-application/tests/system/application_test.js
@@ -215,10 +215,9 @@ moduleFor('Ember.Application, default resolver with autoboot', class extends Def
}
[`@test Minimal Application initialized with just an application template`](assert) {
- this.$().html('');
+ jQuery('#qunit-fixture').html('');
this.runTask(() => this.createApplication());
-
- assert.equal(this.$().text().trim(), 'Hello World');
+ this.assertInnerHTML('Hello World');
}
});
diff --git a/packages/ember-application/tests/system/visit_test.js b/packages/ember-application/tests/system/visit_test.js
index d6bc02079fa..5bbbd105cb3 100644
--- a/packages/ember-application/tests/system/visit_test.js
+++ b/packages/ember-application/tests/system/visit_test.js
@@ -285,7 +285,7 @@ moduleFor('Ember.Application - visit()', class extends ApplicationTestCase {
'promise is resolved with an ApplicationInstance'
);
assert.equal(
- this.$('.ember-view h1').text(), 'Hello world',
+ this.$('h1').text(), 'Hello world',
'the application was rendered once the promise resolves'
);
});
@@ -576,8 +576,8 @@ moduleFor('Ember.Application - visit()', class extends ApplicationTestCase {
}
}));
- let $foo = jQuery('').appendTo(this.$());
- let $bar = jQuery('').appendTo(this.$());
+ let $foo = jQuery('').appendTo('#qunit-fixture');
+ let $bar = jQuery('').appendTo('#qunit-fixture');
let data = encodeURIComponent(JSON.stringify({ name: 'Godfrey' }));
let instances = [];
diff --git a/packages/ember-glimmer/externs.d.ts b/packages/ember-glimmer/externs.d.ts
index ebc11625777..38b837f6545 100644
--- a/packages/ember-glimmer/externs.d.ts
+++ b/packages/ember-glimmer/externs.d.ts
@@ -3,6 +3,7 @@ declare module 'ember/features' {
export const GLIMMER_CUSTOM_COMPONENT_MANAGER: boolean | null;
export const EMBER_ENGINES_MOUNT_PARAMS: boolean | null;
export const EMBER_GLIMMER_DETECT_BACKTRACKING_RERENDER: boolean | null;
+ export const EMBER_GLIMMER_REMOVE_APPLICATION_TEMPLATE_WRAPPER: boolean | null;
export const EMBER_GLIMMER_TEMPLATE_ONLY_COMPONENTS: boolean | null;
export const MANDATORY_SETTER: boolean | null;
}
diff --git a/packages/ember-glimmer/lib/component-managers/outlet.ts b/packages/ember-glimmer/lib/component-managers/outlet.ts
index c194d936430..91234f2ef29 100644
--- a/packages/ember-glimmer/lib/component-managers/outlet.ts
+++ b/packages/ember-glimmer/lib/component-managers/outlet.ts
@@ -9,6 +9,7 @@ import { Destroyable } from '@glimmer/util/dist/types';
import { DEBUG } from 'ember-env-flags';
import { _instrumentStart } from 'ember-metal';
import { generateGuid, guidFor } from 'ember-utils';
+import { EMBER_GLIMMER_REMOVE_APPLICATION_TEMPLATE_WRAPPER } from 'ember/features';
import EmberEnvironment from '../environment';
import {
OwnedTemplate,
@@ -92,13 +93,35 @@ class TopLevelOutletComponentManager extends OutletComponentManager {
}
return new StateBucket(dynamicScope.outletState.value());
}
-
- layoutFor(definition: OutletComponentDefinition, _bucket: StateBucket, env: Environment) {
- return (env as EmberEnvironment).getCompiledBlock(TopLevelOutletLayoutCompiler, definition.template);
- }
}
-const TOP_LEVEL_MANAGER = new TopLevelOutletComponentManager();
+const TOP_LEVEL_MANAGER = (() => {
+ if (EMBER_GLIMMER_REMOVE_APPLICATION_TEMPLATE_WRAPPER) {
+ return new TopLevelOutletComponentManager();
+ } else {
+ class WrappedTopLevelOutletLayoutCompiler {
+ static id = 'wrapped-top-level-outlet';
+
+ constructor(public template: WrappedTemplateFactory) {
+ }
+
+ compile(builder: any) {
+ builder.wrapLayout(this.template);
+ builder.tag.static('div');
+ builder.attrs.static('id', guidFor(this));
+ builder.attrs.static('class', 'ember-view');
+ }
+ }
+
+ class WrappedTopLevelOutletComponentManager extends TopLevelOutletComponentManager {
+ layoutFor(definition: OutletComponentDefinition, _bucket: StateBucket, env: Environment) {
+ return (env as EmberEnvironment).getCompiledBlock(WrappedTopLevelOutletLayoutCompiler, definition.template);
+ }
+ }
+
+ return new WrappedTopLevelOutletComponentManager();
+ }
+})();
export class TopLevelOutletComponentDefinition extends ComponentDefinition {
public template: WrappedTemplateFactory;
@@ -109,23 +132,6 @@ export class TopLevelOutletComponentDefinition extends ComponentDefinition {
public outletName: string;
public template: OwnedTemplate;
diff --git a/packages/ember-glimmer/tests/integration/application/rendering-test.js b/packages/ember-glimmer/tests/integration/application/rendering-test.js
index fab18587e1e..ab3154213a0 100644
--- a/packages/ember-glimmer/tests/integration/application/rendering-test.js
+++ b/packages/ember-glimmer/tests/integration/application/rendering-test.js
@@ -3,14 +3,23 @@ import { moduleFor, ApplicationTest } from '../../utils/test-case';
import { strip } from '../../utils/abstract-test-case';
import { Route } from 'ember-routing';
import { Component } from 'ember-glimmer';
+import { jQuery } from 'ember-views';
moduleFor('Application test: rendering', class extends ApplicationTest {
- ['@test it can render the application template'](assert) {
+ ['@feature(!ember-glimmer-remove-application-template-wrapper) it can render the application template'](assert) {
this.addTemplate('application', 'Hello world!');
return this.visit('/').then(() => {
- this.assertText('Hello world!');
+ this.assertComponentElement(this.element, { content: 'Hello world!' });
+ });
+ }
+
+ ['@feature(ember-glimmer-remove-application-template-wrapper) it can render the application template'](assert) {
+ this.addTemplate('application', 'Hello world!');
+
+ return this.visit('/').then(() => {
+ this.assertInnerHTML('Hello world!');
});
}
@@ -30,15 +39,13 @@ moduleFor('Application test: rendering', class extends ApplicationTest {
`);
return this.visit('/').then(() => {
- this.assertComponentElement(this.firstChild, {
- content: strip`
-
');
});
}
@@ -317,7 +317,7 @@ if (EMBER_ENGINES_MOUNT_PARAMS) {
this.addTemplate('engine-params-contextual-component', '{{mount "componentParamEngine" model=(hash foo=(component "foo-component"))}}');
return this.visit('/engine-params-contextual-component').then(() => {
- this.assertComponentElement(this.firstChild.firstChild, { content: 'foo-component rendered! - rendered app-bar-component from the app' });
+ this.assertComponentElement(this.firstChild, { content: 'foo-component rendered! - rendered app-bar-component from the app' });
});
}
});
diff --git a/packages/ember/tests/component_registration_test.js b/packages/ember/tests/component_registration_test.js
index 19e6f52d96d..80c7ac274e3 100644
--- a/packages/ember/tests/component_registration_test.js
+++ b/packages/ember/tests/component_registration_test.js
@@ -12,8 +12,8 @@ moduleFor('Application Lifecycle - Component Registration', class extends Autobo
this.addTemplate('application', 'Hello world {{#expand-it}}world{{/expand-it}}');
});
- let text = this.$('div.ember-view > div.ember-view').html().trim();
- assert.equal(text, '
hello world
', 'The component is composed correctly');
+ this.assertText('Hello world hello world');
+ this.assertComponentElement(this.element.firstElementChild, { tagName: 'div', content: '
hello world
' });
}
['@feature(ember-glimmer-template-only-components) The helper becomes the body of the component'](assert) {
@@ -24,8 +24,7 @@ moduleFor('Application Lifecycle - Component Registration', class extends Autobo
this.addTemplate('application', 'Hello world {{#expand-it}}world{{/expand-it}}');
});
- let text = this.$('div.ember-view').html().trim();
- assert.equal(text, 'Hello world
hello world
', 'The component is composed correctly');
+ this.assertInnerHTML('Hello world
hello world
');
}
['@test If a component is registered, it is used'](assert) {
diff --git a/packages/ember/tests/routing/basic_test.js b/packages/ember/tests/routing/basic_test.js
index 5b51eadc832..b03d501699c 100644
--- a/packages/ember/tests/routing/basic_test.js
+++ b/packages/ember/tests/routing/basic_test.js
@@ -1738,7 +1738,7 @@ QUnit.test('Child routes should render inside the application template if the ap
bootApplication();
- equal(jQuery('#qunit-fixture > div').text(), 'App posts');
+ equal(jQuery('#qunit-fixture').text(), 'App posts');
});
QUnit.test('The template is not re-rendered when the route\'s context changes', function() {
diff --git a/packages/ember/tests/routing/toplevel_dom_test.js b/packages/ember/tests/routing/toplevel_dom_test.js
index e3f68e438cd..b992b329c75 100644
--- a/packages/ember/tests/routing/toplevel_dom_test.js
+++ b/packages/ember/tests/routing/toplevel_dom_test.js
@@ -1,11 +1,19 @@
import { moduleFor, ApplicationTestCase } from 'internal-test-helpers';
moduleFor('Top Level DOM Structure', class extends ApplicationTestCase {
- ['@test Topmost template always get an element'](assert) {
+ ['@feature(!ember-glimmer-remove-application-template-wrapper) Topmost template always get an element'](assert) {
this.addTemplate('application', 'hello world');
return this.visit('/').then(() => {
- assert.equal(this.$('> .ember-view').text(), 'hello world');
+ this.assertComponentElement(this.element, { content: 'hello world' });
+ });
+ }
+
+ ['@feature(ember-glimmer-remove-application-template-wrapper) Topmost template does not get an element'](assert) {
+ this.addTemplate('application', 'hello world');
+
+ return this.visit('/').then(() => {
+ this.assertInnerHTML('hello world');
});
}
});
diff --git a/packages/internal-test-helpers/lib/test-cases/abstract-application.js b/packages/internal-test-helpers/lib/test-cases/abstract-application.js
index ced04a3715b..eeb4339a4a4 100644
--- a/packages/internal-test-helpers/lib/test-cases/abstract-application.js
+++ b/packages/internal-test-helpers/lib/test-cases/abstract-application.js
@@ -1,13 +1,23 @@
import { compile } from 'ember-template-compiler';
-import AbstractTestCase from './abstract';
import { jQuery } from 'ember-views';
+import { EMBER_GLIMMER_REMOVE_APPLICATION_TEMPLATE_WRAPPER } from 'ember/features';
+import AbstractTestCase from './abstract';
import { runDestroy } from '../run';
export default class AbstractApplicationTestCase extends AbstractTestCase {
- constructor() {
- super();
- this.element = jQuery('#qunit-fixture')[0];
+ get element() {
+ if (this._element) {
+ return this._element;
+ } else if (EMBER_GLIMMER_REMOVE_APPLICATION_TEMPLATE_WRAPPER) {
+ return this._element = jQuery('#qunit-fixture')[0];
+ } else {
+ return this._element = jQuery('#qunit-fixture > div.ember-view')[0];
+ }
+ }
+
+ set element(element) {
+ this._element = element;
}
teardown() {