Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: set intrinsic width and height for SVGs #13126

Merged
merged 1 commit into from
Dec 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading