Импорт изображений вместо прямых ссылок
Введение
Когда в проекте требуется использовать изображения, большинство разработчиков привыкли работать с прямыми ссылками. Кладешь картинку в директорию public или static,
а в теге <img /> указываешь путь до изображения как в файловой системе. Просто и работает, зачем придумывать что-то еще?
Вот только у такого подходя есть ряд недостатков. Рассмотрим что может пойти не так:
- У вас может потенциально возникнуть проблема с кешированием таких картинок. Если вы замените изображение, но не измените название, то при наличии кеша на любом уровне пользователь получит старую версию изображения, пока кеш не сбросится. Можно следить за именованиями вручную, но зачем усложнять себе жизнь?
- Если будете проводить рефакторинг проекта или по иным причинам переместите изображения в другой путь, то вам придется самим выискивать все использования картинок и обновлять пути. Опять лишняя сложность из ничего.
- Также забудьте о любых обработках изображений сборщиками. Хотите при сборке оптимизировать изображения, проводить иные операции - не в этот раз.
Альтернатива
Вместо прямых ссылок на изображения, вы можете использовать альтернативный подход - импортировать их. Выглядит такой подход примерно вот так:
<script lang="ts" setup>
import image from '~/assets/images/file.jpg';
</script>
<template>
<img :src="image" />
</template>
Собственно, а что поменялось, почему так? - все просто. Теперь изображение обработается сборщиком. В большинстве фреймворков на такой случай заложено стандартное поведение: переместить изображение в результат сборки и добавить к имени файла его хэш. Супер просто, не правда ли?
Что дает такой подход
Поменялось крайне мало, но взамен мы получаем сразу ряд преимуществ. Во-первых, автоматическое добавление хэша к названию сделает так, что пока картинка не изменится, ее наименование будет всегда одинаковы. Т.е. на любом уровне кеширования применится правильная политика. А вот если файл будет заменен, то и сразу же изменится хеш, а значит название, а значит пользователь 100% получит новый файл.
Во-вторых, такой синтаксис будут понимать редакторы кода, и многие из них будут понимать вам при некоторых операциях. Если вы переименуете файл, то IDE обновит вам и путь импорта автоматически. Если же вы переместите файл или директорию с файлами, то умный редактор кода также применит эти изменения ко всем местам использования импортированных файлов. Опять же удобство работы.
В-третьих, плагины сборщика. Можете оптимизировать картинки, делать alias'ы для каких-то особенных путей, писать любую собственную логику. Вы вообще при таком подходе не будете ничем ограничены!
Например, можете импортировать изображение с конвертацией формата:
import { imagetools } from 'vite-imagetools';
export default defineNuxtConfig({
vite: {
plugins: [imagetools()],
},
});
Также полезным эффектом будет то, что уменьшается вероятность ошибиться. Вас также начнет проверять и TypeScript и будет подсказывать, если где-то в пути вы ошибетесь. Хотя вот с TypeScript может быть один нюанс - что это еще за импорт картинок такой?!
Чтобы TypeScript понимал импорты
В некоторых фреймворках по умолчанию настроена типизация импортируемых изображений, но иногда им нужно помочь.
К счастью делается это крайне просто. Вам нужно глобально объявить тип импортируемых файлов с расширением изображения. Например, если вы импортируете png:
declare module '*.png' {
const value: string;
export = value;
}
Очень просто, а TypeScript скажет вам спасибо!
Если картинки присылает Backend
В таком сценарии не надо изобретать велосипед и просто работайте со ссылками, которые он присылает. У Backend разработчиков в их фреймворках всегда есть инструментарий для генерации уникальных именований при загрузке изображений. Или на основе хеша, или добавляя uuid к имени файлов - доступные подходы есть разные.
Когда могут быть проблемы
К сожалению, даже разработчики фреймворков и библиотек, которые, обычно, довольно опытные люди, иногда забывают о подобном подходе в работе с файлами. И в итоге иногда не учитывают импорт изображений в своих библиотеках.
Пример подобной ошибки можно посмотреть в созданном мной issue в Nuxt Image библиотеке: Issue 1653. Однако даже тут я предлагаю решение и этой проблемы - надеюсь, разработчики библиотеки интегрируют решение в следующих версиях.
Заключение
Новый подход может быть по началу не привычным, возможно, вы автоматически будете по началу писать по старому, а потом исправлять решение. Но привыкнуть стоит, тем более, что это не так уж сложно, а польза от подхода с импортами есть. Главное стремиться делать свой код лучше😉