Совместимость Rollup-плагинов с Vite

vite-plugin-checker — популярный плагин экосистемы Vite, предназначенный для запуска дополнительных проверок качества кода во время разработки и сборки. Основная задача плагина — вынести тяжёлые операции проверки типов, линтинга и анализа кода в отдельный процесс, не блокируя основной dev-сервер.

Плагин особенно полезен в проектах с:

  • TypeScript
  • ESLint
  • Vue + vue-tsc
  • Stylelint
  • Biome
  • сложной архитектурой
  • большим количеством модулей

Без подобных инструментов Vite остаётся исключительно быстрым сборщиком, но не обеспечивает полноценный контроль качества кода. Например:

  • TypeScript в Vite по умолчанию только транспилирует код;
  • ошибки типов не останавливают запуск проекта;
  • ESLint не запускается автоматически;
  • Vue SFC не проверяются через vue-tsc.

vite-plugin-checker закрывает эти ограничения.


Установка плагина

Установка выполняется через npm:

npm install vite-plugin-checker --save-dev

Либо через pnpm:

pnpm add -D vite-plugin-checker

Либо через yarn:

yarn add -D vite-plugin-checker

Базовое подключение

Минимальная конфигурация:

// vite.config.js
import { defineConfig } from 'vite'
import checker from 'vite-plugin-checker'

export default defineConfig({
    plugins: [
        checker({
            typescript: true
        })
    ]
})

После запуска dev-сервера плагин начинает:

  • проверять типы TypeScript;
  • выводить ошибки в терминал;
  • показывать overlay в браузере.

Почему TypeScript в Vite не проверяет типы

Важно понимать архитектуру самого Vite.

Vite использует:

  • esbuild для dev-режима;
  • Rollup для production-сборки.

esbuild чрезвычайно быстрый, но не выполняет полноценный type-checking.

Например:

const value: string = 123

Такой код успешно запустится в Vite без дополнительных проверок.

Причина:

  • TypeScript-компилятор не участвует в dev-трансформации;
  • Vite использует только transpilation.

vite-plugin-checker запускает отдельный процесс tsc, благодаря чему ошибки типов начинают обнаруживаться автоматически.


Проверка TypeScript

Простая конфигурация

checker({
    typescript: true
})

Эквивалентно запуску:

tsc --noEmit

Использование собственного tsconfig

checker({
    typescript: {
        tsconfigPath: './tsconfig.app.json'
    }
})

Полезно в monorepo и multi-config проектах.


Проверка только в build-режиме

checker({
    typescript: {
        buildMode: true
    }
})

В этом режиме:

  • проверка не запускается в dev;
  • проверки выполняются только при сборке.

Подходит для крупных проектов, где постоянный type-check слишком тяжёлый.


Overlay ошибок в браузере

Одно из ключевых преимуществ плагина — визуальный overlay.

При возникновении ошибки появляется окно поверх страницы:

  • ошибки TypeScript;
  • ошибки ESLint;
  • ошибки Vue;
  • ошибки Stylelint.

Пример ошибки:

const user: string = 42

В браузере будет показано:

Type 'number' is not assignable to type 'string'

Это существенно ускоряет цикл разработки.


Проверка ESLint

Базовая конфигурация

checker({
    eslint: {
        lintCommand: 'eslint "./src/**/*.{js,ts,vue}"'
    }
})

Плагин запускает указанную команду в отдельном процессе.


Почему используется lintCommand

Плагин не реализует собственный ESLint-движок.

Вместо этого:

  • запускается реальная CLI-команда;
  • используется установленный ESLint;
  • применяются все существующие конфиги проекта.

Это обеспечивает:

  • совместимость;
  • предсказуемость;
  • поддержку любых eslint-плагинов.

Работа с Flat Config

Современный ESLint использует Flat Config:

// eslint.config.js
export default [
    {
        rules: {
            semi: 'error'
        }
    }
]

vite-plugin-checker полностью совместим с Flat Config, если CLI-команда ESLint работает корректно.


Проверка Vue через vue-tsc

Подключение

checker({
    vueTsc: true
})

Плагин запускает:

vue-tsc --noEmit

Почему обычный tsc недостаточен для Vue

Файлы .vue содержат:

  • template;
  • script;
  • style.

Стандартный TypeScript-компилятор не умеет полноценно анализировать Vue SFC.

vue-tsc:

  • понимает структуру SFC;
  • анализирует template;
  • проверяет props;
  • проверяет emits;
  • валидирует Composition API.

Пример ошибки Vue

<script setup lang="ts">
defineProps<{
    title: string
}>()
</script>

<template>
    <div>{{ title.toFixed(2) }}</div>
</template>

Ошибка:

Property 'toFixed' does not exist on type 'string'

Проверка Stylelint

Подключение

checker({
    stylelint: {
        lintCommand: 'stylelint "./src/**/*.{css,scss}"'
    }
})

Проверка Biome

Biome — современная альтернатива ESLint и Prettier.

Подключение:

checker({
    biome: {
        command: 'biome check ./src'
    }
})

Одновременное использование нескольких проверок

Наиболее распространённая конфигурация:

checker({
    typescript: true,

    eslint: {
        lintCommand: 'eslint "./src/**/*.{ts,tsx}"'
    },

    stylelint: {
        lintCommand: 'stylelint "./src/**/*.{scss}"'
    }
})

Каждая проверка запускается параллельно.


Архитектура worker-процессов

Главная особенность vite-plugin-checker — использование отдельных worker-процессов.

Схема работы:

