Skip to content

Commit

Permalink
perf: hoist vite asset declarations to module block (#12627)
Browse files Browse the repository at this point in the history
  • Loading branch information
benmccann authored Sep 13, 2024
1 parent 110706c commit 49bfe3f
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 20 deletions.
5 changes: 5 additions & 0 deletions .changeset/friendly-wasps-return.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/enhanced-img': patch
---

perf: hoist vite asset declarations to module block
64 changes: 47 additions & 17 deletions packages/enhanced-img/src/preprocessor.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import MagicString from 'magic-string';
import { asyncWalk } from 'estree-walker';
import { parse } from 'svelte-parse-markup';

const ASSET_PREFIX = '___ASSET___';

// TODO: expose this in vite-imagetools rather than duplicating it
const OPTIMIZABLE = /^[^?]+\.(avif|heif|gif|jpeg|jpg|png|tiff|webp)(\?.*)?$/;

Expand Down Expand Up @@ -35,11 +33,20 @@ export function image(opts) {
const s = new MagicString(content);
const ast = parse(content, { filename });

// Import path to import name
// e.g. ./foo.png => ___ASSET___0
/** @type {Map<string, string>} */
/**
* Import path to import name
* e.g. ./foo.png => __IMPORTED_ASSET_0__
* @type {Map<string, string>}
*/
const imports = new Map();

/**
* Vite name to declaration name
* e.g. __VITE_ASSET_0__ => __DECLARED_ASSET_0__
* @type {Map<string, string>}
*/
const consts = new Map();

/**
* @param {import('svelte/types/compiler/interfaces').TemplateNode} node
* @param {{ type: string, start: number, end: number, raw: string }} src_attribute
Expand Down Expand Up @@ -94,10 +101,10 @@ export function image(opts) {
image = await process(resolved_id, opts);
images.set(resolved_id, image);
}
s.update(node.start, node.end, img_to_picture(content, node, image));
s.update(node.start, node.end, img_to_picture(consts, content, node, image));
} else {
// e.g. <img src="./foo.svg" /> => <img src={___ASSET___0} />
const name = ASSET_PREFIX + imports.size;
// e.g. <img src="./foo.svg" /> => <img src={__IMPORTED_ASSET_0__} />
const name = '__IMPORTED_ASSET_' + imports.size + '__';
const { start, end } = src_attribute;
// update src with reference to imported asset
s.update(
Expand Down Expand Up @@ -131,15 +138,28 @@ export function image(opts) {

// add imports
if (imports.size) {
let import_text = '';
let text = '';
for (const [path, import_name] of imports.entries()) {
import_text += `import ${import_name} from "${path}";`;
text += `import ${import_name} from "${path}";`;
}
if (ast.instance) {
// @ts-ignore
s.appendLeft(ast.instance.content.start, import_text);
s.appendLeft(ast.instance.content.start, text);
} else {
s.prepend(`<script>${text}</script>`);
}
}

if (consts.size) {
let text = '';
for (const [vite_name, declaration_name] of consts.entries()) {
text += `\tconst ${declaration_name} = "${vite_name}";\n`;
}
if (ast.module) {
// @ts-ignore
s.appendLeft(ast.module.content.start, text);
} else {
s.append(`<script>${import_text}</script>`);
s.prepend(`<script context="module">\n${text}</script>\n`);
}
}

Expand Down Expand Up @@ -264,11 +284,12 @@ function stringToNumber(param) {
}

/**
* @param {Map<string,string>} consts
* @param {string} content
* @param {import('svelte/types/compiler/interfaces').TemplateNode} node
* @param {import('vite-imagetools').Picture} image
*/
function img_to_picture(content, node, image) {
function img_to_picture(consts, content, node, image) {
/** @type {Array<import('svelte/types/compiler/interfaces').BaseDirective | import('svelte/types/compiler/interfaces').Attribute | import('svelte/types/compiler/interfaces').SpreadAttribute>} attributes */
const attributes = node.attributes;
const index = attributes.findIndex((attribute) => attribute.name === 'sizes');
Expand All @@ -281,11 +302,11 @@ function img_to_picture(content, node, image) {
let res = '<picture>';

for (const [format, srcset] of Object.entries(image.sources)) {
res += `<source srcset=${to_value(srcset)}${sizes_string} type="image/${format}" />`;
res += `<source srcset=${to_value(consts, srcset)}${sizes_string} type="image/${format}" />`;
}

res += `<img ${serialize_img_attributes(content, attributes, {
src: to_value(image.img.src),
src: to_value(consts, image.img.src),
width: image.img.w,
height: image.img.h
})} />`;
Expand All @@ -294,10 +315,19 @@ function img_to_picture(content, node, image) {
}

/**
* @param {Map<string, string>} consts
* @param {string} src
*/
function to_value(src) {
return src.startsWith('__VITE_ASSET__') ? `{"${src}"}` : `"${src}"`;
function to_value(consts, src) {
if (src.startsWith('__VITE_ASSET__')) {
let var_name = consts.get(src);
if (!var_name) {
var_name = '__DECLARED_ASSET_' + consts.size + '__';
consts.set(src, var_name);
}
return `{${var_name}}`;
}
return `"${src}"`;
}

/**
Expand Down
12 changes: 9 additions & 3 deletions packages/enhanced-img/test/Output.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
<script context="module">
const __DECLARED_ASSET_0__ = "__VITE_ASSET__2AM7_y_a__ 1440w, __VITE_ASSET__2AM7_y_b__ 960w";
const __DECLARED_ASSET_1__ = "__VITE_ASSET__2AM7_y_c__ 1440w, __VITE_ASSET__2AM7_y_d__ 960w";
const __DECLARED_ASSET_2__ = "__VITE_ASSET__2AM7_y_e__ 1440w, __VITE_ASSET__2AM7_y_f__ 960w";
const __DECLARED_ASSET_3__ = "__VITE_ASSET__2AM7_y_g__";
</script>
<script lang="ts">
import ___ASSET___0 from "./foo.svg";
import __IMPORTED_ASSET_0__ from "./foo.svg";
import manual_image1 from './no.png';
Expand All @@ -17,7 +23,7 @@

<picture><source srcset="/1 1440w, /2 960w" type="image/avif" /><source srcset="/3 1440w, /4 960w" type="image/webp" /><source srcset="5 1440w, /6 960w" type="image/png" /><img src="/7" alt="dev test" width=1440 height=1440 /></picture>

<picture><source srcset={"__VITE_ASSET__2AM7_y_a__ 1440w, __VITE_ASSET__2AM7_y_b__ 960w"} type="image/avif" /><source srcset={"__VITE_ASSET__2AM7_y_c__ 1440w, __VITE_ASSET__2AM7_y_d__ 960w"} type="image/webp" /><source srcset={"__VITE_ASSET__2AM7_y_e__ 1440w, __VITE_ASSET__2AM7_y_f__ 960w"} type="image/png" /><img src={"__VITE_ASSET__2AM7_y_g__"} alt="production test" width=1440 height=1440 /></picture>
<picture><source srcset={__DECLARED_ASSET_0__} type="image/avif" /><source srcset={__DECLARED_ASSET_1__} type="image/webp" /><source srcset={__DECLARED_ASSET_2__} type="image/png" /><img src={__DECLARED_ASSET_3__} alt="production test" width=1440 height=1440 /></picture>

<picture><source srcset="/1 1440w, /2 960w" type="image/avif" /><source srcset="/3 1440w, /4 960w" type="image/webp" /><source srcset="5 1440w, /6 960w" type="image/png" /><img src="/7" width="5" height="10" alt="dimensions test" width=1440 height=1440 /></picture>

Expand All @@ -44,7 +50,7 @@
</picture>
{/if}

<img src={___ASSET___0} alt="svg test" />
<img src={__IMPORTED_ASSET_0__} alt="svg test" />

{#each images as image}
{#if typeof image === 'string'}
Expand Down

0 comments on commit 49bfe3f

Please sign in to comment.