PERF: Remove dynamic `<template>` invocations (#29942)
Using Ember's `<template>` dynamically is not supported. For every invocation, glimmer-vm has to run one-time setup, and will cache the result indefinitely. This leads to significant memory leaks, and eventual OOM errors. This commit updates a handful of cases. We'll be following up with the more complex ones, and a linting rule to avoid re-introducing the problem in future.
This commit is contained in:
parent
39932733ee
commit
d4d939bd66
|
@ -7,6 +7,7 @@ import { htmlSafe } from "@ember/template";
|
|||
import { or } from "truth-helpers";
|
||||
import GlimmerComponentWithDeprecatedParentView from "discourse/components/glimmer-component-with-deprecated-parent-view";
|
||||
import concatClass from "discourse/helpers/concat-class";
|
||||
import element from "discourse/helpers/element";
|
||||
import icon from "discourse-common/helpers/d-icon";
|
||||
import deprecated from "discourse-common/lib/deprecated";
|
||||
import { i18n } from "discourse-i18n";
|
||||
|
@ -161,18 +162,14 @@ export default class DButton extends GlimmerComponentWithDeprecatedParentView {
|
|||
}
|
||||
|
||||
get wrapperElement() {
|
||||
const { href, type } = this.args;
|
||||
|
||||
return href
|
||||
? <template><a href={{href}} ...attributes>{{yield}}</a></template>
|
||||
: <template>
|
||||
<button type={{or type "button"}} ...attributes>{{yield}}</button>
|
||||
</template>;
|
||||
return element(this.args.href ? "a" : "button");
|
||||
}
|
||||
|
||||
<template>
|
||||
{{! template-lint-disable no-pointer-down-event-binding }}
|
||||
<this.wrapperElement
|
||||
href={{@href}}
|
||||
type={{unless @href (or @type "button")}}
|
||||
{{! For legacy compatibility. Prefer passing class as attributes. }}
|
||||
class={{concatClass
|
||||
@class
|
||||
|
|
|
@ -18,6 +18,19 @@ import FKControlToggle from "discourse/form-kit/components/fk/control/toggle";
|
|||
import FKControlWrapper from "discourse/form-kit/components/fk/control-wrapper";
|
||||
import FKRow from "discourse/form-kit/components/fk/row";
|
||||
|
||||
const RowColWrapper = <template>
|
||||
<FKRow as |row|>
|
||||
<row.Col @size={{@size}}>
|
||||
{{yield}}
|
||||
</row.Col>
|
||||
</FKRow>
|
||||
</template>;
|
||||
|
||||
const EmptyWrapper = <template>
|
||||
{{! template-lint-disable no-yield-only }}
|
||||
{{yield}}
|
||||
</template>;
|
||||
|
||||
export default class FKField extends Component {
|
||||
@tracked field;
|
||||
@tracked name;
|
||||
|
@ -72,18 +85,9 @@ export default class FKField extends Component {
|
|||
|
||||
get wrapper() {
|
||||
if (this.args.size) {
|
||||
return <template>
|
||||
<FKRow as |row|>
|
||||
<row.Col @size={{@size}}>
|
||||
{{yield}}
|
||||
</row.Col>
|
||||
</FKRow>
|
||||
</template>;
|
||||
return RowColWrapper;
|
||||
} else {
|
||||
return <template>
|
||||
{{! template-lint-disable no-yield-only }}
|
||||
{{yield}}
|
||||
</template>;
|
||||
return EmptyWrapper;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,12 @@ import { connectorsExist } from "discourse/lib/plugin-connectors";
|
|||
import rawRenderGlimmer from "discourse/lib/raw-render-glimmer";
|
||||
import RawHandlebars from "discourse-common/lib/raw-handlebars";
|
||||
|
||||
const GlimmerPluginOutletWrapper = <template>
|
||||
{{~! no whitespace ~}}
|
||||
<PluginOutlet @name={{@data.name}} @outletArgs={{@data.outletArgs}} />
|
||||
{{~! no whitespace ~}}
|
||||
</template>;
|
||||
|
||||
RawHandlebars.registerHelper("plugin-outlet", function (options) {
|
||||
const { name, tagName, outletArgs } = options.hash;
|
||||
|
||||
|
@ -15,11 +21,7 @@ RawHandlebars.registerHelper("plugin-outlet", function (options) {
|
|||
rawRenderGlimmer(
|
||||
this,
|
||||
`${tagName || "span"}.hbr-ember-outlet`,
|
||||
<template>
|
||||
{{~! no whitespace ~}}
|
||||
<PluginOutlet @name={{@data.name}} @outletArgs={{@data.outletArgs}} />
|
||||
{{~! no whitespace ~}}
|
||||
</template>,
|
||||
GlimmerPluginOutletWrapper,
|
||||
{ name, outletArgs }
|
||||
)
|
||||
);
|
||||
|
|
|
@ -4,6 +4,16 @@ import BulkSelectTopicsDropdown from "discourse/components/bulk-select-topics-dr
|
|||
import rawRenderGlimmer from "discourse/lib/raw-render-glimmer";
|
||||
import { i18n } from "discourse-i18n";
|
||||
|
||||
const BulkSelectGlimmerWrapper = <template>
|
||||
<span class="bulk-select-topic-dropdown__count">
|
||||
{{i18n "topics.bulk.selected_count" count=@data.selectedCount}}
|
||||
</span>
|
||||
<BulkSelectTopicsDropdown
|
||||
@bulkSelectHelper={{@data.bulkSelectHelper}}
|
||||
@afterBulkActionComplete={{@data.afterBulkAction}}
|
||||
/>
|
||||
</template>;
|
||||
|
||||
export default class extends EmberObject {
|
||||
@service router;
|
||||
|
||||
|
@ -20,15 +30,7 @@ export default class extends EmberObject {
|
|||
return rawRenderGlimmer(
|
||||
this,
|
||||
"div.bulk-select-topics-dropdown",
|
||||
<template>
|
||||
<span class="bulk-select-topic-dropdown__count">
|
||||
{{i18n "topics.bulk.selected_count" count=@data.selectedCount}}
|
||||
</span>
|
||||
<BulkSelectTopicsDropdown
|
||||
@bulkSelectHelper={{@data.bulkSelectHelper}}
|
||||
@afterBulkActionComplete={{@data.afterBulkAction}}
|
||||
/>
|
||||
</template>,
|
||||
BulkSelectGlimmerWrapper,
|
||||
{
|
||||
bulkSelectHelper: this.bulkSelectHelper,
|
||||
selectedCount: this.selectedCount,
|
||||
|
|
|
@ -10,6 +10,11 @@ import getURL from "discourse-common/lib/get-url";
|
|||
import I18n, { i18n } from "discourse-i18n";
|
||||
import TopicNotificationsOptions from "select-kit/components/topic-notifications-options";
|
||||
|
||||
const ParagraphWrapper = <template><p class="reason">{{yield}}</p></template>;
|
||||
const EmptyWrapper = <template>
|
||||
{{! template-lint-disable no-yield-only}}{{yield}}
|
||||
</template>;
|
||||
|
||||
export default class TopicNotificationsButton extends Component {
|
||||
@service currentUser;
|
||||
|
||||
|
@ -86,11 +91,9 @@ export default class TopicNotificationsButton extends Component {
|
|||
|
||||
get conditionalWrapper() {
|
||||
if (this.args.expanded) {
|
||||
return <template><p class="reason">{{yield}}</p></template>;
|
||||
return ParagraphWrapper;
|
||||
} else {
|
||||
return <template>
|
||||
{{! template-lint-disable no-yield-only}}{{yield}}
|
||||
</template>;
|
||||
return EmptyWrapper;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue