Изучение Vite через исходный код
Как вы, вероятно, слышали, в экосистеме front-end есть новый крутой инструмент для сборки под названием Vite. Хотя он был создан Эваном Ю (который также создал Vue.js), он не зависит от фреймворка, поэтому вы можете использовать Vite с Vue.js, React.js, Svelte.js или даже с обычным JavaScript.
В этой статье мы изучим Vite, чтобы получить некоторые сведения о его внутренней архитектуре. В частности, мы изучим системы шаблонов и плагинов Vite. В конце вы будете лучше понимать разницу между шаблонами и плагинами, а также то, как основная система Vite связана с плагином.
Теперь, без лишних слов, давайте создадим приложение с помощью Vite.
Создание приложения с Vite
Для данной демонстрации мы создадим проект Vue, используя эту команду:
npm init vite@latest
(Наличие @latest
гарантирует, что вы всегда получите последнюю версию, когда будете выполнять npm install
внутри этого нового проекта).
В качестве примечания, вы могли видеть устаревшую версию команды init
.
Как вы можете видеть, предупреждение об устарелости говорит нам использовать npm init vite
вместо этого.
Эта новая команда, по сути, является сокращением для:
npx create-vite
Это позволит установить и запустить инструмент под названием create-vite, который подскажет вам, какой проект вы создаете. Вы выберете имя и шаблон.
Выберите имя для вашего проекта.
И выберите шаблон для использования.
Для изучения вы можете использовать либо vanilla
, либо vue
.
Далее мы изучим инструмент create-vite
через его исходный код на GitHub.
Изучение исходного кода Vite
Сначала зайдите на страницу Vite в GitHub по адресу github.com/vitejs/vite.
Затем перейдите в папку packages
.
Здесь вы можете увидеть create-app
и create-vite
.
create-app
отвечает за первоначальную команду, которая говорит "deprecated (устаревший)". Здесь нас интересует папка create-vite
. В ней находятся все встроенные шаблоны для создания проектов.
Внутри папки packages
мы также можем увидеть несколько папок plugin для нескольких встроенных плагинов.
Теперь самое время изучить различия между шаблонами и плагинами, а также то, как они работают вместе в рабочем процессе инструмента сборки.
Шаблоны
Понятие шаблона можно легко понять: это стартовый код для нового проекта.
Внутри папки packages/create-vite
вы должны увидеть дюжину папок template-*
.
Как вы видите, Vite поддерживает шаблоны для различных фреймворков (и их TypeScript-аналогов).
Вы можете выбрать vanilla
в команде create-vite
.
Если вы выберете vanilla, он возьмет файлы из папки packages/template-vanilla
и клонирует их как ваш новый проект.
Вы также можете выбрать vue
из списка:
Если вы выбрали vue, он будет клонировать файлы в папке packages/template-vue
как ваш новый проект.
Сгенерированный проект из шаблона vue будет иметь стандартную структуру папок, которую вы ожидаете от проекта Vue.
Итак, это шаблон. Теперь поговорим о плагине.
Плагины
Как я уже говорил, Vite не привязан к конкретным фреймворкам. Он способен создавать проекты для различных фреймворков благодаря своей системе плагинов.
Из коробки Vite предоставляет плагины для Vue, Vue with JSX и React.
Вы можете изучить код каждого встроенного плагина в папке packages
:
Примечание: plugin-legacy
предназначен для устаревших браузеров, которые не поддерживают встроенный ESM.
Наиболее распространенный способ использования этих плагинов - через соответствующие шаблоны. Например, шаблон Vue требует использования плагина Vue, а шаблон React - плагина React.
Проект, созданный с помощью шаблона vanilla, не имеет представления о том, как обслуживать однофайловые файлы компонентов Vue (SFC). Но проект Vue, созданный с помощью Vite, сможет обрабатывать файлы типа SFC. И он также знает, как упаковать весь проект Vue для продакшена.
Если мы сравним соответствующие файлы package.json
шаблона Vue и ванильного шаблона, мы легко поймем, почему это так.
📁 /packages/template-vanilla/package.json
📁 /packages/template-vue/package.json
template-vue
содержит все то же, что и template-vanilla
, плюс три дополнительных пакета.
📁 /packages/template-vue/package.json
"dependencies": { "vue": "^3.2.6" // 1 }, "devDependencies": { "@vitejs/plugin-vue": "^1.6.1", // 2 "@vue/compiler-sfc": "^3.2.6", // 3 "vite": "^2.5.4" }
vue
- это основная библиотека, которая работает во время выполнения проекта@vitejs/plugin-vue
- плагин, отвечающий за обслуживание и компоновку проекта Vue@vue/compiler-sfc
необходим для компиляции SFC-файла
Поэтому можно с уверенностью сказать, что эти три пакета дают проекту Vite возможность понимать код Vue. Пакет @vitejs/plugin-vue
- это "мост", соединяющий ядро системы Vite с фреймворком Vue.js.
Vue-плагин
Как мы видели в package.json
плагина Vue, пакет @vitejs/plugin-vue
отвечает за сборку проекта Vue.
Vite делегирует работу по сборке Rollup, который является еще одним очень популярным инструментом сборки. Взаимосвязь между плагинами полагается на ядро vite
для вызова кода пакета плагина
в некоторые определенные моменты времени. Эти определенные моменты называются хуками. Разработчик плагина должен решить, какой код будет выполняться в каждом хуке.
Например, в исходном коде плагина Vue можно увидеть некоторые из этих хуков.
📁 /packages/plugin-vue/src/index.ts
async resolveId(id) { // component export helper if (id === EXPORT_HELPER_ID) { return id } if (parseVueRequest(id).query.vue) { return id } }, load(id, ssr = !!options.ssr) { if (id === EXPORT_HELPER_ID) { return helperCode } const { filename, query } = parseVueRequest(id) // выбрать соответствующий блок для виртуальных модулей подчастей if (query.vue) { if (query.src) { return fs.readFileSync(filename, 'utf-8') } const descriptor = getDescriptor(filename, options)! let block: SFCBlock | null | undefined if (query.type === 'script') { // обработка слияния <script> + <script setup> через compileScript() block = getResolvedScript(descriptor, ssr) } else if (query.type === 'template') { block = descriptor.template! } else if (query.type === 'style') { block = descriptor.styles[query.index!] } else if (query.index != null) { block = descriptor.customBlocks[query.index] } if (block) { return { code: block.content, map: block.map as any } } } }, transform(code, id, ssr = !!options.ssr) { const { filename, query } = parseVueRequest(id) if (query.raw) { return } if (!filter(filename) && !query.vue) { if (!query.vue && refTransformFilter(filename)) { if (!canUseRefTransform) { this.warn('refTransform requires @vue/compiler-sfc@^3.2.5.') } else if (shouldTransformRef(code)) { return transformRef(code, { filename, sourceMap: true }) } } return } if (!query.vue) { // основной запрос return transformMain( code, filename, options, this, ssr, customElementFilter(filename) ) } else { // запрос на подблок const descriptor = getDescriptor(filename, options)! if (query.type === 'template') { return transformTemplateAsModule(code, descriptor, options, this, ssr) } else if (query.type === 'style') { return transformStyle( code, descriptor, Number(query.index), options, this ) } } }
А в основном пакете vite
, Rollup будет использоваться для вызова вышеуказанных хуков плагина.
📁 /packages/vite/src/node/build.ts
// сначала собирает все используемые плагины const plugins = ( ssr ? config.plugins.map((p) => injectSsrFlagToHooks(p)) : config.plugins ) as Plugin[] ... // затем поместите плагины и все остальное в объект options const rollupOptions: RollupOptions = { input, preserveEntrySignatures: ssr ? 'allow-extension' : libOptions ? 'strict' : false, ...options.rollupOptions, plugins, external, onwarn(warning, warn) { onRollupWarning(warning, warn, config) } } ... // наконец, делегировать rollup const bundle = await rollup.rollup(rollupOptions)
Плагин Rollup очень похож на плагин Vite. Но поскольку Rollup не предназначен для использования в качестве инструмента сборки из коробки, плагин Vite будет иметь дополнительные опции и хуки, которые недоступны в классическом плагине Rollup.
Другими словами, плагин Vite - это расширение плагина Rollup.
Команды Vite
Возвращаясь к шаблону Vue, давайте уделим немного внимания опции scripts
.
📁 /packages/create-vite/template-vue/package.json
"scripts": { "dev": "vite", "build": "vite build", "serve": "vite preview" },
Это конфигурации, которые позволяют нам выполнять следующие команды внутри проекта Vite:
npm run dev
для запуска сервера разработкиnpm run build
для создания production сборкиnpm run serve
для предварительного локального просмотра указанной production сборки
Приведенные выше команды сопоставлены со следующими командами:
Как видите, пакет vite
- это то, с чего все начинается.
Вы можете получить представление о том, какие еще сторонние инструменты задействованы, заглянув в файл package.json
пакета vite
.
"dependencies": { "esbuild": "^0.12.17", "postcss": "^8.3.6", "resolve": "^1.20.0", "rollup": "^2.38.5" },
Как вы можете видеть, vite
на самом деле использует два разных пакетника за кадром: Rollup и esbuild.
Rollup vs esbuild
Vite использует оба этих пакетника для различных видов деятельности.
Rollup используется Vite для основных нужд пакетирования. А esbuild используется для совместимости и оптимизации модулей. Эти шаги известны как процесс "Предварительного объединения зависимостей" (Dependency Pre-bundling). Этот процесс считается "тяжелым", поскольку его необходимо выполнять на основе каждого модуля, а в проекте обычно используется много модулей.
Совместимость модулей означает преобразование различных форматов (модули UMD или CommonJS) в стандартный формат ESM.
Оптимизация предназначена для объединения всех различных файлов из одного зависимого пакета в одно "нечто", которое затем нужно получить только один раз.
Rollup был бы слишком медленным для обработки тяжелых вещей по сравнению с esbuild. Esbuild на самом деле является самым быстрым инструментом сборки. Он быстрый, потому что разработан на Go (язык программирования).
Вот сравнение, приведенное на сайте официальной документации.
Как видите, esbuild не просто быстрый, он находится на совершенно другом уровне. Вот почему Vite работает молниеносно.
Заключение
- команда
npm init vite
использует инструментcreate-vite
- пакет
create-vite
содержит все встроенные шаблоны - специфичный для фреймворка шаблон зависит от соответствующего специфичного для фреймворка плагина
- плагины реализованы в архитектуре, основанной на хуках
- Vite использует Rollup и esbuild за кадром.
Теперь у вас должно быть твердое понимание системы Vite. Но на практике вам понадобятся другие общие возможности, которые мы здесь не рассмотрели. Самыми распространенными из них являются поддержка TypeScript и препроцессора CSS.
Источник: https://www.sitepoint.com/exploring-vite-source-code/