Он слишком большой, как его распаковать? --vite
Он слишком большой, как его распаковать? --vite

В традиционном режиме одноблочной упаковки, когда код проекта становится все больше и больше, это в конечном итоге приводит к тому, что браузер загружает огромный файл. С точки зрения производительности загрузки страницы это в основном вызывает две проблемы:

  • Не могу этого сделатьЗагрузка по требованию,Даже если текущая страница не требует кода, она будет загружена.
  • онлайнЧастота повторного использования кэшачрезвычайно низкий,Изменение одной строки кода может привести к тому, что весь bundle аннулирование кэша продукта.

Давайте сначала поговорим о первом вопросе. Вообще говоря, на главной странице. JS Код можно разделить на две части: Initital ChunkиAsync Chunk,Первое относится к тому, что требуется на первом экране страницы.из JS код, и последний не обязательно требуется для текущей страницы. Типичный пример. компонент маршрутизации,Это не имеет никакого отношения к текущему маршруту и ​​компонент не нужно загружать. После упаковки проекта в единый пакет,ИлиInitial Chunkвсе ещеAsync Chunk,Все упаковано в один и тот же продукт,То есть,Когда браузер загружает код продукта из,Будут ли Воля оба загружены вместе?,В результате возникает множество дублирующих процессов загрузки.,что влияет на производительность страницы。И пройтиCode Splittingмы можем Воля Загрузка по программный код разделен на отдельные части chunk,Подать заявку вот таксуществовать Загружать нужно только при загрузке первого экранаInitial Chunk Вот и все: избегаются избыточные процессы загрузки и повышается производительность страницы.

Во-вторых,онлайнизКонец жизнисередина Ставкадаважныйизпоказатели производительности。дляонлайнсайтс точки внимание, сервер обычно добавляет немного при ответе на ресурсы HTTP Заголовок ответа,наиболее распространенныйиз Один из заголовков ответаcache-control,Он может указать браузеризСильное кэширование,Например, установите его следующим образом:

Язык кода:shell
копировать
cache-control: max-age=31536000

Указывает, что срок действия ресурса составляет один год.,существоватьдо истечения срока действия,доступТо же, что и URL-адрес ресурса,Браузер напрямую использует локальный кеш,Нет необходимости отправлять запрос на сервер,Это значительно снижает загрузку страниц и нагрузку на сеть. но,существоватьодин chunk В режиме упаковки при изменении строки кода весь chunk из url Адрес изменится.

Поскольку инструмент сборки обычно генерирует хеш-значение на основе содержимого продукта, как только содержимое изменяется, вся chunk продуктиз Сильное кэширование недействительно, поэтому одиночное chunk В режиме упаковкииз Конец жизнисередина Ставкачрезвычайно низкий,В основном ноль.

и продолжайтеCode Splittingпосле,Изменения кода повлияют только на часть чанка:

Вход Ссылки на файлыABCDчетыре компонента,когда мы изменяем A из Код после изменения из Chunk Только A киЗависит от A из чанка Средний, А Переписка chunk встречаизменять,Это легко понять,Последний такжевстречаизменятьда Потому что соответствующийизпредставлятьзаявлениевстречаизменять,Как здесьиз Входдокументвстречапроисходитьнравиться下内容изменять:

Язык кода:typescript
копировать
import CompA from './A.d3e2f17a.js'
// возобновлять import заявление
import CompA from './A.a5d2f82b.js'

Другими словами, изменение A изпосле кода,BCDиз chunk продукт url не изменилось, что позволяет браузеру повторно использовать локальное из Сильное кэширование, значительно улучшающее скорость загрузки онлайн-приложений.

Стратегия распаковки Vite по умолчанию

Мы только что говорили о том, зачем нам нужно распаковывать вещи. Vite В него уже встроена стратегия распаковки, давайте посмотрим на нее дальше. Vite Какой режим распаковки установлен по умолчанию?

