Если ты разрабатываешь интерфейсы на Vue 3 с использованием TypeScript, то наверняка помнишь, какой болью долгие годы сопровождалась проверка типов в Single File Components (.vue).
Поскольку официальный компилятор tsc от Microsoft исторически ничего не знал про файлы с расширением .vue и умел работать только с .ts и .tsx, сообществу приходилось выкручиваться. Так появился пакет vue-tsc — хитроумная надстройка авторства создателя проекта Volar Джонсона Чу. Утилита занималась изощрённым monkey-patching: она на лету перехватывала внутренние методы Node.js-рантайма компилятора TypeScript, подсовывала виртуальные файлы и выдавала ошибки наружу.
Работало это медленно, регулярно ломалось при обновлениях минорных версий языка и создавало зоопарк форков. Но настоящий кризис грянул, когда Microsoft полностью переписала компилятор TypeScript 7 на язык Go ради десятикратного ускорения сборки. Старый трюк с подменой методов в JavaScript-рантайме компилятора в одночасье стал технически невозможным.
Ответом на этот вызов стал официальный механизм TypeScript 7.1 Content Mappers, подробный разбор которого опубликовал разработчик Алекс Опа в издании VueDigest. Механизм открывает прямую нативную поддержку сторонних форматов файлов прямо в компиляторе tsc.
Исторический тупик: как vue-tsc ломал компилятор и почему Go всё изменил
Чтобы оценить масштаб прорыва, давай заглянем под капот старой схемы с vue-tsc.
Когда запускалась команда vue-tsc --noEmit, процесс запускал отдельный инстанс Node.js. Утилита читала файл .vue, парсила его на три секции (<template>, <script> и <style>), генерировала из шаблона искусственный виртуальный TypeScript-код рендер-функции с сохранением sourcemaps и через приватные недокументированные API компилятора инжектировала этот виртуальный код в дерево зависимостей.
Накладные расходы были чудовищными:
- Потребление оперативной памяти на больших монорепозиториях легко пробивало потолок в 4–8 гигабайт.
- В CI/CD пайплайнах проверка типов занимала по 3–5 минут, из-за чего многие команды отключали шаг typecheck на pre-commit хуках, пропуская глупые ошибки в прод.
- Несоответствие версий: ты мог обновить
typescriptв проекте, ноvue-tscвнутри тянул старый движок, из-за чего свежие фичи синтаксиса TS не работали в шаблонах.
Переход TypeScript 7 на нативный бинарник на Go поставил сообщество перед фактом: либо мы получаем официальный API плагинов в tsc, либо Vue навсегда остаётся без проверки типов в новой версии компилятора. Команда TypeScript пошла навстречу фронтенд-экосистеме и внедрила Content Mappers.
Анатомия Content Mappers: виртуальный код и нативный вызов tsc
Как устроен новый механизм? Теперь компилятор tsc сам умеет делегировать чтение нестандартных файлов внешним мапперам через секцию plugins в конфигурационном файле tsconfig.json.
Когда tsc натыкается на файл MyComponent.vue, он передаёт его содержимое зарегистрированному плагину @vue/language-plugin-content-mapper. Плагин преобразует шаблон и блок <script setup lang="ts"> в виртуальный TypeScript-файл в памяти компилятора. Все позиции символов и номера строк точно привязываются к оригинальному файлу .vue.
В результате проверка типов запускается напрямую через официальный компилятор:
# Прямая нативная проверка типов в проекте Vue через официальный tsc
tsc --noEmit --runExternalCode
Никаких сторонних бинарников и форков компилятора. Если проверка прошла успешно, ты на 100% уверен, что код соответствует спецификации TypeScript.
Параметр --runExternalCode обязателен: компилятор TypeScript требует явного подтверждения от разработчика на запуск внешнего JavaScript-плагина маппера в процессе сборки.
Бенчмарк на базе Directus: 4.6-кратное ускорение и 1100 строгих ошибок
Разработчик Алекс Опа провёл масштабный эксперимент, переведя на TypeScript 7.1 Content Mappers кодовую базу популярной headless-CMS Directus — проекта с сотнями сложных Vue-компонентов, кастомных директив и сервисных модулей.
Результаты бенчмарка оказались ошеломляющими:
- Скорость проверки типов: время полного прогона тайпчека сократилось в 4.6 раза по сравнению с
vue-tsc. То, что раньше подвешивало консоль на пару минут, теперь отрабатывает за считанные секунды. - Строгость типизации: новый пайплайн выявил более 1 100 ошибок против 445, которые находил старый
vue-tsc.
Почему ошибок стало больше? Старый vue-tsc из-за ограничений monkey-patching делал множество эвристических допущений и закрывал глаза на несовпадения типов в краевых случаях шаблонов. Нативный компилятор tsc проверяет типы пропсов, событий $emit и слотов с бескомпромиссной строгостью.
Пошаговая настройка tsconfig.json и переход на новый стандарт
Для миграции существующего проекта на Vue 3 достаточно трёх простых шагов:
- Удаляем
vue-tscи устанавливаем свежий TypeScript и языковой плагин:
npm uninstall vue-tsc
npm install -D typescript@^7.1.0 @vue/language-plugin-content-mapper@next
- Подключаем плагин маппинга контента в секции
compilerOptionsв файлеtsconfig.json:
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"noEmit": true,
"plugins": [
{
"name": "@vue/language-plugin-content-mapper",
"extensions": [".vue"]
}
]
},
"include": [
"src/**/*.ts",
"src/**/*.d.ts",
"src/**/*.vue"
]
}
- Обновляем команду в секции
scriptsфайлаpackage.json:
{
"scripts": {
"typecheck": "tsc --noEmit --runExternalCode"
}
}
Появление Content Mappers — поворотный момент для всей экосистемы Vue. Компоненты .vue наконец-то стали полноправными гражданами мира TypeScript, избавившись от шатких прокладок и подарив разработчикам невероятную скорость проверок в CI/CD.
