From fde17007f0391fdf7cd6f1512477a8a67b65a1b6 Mon Sep 17 00:00:00 2001 From: Lukas Spirig Date: Wed, 5 Jun 2024 08:32:30 +0200 Subject: [PATCH] fix(sbb-image): render URL correctly with SSR (#2712) Closes #2690 --------- Co-authored-by: Jeri Peier --- src/elements/image/image.ssr.spec.ts | 27 +++++++++++++++++++++------ src/elements/image/image.ts | 14 ++++++++++---- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/src/elements/image/image.ssr.spec.ts b/src/elements/image/image.ssr.spec.ts index e1fc4017d5..2dc6d037da 100644 --- a/src/elements/image/image.ssr.spec.ts +++ b/src/elements/image/image.ssr.spec.ts @@ -1,4 +1,4 @@ -import { assert } from '@open-wc/testing'; +import { assert, expect } from '@open-wc/testing'; import { html } from 'lit'; import { fixture } from '../core/testing/private.js'; @@ -7,15 +7,30 @@ import { SbbImageElement } from './image.js'; describe(`sbb-image ${fixture.name}`, () => { let root: SbbImageElement; + const url = import.meta.resolve('../clock/assets/sbb_clock_face.svg'); - beforeEach(async () => { - const url = `${location.protocol}//${location.host}/src/elements/clock/assets/sbb_clock_face.svg`; + it('renders', async () => { root = await fixture(html``, { modules: ['./image.js'], }); - }); - - it('renders', () => { assert.instanceOf(root, SbbImageElement); }); + + const urls = [ + { name: 'fully qualified url', url }, + { name: 'local url', url: 'src/elements/clock/assets/sbb_clock_face.svg' }, + { name: 'local root url', url: '/src/elements/clock/assets/sbb_clock_face.svg' }, + ]; + for (const { name, url } of urls) { + it(`should work with ${name}`, async () => { + root = await fixture(html``, { + modules: ['./image.js'], + }); + const sources = Array.from(root.shadowRoot!.querySelectorAll('source')); + expect(sources.length).greaterThan(0); + for (const source of sources) { + expect(source.srcset.startsWith(url)).to.be.true; + } + }); + } }); diff --git a/src/elements/image/image.ts b/src/elements/image/image.ts index a706aba5e7..a11c0fe0f6 100644 --- a/src/elements/image/image.ts +++ b/src/elements/image/image.ts @@ -18,7 +18,6 @@ import { import { type CSSResultGroup, html, - isServer, LitElement, nothing, type PropertyValues, @@ -406,11 +405,14 @@ export class SbbImageElement extends LitElement { } private _prepareImageUrl(baseUrl: string | undefined, lquip = false): string { - if (!baseUrl || baseUrl === '' || isServer) { + if (!baseUrl || baseUrl === '') { return ''; } - const imageUrlObj = new URL(baseUrl); + // Creating an URL without a schema will fail, but is a valid input for baseUrl. + // e.g. image-src can be https://example.com/my-image.png or /my-image.png + const isFullyQualifiedUrl = !!baseUrl.match(/^\w+:\/\//); + const imageUrlObj = isFullyQualifiedUrl ? new URL(baseUrl) : new URL(`http://noop/${baseUrl}`); if (lquip) { // blur and size: ?blur=100&w=100&h=56 @@ -437,7 +439,11 @@ export class SbbImageElement extends LitElement { imageUrlObj.searchParams.append('fp-debug', 'true'); } - return imageUrlObj.href; + // In case of "noop" host, we don't return the host and must remove the + // starting `/` of the pathname. + return isFullyQualifiedUrl + ? imageUrlObj.href + : imageUrlObj.pathname.substring(1) + imageUrlObj.search; } private _preparePictureSizeConfigs(): InterfaceImageAttributesSizesConfigBreakpoint[] {