в производственной среде Vite полностью использован Rollup для сборки, поэтому распаковка также основана на Rollup завершить из, но Rollup Это фокус сам по себе JS Инструментам упаковки библиотек по-прежнему не хватает возможностей создания приложений Vite. Это просто компенсирует это. Rollup Возможности создания приложений и существующие возможности распаковки хорошо отражены в этом расширении.

Давайте сначала испытаем это на конкретных проектах. Vite Распаковывая, я положил образец проекта в буклет. Gihub На складе у него можно поучиться.

существоватьпроектсерединаосуществлятьnpm run build,Затем в терминале появится следующая информация о сборке:

Пример использования проекта из is Vite 2.9 Предыдущая версия,Нажмите, чтобы войти в проект。Vite 2.9 Стратегия распаковки будущих версий будет другой, о чем будет сказано позже.

Здесь я объясню структуру продукта:

Язык кода:shell
копировать
.
├── assets
│   ├── Dynamic.3df51f7a.js    // Async Chunk
│   ├── Dynamic.f2cbf023.css   // Async Chunk (CSS)
│   ├── favicon.17e50649.svg   // Статические ресурсы
│   ├── index.1e236845.css     // Initial Chunk (CSS)
│   ├── index.6773c114.js      // Initial Chunk
│   └── vendor.ab4b9e1f.js     // Сторонние пакеты Chunk
└── index.html                 // Вход HTML

для Vite из возможности распаковки,отпродуктструктурасередина Это очевидно。

с одной стороны Vite Реализовано автоматическое Разделение CSS-кодаизспособность,То есть реализовать чанк. Соответствует одному CSS-файлу.,Например, вышепродуктсерединаindex.jsСоответствует одному экземпляруindex.css,и Загрузка по требованиюиз chunk Danamic.jsТакже соответствуетодинодинизодна порцияDanamic.cssдокумент,и JS Разделение файлов код Аналогично, это также может улучшить CSS Файл из Частота повторного использования кэша。

И еще одной стороны, Vite на основе Rollup изmanualChunksAPI выполнить ПонятноРаспаковка приложенияиз Стратегия:

  • для Initital Chunk с точки вопрос, бизнес-код и код стороннего пакета упаковываются отдельно из chunk,существоватьвышеизпримерсерединасоответствующий соответственноindex.jsиvendor.js。Нужно объяснениеизда,этотда Vite 2.9 Версия до практики и существования Vite 2.9 и более поздних версиях стратегия упаковки по умолчанию проще и грубее, сочетая в себе все js Все коды упакованы в index.js середина.
  • для Async Chunk с точки зрения , динамичный import код будет разбит на отдельные chunk,нравитьсявышеизDynacmicкомпоненты。

Подводя итог, Вите Реализована распаковка по умолчанию из существующего преимущества. CSS Разделение кода и бизнес-код, код сторонних библиотек, динамика import Код модуля триизразделение,Но недостатки также более интуитивны.,Упаковка сторонней библиотеки может легко раздуться.,вышепримерсерединаизvendor.jsизразмер достигнут 500 KB Выше явно есть место для дальнейшей распаковки и оптимизации, и нам нужно его использовать в данный момент. Rollup Распаковка API ——manualChunks .

Пользовательская стратегия распаковки

Для более детальной распаковки используйте Vite из Базовый механизм упаковки Rollup предоставилmanualChunks,Давайте Пользовательская стратегия распаковки, принадлежит Vite Конфигурацияизчасть,Примеры следующие:

Язык кода:typescript
копировать
// vite.config.ts
export default {
  build: {
    rollupOptions: {
      output: {
        // manualChunks Конфигурация
        manualChunks: {},
      },
    }
  },
}

manualChunks Существует две основные формы Конфигурации.,Может Конфигурациядля объекта или функции。Давайте сначала посмотрим на объектыиз Конфигурация,такжеда Самый простойодиниз Конфигурация Способ,ты Можетсуществоватьвышеиз Примерпроектсередина Добавьте следующееизmanualChunksКонфигурациякод:

