diff --git a/packages/ember-template-compiler/lib/system/compile-options.js b/packages/ember-template-compiler/lib/system/compile-options.js index 231b4727a28..b7e8c6c9f59 100644 --- a/packages/ember-template-compiler/lib/system/compile-options.js +++ b/packages/ember-template-compiler/lib/system/compile-options.js @@ -30,20 +30,28 @@ function wrapLegacyPluginIfNeeded(_plugin) { let plugin = _plugin; if (_plugin.prototype && _plugin.prototype.transform) { plugin = (env) => { + let pluginInstantiated = false; + return { name: _plugin.constructor && _plugin.constructor.name, visitor: { Program(node) { - let plugin = new _plugin(env); + if (!pluginInstantiated) { + + pluginInstantiated = true; + let plugin = new _plugin(env); - plugin.syntax = env.syntax; + plugin.syntax = env.syntax; - return plugin.transform(node); + return plugin.transform(node); + } } } }; }; + + plugin.__raw = _plugin; } return plugin; @@ -54,6 +62,13 @@ export function registerPlugin(type, _plugin) { throw new Error(`Attempting to register ${_plugin} as "${type}" which is not a valid Glimmer plugin type.`); } + for (let i = 0; i < USER_PLUGINS.length; i++) { + let PLUGIN = USER_PLUGINS[i]; + if (PLUGIN === _plugin || PLUGIN.__raw === _plugin) { + return; + } + } + let plugin = wrapLegacyPluginIfNeeded(_plugin); USER_PLUGINS = [plugin, ...USER_PLUGINS]; @@ -64,5 +79,5 @@ export function unregisterPlugin(type, PluginClass) { throw new Error(`Attempting to unregister ${PluginClass} as "${type}" which is not a valid Glimmer plugin type.`); } - USER_PLUGINS = USER_PLUGINS.filter((plugin) => plugin !== PluginClass); + USER_PLUGINS = USER_PLUGINS.filter((plugin) => plugin !== PluginClass && plugin.__raw !== PluginClass); } diff --git a/packages/ember-template-compiler/tests/system/compile_options_test.js b/packages/ember-template-compiler/tests/system/compile_options_test.js index f4c78dc12dd..aaa423b010c 100644 --- a/packages/ember-template-compiler/tests/system/compile_options_test.js +++ b/packages/ember-template-compiler/tests/system/compile_options_test.js @@ -18,8 +18,10 @@ moduleFor('ember-template-compiler: default compile options', class extends Abst } }); +let customTransformCounter = 0; class CustomTransform { constructor(options) { + customTransformCounter++; this.options = options; this.syntax = null; } @@ -45,13 +47,10 @@ class CustomTransform { } } -moduleFor('ember-template-compiler: registerPlugin with a custom plugins', class extends RenderingTestCase { - beforeEach() { - registerPlugin('ast', CustomTransform); - } - +class CustomPluginsTests extends RenderingTestCase { afterEach() { - unregisterPlugin('ast', CustomTransform); + customTransformCounter = 0; + return super.afterEach(); } ['@test custom plugins can be used']() { @@ -62,6 +61,28 @@ moduleFor('ember-template-compiler: registerPlugin with a custom plugins', class content: '' }); } + + ['@test wrapped plugins are only invoked once per template'](assert) { + this.render('
{{#if falsey}}nope{{/if}}
'); + assert.equal(customTransformCounter, 1, 'transform should only be instantiated once'); + } +} + +moduleFor('ember-template-compiler: registerPlugin with a custom plugins', class extends CustomPluginsTests { + beforeEach() { + registerPlugin('ast', CustomTransform); + } + + afterEach() { + unregisterPlugin('ast', CustomTransform); + return super.afterEach(); + } + + ['@test custom registered plugins are deduplicated'](assert) { + registerPlugin('ast', CustomTransform); + this.registerTemplate('application', '
'); + assert.equal(customTransformCounter, 1, 'transform should only be instantiated once'); + } }); moduleFor('ember-template-compiler: custom plugins passed to compile', class extends RenderingTestCase { @@ -73,13 +94,4 @@ moduleFor('ember-template-compiler: custom plugins passed to compile', class ext } }); } - - ['@test custom plugins can be used']() { - this.render('
'); - this.assertElement(this.firstChild, { - tagName: 'div', - attrs: { class: 'hahaha', 'data-blah': 'derp' }, - content: '' - }); - } });