From 23d58e79bbe82244ed58c8816d16838a97ea3077 Mon Sep 17 00:00:00 2001 From: ole-martin <47389666+ole-martin@users.noreply.github.com> Date: Mon, 18 Nov 2019 21:21:03 +0100 Subject: [PATCH] fix(runtime.js): partials compile not caching (#1600) Reintroduce "merge" function, no called "mergeIfNeeded", that only creates a new partials object if both "env.partials" and "options.partials" are set. closes #1598 --- lib/handlebars/runtime.js | 12 +++++++++++- spec/regressions.js | 27 +++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/lib/handlebars/runtime.js b/lib/handlebars/runtime.js index 958afc3ef..59b1cc106 100644 --- a/lib/handlebars/runtime.js +++ b/lib/handlebars/runtime.js @@ -124,6 +124,15 @@ export function template(templateSpec, env) { } return value; }, + mergeIfNeeded: function(param, common) { + let obj = param || common; + + if (param && common && (param !== common)) { + obj = Utils.extend({}, common, param); + } + + return obj; + }, // An empty object to use as replacement for null-contexts nullContext: Object.seal({}), @@ -161,7 +170,8 @@ export function template(templateSpec, env) { container.helpers = Utils.extend({}, env.helpers, options.helpers); if (templateSpec.usePartial) { - container.partials = Utils.extend({}, env.partials, options.partials); + // Use mergeIfNeeded here to prevent compiling global partials multiple times + container.partials = container.mergeIfNeeded(options.partials, env.partials); } if (templateSpec.usePartial || templateSpec.useDecorators) { container.decorators = Utils.extend({}, env.decorators, options.decorators); diff --git a/spec/regressions.js b/spec/regressions.js index 74594de6b..3eccb2817 100644 --- a/spec/regressions.js +++ b/spec/regressions.js @@ -334,4 +334,31 @@ describe('Regressions', function() { shouldCompileTo('{{helpa length="foo"}}', [obj, helpers], 'foo'); }); + + describe('GH-1598: Performance degradation for partials since v4.3.0', function() { + // Do not run test for runs without compiler + if (!Handlebars.compile) { + return; + } + + var newHandlebarsInstance; + beforeEach(function() { + newHandlebarsInstance = Handlebars.create(); + }); + afterEach(function() { + sinon.restore(); + }); + + it('should only compile global partials once', function() { + var templateSpy = sinon.spy(newHandlebarsInstance, 'template'); + newHandlebarsInstance.registerPartial({ + 'dude': 'I am a partial' + }); + var string = 'Dudes: {{> dude}} {{> dude}}'; + newHandlebarsInstance.compile(string)(); // This should compile template + partial once + newHandlebarsInstance.compile(string)(); // This should only compile template + equal(templateSpy.callCount, 3); + sinon.restore(); + }); + }); });