Skip to content

Commit e293068

Browse files
authored
fix: auto-import of svg images (#11035)
1 parent 4426dae commit e293068

File tree

4 files changed

+52
-4
lines changed

4 files changed

+52
-4
lines changed

packages/enhanced-img/src/preprocessor.js

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ export function image(opts) {
3131
const s = new MagicString(content);
3232
const ast = parse(content, { filename });
3333

34+
// Import path to import name
35+
// e.g. ./foo.png => ___ASSET___0
36+
/** @type {Map<string, string>} */
37+
const imports = new Map();
38+
3439
/**
3540
* @param {import('svelte/types/compiler/interfaces').TemplateNode} node
3641
* @param {{ type: string, start: number, end: number, raw: string }} src_attribute
@@ -46,7 +51,8 @@ export function image(opts) {
4651
return;
4752
}
4853

49-
let url = src_attribute.raw.trim();
54+
const original_url = src_attribute.raw.trim();
55+
let url = original_url;
5056

5157
const sizes = get_attr_value(node, 'sizes');
5258
const width = get_attr_value(node, 'width');
@@ -74,8 +80,17 @@ export function image(opts) {
7480
if (OPTIMIZABLE.test(url)) {
7581
s.update(node.start, node.end, img_to_picture(content, node, details));
7682
} else {
77-
// e.g. <img src="./foo.svg" /> => <img src="{___ASSET___0}" />
78-
s.update(src_attribute.start, src_attribute.end, `{${details}}`);
83+
// e.g. <img src="./foo.svg" /> => <img src={___ASSET___0} />
84+
const { start, end } = src_attribute;
85+
// update src with reference to imported asset
86+
s.update(
87+
is_quote(content, start - 1) ? start - 1 : start,
88+
is_quote(content, end) ? end + 1 : end,
89+
`{${details.name}}`
90+
);
91+
// update `enhanced:img` to `img`
92+
s.update(node.start + 1, node.start + 1 + 'enhanced:img'.length, 'img');
93+
imports.set(original_url, details.name);
7994
}
8095
}
8196

@@ -97,6 +112,20 @@ export function image(opts) {
97112
}
98113
});
99114

115+
// add imports
116+
if (imports.size) {
117+
let import_text = '';
118+
for (const [path, import_name] of imports.entries()) {
119+
import_text += `import ${import_name} from "${path}";`;
120+
}
121+
if (ast.instance) {
122+
// @ts-ignore
123+
s.appendLeft(ast.instance.content.start, import_text);
124+
} else {
125+
s.append(`<script>${import_text}</script>`);
126+
}
127+
}
128+
100129
return {
101130
code: s.toString(),
102131
map: s.generateMap()
@@ -105,6 +134,15 @@ export function image(opts) {
105134
};
106135
}
107136

137+
/**
138+
* @param {string} content
139+
* @param {number} index
140+
* @returns {boolean}
141+
*/
142+
function is_quote(content, index) {
143+
return content.charAt(index) === '"' || content.charAt(index) === "'";
144+
}
145+
108146
/**
109147
* @param {{
110148
* plugin_context: import('rollup').PluginContext

packages/enhanced-img/test/Input.svelte

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131

3232
<enhanced:img src="/src/foo.png" alt="absolute path test" />
3333

34+
<enhanced:img src="./foo.svg" alt="svg test" />
35+
3436
{#each images as image}
3537
<enhanced:img src={image} alt="opt-in test" />
3638
{/each}

packages/enhanced-img/test/Output.svelte

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
<script lang="ts">
2+
import ___ASSET___6 from "./foo.svg";
3+
24
import manual_image1 from './no.png';
5+
36
import manual_image2 from './no.svg';
47
58
const images = [manual_image1, manual_image2];
@@ -27,6 +30,8 @@
2730

2831
<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="absolute path test" width=1440 height=1440 /></picture>
2932

33+
<img src={___ASSET___6} alt="svg test" />
34+
3035
{#each images as image}
3136
{#if typeof image === 'string'}
3237
<img src={image.img.src} alt="opt-in test" width={image.img.w} height={image.img.h} />

packages/enhanced-img/test/preprocessor.spec.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@ it('Image preprocess snapshot test', async () => {
2929
{ filename }
3030
);
3131

32-
expect(processed.code).toMatchFileSnapshot('./Output.svelte');
32+
// Make imports readable
33+
const ouput = processed.code.replace(/import/g, '\n\timport');
34+
35+
expect(ouput).toMatchFileSnapshot('./Output.svelte');
3336
});
3437

3538
it('parses a minimized object', () => {

0 commit comments

Comments
 (0)