предисловие
ViteСумасшедшее обновление сейчас, в настоящее время вBeta, и 1.0 может быть выпущена в ближайшее время.
Что такое Вите
Vite, нативный браузерныйES importsсервер разработки. Используйте браузер для разбораimports, компилировать и возвращать по мере необходимости на стороне сервера, полностью пропуская концепцию упаковки, и сервер можно использовать в любое время. При этом не толькоVueТакже реализована файловая поддержка и горячее обновление, при этом скорость горячего обновления не будет замедляться по мере увеличения количества модулей. Для производственной среды можно использовать тот же кодrollupПакет. Несмотря на то, что пока это относительно грубо, я думаю, что у этого направления есть потенциал, и если оно будет сделано хорошо, оно может полностью решить проблему полдня горячих обновлений, таких как изменение строки кода.
- Быстрый холодный старт сервера
- Мгновенная замена горячего модуля (HMR)
- Настоящая компиляция по запросу
Родилась ленивая загрузка!
Javascript-модуль
Во-первых, нужно поставитьtype="module"помещать<script>тег, чтобы объявить, что этот скрипт является модулем:
<script type="module" src="main.js"></script>
когдаscript.typeдляmoduleкогда черезsrcа такжеimportИмпортированный файл будет отправленhttpпросить.
запрос на перехват
ViteЭти запросы перехватываются, и запрошенные файлы обрабатываются особым образом.
import Vue from 'vue'
когда прошлоimportпытаюсь импортироватьnode_modulesфайл внутриViteзаменит путь, потому что только в браузереотносительный путьа такжеабсолютный путь.
import Vue from '/@modules/vue'
Код
// server.js
const Koa = require('koa');
const fs = require('fs');
const path = require('path');
const app = new Koa();
app.use(async (ctx) => {
const {
request: { url, query }
} = ctx;
if (url == '/') {
// 返回静态资源
ctx.type = 'text/html';
ctx.body = fs.readFileSync('./index.html', 'utf-8');
}
if (url.endsWith('.js')) {
// 处理 js 文件
const p = path.resolve(__dirname, url.slice(1));
const res = fs.readFileSync(p, 'utf-8');
ctx.type = 'application/javascript';
// 返回替换路径后的文件
ctx.body = rewriteImports(res);
}
});
function rewriteImports(content) {
return content.replace(/from ['|"]([^'"]+)['|"]/g, function ($0, $1) {
// 要访问 node_modules 里的文件
if ($1[0] !== '.' && $1[1] !== '/') {
return `from '/@modules/${$1}'`;
} else {
return $0;
}
});
}
app.listen(3000, function () {
console.log('success listen 3000');
});
разрешить /@модули
Далее следует/@modulesПуть в начале разрешается в реальный адрес файла и возвращает его браузеру. былоwebpackПомогите нам сделать это.
пройти черезimportимпортированный файлwebpackПойдуpackage.jsonнайти в файлеmoduelАтрибуты.
{
"license": "MIT",
"main": "index.js",
"module": "dist/vue.runtime.esm-bundler.js",
"name": "vue",
"repository": {
"type": "git",
"url": "git+https://github.com/vuejs/vue-next.git"
},
"types": "dist/vue.d.ts",
"unpkg": "dist/vue.global.js",
"version": "3.0.0-beta.15"
}
нам просто нужно поставить этоdist/vue.runtime.esm-bundler.jsФайл адреса возвращается просто отлично.
Код
if (url.startsWith('/@modules/')) {
// 找到 node_modules 内的文件夹
const prefix = path.resolve(
__dirname,
'node_modules',
url.replace('/@modules/', '')
);
// 获取 package.json 内的 module 属性
const module = require(prefix + '/package.json').module;
const p = path.resolve(prefix, module);
// 读取文件
const res = fs.readFileSync(p, 'utf-8');
ctx.type = 'application/javascript';
// 读取的文件内还通过 import 导入了其他的依赖,继续把路径替换为 /@modules/
ctx.body = rewriteImports(res);
}
Односорный компонент анализа
каждый знаетvueФайл состоит из трех частей, а именноtemplate script style.
ViteЭти части рассматриваются отдельно.
Далее мы реализуем обработку этих частей.
сценарий процесса
@vue/compiler-sfcиспользуется для разбора однофайловых компонентов, таких какvue-loaderСписок задач.
Результат его разбора следующий.
Код
const compilerSfc = require('@vue/compiler-sfc');
if (url.includes('.vue')) {
const p = path.resolve(__dirname, url.slice(1));
const { descriptor } = compilerSfc.parse(fs.readFileSync(p, 'utf-8'));
if (!query.type) {
ctx.type = 'application/javascript';
ctx.body = `
// 拿到 script 的内容
const __script = ${descriptor.script.content.replace('export default ', '')}
// 如果有 style 就发送请求获取 style 的部分
${descriptor.styles.length ? `import "${url}?type=style"` : ''}
// 发送请求获取 template 的部分
import { render as __render } from "${url}?type=template"
// 渲染 template 的内容
__script.render = __render;
export default __script;
`;
}
}
шаблон процесса
@vue/compiler-domиспользуется для компиляцииtemplateиз.
потому что вернулся в браузерvueдаruntimeверсия да нетпереводчикДа, все должно быть скомпилировано на сервере и возвращено в браузер.
const compilerDom = require('@vue/compiler-dom');
...
if (query.type === 'template') {
const template = descriptor.template;
// 在服务端编译 template 并且返回
const render = compilerDom.compile(template.content, {
mode: 'module',
}).code;
ctx.type = 'application/javascript';
ctx.body = render;
}
стиль ручки
правильноstyleОбработка немного особенная, вы можете видеть, что возвращаемый контент называетсяupdateStyleметод, вViteположить его вГорячее обновлениеВ модуле здесь мы не реализовали горячее обновление, поэтому сначалаhashвниз вclientреализовать эту функцию.
// server.js
if (query.type === 'style') {
const styleBlock = descriptor.styles[0];
ctx.type = 'application/javascript';
ctx.body = `
const css = ${JSON.stringify(styleBlock.content)};
updateStyle(css);
export default css;
`;
}
Используется метод 1Конструктивные таблицы стилейВот два источника для справки.
- Конструируемые таблицы стилей — новый способ создания CSS из javascript.
- Microsoft предлагает модули CSS V1: импортируйте модули CSS в компоненты с помощью операторов импорта.
Способ 2 неbalabala.
<body>
<div id="app"></div>
<script>
// hash: 规避 shared 文件内的环境判断
window.process = {
env: {
NODE_ENV: 'dev',
}
};
function updateStyle(content) {
// 方法1
let style = new CSSStyleSheet();
style.replaceSync(content);
document.adoptedStyleSheets = [
...document.adoptedStyleSheets,
style,
];
// 方法2
let style = document.createElement('style')
style.setAttribute('type', 'text/css')
style.innerHTML = content
document.head.appendChild(style)
}
</script>
<script type="module" src="./main.js"></script>
</body>
полный код
GitHub.com/18Qualifications/Vite…
Эпилог
Наконец-то я дождалась тебя~ К счастью, я не сдалась~
"
Прошлые статьи
- Отзывчивая реализация Vue1.x 2.x 3.x
- 50 строк кода подведут вас к предварительному пониманию принципа работы Vue-Router
- Вы должны использовать серию - Синхронизация расширений и настроек VSCode (Графический и текстовый учебник) - Синхронизация настроек
В этой статье используетсяmdniceнабор текста