Язык кода:typescript
копировать
// vite.config.ts
{
  build: {
    rollupOptions: {
      output: {
        // manualChunks Конфигурация
        manualChunks: {
          // Воля React Сопутствующие библиотеки упакованы отдельно. chunk середина
          'react-vendor': ['react', 'react-dom'],
          // Воля Lodash Код библиотеки упакован отдельно
          'lodash': ['lodash-es'],
          // Волякомпоненты Библиотекаизкод Пакет
          'library': ['antd', '@arco-design/web-react'],
        },
      },
    }
  },
}

существоватьформат объектаиз Конфигурациясередина,keyпредставлять chunk изимя,valueэто массив строк,Каждый товар представляет собой сторонний пакет.изимя пакета。существовать Действовало, как указано вышеиз Конфигурацияпосле,мы можемосуществлятьnpm run buildПопробуйте упаковку

Вы можете посмотреть оригинал vendor Большой файл разбивается на несколько маленьких файлов, которые мы указываем вручную. кусок, каждый chunk возможно 200 KB О, это более идеальный из chunk объем。так,Когда сторонние пакеты возобновляютсяиз,также只встречавозобновлять Чтосерединаодин chunk из url,и Нетвстреча Вся суммавозобновлять,отиулучшать Понятно Сторонние пакетыиз Конец жизнисередина Ставка。

кроме объектаиз Конфигурация Способснаружи,Мы также Можетпроходитьфункция Будьте более гибкимииз Конфигурация,и Vite серединаиз Стратегия распаковки по умолчаниютакжедапроходитьфункцияиз Способвыполнять Конфигурацияиз,мы можемсуществовать Vite извыполнитьсередина Взгляните:

Язык кода:typescript
копировать
// Vite Часть исходного кода
function createMoveToVendorChunkFn(config: ResolvedConfig): GetManualChunk {
  const cache = new Map<string, boolean>()
  // Возвращаемое значение manualChunks из Конфигурация
  return (id, { getModuleInfo }) => {
    // Vite по умолчаниюиз Конфигурациялогика Что Это действительно простоодин
    // В основном ставить Initial Chunk серединаиз Сторонний пакеткододинодин Пакет成`vendor.[hash].js`
    if (
      id.includes('node_modules') &&
      !isCSSRequest(id) &&
      // Определите, является ли это Initial Chunk
      staticImportedByEntry(id, getModuleInfo, cache)
    ) {
      return 'vendor'
    }
  }
}

Rollup будет вызываться для каждого модуля manualChunks функция, в manualChunks извходные параметры функциисерединаты Можетполучатьидентификатор модуля иДетали модуля,Через определенное времяиз Возврат после обработки имя файла фрагмента,таккогдавперед id Представитель модуля будет упакован в указанный вами размер. chunk в файле.

Давайте теперь попробуем реализовать логику распаковки с помощью функций:

Язык кода:typescript
копировать
manualChunks(id) {
  if (id.includes('antd') || id.includes('@arco-design/web-react')) {
    return 'library';
  }
  if (id.includes('lodash')) {
    return 'lodash';
  }
  if (id.includes('react')) {
    return 'react';
  }
}

Похоже, что различные сторонние пакеты chunk (нравитьсяlodashreactи т. д.)Его можно разделить,但实际上ты Можетбегать npx vite preview Предварительный просмотрпродукт,Вы обнаружите, что продукт вообще невозможно запустить.,На странице появляется белый экран,При этом на консоли появляется сообщение об ошибке

этоттакже就дафункция Конфигурацияиз Подводные камнисуществовать Понятно,Хоть и гибкий и удобный,Но если вы не обратите внимания, вы столкнетесь с такой проблемой. Так в чем же причина вышеуказанной ошибки?

Решение проблем с циклическими ссылками

