Другие статьи министра из серии Vite, приглашаем друзей стрелять кирпичами:
Подготовка к 2021 году: инженерная практика Vite, рекомендуемая коллекция
предисловие
Многие друзья спрашивали меня, почемуvite
Может ли запуск и разработка быть такими быстрыми?
На самом деле, в документе есть довольно четкие инструкции для этой части, текст будет обсуждать эти знания и приведет вас к тому, чтобы углубиться в нижний слой и реализовать свои собственные от руки.Vite
, эти проблемы будут решены легко! Мало того, мы также можем полностью понять детали компиляции и разбора vue3 SFC, которые, можно сказать, полны урожая!
Аннотация
- Проблемы с вебпаком
- Vite использует другой подход
- Как работает Вайт
- Внедрите свой собственный Vite вручную
- Загрузка исходного кода
- видеоурок
- Последующий творческий план
Проблемы с вебпаком
Знакомый веб-пакет должен запускать предварительный просмотр локального сервера разработки в реальном времени во время разработки. потому чтоВесь файл проекта должен быть упакован, скорость запуска во время разработки будет становиться все медленнее и медленнее по мере расширения масштаба проекта. Та же проблема существует для горячих обновлений после изменения файлов во время разработки.
Смотрите, неважно, нужно вам это или нет, вас будут насильно кормить тортом!
Vite использует другой подход
Vite
Он очень хорошо решает две вышеуказанные проблемы. Запустите сервер разработки без упаковки кода файла, загрузите необходимую обработку модуля в соответствии с запросом клиента,Реализуйте настоящую загрузку по требованию. Для обновления файлов,Vite
HMR выполняется на собственном ESM. Нужно только точно аннулировать цепочку между редактируемым модулем и его ближайшей границей HMR (чаще всего только сам модуль), чтобы обновления HMR всегда были быстрыми, независимо от размера приложения. Дайте то, что вы действительно хотите съесть!
Как работает Вайт
Как работает магия? Секрет в том, что Vite использует преимущества браузераnative ES module importsОсобенности, используя метод ES для организации кода, браузер автоматически запрашивает необходимые файлы, а также компилирует и возвращает по мере необходимости на стороне сервера, полностью пропуская процесс упаковки. Ключевое изменениеindex.html
Метод импорта входного файла в
Таким образом, код может быть организован в виде модуля ES6 в main.js:
vite должен выполнять различную работу по синтаксическому анализу в соответствии с запрошенным типом ресурса, напримерApp.vue
, содержимое, возвращаемое пользователю, выглядит следующим образом:
// 原先的script部分内容
import HelloWorld from '/src/components/HelloWorld.vue'
const __script = {
name: 'App',
components: {
HelloWorld
}
}
// 可见`template`部分转换为了一个模板请求,解析结果是一个渲染函数
import {render as __render} from "/src/App.vue?type=template"
__script.render = __render
__script.__hmrId = "/src/App.vue"
__script.__file = "/Users/yt/projects/vite-study/src/App.vue"
export default __script
Ниже приведено содержимое проанализированной функции рендеринга:
Внедрите свой собственный Vite вручную
Создайте сервер разработки
Сервер разработки можетindex.html
Вернитесь в браузер:
const Koa = require('koa')
const app = new Koa()
app.use(async (ctx) => {
const url = ctx.request.url
if (url === '/') {
ctx.type = 'text/html'
ctx.body = fs.readFileSync('./index.html', 'utf-8')
}
})
app.listen(3000, () => {
console.log('kvite start');
})
Ошибка просмотра, нужно исправитьmain.js
нагрузка
загрузить js
Сервер добавляет поддержку запросов файлов js:
// 导入path
const path = require('path')
app.use(async (ctx) => {
if (url === '/') {}
else if (url.endsWith('.js')) {
// 获取js文件绝对路径,读取并返回
const p = path.join(__dirname, url)
ctx.type = 'text/javascript'
ctx.body = fs.readFileSync(p, 'utf-8')
}
})
Загружать сторонние библиотеки
Если пользователь импортирует стороннюю зависимость, такую какvue
import {createApp, h} from 'vue'
createApp({
render: () => h('div', 'hello, kvite!')
}).mount('#app')
main.js
Запрос успешно вернул содержимое:
Но мы обнаружили, что браузеры поддерживают загрузку файлов только по относительному пути:
Здесь главное заменить裸模块路径
для相对路径
, например, мы будемfrom 'vue'
заменитьfrom '/@modules/vue'
function rewriteImport(content) {
return content.replace(/ from ['|"]([^'"]+)['|"]/g, function(s0, s1){
if (s1.startsWith('./') || s1.startsWith('/') || s1.startsWith('../')) {
return s0
} else {
return ` from '/@modules/${s1}'`
}
})
}
app.use(async (ctx) => {
const url = ctx.request.url
if (url === '/') {
// ...
} else if (url.endsWith('.js')) {
// ...
const ret = fs.readFileSync(p, 'utf-8')
// 重写裸模块导入部分
ctx.body = rewriteImport(ret)
}
})
Просмотр результатов преобразования
Вы можете видеть, что браузер пытается загрузить/@modules/vue
, что означает, что замена прошла успешно
Наконец, обработайте загрузку модуля зависимостей: объектный файл находится в папке модуля.package.json
Есть описания:
Получите этот путь и прочитайте целевой файл, конкретная реализация выглядит следующим образом:
else if (url.startsWith('/@modules')) {
const moduleName = url.replace("/@modules/", "");
const prefix = path.join(__dirname, "../node_modules", moduleName);
const module = require(prefix + "/package.json").module;
const filePath = path.join(prefix, module);
const ret = fs.readFileSync(filePath, "utf8");
ctx.type = "text/javascript";
ctx.body = rewriteImport(ret);
}
моделирование процесса
некоторые библиотеки будут иметь доступprocess
, поэтому он сообщитprocess
Неопределенная ошибка, добавьте ее на главную страницуmock
Просто избегайте
if (url === '/') {
ctx.type = 'text/html'
const content = fs.readFileSync('./index.html', 'utf-8').replace(
'<script type="module" src="/src/main.js"></script>',
`
<script>
window.process = {env:{NODE_ENV:'dev'}}
</script>
<script type="module" src="/src/main.js"></script>
`,
)
ctx.body = content
}
Контент отрендерен успешно!
Обработка запроса SFC
окончательная обработкаSFC
разбор, напримерApp.vue
,
<template>
<div>{{ title }}</div>
</template>
<script>
import { ref } from "vue";
export default {
setup() {
const title = ref("hello, kvite!");
return { title };
},
};
</script>
import { createApp, h } from "vue";
import App from './App.vue'
createApp(App).mount("#app");
использоватьcompiler-sfc
а такжеcompiler-dom
Скомпилировать SFC
const compilerSfc = require("@vue/compiler-sfc");
const compilerDom = require("@vue/compiler-dom");
else if (url.indexOf('.vue') > -1) {
// SFC路径
const p = path.join(__dirname, url.split("?")[0]);
const ret = compilerSfc.parse(fs.readFileSync(p, 'utf-8'))
// SFC文件请求
if (!query.type) {
const scriptContent = ret.descriptor.script.content
const script = scriptContent.replace('export default ', 'const __script = ')
// 返回App.vue解析结果
ctx.type = 'text/javascript'
ctx.body = `
${rewriteImport(script)}
import { render as __render } from '${url}?type=template'
__script.render = __render
export default __script
`
} else if (query.type === 'template') {
// 模板内容
const template = ret.descriptor.template.content
// 编译为render
const render = compilerDom.compile(template, { mode: 'module' }).code
ctx.type = 'text/javascript'
ctx.body = rewriteImport(render)
}
}
Вы закончили~
видеоурок
Сельский староста специально записал поддерживающее видео и повелел всем показать своеVite
:
Принцип работы Vite и реализация рукописного ввода «завершены»
добро пожаловать друзьяТройной + подписка, ваша поддержка - самая большая мотивация для меня продолжать ❤️
Поддержка исходного кода
Добро пожаловать в публичный аккаунт村长学前端
самовывоз