Исходное заявление: эта статья была впервые опубликована в общедоступном аккаунте: внешние мелочи (qianduansuohua), добро пожаловать на внимание
предисловие
Особенно два дня назадvue 3.0 betaупоминается в прямом эфиреviteинструмент, и написал в Твиттере, что никогда не вернетсяwebpack, также привлекаетwebpackВеселый ответ от основного разработчика Шона, так что давайте посмотримviteВ чем магия?
Что такое Вите?
гитхаб:github.com/vitejs/vite
Vite — это инструмент для веб-разработки, управляемый собственным ESM. Основанная на среде разработки, основанной на разработке ES IMPORTS для браузера, упаковка ROLLUP основана на производственной среде.
В основном он имеет следующие характеристики:
- быстрый холодный пуск
- Мгновенное горячее обновление модуля
- Настоящая компиляция по запросу
Без лишних слов, давайте попробуем.
$ npm init vite-app <project-name>
$ cd <project-name>
$ npm install
$ npm run dev
Давайте посмотрим на сгенерированный код, потому чтоviteпостарайтесь отразить как можно большеvue-cliконфигурация по умолчанию в , поэтому мы найдем, что выглядит иvue-cliСгенерированный код мало чем отличается.
├── index.html
├── package.json
├── public
│ └── favicon.ico
└── src
├── App.vue
├── assets
│ └── logo.png
├── components
│ └── HelloWorld.vue
├── index.css
└── main.js
Затем давайте посмотрим на запись index.html и main.js.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vite App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
// main.js
// 只是引用的是最新的 vue3 语法,其余没有啥不同
import { createApp } from 'vue'
import App from './App.vue'
import './index.css'
createApp(App).mount('#app')
Я обнаружил, что главное отличие в том, что есть так много вещей
<script type="module" src="/src/main.js"></script>
Итак, давайте посмотрим, что это?
принцип
ESM
script moduleЭто реализация модулей ES на стороне браузера, и все основные браузеры уже поддерживают его.
Его самая большая особенность заключается в том, что он используется на стороне браузера.export,importспособ импорта и экспорта модулей, вscriptнастройки в этикеткеtype="module"
<script type="module">
import { createApp } from './main.js‘;
createApp();
</script>
Браузер распознает добавлениеtype="module"из<script>элемент, браузер будет рассматривать этот встроенный скрипт или скрипт внешней цепочки какECMAScriptмодуль, браузер будетimportСсылаясь на инициирование http-запроса для получения содержимого модуля.
В main.js мы используем именованный экспорт для экспортаcreateAppфункция, которую можно получить в скрипте выше
// main.js
export function createApp(){
console.log('create app!');
};
Фактически, на данный момент мы можем в основном понять несколько функций, на которые претендует vite.
- Инструменты упаковки, такие как веб-пакет, используют связующий код для сборки каждого модуля, чтобы загрузить каждый модуль в браузере.Например, веб-пакет использует карту для хранения идентификатора модуля и пути, а также используетwebpack_requireЭкспорт модуля приобретения метода, Vite использует встроенную поддержку браузера, модульный импорт этой функции, опущенную сборку модулей и не нужно генерировать пакет, поэтомуХолодный старт очень быстрый
- Инструмент упаковки заранее упакует каждый модуль в бандл, но процесс упаковки статичен - независимо от того, выполняется код модуля или нет, модуль должен быть упакован в бандл. Недостаток в том, что по мере того, как проект становится все больше и больше После большой упаковки комплект также становится все больше и больше. а такжеESM изначально загружается по запросу, и только при импорте он будет загружаться по запросу.
Вам любопытно, когда вы видите это?viteЧто мы сделали, мы можем просто использовать ESM браузера напрямую, так что давайте попробуем.
Вите работает
предоставить веб-сервер
В базе кода, которую мы только что сгенерировали, мы не передаемnpm run devДля запуска проекта откройте index.html прямо через браузер, вы увидите следующую ошибку
Использование модуля ES в браузере означает использование http-запроса для получения модуля, поэтомуОдна из задач vite — запуск веб-сервера для проксирования этих модулей, у vite koa заимствуется для запуска сервиса
export function createServer(config: ServerConfig): Server {
// ...
const app = new Koa<State, Context>()
const server = resolveServer(config, app.callback())
// ...
const listen = server.listen.bind(server)
server.listen = (async (...args: any[]) => {
if (optimizeDeps.auto !== false) {
await require('../optimizer').optimizeDeps(config)
}
return listen(...args)
}) as any
return server
}
Разрешение модуля
Затем мы запустим статическую службу локально, а затем откроем index.html, чтобы увидеть
Это, вероятно, означает, что если модуль vue не может быть найден, путь импорта, начинающийся с «/», «./» или «../», является допустимым.
import vue from 'vue'
То есть ЕСМ в браузере не может получить содержимое импортированного модуля.Обычно мы пишем код, если не модуль ссылается на относительный путь, а на ссылкуnode_modulesмодули, непосредственноimport xxx from 'xxx',Зависит отWebpackПодождите, пока инструменты помогут нам найти конкретный путь этого модуля для упаковки. Но браузер не знает, что ваш проектnode_modules, он может находить модули только по относительному или абсолютному пути.
Тогда это приводит кОсновная реализация vite — перехватывает запросы браузера на модули и возвращает обработанные результаты.
Посмотрим, как Vite справится с этим?
/@module/приставка
При сравнении main.js в рамках проекта с main.js, фактически загруженным в среде разработки, обнаруживается, что содержимое main.js изменилось.
import { createApp } from 'vue'
import App from './App.vue'
import './index.css'
createApp(App).mount('#app')
стал
import { createApp } from '/@modules/vue.js'
import App from '/src/App.vue'
import '/src/index.css?import'
createApp(App).mount('#app')
чтобы решитьimport xxx from 'xxx'Что касается проблемы сообщения об ошибках, vite обрабатывает этот путь к ресурсу унифицированным образом, добавляя/@module/приставка.
мы вsrc/node/server/serverPluginModuleRewrite.tsВ промежуточном освещении исходного кода KOA вы можете увидеть, что Vite сделал слой обработки на импорте. Процесс выглядит следующим образом:
- Получите тело запроса в промежуточной программе KOA
- пройти черезes-module-lexerРазберите ресурс ast, чтобы получить содержимое импорта
- Определите, является ли импортированный ресурс абсолютным путем, который абсолютно рассматривается как модуль npm.
- Вернуть путь обработанного ресурса: "vue" => "/@modules/vue"
служба поддержки/@module/
существует/src/node/server/serverPluginModuleResolve.tsВы можете видеть, что приблизительная логика обработки
- Получите тело запроса в промежуточном программном обеспечении koa
- Определите, начинается ли путь с /@module/, и если да, удалите имя пакета.
- Перейдите к node_module, чтобы найти эту библиотеку, и верните соответствующий контент на основе package.json.
компиляция файлов
То, что мы упоминали выше, это обработка обычных модулей js, что для других файлов, таких какvue,css,tsКак это обрабатывается?
В качестве примера возьмем файл vue.В webpack мы используем vue-loader для компиляции однофайловых компонентов.На самом деле, vite также перехватывает запросы на модули и выполняет компиляцию в реальном времени.
При сравнении App.vue под проектом и реально загруженного App.vue в среде разработки обнаруживается, что содержимое изменилось
Оригинальный App.vue
<template>
<img alt="Vue logo" src="./assets/logo.png" />
<HelloWorld msg="Hello Vue 3.0 + Vite" />
</template>
<script>
import HelloWorld from './components/HelloWorld.vue';
export default {
name: 'App',
components: {
HelloWorld,
},
};
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
стал
import HelloWorld from '/src/components/HelloWorld.vue';
const __script = {
name: 'App',
components: {
HelloWorld,
},
};
import "/src/App.vue?type=style&index=0&t=1592811240845"
import {render as __render} from "/src/App.vue?type=template&t=1592811240845"
__script.render = __render
__script.__hmrId = "/src/App.vue"
__script.__file = "/Users/wang/qdcares/test/vite-demo/src/App.vue"
export default __script
Таким образом, исходный.vueФайл разделен на три запроса (соответствующих скрипту, стилю и шаблону соответственно), браузер сначала получит ответ App.vue, содержащий логику скрипта, а затем проанализирует путь к шаблону и стилю и инициирует HTTP-запрос. снова Запросить соответствующий ресурс, в это время Vite его перехватывает и снова обрабатывает и возвращает соответствующий контент.
// App.vue?type=style
import { updateStyle } from "/vite/hmr"
const css = "\n#app {\n font-family: Avenir, Helvetica, Arial, sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n text-align: center;\n color: #2c3e50;\n margin-top: 60px;\n}\n"
updateStyle("7ac74a55-0", css)
export default css
// App.vue?type=template
import {createVNode as _createVNode, resolveComponent as _resolveComponent, Fragment as _Fragment, openBlock as _openBlock, createBlock as _createBlock} from "/@modules/vue.js"
const _hoisted_1 = /*#__PURE__*/
_createVNode("img", {
alt: "Vue logo",
src: "/src/assets/logo.png"
}, null, -1 /* HOISTED */
)
export function render(_ctx, _cache) {
const _component_HelloWorld = _resolveComponent("HelloWorld")
return (_openBlock(),
_createBlock(_Fragment, null, [_hoisted_1, _createVNode(_component_HelloWorld, {
msg: "Hello Vue 3.0 + Vite"
})], 64 /* STABLE_FRAGMENT */
))
}
Фактически, увидев эту идею, обработка других типов файлов почти аналогична, и выполняется различная обработка компиляции в соответствии с запрошенными типами файлов.
По сути, vite реализует компиляцию по требованию в реальном времени, перехватывая запросы на основе загрузки по требованию.
послесловие
Здесь мы фактически имеем базовое пониманиеviteХотя полностью заменить webpack в текущей экологии невозможно, в конце концов, это исследование нового решения.
На самом деле, кромеvite, похожие схемы есть в сообществеsnowpack, Заинтересованные могут пойти узнать.