от Сообщить об ошибкеотслеживаемая информацияпродуктсередина,Можетволосысейчасreact-vendor.jsиindex.jsпроисходить Понятноциклическая ссылка:

Язык кода:typescript
копировать
// react-vendor.e2c4883f.js
import { q as objectAssign } from "./index.37a7b2eb.js";

// index.37a7b2eb.js
import { R as React } from "./react-vendor.e2c4883f.js";

Это очень типичный сценарий циклической ссылки модуля ES. Мы можем использовать самый простой пример для восстановления этого сценария:

Язык кода:typescript
копировать
// a.js
import { funcB } from './b.js';

funcB();

export var funcA = () => {
  console.log('a');
} 
// b.js
import { funcA } from './a.js';

funcA();

export var funcB = () => {
  console.log('b')
}

затеммы можемосуществлятьодин разa.jsдокумент:

Язык кода:html
копировать
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <script type="module" src="/a.js"></script>
</body>
</html>

существовать Браузерсередина Открытьвстречавнесейчаспохожийиз Сообщить об ошибке

Принцип выполнения кода следующий:

    1. JS исполнение двигателя a.js Когда выяснилось, что введение b.js,Вдаидтиосуществлять b.js
    1. исполнение двигателяb.js,волосысейчасвпредставлять Понятноa.js(Возникает циклическая ссылка),думатьa.jsЗагрузка завершена,Продолжить выполнение
    1. осуществлятьприезжатьfuncA()заявлениеобнаружил, когда funcA Определения нет, поэтому сообщается об ошибке.

Процесс выполнения упакованного продукта такой же, как указано выше:

Возможно, у вас есть вопросы: react-vendorЗачем нужно цитированиеindex.jsизкод Шерстяная ткань?Что实также很好理解,нас ДосуществоватьmunaulChunksсерединатолько Воляпуть содержит react из Модули упакованы вreact-vendorсередина,Как все знают,картинаobject-assignЭтот вид react самиз Зависимости не упакованыreact-vendorсередина,ида Пакетприезжать另外из chunk когдасередина,Это приводит к следующим циклическим зависимостям:

Так можем ли мы избежать этой проблемы? Конечно, вы можете, прежде чем из manualChunksлогика过В简одингрубый,толькопроходитьпуть id решить, какой из них взять с собой chunk середина,искучать Понятнокосвенная зависимостьиз Состояние。нравиться Целевойкартинаobject-assignЭтот видкосвенная зависимость,Мы также можем определить, что это относится к реакции из зависимости.,Воля Что自动Пакетприезжатьreact-vendorсередина,Таким образом, вы можете избежать проблем с циклическими ссылками.

Разберем решения:

    1. Конечно react Связанные пакетыиз Входпуть。
    1. существовать manualChunks серединаполучить модуль подробнее,проследить это вверх по цитате,нравитьсяплодотворныйсередина react изпуть,Затем модуль Воля ставится в react-vendorсередина.

Далее приступим к фактической реализации кода:

Язык кода:typescript
копировать
// Конечно react Связанные пакетыиз Входпуть
const chunkGroups = {
  'react-vendor': [
    require.resolve('react'),
    require.resolve('react-dom')
  ],
}

// Vite серединаиз manualChunks Конфигурация
function manualChunks(id, { getModuleInfo }) { 
  for (const group of Object.keys(chunkGroups)) {
    const deps = chunkGroups[group];
    if (
      id.includes('node_modules') && 
      // Рекурсивный поиск реферера,исследоватьдаотрицать жизньсередина chunkGroups Выписка из упаковки 
      isDepInclude(id, deps, [], getModuleInfo)
     ) { 
      return group;
    }
  }
}

Фактически, основная логика содержитсуществоватьisDepIncludeфункция,Используется для рекурсивного поиска модуля реферера:

Язык кода:typescript
копировать
// Кэшировать объект
const cache = new Map();

