From 5b863a2bbaa8647b29cc6818ffb6dadc7297caae Mon Sep 17 00:00:00 2001 From: Manuel Martin Date: Wed, 1 Apr 2020 10:37:29 +0200 Subject: [PATCH] fix(scoped-elements): define unused lazy scoped elements --- .../src/ScopedElementsMixin.js | 43 ++++++++++----- .../scoped-elements/src/registerElement.js | 6 ++- .../test/ScopedElementsMixin.test.js | 52 +++++++++++++++++++ 3 files changed, 88 insertions(+), 13 deletions(-) diff --git a/packages/scoped-elements/src/ScopedElementsMixin.js b/packages/scoped-elements/src/ScopedElementsMixin.js index 3f691c56..5b3b6a09 100644 --- a/packages/scoped-elements/src/ScopedElementsMixin.js +++ b/packages/scoped-elements/src/ScopedElementsMixin.js @@ -17,6 +17,19 @@ import { shadyTemplateFactory } from './shadyTemplateFactory.js'; */ const templateCaches = new WeakMap(); +/** + * Retrieves or creates a templateCache for a specific key + * @param {Function} key + * @returns {Map} + */ +const getTemplateCache = key => { + if (!templateCaches.has(key)) { + templateCaches.set(key, new Map()); + } + + return templateCaches.get(key); +}; + /** * Tags caches * @@ -24,6 +37,19 @@ const templateCaches = new WeakMap(); */ const tagsCaches = new WeakMap(); +/** + * Retrieves or creates a tagsCache for a specific key + * @param {object} key + * @returns {Map} + */ +const getTagsCache = key => { + if (!tagsCaches.has(key)) { + tagsCaches.set(key, new Map()); + } + + return tagsCaches.get(key); +}; + /** * Transforms an array of TemplateResults or arrays into another one with resolved scoped elements * @@ -91,15 +117,8 @@ export const ScopedElementsMixin = dedupeMixin( } const { scopeName } = options; - if (!templateCaches.has(this)) { - templateCaches.set(this, new Map()); - } - if (!tagsCaches.has(this)) { - tagsCaches.set(this, new Map()); - } - - const templateCache = templateCaches.get(this); - const tagsCache = tagsCaches.get(this); + const templateCache = getTemplateCache(this); + const tagsCache = getTagsCache(this); const { scopedElements } = this; // @ts-ignore @@ -121,7 +140,7 @@ export const ScopedElementsMixin = dedupeMixin( * @param {typeof HTMLElement} klass */ defineScopedElement(tagName, klass) { - return defineScopedElement(tagName, klass, tagsCaches.get(this.constructor)); + return defineScopedElement(tagName, klass, getTagsCache(this.constructor)); } /** @@ -134,8 +153,8 @@ export const ScopedElementsMixin = dedupeMixin( const klass = this.scopedElements[tagName]; return klass - ? registerElement(tagName, klass, tagsCaches.get(this)) - : tagsCaches.get(this).get(tagName); + ? registerElement(tagName, klass, getTagsCache(this)) + : getTagsCache(this).get(tagName); } }, ); diff --git a/packages/scoped-elements/src/registerElement.js b/packages/scoped-elements/src/registerElement.js index 4ce31743..903247e0 100644 --- a/packages/scoped-elements/src/registerElement.js +++ b/packages/scoped-elements/src/registerElement.js @@ -76,5 +76,9 @@ export function registerElement(tagName, klass, tagsCache = undefined) { export function defineScopedElement(tagName, klass, tagsCache) { const tag = tagsCache.get(tagName); - defineElement(tag, klass, customElements); + if (tag) { + defineElement(tag, klass, customElements); + } else { + tagsCache.set(tagName, registerElement(tagName, klass, tagsCache)); + } } diff --git a/packages/scoped-elements/test/ScopedElementsMixin.test.js b/packages/scoped-elements/test/ScopedElementsMixin.test.js index 9ca17807..d32059f2 100644 --- a/packages/scoped-elements/test/ScopedElementsMixin.test.js +++ b/packages/scoped-elements/test/ScopedElementsMixin.test.js @@ -294,6 +294,58 @@ describe('ScopedElementsMixin', () => { expect(el.shadowRoot.children[1]).to.be.an.instanceOf(FeatureB); }); + it("support define a lazy element even if it's not used in previous templates", async () => { + class LazyElement extends LitElement { + render() { + return html` +
Lazy element
+ `; + } + } + + const tag = defineCE( + class extends ScopedElementsMixin(LitElement) { + static get scopedElements() { + return { + 'feature-a': FeatureA, + }; + } + + constructor() { + super(); + + const defineScopedElement = this.defineScopedElement.bind(this); + + this.loading = new Promise(resolve => { + defineScopedElement('lazy-element', LazyElement); + + resolve( + html` + + `, + ); + }); + } + + render() { + return html` + + ${until( + this.loading, + html` +
Loading...
+ `, + )} + `; + } + }, + ); + + const el = await fixture(`<${tag}>`); + + await waitUntil(() => el.shadowRoot.children[1] instanceof LazyElement); + }); + describe('getScopedTagName', () => { it('should return the scoped tag name for a registered element', async () => { const chars = `-|\\.|[0-9]|[a-z]`;