Vite Dev Server
        |
        +---- TypeScript Worker
        |
        +---- ESLint Worker
        |
        +---- Stylelint Worker

Это предотвращает:

  • блокировку HMR;
  • подвисание dev-сервера;
  • деградацию скорости обновления.

Проверки без блокировки HMR

Даже при огромном количестве ошибок:

  • HMR продолжает работать;
  • страница обновляется;
  • dev-сервер остаётся отзывчивым.

Это важное отличие от старых webpack-подходов.


Использование overlay

Overlay включён по умолчанию.

Отключение:

checker({
    overlay: false,
    typescript: true
})

Настройка overlay

Можно отключить отдельные категории ошибок:

checker({
    overlay: {
        initialIsOpen: false
    }
})

Поведение overlay

Overlay:

  • автоматически обновляется;
  • исчезает после исправления ошибок;
  • не требует перезапуска dev-сервера.

Интеграция с React

Типичная конфигурация React + TS:

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import checker from 'vite-plugin-checker'

export default defineConfig({
    plugins: [
        react(),

        checker({
            typescript: true,
            eslint: {
                lintCommand: 'eslint "./src/**/*.{ts,tsx}"'
            }
        })
    ]
})

Интеграция с Vue

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import checker from 'vite-plugin-checker'

export default defineConfig({
    plugins: [
        vue(),

        checker({
            vueTsc: true
        })
    ]
})

Интеграция с Svelte

checker({
    typescript: true
})

Для Svelte обычно используется отдельная проверка через svelte-check.


Интеграция в monorepo

В monorepo важно правильно указывать tsconfigPath.

Пример:

checker({
    typescript: {
        tsconfigPath: './packages/frontend/tsconfig.json'
    }
})

Проблемы производительности

На очень крупных проектах проверки могут стать тяжёлыми.

Основные причины:

  • большое число файлов;
  • сложные generic-типы;
  • тяжёлые ESLint-правила;
  • глубокие зависимости TypeScript.

Оптимизация ESLint

Ограничение области проверки

Плохо:

lintCommand: 'eslint "./**/*"'

Лучше:

lintCommand: 'eslint "./src/**/*.{ts,tsx}"'

Исключение директорий

dist
coverage
node_modules

Через .eslintignore.


Оптимизация TypeScript

Использование incremental

{
    "compilerOptions": {
        "incremental": true
    }
}

Разделение tsconfig

Часто создаются:

tsconfig.app.json
tsconfig.node.json
tsconfig.test.json

Это уменьшает объём проверяемого кода.


Проблемы overlay при большом количестве ошибок

При тысячах ошибок overlay становится неудобным.

В таких случаях:

checker({
    overlay: false
})

Ошибки остаются в терминале.


Проверка только CI

Иногда плагин отключают локально:

plugins: [
    process.env.CI &&
        checker({
            typescript: true
        })
]

Условное подключение

const isDev = process.env.NODE_ENV === 'development'

checker({
    typescript: isDev
})

Использование в production-сборке

Плагин может завершать build с ошибкой.

Например:

const value: number = 'abc'

Build завершится неуспешно.

Это предотвращает публикацию некорректного кода.


Отличие от отдельного запуска tsc

Многие проекты используют:

tsc --noEmit

отдельно от Vite.

vite-plugin-checker отличается тем, что:

  • интегрирован в dev-сервер;
  • показывает overlay;
  • автоматически отслеживает изменения;
  • запускается параллельно с HMR.

Отличие от webpack-подходов

В webpack проверка типов часто:

  • блокировала сборку;
  • замедляла rebuild;
  • ухудшала DX.

Vite + vite-plugin-checker разделяют:

  • bundling;
  • transpilation;
  • diagnostics.

Это обеспечивает значительно более быстрый workflow.


Распространённые ошибки конфигурации

Неправильный glob ESLint

Ошибка:

eslint: {
    lintCommand: 'eslint src'
}

Может пропускать файлы.

Лучше:

eslint: {
    lintCommand: 'eslint "./src/**/*.{js,ts,tsx}"'
}

Отсутствие TypeScript

Ошибка:

Cannot find module 'typescript'

Решение:

npm install typescript -D

Отсутствие vue-tsc

Ошибка:

Cannot find module 'vue-tsc'

Решение:

npm install vue-tsc -D

Проверка в Docker

Иногда watcher внутри контейнера работает нестабильно.

Решение:

server: {
    watch: {
        usePolling: true
    }
}

Использование с CI/CD

Плагин особенно полезен в:

  • GitHub Actions;
  • GitLab CI;
  • Jenkins;
  • TeamCity.

Однако чаще в CI выполняются отдельные команды:

tsc --noEmit
eslint .

а vite-plugin-checker используется локально для DX.


Когда плагин особенно полезен

Наибольшая ценность проявляется в проектах:

  • на TypeScript;
  • с большим количеством разработчиков;
  • со строгими ESLint-правилами;
  • с Vue SFC;
  • с monorepo;
  • с долгоживущими enterprise-приложениями.

Когда плагин может быть избыточен

В небольших проектах:

  • без TypeScript;
  • без ESLint;
  • без сложной архитектуры;

дополнительные проверки могут не окупать накладные расходы.


Типичная production-конфигурация

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import checker from 'vite-plugin-checker'

export default defineConfig({
    plugins: [
        react(),

        checker({
            typescript: {
                tsconfigPath: './tsconfig.json'
            },

            eslint: {
                lintCommand:
                    'eslint "./src/**/*.{ts,tsx}"'
            },

            overlay: {
                initialIsOpen: false
            }
        })
    ]
})