function isDepInclude (id: string, depPaths: string[], importChain: string[], getModuleInfo): boolean | undefined  {
  const key = `${id}-${depPaths.join('|')}`;
  // Циклические зависимости возникают и не учитываются
  if (importChain.includes(id)) {
    cache.set(key, false);
    return false;
  }
  // Проверить кеш
  if (cache.has(key)) {
    return cache.get(key);
  }
  // Список зависимостей команды середина
  if (depPaths.includes(id)) {
    // Ссылочная цепочкасерединаиздокумент都记录приезжать缓存середина
    importChain.forEach(item => cache.set(`${item}-${depPaths.join('|')}`, true));
    return true;
  }
  const moduleInfo = getModuleInfo(id);
  if (!moduleInfo || !moduleInfo.importers) {
    cache.set(key, false);
    return false;
  }
  // Основная логика, рекурсивный поиск рефереров верхнего уровня.
  const isInclude = moduleInfo.importers.some(
    importer => isDepInclude(importer, depPaths, importChain.concat(id), getModuleInfo)
  );
  // Настроить кеш
  cache.set(key, isInclude);
  return isInclude;
};

При реализации функции дляиз необходимо обратить внимание на две вещи:

    1. мы можем пройти manualChunks поставлятьиз ВходgetModuleInfoчтобы получить модульиз ПодробностиmoduleInfo,тогда пройдиmoduleInfo.importersполучить модульиз Цитируется,Этот процесс может выполняться рекурсивно для каждого реферера.,Для получения информации о ссылочной цепочке.
    1. Используйте кэш, когда это возможно. Поскольку количество модулей сторонних пакетов обычно относительно велико,,Поиск цепочки ссылок для каждого модуля приведет к большим накладным расходам.,И это будет производить много повторяющейся логики,Использование кэша значительно ускорит этот процесс.

ЗаканчиватьвышеmanualChunksиз После полной логики,сейчассуществоватьнас来осуществлятьnpm run buildупаковать:

Можетволосысейчасreact-vendorМожет正常拆分вне来,Посмотреть его содержимое

отсерединаты Может看внеreactиз一些косвенная зависимость已经成功Пакетприезжать Понятноreact-vendorкогдасередина,осуществлятьnpx view previewПредварительный просмотрпродукт页面также能正常渲染Понятно

Это показывает, что проблема циклической зависимости нами решена.

окончательное решение

Хотя приведенные выше решения уже могут помочь нам нормально распаковать продукт.,Но с точки зрения реализации,Все равно кажется немного громоздким,Так есть ли какое-нибудь готовое решение для распаковки?,能让нас直接用приезжатьпроектсередина Шерстяная ткань?

Ответ — да, я познакомлю вас с этим дальше. Vite Заказная распаковка изокончательное решение——vite-plugin-chunk-split

Сначала установите этот плагин:

Язык кода:typescript
копировать
pnpm i vite-plugin-chunk-split -D

Затем вы можете представить и использовать его в своем проекте:

Язык кода:typescript
копировать
// vite.config.ts
import { chunkSplitPlugin } from 'vite-plugin-chunk-split';

export default {
  chunkSplitPlugin({
    // Укажите стратегию распаковки
    customSplitting: {
      // 1. Поддержка заполнения имени пакета. `реагировать` и `react-dom` будет упакован в файл с именем `render-vendor`iz chunk внутри (включая их зависимости, такие как object-assign)
      'react-vendor': ['react', 'react-dom'],
      // 2. Поддержка заполнения регулярных выражений. источник середина components и utils Все файлы в папке будут упакованы как `comment-util`iz. chunk середина
      'components-util': [/src\/components/, /src\/utils/]
    }
  })
}

По сравнению с зависимостями, работающими вручную, использование плагина можно завершить всего несколькими строками конфигурации, что очень удобно. Конечно, этот плагин также может поддерживать различные стратегии упаковки, в том числе unbundle Выкройка упаковки, вы можете перейти на Используйте документацию Узнайте больше об использовании.

