Skip to content

Commit

Permalink
feat: set intrinsic width and height for SVGs (#13126)
Browse files Browse the repository at this point in the history
  • Loading branch information
benmccann authored Dec 9, 2024
1 parent eb25a62 commit e2746ef
Show file tree
Hide file tree
Showing 14 changed files with 169 additions and 160 deletions.
5 changes: 5 additions & 0 deletions .changeset/tricky-squids-provide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/enhanced-img': patch
---

feat: set intrinsic width and height for SVGs
1 change: 1 addition & 0 deletions packages/enhanced-img/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"types": "types/index.d.ts",
"dependencies": {
"magic-string": "^0.30.5",
"sharp": "^0.33.5",
"svelte-parse-markup": "^0.1.5",
"vite-imagetools": "^7.0.1",
"zimmerframe": "^1.1.2"
Expand Down
74 changes: 33 additions & 41 deletions packages/enhanced-img/src/preprocessor.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import { existsSync } from 'node:fs';
import * as path from 'node:path';

import MagicString from 'magic-string';
import { walk } from 'zimmerframe';
import sharp from 'sharp';
import { parse } from 'svelte-parse-markup';
import { walk } from 'zimmerframe';

// TODO: expose this in vite-imagetools rather than duplicating it
const OPTIMIZABLE = /^[^?]+\.(avif|heif|gif|jpeg|jpg|png|tiff|webp)(\?.*)?$/;
Expand Down Expand Up @@ -70,51 +71,51 @@ export function image(opts) {
const original_url = src_attribute.raw.trim();
let url = original_url;

const sizes = get_attr_value(node, 'sizes');
const width = get_attr_value(node, 'width');
url += url.includes('?') ? '&' : '?';
if (sizes && 'raw' in sizes) {
url += 'imgSizes=' + encodeURIComponent(sizes.raw) + '&';
}
if (width && 'raw' in width) {
url += 'imgWidth=' + encodeURIComponent(width.raw) + '&';
if (OPTIMIZABLE.test(url)) {
const sizes = get_attr_value(node, 'sizes');
const width = get_attr_value(node, 'width');
url += url.includes('?') ? '&' : '?';
if (sizes && 'raw' in sizes) {
url += 'imgSizes=' + encodeURIComponent(sizes.raw) + '&';
}
if (width && 'raw' in width) {
url += 'imgWidth=' + encodeURIComponent(width.raw) + '&';
}
url += 'enhanced';
}
url += 'enhanced';

if (OPTIMIZABLE.test(url)) {
// resolves the import so that we can build the entire picture template string and don't
// need any logic blocks
const resolved_id = (await opts.plugin_context.resolve(url, filename))?.id;
if (!resolved_id) {
const file_path = url.substring(0, url.indexOf('?'));
if (existsSync(path.resolve(opts.vite_config.publicDir, file_path))) {
throw new Error(
`Could not locate ${file_path}. Please move it to be located relative to the page in the routes directory or reference it beginning with /static/. See https://vitejs.dev/guide/assets for more details on referencing assets.`
);
}
// resolves the import so that we can build the entire picture template string and don't
// need any logic blocks
const resolved_id = (await opts.plugin_context.resolve(url, filename))?.id;
if (!resolved_id) {
const query_index = url.indexOf('?');
const file_path = query_index >= 0 ? url.substring(0, query_index) : url;
if (existsSync(path.resolve(opts.vite_config.publicDir, file_path))) {
throw new Error(
`Could not locate ${file_path}. See https://vitejs.dev/guide/assets for more details on referencing assets.`
`Could not locate ${file_path}. Please move it to be located relative to the page in the routes directory or reference it beginning with /static/. See https://vitejs.dev/guide/assets for more details on referencing assets.`
);
}
throw new Error(
`Could not locate ${file_path}. See https://vitejs.dev/guide/assets for more details on referencing assets.`
);
}

if (OPTIMIZABLE.test(url)) {
let image = images.get(resolved_id);
if (!image) {
image = await process(resolved_id, opts);
images.set(resolved_id, image);
}
s.update(node.start, node.end, img_to_picture(content, node, image));
} else {
// 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(
is_quote(content, start - 1) ? start - 1 : start,
is_quote(content, end) ? end + 1 : end,
`{${name}}`
);
// update `enhanced:img` to `img`
s.update(node.start + 1, node.start + 1 + 'enhanced:img'.length, 'img');
const metadata = await sharp(resolved_id).metadata();
const new_markup = `<img ${serialize_img_attributes(content, node.attributes, {
src: `{${name}}`,
width: metadata.width || 0,
height: metadata.height || 0
})} />`;
s.update(node.start, node.end, new_markup);
imports.set(original_url, name);
}
}
Expand Down Expand Up @@ -175,15 +176,6 @@ export function image(opts) {
};
}

/**
* @param {string} content
* @param {number} index
* @returns {boolean}
*/
function is_quote(content, index) {
return content.charAt(index) === '"' || content.charAt(index) === "'";
}

/**
* @param {string} resolved_id
* @param {{
Expand Down
2 changes: 0 additions & 2 deletions packages/enhanced-img/test/Input.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,6 @@

<enhanced:img {src} alt="attribute shorthand test" />

<enhanced:img src="./foo.svg" alt="svg test" />

{#each images as image}
<enhanced:img src={image} alt="opt-in test" />
{/each}
Expand Down
6 changes: 1 addition & 5 deletions packages/enhanced-img/test/Output.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
<script lang="ts">
import __IMPORTED_ASSET_0__ from "./foo.svg";
<script lang="ts">
import manual_image1 from './no.png';
Expand Down Expand Up @@ -50,8 +48,6 @@
</picture>
{/if}

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

{#each images as image}
{#if typeof image === 'string'}
<img src={image.img.src} alt="opt-in test" width={image.img.w} height={image.img.h} />
Expand Down
2 changes: 1 addition & 1 deletion packages/enhanced-img/test/preprocessor.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ it('Image preprocess snapshot test', async () => {
// Make imports readable
const ouput = processed.code.replace(/import/g, '\n\timport');

expect(ouput).toMatchFileSnapshot('./Output.svelte');
await expect(ouput).toMatchFileSnapshot('./Output.svelte');
});

it('parses a minimized object', () => {
Expand Down
1 change: 1 addition & 0 deletions playgrounds/basic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"@sveltejs/adapter-static": "workspace:*",
"@sveltejs/adapter-vercel": "workspace:*",
"@sveltejs/amp": "workspace:*",
"@sveltejs/enhanced-img": "workspace:*",
"@sveltejs/kit": "workspace:*",
"@sveltejs/package": "workspace:*",
"@sveltejs/vite-plugin-svelte": "^5.0.1",
Expand Down
6 changes: 6 additions & 0 deletions playgrounds/basic/src/routes/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,9 @@
<h1>Welcome to SvelteKit</h1>

2 + 2 = {data.sum}

<h2>Pages:</h2>

<ul>
<li><a href="images">images</a></li>
</ul>
1 change: 0 additions & 1 deletion playgrounds/basic/src/routes/about/+page.svelte

This file was deleted.

11 changes: 11 additions & 0 deletions playgrounds/basic/src/routes/images/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<div><a href="/">home</a></div>
<br />
<div>
<enhanced:img
src="./state-of-js-chart.png"
style="width:700px; height:auto"
alt="Svelte Collective"
/>
</div>
<br />
<div><enhanced:img src="./svelte-logo.svg" alt="Svelte" /></div>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions playgrounds/basic/src/routes/images/svelte-logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion playgrounds/basic/vite.config.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { enhancedImages } from '@sveltejs/enhanced-img';
import { sveltekit } from '@sveltejs/kit/vite';

export default {
plugins: [sveltekit()],
plugins: [enhancedImages(), sveltekit()],
server: {
fs: {
allow: ['../../packages/kit']
Expand Down
Loading

0 comments on commit e2746ef

Please sign in to comment.