Как вы, наверное, слышали, у интерфейсной экосистемы появился новый классный ребенок: инструмент сборки под названием Vite. Хотя он был создан Эваном Ю (который также создал Vue. js), он не зависит от фреймворка, поэтому вы можете использовать Vite с Vue. js, React. js, Svelte. js или даже ванильным JavaScript.
В этой статье мы расширим обзор, который уже был здесь опубликован, и изучим исходный код Vite, чтобы получить некоторое представление о его внутренней архитектуре. В частности, мы исследуем системы шаблонов и плагинов Vite. К концу вы лучше поймете разницу между шаблонами и плагинами, а также то, как основная система Vite связана с плагином.
Теперь, без лишних слов, давайте создадим приложение с Vite.
Создание приложения с Vite
Для целей этой демонстрации мы создадим проект Vue, используя эту команду:
npm init vite@latest
(Наличие @latestwill гарантирует, что вы всегда будете получать последнюю версию, когда будете 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отвечал за исходную команду с надписью «устарело». Что нас здесь интересует, так это create-viteпапка. В нем размещены все встроенные шаблоны для создания проектов.
Внутри packagesпапки мы также можем увидеть несколько папок плагинов для нескольких встроенных плагинов.
Теперь самое время изучить различия между шаблонами и плагинами и то, как они работают вместе в рабочем процессе инструмента сборки.
Шаблоны
Шаблон должен быть простой для понимания концепцией: это стартовый код для нового проекта.
Внутри packages/create-viteпапки вы должны увидеть с десяток template-*папок.
📁 /packages/create-vite
Как видите, Vite поддерживает шаблоны для различных фреймворков (и их аналоги на TypeScript).
Вы можете выбрать vanillaиз create-viteподсказки.
Если вы выберете ванильный, он в основном возьмет файлы в packages/template-vanillaпапке и клонирует их как ваш новый проект.
📁 /packages/template-vanilla
Вы также можете выбрать vueиз подсказки:
Если вы выберете vue, он будет клонировать файлы в packages/template-vueпапке как ваш новый проект.
📁 /packages/template-vue
Созданный проект из шаблона vue будет иметь стандартную структуру папок, которую вы ожидаете от проекта Vue.
Итак, это шаблон. Теперь поговорим о плагине.
Плагины
Как я уже упоминал, Vite не зависит от фреймворка. Он может создавать проекты для различных фреймворков благодаря своей системе плагинов.
По умолчанию Vite предоставляет плагины для Vue, Vue с JSX и React.
Вы можете изучить код каждого встроенного плагина в packagesпапке:
📁 /packages
Примечание: plugin-legacyпредназначен для устаревших браузеров, которые не поддерживают собственный ESM.
Чаще всего эти плагины используются с помощью соответствующих им шаблонов. Например, шаблон Vue потребует использования плагина Vue, а шаблон React потребует использования плагина React.
В качестве простого варианта проект, созданный с использованием стандартного шаблона, не знает, как обслуживать файлы однофайловых компонентов (SFC) Vue. Но проект 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
Как мы видели в плагине Vue package. json, @vitejs/plugin-vueпакет отвечает за объединение проекта Vue.
Vite делегирует работу по объединению в Rollup, еще один очень популярный инструмент для сборки. Отношения между плагинами основаны на том, что viteядро вызывает pluginкод пакета в определенные моменты времени. Эти специфические точки называются » крючками «. Разработчик плагина должен решить, какой код будет выполняться в каждом хуке.
Например, в исходном коде плагина Vue вы можете увидеть, как реализованы некоторые из этих хуков.
📁 /packages/plugin-vue/src/index.ts
async resolveId(id) { // component export helper if (id === EXPORT_HELPER_ID) { return id } // serve sub-part requests (*?vue) as virtual modules if (parseVueRequest(id).query.vue) { return id } }, load(id, ssr = !!options.ssr) { if (id === EXPORT_HELPER_ID) { return helperCode } const { filename, query } = parseVueRequest(id) // select corresponding block for sub-part virtual modules 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') { // handle <scrip> + <script setup> merge via 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) { // main request return transformMain( code, filename, options, this, ssr, customElementFilter(filename) ) } else { // sub block request 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
// first, gathers all the plugins used const plugins = ( ssr ? config.plugins.map((p) => injectSsrFlagToHooks(p)) : config.plugins ) as Plugin[] ... // then, put the plugins and everything else in an options object const rollupOptions: RollupOptions = { input, preserveEntrySignatures: ssr ? 'allow-extension' : libOptions ? 'strict' : false, ...options.rollupOptions, plugins, external, onwarn(warning, warn) { onRollupWarning(warning, warn, config) } } ... // lastly, delegate to 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 для создания производственной сборки
- npm run serve для предварительного просмотра указанной производственной сборки на месте
Вышеуказанные команды сопоставлены со следующими командами:
- vite
- vite build
- vite preview
Как видите, viteвсе начинается с пакета.
Вы можете получить представление о том, какие другие сторонние инструменты задействованы, заглянув в package.jsonфайл viteпакета.
📁 /packages/vite/package.json
"dependencies": { "esbuild": "^0.12.17", "postcss": "^8.3.6", "resolve": "^1.20.0", "rollup": "^2.38.5" },
Как видите, viteна самом деле за сценой используются два разных сборщика: Rollup и esbuild.
Rollup против esbuild
Vite использует оба этих бандлера для разных видов деятельности.
Накопительный пакет используется Vite для основных нужд объединения. А esbuild используется для совместимости и оптимизации модулей. Эти шаги известны как процесс «предварительного объединения зависимостей». Этот процесс считается «тяжелым», потому что он должен выполняться для каждого модуля, а в проекте обычно используется много модулей.
Совместимость модулей означает преобразование различных форматов (модули UMD или CommonJS) в стандартный формат ESM.
Оптимизация предназначена для объединения всех различных файлов из одного зависимого пакета в одну «вещь», которую затем нужно получить только один раз.
Rollup будет слишком медленным, чтобы справиться с этими сверхмощными вещами по сравнению с esbuild. Esbuild на самом деле самый быстрый инструмент для сборки. Это быстро, потому что он разработан на Go (языке программирования).
Как видите, esbuild не просто быстрый; это на совершенно другом уровне. И поэтому Vite работает молниеносно. ⚡
Заключение
В этой статье мы просмотрели источник и узнали, что:
- npm init viteкоманда использует create-viteинструмент
- create-viteпакет содержит все встроенные шаблоны
- специфичный для фреймворка шаблон зависит от соответствующего ему специфичного для фреймворка плагина
- плагины реализованы в архитектуре на основе хуков
- Vite за кулисами использует как Rollup, так и esbuild
Теперь у вас должно быть твердое представление о системе Vite. Но на практике вам понадобятся другие общие функции, которые мы здесь не рассмотрели. Наиболее распространенными из них являются поддержка препроцессора TypeScript и CSS.