Dynamic SVG Loading in Vue 3 with TypeScript and Vite
Processing Country Data and Loading Dynamic SVGs
In this implementation, we'll demonstrate how to process API data containing country information and dynamically load corresponding SVG flags using Vue 3, TypeScript, and Vite.
Processing API Response Data
First, we need to process the raw data from our API to extract relevant information and prepare it for rendering:
for (let index = 0; index < apiData.value!.length; index++) {
if (apiData.value !== undefined && apiData.value) {
const responseContent: any = apiData.value[index].flagData;
const htmlTagPosition = responseContent.indexOf('<');
let textBeforeHTML: any;
if (htmlTagPosition !== -1) {
textBeforeHTML = responseContent.substring(0, htmlTagPosition);
apiData.value[index].flagData = textBeforeHTML;
}
}
const countryCode = apiData.value[index].nationCode;
console.log(countryCode);
if (countryCode) {
const matchedNation = allNations.find((nation) => nation.code === countryCode);
if (matchedNation) {
// Add the SVG file path to our data object
apiData.value[index].flagPath = matchedNation.svgPath;
console.log('Matched nation SVG:', matchedNation.svgPath);
} else {
console.log('No matching nation found for:', countryCode);
}
}
const currentItem = apiData.value[index];
const processedItem = { _score: apiData.value[index] };
displayList.value.push(processedItem);
console.log(displayList.value);
}
The allNations is a JSON file containing country information with their corresponding SVG file paths. We match the API data with this JSON to get the appropriate SVG path.
Dynamic SVG Component
Here's how to implement a component that dynamically loads SVG images based on the processed data:
<template>
<img :src="flagImageSrc" />
</template>
<script setup lang="ts">
import { ref, watchEffect } from 'vue';
const flagImageSrc = ref('');
watchEffect(() => {
for (const item of displayList.value) {
if (item._score && item._score.flagPath) { // Check if _score and flagPath exist
loadFlagImage(item._score.flagPath);
}
}
});
async function loadFlagImage(path: string) {
try {
const imageModule = await import(`/@/assets/flags/${path}.svg`);
flagImageSrc.value = imageModule.default;
} catch (error) {
console.error(`Failed to import SVG file for ${path}:`, error);
// Fallback to default image if import fails
flagImageSrc.value = require('/@/assets/flags/default.svg');
}
}
</script>
Implementation in Other Components
When receiving data in other components, first check if the SVG path exists before attempting to render:
async function renderDynamicFlag(flagPath: string | undefined) {
if (!flagPath) {
console.log('No flag path provided');
return;
}
try {
const imageModule = await import(`/@/assets/flags/${flagPath}.svg`);
return imageModule.default;
} catch (error) {
console.error(`Failed to load flag for ${flagPath}:`, error);
return require('/@/assets/flags/default.svg');
}
}
This approach ensures that only valid SVG paths are processed, providing a fallback mechanism when resources are unavailable.
Optimizing with Vite
Vite's native support for dynamic imports makes this implementation efficient. When you use import() with a static path, Vite will automatically code-split and bundle these assets separately.
For optimal performance, consider implementing a caching mechanism to avoid repeated imports of the same SVG files:
const svgCache = new Map();
async function getSvgWithCache(path: string) {
if (svgCache.has(path)) {
return svgCache.get(path);
}
try {
const imageModule = await import(`/@/assets/flags/${path}.svg`);
svgCache.set(path, imageModule.default);
return imageModule.default;
} catch (error) {
console.error(`Failed to load SVG for ${path}:`, error);
return require('/@/assets/flags/default.svg');
}
}
This implementation demonstrates how to efficiently load dynamic SVG resources in a Vue 3 application with TypeScript and Vite, handling various edge cases while maintaining good performance.