Skip to content

Commit d174a7d

Browse files
committed
feat: implement SVG minification and optimize SVG loading
1 parent cc16a2e commit d174a7d

File tree

8 files changed

+143
-83
lines changed

8 files changed

+143
-83
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
"sass": "1.97.2",
6565
"simple-git": "3.30.0",
6666
"simple-git-hooks": "2.13.1",
67+
"svgo": "4.0.0",
6768
"tsx": "4.21.0",
6869
"typescript": "5.9.3",
6970
"typescript-eslint": "8.53.1",

plugins/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export * from './mirror';
22
export * from './unAutoImport';
33
export * from './_404Page';
4+
export * from './miniSvg';

plugins/miniSvg.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import type { Plugin } from 'vite';
2+
3+
export function svgMinify(): Plugin {
4+
return {
5+
name: 'vite-svg-minify',
6+
apply: 'build',
7+
enforce: 'pre',
8+
async load(id) {
9+
if (!id.endsWith('.svg?raw')) return;
10+
const [fp] = id.split('?');
11+
const text = await this.fs.readFile(fp, { encoding: 'utf8' });
12+
const { optimize } = await import('svgo');
13+
const result = optimize(text);
14+
return `export default ${JSON.stringify(result.data)};`;
15+
},
16+
};
17+
}

pnpm-lock.yaml

Lines changed: 99 additions & 42 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/components/SvgIcon.vue

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,8 @@
11
<script lang="ts">
2-
const modules: Record<string, { default: string }> = import.meta.glob(
3-
'@/assets/svg/*.svg',
4-
{
5-
eager: true,
6-
query: 'raw',
7-
},
2+
const svgElMap = computedAsync(
3+
async () => (await import('@/utils/svg')).default,
4+
{},
85
);
9-
10-
const svgElMap = (() => {
11-
return Object.fromEntries(
12-
Object.entries(modules).map(([k, v]) => {
13-
const svgName = k.split('/').at(-1)!.split('.')[0];
14-
const t = document.createElement('template');
15-
t.innerHTML = v.default;
16-
return [svgName, t.content.firstChild as SVGSymbolElement | null];
17-
}),
18-
);
19-
})();
206
</script>
217
<script setup lang="ts">
228
const props = withDefaults(
@@ -26,7 +12,7 @@ const props = withDefaults(
2612
{},
2713
);
2814
29-
const svgEl = computed(() => svgElMap[props.name]);
15+
const svgEl = computed(() => svgElMap.value[props.name]);
3016
const actualEl = shallowRef<SVGSVGElement>();
3117
watchEffect(() => {
3218
const s = svgEl.value;

src/utils/svg.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
const modules = import.meta.glob<string>('@/assets/svg/*.svg', {
2+
eager: true,
3+
query: 'raw',
4+
import: 'default',
5+
});
6+
7+
export default Object.fromEntries(
8+
Object.entries(modules).map(([k, v]) => {
9+
const name = k.split('/').at(-1)!.split('.')[0];
10+
const t = document.createElement('template');
11+
t.innerHTML = v;
12+
return [name, t.content.firstChild as SVGSymbolElement];
13+
}),
14+
);

src/views/SvgPage.vue

Lines changed: 5 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,11 @@
11
<script setup lang="ts">
22
import { message } from '@/utils/discrete';
33
4-
const getIds = () => {
5-
return Array.from(
6-
document.querySelectorAll('#__svg_icon_container__ > *'),
7-
).map((v) => v.getAttribute('id')!.substring('svg-icon-'.length));
8-
};
9-
10-
const svgIds = ref(getIds());
11-
12-
const observer = new MutationObserver(() => {
13-
svgIds.value = getIds();
14-
});
15-
onMounted(() => {
16-
observer.observe(
17-
document.querySelector('#__svg_icon_container__') as HTMLElement,
18-
{
19-
attributes: true,
20-
},
21-
);
22-
});
23-
onUnmounted(() => {
24-
observer.disconnect();
25-
});
4+
const svgElMap = computedAsync(
5+
async () => (await import('@/utils/svg')).default,
6+
{},
7+
);
8+
const svgIds = computed(() => Object.keys(svgElMap.value));
269
2710
const search = ref('');
2811
const filterSvgIds = computed(() => {

vite.config.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import unocss from 'unocss/vite';
66
import data from 'unplugin-data/vite';
77
import { defineConfig } from 'vite';
88
import type { ESBuildOptions } from 'vite';
9-
import { mirror, unAutoImport, _404Page } from './plugins';
9+
import { mirror, unAutoImport, _404Page, svgMinify } from './plugins';
1010

1111
// support top-level-await
1212
const chromeVersion = 89;
@@ -16,6 +16,7 @@ const port = 8444;
1616
export default defineConfig(() => {
1717
return {
1818
plugins: [
19+
svgMinify(),
1920
vue(),
2021
vueJsx(),
2122
unocss({ inspector: false }),

0 commit comments

Comments
 (0)