Статическая обработка ресурсов — распространенная проблема, с которой сталкиваются интерфейсные проекты.,существуют Реальные проекты включают в себя нечто большее, чем просто динамическое выполнение кода.,Также неизбежно введение различных статических ресурсов.,нравитьсякартина
、JSON
、Worker документ
、Файлы веб-сборки
и т. д.。
Сами статические ресурсы не являются модулями в стандартном понимании.,Так что для нихизиметь дело сиобычноиз К коду нужно относиться по-другомуиз。С одной стороны, нам нужно решитьЗагрузка ресурсовизвопрос,верно Vite Другими словами, как анализировать и загружать статические ресурсы в ES 模块извопрос;с другой сторонысуществоватьпроизводственная средаДалее нам также необходимо рассмотреть статические ресурсы.из部署вопрос、Проблема с громкостью、Производительность сетивопрос,и принять соответствующиеизпланирую продолжитьоптимизация。
В этой статье я обсужу с вами эти два аспекта, объединив собственные возможности Vite и его экологию для решения различных трудностей при обработке статических ресурсов в проекте, а также продолжу улучшать текущий проект строительных лесов Vite.
Изображения являются одними из наиболее часто используемых статических ресурсов в проектах и включают в себя множество форматов, например png, jpeg, webp, avif, gif, конечно, включая те, которые часто используются в качестве иконок svg Формат。В этой части мы в основном обсуждаемизданравитьсячтонагрузкакартина,也就да说怎么让картинасуществоватьна страницеНормальный дисплей。
В процессе ежедневной разработки проектов мы обычно сталкиваемся с тремя сценариями загрузки изображений:
<img src="../../assets/a.png"></img>
background: url('../../assets/b.png') norepeat;
src
свойство,нравиться:document.getElementById('hero-img').src = '../../assets/c.png'
конечно,Обычно у каждого есть требования к пути к псевдониму.,Сравниватьнравитьсяпрефикс адреса Заменить непосредственно на@assets
,так устраняется необходимость разработчикам вручную решать,Уменьшите умственную нагрузку во время разработки.
Далее давайте выполним фактическое кодирование текущего проекта строительных лесов. Вы можете настроить псевдоним в файле конфигурации Vite, чтобы облегчить последующее введение изображения:
// vite.config.ts
import path from 'path';
{
resolve: {
// Конфигурация псевдонима
alias: {
'@assets': path.join(__dirname, 'src/assets')
}
}
}
так Vite существоватьвстретиться@assets
путьизкогда,Это автоматически поможет нам найти корневой каталог.изsrc/assets
Оглавление。Стоит отметить, что,alias Настройка псевдонимов есть не только в JavaScript из import Оно вступает в силу в заявлении, в CSS Код из @import
и url
Это также вступает в силу в операторе импорта.。
Сейчас src/assets
Оглавлениеизсодержаниенравиться Вниз:
.
├── icons
│ ├── favicon.svg
│ ├── logo-1.svg
│ ├── logo-2.svg
│ ├── logo-3.svg
│ ├── logo-4.svg
│ ├── logo-5.svg
│ └── logo.svg
└── imgs
├── background.png
└── vite.png
Далее мы Header представлен в компоненте vite.png
Вот этоткартина:
// Header/index.tsx
import React, { useEffect } from 'react';
import { devDependencies } from '../../../package.json';
import styles from './index.module.scss';
// 1. Импортировать изображения
import logoSrc from '@assets/imgs/vite.png';
// Способ первый
export function Header() {
return (
<div className={`p-20px text-center ${styles.header}`}>
<!-- Опустить предыдущее содержимое компонента -->
<!-- Используйте изображения -->
<img className="m-auto mb-4" src={logoSrc} alt="" />
</div>
);
}
// Способ 2
export function Header() {
useEffect(() => {
const img = document.getElementById('logo') as HTMLImageElement;
img.src = logoSrc;
}, []);
return (
<div className={`p-20px text-center ${styles.header}`}>
<!-- Опустить предыдущее содержимое компонента -->
<!-- Используйте изображения -->
<img id="logo" className="m-auto mb-4" alt="" />
</div>
);
}
Видно, что изображение может отображаться нормально
икартинапуть也被анализировать为了正确из Формат(/
表示项目根путь)
ОК, сейчас давайте войдём Header компонентыизстильдокумент Добавитьbackground
свойство:
.header {
// Предыдущий код стиля опущен.
background: url('@assets/imgs/background.png') no-repeat;
}
Вернитесь в браузер еще раз, и вы увидите фон после вступления в силу.
Только что мы успешно Vite Изображения изнагрузки реализуются такими способами нагрузки для svg Формат по-прежнему актуален. Однако обычно мы также хотим иметь возможность svg Представленный как индивидуальный компонент, мы можем легко его изменить. svg из Различные атрибуты и более img Тег из представлен более элегантно.
SVG Реализация в разных интерфейсных фреймворках неодинакова.,Также в сообществе есть поддержка соответствующих плагинов:
Сейчас Установим соответствующие зависимости в существующий проект React scaffolding:
pnpm i vite-plugin-svgr -D
Затем вам нужно добавить этот плагин в файл конфигурации vite:
// vite.config.ts
import svgr from 'vite-plugin-svgr';
{
plugins: [
// Другие плагины опущены
svgr()
]
}
Тогда обратите внимание на tsconfig.json
Добавьте следующую конфигурацию, иначе будет ошибка типа:
{
"compilerOptions": {
// Опустить другую конфигурацию
"types": ["vite-plugin-svgr/client"]
}
}
Далее давайте воспользуемся компонентом svg в нашем проекте:
import { ReactComponent as ReactLogo } from '@assets/icons/logo.svg';
export function Header() {
return (
// Содержимое других компонентов опущено
<ReactLogo />
)
}
Вернувшись в браузер, вы можете увидеть, что svg успешно отрисован:
Vite Уже встроен в JSON документизанализировать,Низкоуровневое использование@rollup/pluginutils
из dataToEsm
метод будет JSON Объект, преобразованный в индивидуальный, содержащий различные именованные экспорты из ES Модуль, порядок использования следующий:
import { version } from '../../../package.json';
Однако вы также можете настроить документ, чтобы отключить импорт по имени:
// vite.config.ts
{
json: {
stringify: true
}
}
такволя JSON изсодержаниеанализировать为export default JSON.parse("xxx")
,такпроиграетЭкспортировать по имени
изспособность,Однако если объем данных JSON относительно велик,,Можетоптимизацияанализировать性能。
Vite используется в Web Worker тоже очень просто,我们Можетсуществовать НовыйHeader/example.js
документ:
const start = () => {
let count = 0;
setInterval(() => {
// Передать значение в основной поток
postMessage(++count);
}, 2000);
};
start();
затем в Header представлен в компоненте,представлятьизкогда Уведомление加上?worker
суффикс,Эквивалентно рассказу Vite это Сценарий веб-рабочегодокумент:
import Worker from './example.js?worker';
// 1. инициализация Worker Пример
const worker = new Worker();
// 2. Прослушивание основного потока worker из информации
worker.addEventListener('message', (e) => {
console.log(e);
});
Откройте браузер из панели управления, вы увидите Worker Перенесено в основную тему из информации Напечатано успешно:
иллюстрировать Сценарий веб-рабочего успешно выполнен и может нормально взаимодействовать с основным потоком.
Vite для .wasm
документ также обеспечивает готовую поддержку, мы берем индивидуальный Фибоначчи из .wasm
документ(Оригиналдокумент Уже размещеноРепозиторий на Гитхабесередина)来进行一Вниз实际操作,верно应из JavaScript Исходный документ выглядит следующим образом:
export function fib(n) {
var a = 0,
b = 1;
if (n > 0) {
while (--n) {
let t = a + b;
a = b;
b = t;
}
return b;
}
return a;
}
Давайтесуществоватькомпонентысередина导入fib.wasm
документ:
// Header/index.tsx
import init from './fib.wasm';
type FibFunc = (num: number) => number;
init({}).then((exports) => {
const fibFunc = exports.fib as FibFunc;
console.log('Fib result:', fibFunc(10));
});
Vite 会верно.wasm
документизсодержание进行封装,Экспорт по умолчанию init функция, эта функция возвращает Обещай, чтобы мы могли then методсередина拿到其导出изчлен——fib
метод。
Вернуться в браузер,Мы видим результаты расчета,иллюстрировать .wasm Файл успешно выполнен
В дополнение к вышеуказанным форматам ресурсов Vite также предоставляет встроенную поддержку следующих форматов:
mp4
、webm
、ogg
、mp3
、wav
、flac
иaac
。woff
、woff2
、eot
、ttf
и otf
。webmanifest
、pdf
иtxt
。То есть, вы можете Vite Думайте об этих типах документов как об индивидуальном ES модуль для импорта и использования。нравиться Если тыиз项目середина还存существовать其它Форматиз Статические ресурсы,你Может通过assetsInclude
Конфигурация让 Vite Для поддержки загрузки:
// vite.config.ts
{
assetsInclude: ['.gltf']
}
Vite При добавлении статических ресурсов в , он также поддерживает добавление некоторых специальных файлов в конце пути существования. query Суффиксы, в том числе:
?url
: Указывает на получение ресурса по пути. Это существование хочет получить только путь к документу, а не содержимое по сценарию.?raw
: 表示获取ресурсиз字符串содержание,нравиться Если ты只想拿到ресурсиз Оригинал始содержание,Вы можете использовать индивидуальный суффикс.?inline
: Указывает, что ресурс принудительно встраивается, а не упаковывается в отдельный документ.существовать Переднийизсодержаниесередина,мы окружаемнравитьсячтонагрузка Статические ресурсыэтотиндивидуальныйвопрос,существовать Vite Выполните конкретные методы кодирования в Vite Вы уже знакомы с использованием различных статических ресурсов. Но с другой стороны, существующаяпроизводственная Теперь мы столкнулись с некоторыми новыми проблемами.
Обычно существуют, когда мы посещаем сайты в Интернете.,Некоторые статические адреса ресурсов на сайте содержат соответствующее доменное имя и префикс.,нравиться:
<img src="https://sanyuan.cos.ap-beijing.myqcloud.com/logo.png" />
Возьмите приведенный выше пример индивидуального адреса.,https://sanyuan.cos.ap-beijing.myqcloud.com
да CDN префикс адреса,/logo.png
则да我们开发阶段使用изпуть。Так,Нужно ли нам загружать изображения в CDN перед выходом в Интернет?,Затем вручную заменить адрес из в коде на онлайн-адрес? так это слишком много хлопот!
существования В Vite у нас может быть более автоматизированный способ замены адресов.,Просто нужносуществовать Конфигурациядокументсередина指定base
параметров достаточно:
// vite.config.ts
// Он не производится среда,существоватьпроизводственная окружающая среда обычно вводит NODE_ENV Эта отдельная переменная среды, см. ниже в документе конфигурации переменной среды.
const isProduction = process.env.NODE_ENV === 'production';
// Заполните пункт из CDN Адрес доменного имени
const CDN_URL = 'xxxxxx';
// Конкретное размещение
{
base: isProduction ? CDN_URL: '/'
}
// .env.development
NODE_ENV=development
// .env.production
NODE_ENV=production
Уведомлениесуществовать项目根Оглавление新增издваиндивидуальныйпеременные средыдокумент.env.development
и.env.production
,Как следует из названия,То есть отдельно существующая среда разработки ипроизводственная среда вводят некоторые переменные среды.,этот里为了区分другой环境我们加上了NODE_ENV
,При необходимости вы также можете добавить другие переменные среды.
При упаковке Vite автоматически заменит эти переменные среды соответствующими строками.
Затем выполнитеpnpm run build
,Можно обнаружить, что статический адрес ресурса в продукте был автоматически добавлен с префиксным адресом CDN.
Конечно, HTML Немного средний JS、CSS Также добавлены ссылки на ресурсы. CDN префикс адреса
конечно,Иногда некоторые изображения в проекте необходимо сохранить в другом хранилище.,Простое решение — записать полный адрес в свойства src, например:
<img src="https://my-image-cdn.com/logo.png">
очевидно, что это не очень элегантно из-за,Мы можем решить эту проблему, определив переменные среды индивидуально.,существовать项目根Оглавление新增.env
документ:
// Приоритет среды разработки: .env.development > .env
// производственная Приоритет окружающей среды: .env.production > .env
// .env документ
VITE_IMG_BASE_URL=https://my-image-cdn.com
затем введите src/vite-env.d.ts
Добавить объявление типа:
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_APP_TITLE: string;
// Настраиваемые переменные среды
readonly VITE_IMG_BASE_URL: string;
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}
Стоит отметить, что,нравиться Гоиндивидуальныйпеременные среды要существовать Vite проходить import.meta.env
доступ,Так它必须以VITE_
начало,нравитьсяVITE_IMG_BASE_URL
。Далее мыкомпонентысередина来使用этотиндивидуальныйпеременные среды:
<img src={new URL('./logo.png', import.meta.env.VITE_IMG_BASE_URL).href} />
接Вниз来существоватьсреда разработки
Начать проектилипроизводственная среда
打包后Может看到переменные среды已经被替换,Адрес может Нормальный дисплей
До сих пор,Мы полностью решили эту проблемукартинаресурспроизводственная Замена доменного имени среды из-за проблемы.
существовать Vite , все статические ресурсы имеют два метода создания: один — упаковать в отдельный документ, а другой — base64 Кодировка из формата встроена в код.
Как выбрать между этими двумя вариантами?
для относительно небольших ресурсов,Подходит для встраивания в код,一方面верноРазмер кода
изнебольшое влияние,С другой стороны, это может уменьшить количество ненужных сетевых запросов.,оптимизация Производительность сети
。идля Сравнивать较大изресурс,Рекомендуется упаковывать его отдельно в один индивидуальный документ.,вместо встроенного,В противном случае это может привести к MB из base64 Строки встраиваются в код, в результате чего размер кода мгновенно становится большим, а производительность загрузки страниц резко падает.
Vite середина内置изоптимизацияпланда Вниз面такиз:
вышеиз4 KB
То есть отозвать заказдокументизкритическое значение,конечно,этотиндивидуальныйкритическое значение你Может通过build.assetsInlineLimit
自行Конфигурация,нравиться Вниз代码所示:
// vite.config.ts
{
build: {
// 8 KB
assetsInlineLimit: 8 * 1024
}
}
Издокумент на формат svg не зависит от этого индивидуального временного значения.,Всегда будет упаковываться отдельно,Потому что это и обычный формат картинок разные,Некоторые свойства необходимо устанавливать динамически
картинаресурсизобъем往往да项目产物объемиз Большая голова,нравитьсябыть максимально упрощеннымкартинаизобъем,Такверно项目整体打包产物объемизоптимизация将会да非常明显из。существовать JavaScript Есть очень известный человек в области из Сжатие. изображения Библиотекаimagemin,Как инструмент низкоуровневого сжатия,На этом часто основываются фронтенд-проекты.,Сравниватьнравиться Webpack середина大名鼎鼎изimage-webpack-loader
。社区当середина也已经有了开箱即用из Vite плагин——vite-plugin-imagemin
,Сначала давайте установим его:
pnpm i vite-plugin-imagemin -D
впоследствиисуществовать Vite Представлено в файле конфигурации:
//vite.config.ts
import viteImagemin from 'vite-plugin-imagemin';
{
plugins: [
// Игнорировать предыдущий плагин
viteImagemin({
// Конфигурация сжатия без потерь, качество изображения не ухудшается при сжатии без потерь.
optipng: {
optimizationLevel: 7
},
// Конфигурация сжатия с потерями, качество изображения может ухудшиться при сжатии с потерями.
pngquant: {
quality: [0.8, 0.9],
},
// svg оптимизация
svgo: {
plugins: [
{
name: 'removeViewBox'
},
{
name: 'removeEmptyAttrs',
active: false
}
]
}
})
]
}
接Вниз来我们Может尝试执行pnpm run build
Упаковка
Vite Плагин автоматически помог нам позвонить imagemin
Сожмите изображение проекта, вы увидите, что эффект сжатия очень очевиден, настоятельно рекомендуется всем, кто существует в проекте. в。
существуют В реальных проектах мы часто используем различные виды svg хотя значок svg Файлы обычно небольшого размера, но Vite серединадля svg документ всегда будет упакован в один документ. Введение большого количества значков приведет к увеличению количества сетевых запросов. HTTP Запрос приведет к тому, что синтаксический анализ сети займет больше времени, и это напрямую повлияет на производительность загрузки страниц. Как решить эту проблему?
HTTP2 Мультиплексирование позволяет решить большое количество HTTP из-за запросов, из-за проблем с производительностью сетевой нагрузки, поэтому технология Sprite существует HTTP2 Нет явного эффекта изоптимизации,этотиндивидуальный Технология более подходитсуществовать Традицияиз HTTP 1.1 Используется в сценариях (таких как локальное из Dev Server)。
Сравниватьнравитьсясуществовать Header представлено отдельно в 5 индивидуальный svg документ:
import Logo1 from '@assets/icons/logo-1.svg';
import Logo2 from '@assets/icons/logo-2.svg';
import Logo3 from '@assets/icons/logo-3.svg';
import Logo4 from '@assets/icons/logo-4.svg';
import Logo5 from '@assets/icons/logo-5.svg';
Кстати, Вите середина提供了import.meta.glob
из语法糖来解决этот种Пакетный импортизвопрос,нравитьсявышеиз import Утверждение можно записать так:
const icons = import.meta.glob('../../assets/icons/logo-*.svg');
Виден объект из value Это все динамично импорт, подходящий для сценариев по требованию. существования Здесь нам нужно только синхронизировать нагрузку, которую можно использовать import.meta.globEager
завершить:
const icons = import.meta.globEager('../../assets/icons/logo-*.svg');
icons
из Печать результатовнравиться Вниз
Далее мы немного разбираем его, а затем применяем svg к компоненту:
// Header/index.tsx
const iconUrls = Object.values(icons).map(mod => mod.default);
// Содержимое возврата компонента добавляется следующим образом
{iconUrls.map((item) => (
<img src={item} key={item} width="50" alt="" />
))}
Вернувшись на страницу, мы обнаружили, что браузер выдал 5 индивидуальный svg изпросить
Предположим, что на странице есть 100 индивидуальный svg значок, будет еще 100 индивидуальный HTTP запрос и так далее. можем ли мы поставить это svg А как насчет объединения их вместе, чтобы значительно сократить сетевые запросы?
答案да Можетиз。этот种合并图标из План еще называютСпрайтовое изображение
,我们Может通过vite-plugin-svg-icons
来实现этотиндивидуальныйплан,Сначала установите этот индивидуальный плагин:
pnpm i vite-plugin-svg-icons -D
затемсуществовать Vite Добавьте в файл конфигурации следующее содержимое:
// vite.config.ts
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons';
{
plugins: [
// Опустить другие плагины
createSvgIconsPlugin({
iconDirs: [path.join(__dirname, 'src/assets/icons')]
})
]
}
существовать src/components
Оглавление Вниз НовыйSvgIcon
Компоненты:
// SvgIcon/index.tsx
export interface SvgIconProps {
name?: string;
prefix: string;
color: string;
[key: string]: string;
}
export default function SvgIcon({
name,
prefix = 'icon',
color = '#333',
...props
}: SvgIconProps) {
const symbolId = `#${prefix}-${name}`;
return (
<svg {...props} aria-hidden="true">
<use href={symbolId} fill={color} />
</svg>
);
}
Сейчасмы возвращаемся в Header Компонент, слегка измененный:
// index.tsx
const icons = import.meta.globEager('../../assets/icons/logo-*.svg');
const iconUrls = Object.values(icons).map((mod) => {
// нравиться ../../assets/icons/logo-1.svg -> logo-1
const fileName = mod.default.split('/').pop();
const [svgName] = fileName.split('.');
return svgName;
});
// рендеринг svg компоненты
{iconUrls.map((item) => (
<SvgIcon name={item} key={item} width="50" height="50" />
))}
наконецсуществоватьsrc/main.tsx
документ Добавить一行代码:
import 'virtual:svg-icons-register';
Сейчас Вернуться в браузеризна странице,Обнаружить Спрайтовое изображение Уже создано
Спрайтовое изображение Содержит все значкииз具体содержание,И для каждой страницы индивидуальный значок,тогда пройди use
свойство来引用Спрайтовое изображениеизверно应содержание
нравиться На этот раз,Мы можем разместить все svg контент встроен в HTML , что экономит много svg из Сетевой запрос.
Я участвую в специальном учебном лагере Tencent Technology Creation 2023 Третий. выпуск Конкурс сочинений, получивший приз. Соберите команду, чтобы выиграть приз!