Я участвую в третьем этапе специального тренировочного лагеря Tencent Technology Creation 2023 с эссе, получившими приз, и сформирую команду, которая разделит приз!

boy illustration
Неразрушающее увеличение изображений одним щелчком мыши, чтобы сделать их более четкими артефактами искусственного интеллекта, включая руководства по установке и использованию.
boy illustration
Копикодер: этот инструмент отлично работает с Cursor, Bolt и V0! Предоставьте более качественные подсказки для разработки интерфейса (создание навигационного веб-сайта с использованием искусственного интеллекта).
boy illustration
Новый бесплатный RooCline превосходит Cline v3.1? ! Быстрее, умнее и лучше вилка Cline! (Независимое программирование AI, порог 0)
boy illustration
Разработав более 10 проектов с помощью Cursor, я собрал 10 примеров и 60 подсказок.
boy illustration
Я потратил 72 часа на изучение курсорных агентов, и вот неоспоримые факты, которыми я должен поделиться!
boy illustration
Идеальная интеграция Cursor и DeepSeek API
boy illustration
DeepSeek V3 снижает затраты на обучение больших моделей
boy illustration
Артефакт, увеличивающий количество очков: на основе улучшения характеристик препятствия малым целям Yolov8 (SEAM, MultiSEAM).
boy illustration
DeepSeek V3 раскручивался уже три дня. Сегодня я попробовал самопровозглашенную модель «ChatGPT».
boy illustration
Open Devin — инженер-программист искусственного интеллекта с открытым исходным кодом, который меньше программирует и больше создает.
boy illustration
Эксклюзивное оригинальное улучшение YOLOv8: собственная разработка SPPF | SPPF сочетается с воспринимаемой большой сверткой ядра UniRepLK, а свертка с большим ядром + без расширения улучшает восприимчивое поле
boy illustration
Популярное и подробное объяснение DeepSeek-V3: от его появления до преимуществ и сравнения с GPT-4o.
boy illustration
9 основных словесных инструкций по доработке академических работ с помощью ChatGPT, эффективных и практичных, которые стоит собрать
boy illustration
Вызовите deepseek в vscode для реализации программирования с помощью искусственного интеллекта.
boy illustration
Познакомьтесь с принципами сверточных нейронных сетей (CNN) в одной статье (суперподробно)
boy illustration
50,3 тыс. звезд! Immich: автономное решение для резервного копирования фотографий и видео, которое экономит деньги и избавляет от беспокойства.
boy illustration
Cloud Native|Практика: установка Dashbaord для K8s, графика неплохая
boy illustration
Краткий обзор статьи — использование синтетических данных при обучении больших моделей и оптимизации производительности
boy illustration
MiniPerplx: новая поисковая система искусственного интеллекта с открытым исходным кодом, спонсируемая xAI и Vercel.
boy illustration
Конструкция сервиса Synology Drive сочетает проникновение в интрасеть и синхронизацию папок заметок Obsidian в облаке.
boy illustration
Центр конфигурации————Накос
boy illustration
Начинаем с нуля при разработке в облаке Copilot: начать разработку с минимальным использованием кода стало проще
boy illustration
[Серия Docker] Docker создает мультиплатформенные образы: практика архитектуры Arm64
boy illustration
Обновление новых возможностей coze | Я использовал coze для создания апплета помощника по исправлению домашних заданий по математике
boy illustration
Советы по развертыванию Nginx: практическое создание статических веб-сайтов на облачных серверах
boy illustration
Feiniu fnos использует Docker для развертывания личного блокнота Notepad
boy illustration
Сверточная нейронная сеть VGG реализует классификацию изображений Cifar10 — практический опыт Pytorch
boy illustration
Начало работы с EdgeonePages — новым недорогим решением для хостинга веб-сайтов
boy illustration
[Зона легкого облачного игрового сервера] Управление игровыми архивами
boy illustration
Развертывание SpringCloud-проекта на базе Docker и Docker-Compose