Skip to content

Commit

Permalink
feat(image-jsx): change the jsx output so that it uses <picture> inst…
Browse files Browse the repository at this point in the history
…ead of <img>
  • Loading branch information
xhcy1314 committed May 7, 2024
1 parent 174f424 commit 3bec36a
Showing 1 changed file with 57 additions and 17 deletions.
74 changes: 57 additions & 17 deletions packages/qwik-city/buildtime/vite/image-jsx.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { OutputFormat } from 'vite-imagetools';
import type { OutputFormat, ImageMetadata } from 'vite-imagetools';
import type { PluginOption } from 'vite';
import { optimize } from 'svgo';
import fs from 'node:fs';
Expand All @@ -7,6 +7,14 @@ import { parseId } from '../../../qwik/src/optimizer/src/plugins/plugin';
import type { QwikCityVitePluginOptions } from './types';
import type { Config as SVGOConfig } from 'svgo';

/** Normalizes the format for use in mime-type */
const getFormat = (m: ImageMetadata) => {
if (!m.format) {
throw new Error(`Could not determine image format`);
}
return m.format.replace('jpg', 'jpeg');
};

/** @public */
export function imagePlugin(userOpts?: QwikCityVitePluginOptions): PluginOption[] {
const supportedExtensions = ['.jpg', '.jpeg', '.png', '.webp', '.gif', '.avif', '.tiff'];
Expand All @@ -17,22 +25,51 @@ export function imagePlugin(userOpts?: QwikCityVitePluginOptions): PluginOption[
exclude: [],
extendOutputFormats(builtins) {
const jsx: OutputFormat = () => (metadatas) => {
const srcSet = metadatas.map((meta) => `${meta.src} ${meta.width}w`).join(', ');
let largestImage: any;
let largestImageSize = 0;
const fallbackFormat = [...new Set(metadatas.map((m) => getFormat(m)))].pop();

let largestFallback;
let largestFallbackSize = 0;
let fallbackFormatCount = 0;
for (let i = 0; i < metadatas.length; i++) {
const m = metadatas[i];
if (getFormat(m) === fallbackFormat) {
fallbackFormatCount++;
if ((m.width as number) > largestFallbackSize) {
largestFallback = m;
largestFallbackSize = m.width as number;
}
}
}

const sourceMetadatas: Record<string, ImageMetadata[]> = {};
for (let i = 0; i < metadatas.length; i++) {
const m = metadatas[i] as any;
if (m.width > largestImageSize) {
largestImage = m;
largestImageSize = m.width;
const m = metadatas[i];
const f = getFormat(m);
// we don't need to create a source tag for the fallback format if there is
// only a single image in that format
if (f === fallbackFormat && fallbackFormatCount < 2) {
continue;
}
if (sourceMetadatas[f]) {
sourceMetadatas[f].push(m);
} else {
sourceMetadatas[f] = [m];
}
}
const sources: Record<string, string>[] = [];
for (const [key, value] of Object.entries(sourceMetadatas)) {
sources.push({
srcSet: value.map((meta) => `${meta.src} ${meta.width}w`).join(', '),
type: `image/${key}`,
});
}
return {
srcSet,
width:
largestImage === null || largestImage === void 0 ? void 0 : largestImage.width,
height:
largestImage === null || largestImage === void 0 ? void 0 : largestImage.height,
sources,
img: {
src: largestFallback?.src as string,
width: largestFallback?.width as number,
height: largestFallback?.height as number,
},
};
};
return {
Expand All @@ -50,7 +87,7 @@ export function imagePlugin(userOpts?: QwikCityVitePluginOptions): PluginOption[
withoutEnlargement: '',
...userOpts?.imageOptimization?.jsxDirectives,
...params,
as: 'jsx',
as: 'picture',
});
}
return new URLSearchParams();
Expand Down Expand Up @@ -84,17 +121,20 @@ export function imagePlugin(userOpts?: QwikCityVitePluginOptions): PluginOption[
const extension = path.extname(pathId).toLowerCase();

if (supportedExtensions.includes(extension)) {
if (!code.includes('srcSet')) {
if (!code.includes('sources')) {
this.error(`Image '${id}' could not be optimized to JSX`);
}
const index = code.indexOf('export default');
return (
code.slice(0, index) +
`
import { _jsxQ } from '@builder.io/qwik';
const PROPS = {srcSet, width, height};
const PROPS = {...img};
export default function (props, key, _, dev) {
return _jsxQ('img', {...{decoding: 'async', loading: 'lazy'}, ...props}, PROPS, undefined, 3, key, dev);
return _jsxQ('picture', null, null,
[...sources?.map((source) => _jsxQ('source', {...source}, null, undefined, 3, key, dev)),
_jsxQ('img', {...{decoding: 'async', loading: 'lazy'}, ...props}, PROPS, undefined, 3, key, dev)]
);
}`
);
} else if (extension === '.svg') {
Expand Down

0 comments on commit 3bec36a

Please sign in to comment.