From e85e5b1717bf7c58b19a43945e5a8a8e42a0e3e8 Mon Sep 17 00:00:00 2001 From: Justin Ribeiro Date: Fri, 22 Jul 2022 09:10:14 -0700 Subject: [PATCH] fix(preload): prevent multiple rules in multi-instance scenario (#69) --- lite-youtube.ts | 12 ++++++++---- test/lite-youtube.test.ts | 35 +++++++++++++++++++++++++---------- 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/lite-youtube.ts b/lite-youtube.ts index f2db6f5..92b89db 100644 --- a/lite-youtube.ts +++ b/lite-youtube.ts @@ -318,9 +318,6 @@ export class LiteYTEmbed extends HTMLElement { * Setup the placeholder image for the component */ private initImagePlaceholder(): void { - // we don't know which image type to preload, so warm the connection - LiteYTEmbed.addPrefetch('preconnect', 'https://i.ytimg.com/'); - const posterUrlWebp = `https://i.ytimg.com/vi_webp/${this.videoId}/${this.posterQuality}.webp`; const posterUrlJpeg = `https://i.ytimg.com/vi/${this.videoId}/${this.posterQuality}.jpg`; this.domRefImg.fallback.loading = this.posterLoading; @@ -422,7 +419,10 @@ export class LiteYTEmbed extends HTMLElement { * Isolation and split caches adding serious complexity. */ private static warmConnections(): void { - if (LiteYTEmbed.isPreconnected) return; + if (LiteYTEmbed.isPreconnected || window.liteYouTubeIsPreconnected) return; + // we don't know which image type to preload, so warm the connection + LiteYTEmbed.addPrefetch('preconnect', 'https://i.ytimg.com/'); + // Host that YT uses to serve JS needed by player, per amp-youtube LiteYTEmbed.addPrefetch('preconnect', 'https://s.ytimg.com'); @@ -441,6 +441,9 @@ export class LiteYTEmbed extends HTMLElement { ); LiteYTEmbed.addPrefetch('preconnect', 'https://static.doubleclick.net'); LiteYTEmbed.isPreconnected = true; + + // multiple embeds in the same page don't check for each other + window.liteYouTubeIsPreconnected = true; } } // Register custom element @@ -452,5 +455,6 @@ declare global { } interface Window { liteYouTubeNonce: string; + liteYouTubeIsPreconnected: boolean; } } diff --git a/test/lite-youtube.test.ts b/test/lite-youtube.test.ts index cb11823..eefd524 100644 --- a/test/lite-youtube.test.ts +++ b/test/lite-youtube.test.ts @@ -1,13 +1,22 @@ /* eslint-disable import/no-duplicates */ import { html, fixture, expect } from '@open-wc/testing'; +import { fixtureCleanup } from '@open-wc/testing-helpers'; + import { setViewport } from '@web/test-runner-commands'; import { LiteYTEmbed } from '../lite-youtube.js'; import '../lite-youtube.js'; -const baseTemplate = html``; +const baseTemplate = html``; describe('', () => { + afterEach(() => { + fixtureCleanup(); + }); + it('attr sets the videoid', async () => { const el = await fixture(baseTemplate); expect(el.videoId).to.equal('guJLfqTFfIw'); @@ -78,7 +87,7 @@ describe('', () => { ); // this is a cheeky test by counting the test runner + the warm injector // TODO write a better observer - expect(document.head.querySelectorAll('link').length).to.be.equal(12); + expect(document.head.querySelectorAll('link').length).to.be.equal(1); }); it('nocookie attr should change iframe url target', async () => { @@ -146,10 +155,7 @@ describe('', () => { it('YouTube Short desktop check', async () => { const el = await fixture( - html`` + html`` ); expect(el['isYouTubeShort']()).to.be.equal(false); }); @@ -157,10 +163,7 @@ describe('', () => { it('YouTube Short mobile check', async () => { setViewport({ width: 360, height: 640 }); const el = await fixture( - html`` + html`` ); el.click(); expect(el['isYouTubeShort']()).to.be.equal(true); @@ -176,6 +179,18 @@ describe('', () => { ).to.equal(window.liteYouTubeNonce); }); + it('check global preconnect state', async () => { + const el = await fixture( + html` + + ` + ); + expect(window.liteYouTubeIsPreconnected).to.be.true; + expect( + document.querySelectorAll('head > link[rel=preconnect]').length + ).to.equal(6); + }); + it('is valid A11y via aXe', async () => { const el = await fixture(baseTemplate); await expect(el).shadowDom.to.be.accessible();