Skip to content

Plugin API

Плагины Vite расширяют интерфейс плагинов Rolldown несколькими дополнительными специфичными для Vite опциями. В результате вы можете написать плагин Vite один раз, и он будет работать как для разработки, так и для сборки.

Рекомендуется сначала ознакомиться с документацией по плагинам Rolldown, прежде чем читать разделы ниже.

Создание плагина

Vite стремится предлагать устоявшиеся паттерны из коробки, поэтому перед созданием нового плагина убедитесь, что вы вы ознакомились с разделом Возможности, чтобы понять, покрывают ли они ваши потребности. Также ознакомьтесь с доступными плагинами сообщества, как в виде совместимых плагинов Rollup, так и специфичных для Vite плагинов.

При создании плагина вы можете встроить его в ваш vite.config.js. Нет необходимости создавать для него новый пакет. Как только вы увидите, что плагин был полезен в ваших проектах, подумайте о том, чтобы поделиться им для помощи другим в экосистеме.

СОВЕТ

При обучении, отладке или написании плагинов мы рекомендуем включить vite-plugin-inspect в ваш проект. Он позволяет вам просматривать промежуточное состояние плагинов Vite. После установки вы можете посетить localhost:5173/__inspect/, чтобы просмотреть модули и стек трансформаций вашего проекта. Ознакомьтесь с инструкциями по установке в документации vite-plugin-inspect. vite-plugin-inspect

Конвенции

Если плагин не использует специфичные для Vite хуки и может быть реализован как совместимый плагин Rolldown, то рекомендуется использовать соглашения об именовании плагинов Rolldown.

  • Плагины Rolldown должны иметь чёткое название с префиксом rolldown-plugin-.
  • Включите ключевые слова rolldown-plugin и vite-plugin в поле keywords package.json.

Это позволяет использовать плагин также в чистых проектах на базе Rolldown или Rollup.

Что касается плагинов, предназначенных только для Vite:

  • Плагины Vite должны иметь понятное имя с префиксом vite-plugin-.
  • Включите ключевое слово vite-plugin в поле keywords package.json.
  • Включите раздел в документации плагина, объясняющий, почему это плагин только для Vite (например, он использует специфические для Vite хуки).

Если ваш плагин будет работать только для определённого фреймворка, его имя должно быть включено в префикс:

  • Префикс vite-plugin-vue- для плагинов Vue
  • Префикс vite-plugin-react- для плагинов React
  • Префикс vite-plugin-svelte- для плагинов Svelte

Смотрите также Конвенция виртуальных модулей.

Конфигурация плагинов

Пользователи добавят плагины в devDependencies проекта и настроят их с помощью опции массива plugins:

vite.config.js
js
import vitePlugin from 'vite-plugin-feature'
import rollupPlugin from 'rollup-plugin-feature'

export default defineConfig({
  plugins: [vitePlugin(), rollupPlugin()],
})

Ложные плагины будут игнорироваться, что позволяет легко активировать или деактивировать плагины.

plugins также принимает пресеты, включающие несколько плагинов в качестве одного элемента. Это полезно для сложных функций (например, интеграции с фреймворками), которые реализованы с использованием нескольких плагинов. Массив будет внутренне уплощён.

js
// framework-plugin
import frameworkRefresh from 'vite-plugin-framework-refresh'
import frameworkDevtools from 'vite-plugin-framework-devtools'

export default function framework(config) {
  return [frameworkRefresh(config), frameworkDevTools(config)]
}
vite.config.js
js
import { defineConfig } from 'vite'
import framework from 'vite-plugin-framework'

export default defineConfig({
  plugins: [framework()],
})

Простые примеры

СОВЕТ

Общепринятой конвенцией является создание плагина Vite/Rolldown/Rollup в виде фабричной функции, которая возвращает фактический объект плагина. Функция может принимать параметры, что позволяет пользователям настраивать поведение плагина.

Преобразование пользовательских типов файлов

js
const fileRegex = /\.(my-file-ext)$/

export default function myPlugin() {
  return {
    name: 'transform-file',

    transform: {
      filter: {
        id: fileRegex,
      },
      handler(src, id) {
        return {
          code: compileFileToJS(src),
          map: null, // предоставьте карту источников, если она доступна
        }
      },
    },
  }
}

Импорт виртуального файла

Виртуальные модули позволяют передавать информацию, полученную во время сборки, в исходные файлы с помощью обычного синтаксиса импорта ESM. Полное описание соглашения об именовании см. в разделе Соглашение для виртуальных модулей.

js
import { exactRegex } from '@rolldown/pluginutils'

export default function myPlugin() {
  const virtualModuleId = 'virtual:my-module'
  const resolvedVirtualModuleId = '\0' + virtualModuleId

  return {
    name: 'my-plugin', // обязательно, будет отображаться в предупреждениях и ошибках
    resolveId: {
      filter: { id: exactRegex(virtualModuleId) },
      handler() {
        return resolvedVirtualModuleId
      },
    },
    load: {
      filter: { id: exactRegex(resolvedVirtualModuleId) },
      handler() {
        return `export const msg = "from virtual module"`
      },
    },
  }
}

Что позволяет импортировать модуль в JavaScript:

js
import { msg } from 'virtual:my-module'

console.log(msg)

В Vite, поскольку \0 не является допустимым символом в URL импорта, виртуальный идентификатор \0{id} в режиме разработки в браузере преобразуется в /@id/__x00__{id}. Перед передачей в конвейер плагинов идентификатор декодируется обратно, поэтому в коде хуков плагинов это преобразование не видно.

Хуки Rolldown

Во время разработки dev-сервер Vite создает контейнер плагинов, который вызывает хуки сборки Rolldown точно так же, как это делает Rolldown.

Все хуки Rolldown являются хуками уровня окружения.

Следующие хуки вызываются один раз при запуске сервера:

Следующие хуки вызываются при каждом входящем запросе модуля:

Эти хуки также имеют расширенный параметр options с дополнительными свойствами, специфичными для Vite. Вы можете прочитать больше в документации по SSR.

Некоторые вызовы resolveId могут иметь значение importer в виде абсолютного пути к общему index.html в корне, так как не всегда возможно определить фактический импортёр из-за паттерна разработки без сборки пакета в сервере Vite. Для импортов, обрабатываемых в рамках разрешающего конвейера Vite, импортёр может отслеживаться на этапе анализа импорта, обеспечивая правильное значение importer.

Следующие хуки вызываются, когда сервер закрывается:

Обратите внимание, что хук moduleParsed не вызывается во время разработки, поскольку Vite избегает полного разбора AST для повышения производительности.

Хуки генерации вывода (за исключением closeBundle) не вызываются во время разработки.

Специфические хуки Vite

Плагины Vite также могут предоставлять хуки, которые служат специфическим для Vite целям. Эти хуки игнорируются Rollup.

config

  • Тип: (config: UserConfig, env: { mode: 'build' | 'serve', command: string, isSsrBuild?: boolean, isPreview?: boolean }) => UserConfig | null | void

  • Режим работы: async, sequential

  • Область применения: Глобальная

    Измените конфигурацию Vite перед её разрешением. Хук получает необработанную пользовательскую конфигурацию (опции CLI, объединённые с файлом конфигурации) и текущую среду конфигурации, которая предоставляет используемые mode и command. Он может вернуть частичный объект конфигурации, который будет глубоко объединён с существующей конфигурацией, или напрямую изменить конфигурацию (если стандартное объединение не может достичь желаемого результата).

    Пример:

    js
    // возврат частичной конфигурации (рекомендуется)
    const partialConfigPlugin = () => ({
      name: 'return-partial',
      config: () => ({
        resolve: {
          alias: {
            foo: 'bar',
          },
        },
      }),
    })
    
    // прямое изменение конфигурации (используйте только когда объединение не работает)
    const mutateConfigPlugin = () => ({
      name: 'mutate-config',
      config(config, { command }) {
        if (command === 'build') {
          config.root = 'foo'
        }
      },
    })

    ПРЕДУПРЕЖДЕНИЕ

    Пользовательские плагины разрешаются перед выполнением этого хука, поэтому внедрение других плагинов внутри хука config не будет иметь эффекта.

configResolved

  • Тип: (config: ResolvedConfig) => void | Promise<void>

  • Режим работы: async, parallel

  • Область применения: Глобальная

    Вызывается после разрешения конфигурации Vite. Используйте этот хук, чтобы прочитать и сохранить окончательную разрешённую конфигурацию. Он также полезен, когда плагин должен выполнять что-то другое в зависимости от выполняемой команды.

    Пример:

    js
    const examplePlugin = () => {
      let config
    
      return {
        name: 'read-config',
    
        configResolved(resolvedConfig) {
          // сохраняем разрешённую конфигурацию
          config = resolvedConfig
        },
    
        // используем сохранённую конфигурацию в других хуках
        transform(code, id) {
          if (config.command === 'serve') {
            // dev: плагин вызывается dev-сервером
          } else {
            // build: плагин вызывается Rollup
          }
        },
      }
    }

    Обратите внимание, что значение command равно serve в режиме разработки (в CLI vite, vite dev и vite serve являются псевдонимами).

configureServer

  • Тип: (server: ViteDevServer) => (() => void) | void | Promise<(() => void) | void>

  • Режим работы: async, sequential

  • Смотрите также: ViteDevServer

  • Область применения: Глобальная

    Хук для настройки dev-сервера. Наиболее распространённый случай использования — добавление пользовательских прослоек к внутреннему connect приложению:

    js
    const myPlugin = () => ({
      name: 'configure-server',
      configureServer(server) {
        server.middlewares.use((req, res, next) => {
          // пользовательская обработка запроса...
        })
      },
    })

    Внедрение прослойки с пост-обработкой

    Хук configureServer вызывается до установки внутренних прослоек, поэтому пользовательские будут выполняться раньше стандартных. Если вы хотите внедрить свою прослойку после внутренних, вы можете вернуть функцию из configureServer — она вызовется уже после того, как внутренние прослойки будут установлены.

    js
    const myPlugin = () => ({
      name: 'configure-server',
      configureServer(server) {
        // возвращаем пост-хук, который вызывается
        // после установки внутренних прослоек
        return () => {
          server.middlewares.use((req, res, next) => {
            // пользовательская обработка запроса...
          })
        }
      },
    })

    Хранение доступа к серверу

    В некоторых случаях другие хуки плагинов могут нуждаться в доступе к экземпляру dev-сервера (например, для доступа к WebSocket-серверу, наблюдателю за файловой системой или графу модулей). Этот хук также можно использовать для хранения экземпляра сервера для доступа в других хуках:

    js
    const myPlugin = () => {
      let server
      return {
        name: 'configure-server',
        configureServer(_server) {
          server = _server
        },
        transform(code, id) {
          if (server) {
            // используем сервер...
          }
        },
      }
    }

    Обратите внимание, что configureServer не вызывается при создании рабочей сборки, поэтому ваши другие хуки должны учитывать его отсутствие.

configurePreviewServer

  • Тип: (server: PreviewServer) => (() => void) | void | Promise<(() => void) | void>

  • Режим работы: async, sequential

  • Смотрите также: PreviewServer

  • Область применения: Глобальная

    То же самое, что и configureServer, но для сервера предварительного просмотра. Аналогично configureServer, хук configurePreviewServer вызывается до установки других прослоек. Если вы хотите внедрить свою прослойку после стандартных, вы можете вернуть функцию из configurePreviewServer, которая будет вызвана после установки внутренних прослоек:

    js
    const myPlugin = () => ({
      name: 'configure-preview-server',
      configurePreviewServer(server) {
        // возвращаем пост-хук, который вызывается
        // после установки других прослоек
        return () => {
          server.middlewares.use((req, res, next) => {
            // пользовательская обработка запроса...
          })
        }
      },
    })

transformIndexHtml

  • Тип: IndexHtmlTransformHook | { order?: 'pre' | 'post', handler: IndexHtmlTransformHook }

  • Режим работы: async, sequential

  • Область применения: Уровень окружения

    Специальный хук для преобразования файлов HTML-точек входа, таких как index.html. Хук получает текущую строку HTML и контекст преобразования. Контекст предоставляет экземпляр ViteDevServer во время разработки и выводной пакет Rollup во время сборки.

    Хук может быть асинхронным и может возвращать одно из следующих значений:

    • Преобразованную строку HTML
    • Массив объектов-дескрипторов тегов ({ tag, attrs, children }), которые нужно вставить в существующий HTML. Каждый тег также может указывать, куда он должен быть вставлен (по умолчанию — добавление в <head>)
    • Объект, содержащий оба значения в виде { html, tags }

    По умолчанию order равен undefined, и этот хук применяется после преобразования HTML. Чтобы вставить скрипт, который должен пройти через конвейер плагинов Vite, order: 'pre' применит хук до обработки HTML. order: 'post' применяет хук после того, как все хуки с order, равным undefined, были применены.

    Простой пример:

    js
    const htmlPlugin = () => {
      return {
        name: 'html-transform',
        transformIndexHtml(html) {
          return html.replace(
            /<title>(.*?)<\/title>/,
            `<title>Title replaced!</title>`,
          )
        },
      }
    }

    Полная сигнатура хука:

    ts
    type IndexHtmlTransformHook = (
      html: string,
      ctx: {
        path: string
        filename: string
        server?: ViteDevServer
        bundle?: import('rolldown').OutputBundle
        chunk?: import('rolldown').OutputChunk
        originalUrl?: string
      },
    ) =>
      IndexHtmlTransformResult | void | Promise<IndexHtmlTransformResult | void>
    
    type IndexHtmlTransformResult =
      | string
      | HtmlTagDescriptor[]
      | {
          html: string
          tags: HtmlTagDescriptor[]
        }
    
    interface HtmlTagDescriptor {
      tag: string
      /**
       * значения атрибутов будут экранированы автоматически, если это необходимо
       */
      attrs?: Record<string, string | boolean>
      children?: string | HtmlTagDescriptor[]
      /**
       * по умолчанию: 'head-prepend'
       */
      injectTo?: 'head' | 'body' | 'head-prepend' | 'body-prepend'
    }

    ПРЕДУПРЕЖДЕНИЕ

    Этот хук не будет вызван, если вы используете фреймворк, который имеет собственную обработку файлов входа (например, SvelteKit).

handleHotUpdate

  • Тип: (ctx: HmrContext) => Array<ModuleNode> | void | Promise<Array<ModuleNode> | void>

  • Режим работы: async, sequential

  • Смотрите также: HMR API

  • Область применения: Уровень окружения

    Выполняет пользовательскую обработку обновлений HMR. Хук получает объект контекста со следующей сигнатурой:

    ts
    interface HmrContext {
      file: string
      timestamp: number
      modules: Array<ModuleNode>
      read: () => string | Promise<string>
      server: ViteDevServer
    }
    • modules — это массив модулей, на которые повлиял изменённый файл. Это массив, потому что один файл может соответствовать нескольким обслуживаемым модулям (например, Vue SFC).

    • read — это асинхронная функция чтения, которая возвращает содержимое файла. Это предоставляется, потому что в некоторых системах обратный вызов изменения файла может срабатывать слишком быстро, прежде чем редактор завершит обновление файла, и прямой вызов fs.readFile вернет пустое содержимое. Функция чтения, переданная в хук, нормализует это поведение.

    Хук может выбрать:

    • Отфильтровать и уточнить список затронутых модулей, чтобы HMR был более точным.

    • Вернуть пустой массив и выполнить полную перезагрузку:

      js
      handleHotUpdate({ server, modules, timestamp }) {
        // Ручное аннулирование модулей
        const invalidatedModules = new Set()
        for (const mod of modules) {
          server.moduleGraph.invalidateModule(
            mod,
            invalidatedModules,
            timestamp,
            true
          )
        }
        server.ws.send({ type: 'full-reload' })
        return []
      }
    • Вернуть пустой массив и выполнить полную пользовательскую обработку HMR, отправляя пользовательские события клиенту:

      js
      handleHotUpdate({ server }) {
        server.ws.send({
          type: 'custom',
          event: 'special-update',
          data: {}
        })
        return []
      }

      Код клиента должен зарегистрировать соответствующий обработчик, используя HMR API (это может быть внедрено через хук transform того же плагина):

      js
      if (import.meta.hot) {
        import.meta.hot.on('special-update', (data) => {
          // выполняем пользовательское обновление
        })
      }

Метаданные контекста плагина

Для хуков плагина, имеющих доступ к контексту плагина, Vite предоставляет дополнительные свойства в this.meta:

  • this.meta.viteVersion: Строка с текущей версией Vite (например, "8.0.0").

Определение Vite на базе Rolldown

this.meta.rolldownVersion доступно только для Vite, работающего на Rolldown (т. е. Vite 8+). Вы можете использовать это свойство, чтобы определить, работает ли текущий экземпляр Vite на базе Rolldown:

ts
function versionCheckPlugin(): Plugin {
  return {
    name: 'version-check',
    buildStart() {
      if (this.meta.rolldownVersion) {
        // Действуем только в случае, если Vite работает на Rolldown
      } else {
        // В противном случае (Vite на Rollup) делаем что-то другое
      }
    },
  }
}

Метаданные выходного бандла

Во время сборки Vite дополняет объекты вывода сборки Rolldown специфическим для Vite полем viteMetadata.

Оно доступно через:

  • RenderedChunk (например, в хуках renderChunk и augmentChunkHash)
  • OutputChunk и OutputAsset (например, в хуках generateBundle и writeBundle)

viteMetadata предоставляет:

  • viteMetadata.importedCss: Set<string>
  • viteMetadata.importedAssets: Set<string>

Это полезно при написании плагинов, которым нужно проверить сгенерированные CSS-файлы и статические ресурсы, не полагаясь на build.manifest.

Пример:

vite.config.ts
ts
function outputMetadataPlugin(): Plugin {
  return {
    name: 'output-metadata-plugin',
    enforce: 'post',
    generateBundle(_, bundle) {
      for (const output of Object.values(bundle)) {
        const css = output.viteMetadata?.importedCss
        const assets = output.viteMetadata?.importedAssets
        if (!css?.size && !assets?.size) continue

        console.log(output.fileName, {
          css: css ? [...css] : [],
          assets: assets ? [...assets] : [],
        })
      }
    },
  }
}

Порядок плагинов

Плагин Vite может дополнительно указать свойство enforce (аналогично загрузчикам webpack), чтобы настроить порядок его применения. Значение enforce может быть либо "pre", либо "post". Разрешённые плагины будут выполняться в следующем порядке:

  • Алиасы
  • Пользовательские плагины с enforce: 'pre'
  • Ядро плагинов Vite
  • Пользовательские плагины без значения enforce
  • Плагины сборки Vite
  • Пользовательские плагины с enforce: 'post'
  • Постсборочные плагины Vite (минификация, манифест, отчетность)

Обратите внимание, что это работает отдельно от порядка хуков — они по-прежнему подчиняются своему атрибуту order, как обычно для хуков Rolldown.

Применение по условию

По умолчанию плагины вызываются как для сервера, так и для сборки. В случаях, когда плагин необходимо применять условно только во время сервера или сборки, используйте свойство apply, чтобы вызывать их только во время 'build' или 'serve':

js
function myPlugin() {
  return {
    name: 'build-only',
    apply: 'build', // или 'serve'
  }
}

Функция также может быть использована для более точного контроля:

js
apply(config, { command }) {
  // применяем только при сборке, но не для SSR
  return command === 'build' && !config.build.ssr
}

Совместимость плагинов Rolldown

Достаточное количество плагинов Rolldown / Rollup будет работать напрямую как плагины Vite (например, @rollup/plugin-alias или @rollup/plugin-json), но не все из них, так как некоторые хуки плагинов не имеют смысла в контексте dev-сервера без сборки пакета.

В общем, если плагин Rolldown / Rollup соответствует следующим критериям, он должен работать как плагин Vite:

  • Не использует хук moduleParsed.
  • Не зависит от специфичных для Rolldown опций, таких как transform.inject.
  • У него нет сильной связи между хуками фазы сборки и хуками фазы вывода.

Если плагин Rolldown / Rollup имеет смысл только для фазы сборки, его можно указать в build.rolldownOptions.plugins. Он будет работать так же, как плагин Vite с enforce: 'post' и apply: 'build'.

Вы также можете дополнить существующий плагин Rolldown / Rollup свойствами, специфичными для Vite:

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

export default defineConfig({
  plugins: [
    {
      ...example(),
      enforce: 'post',
      apply: 'build',
    },
  ],
})

Нормализация путей

Vite нормализует пути при разрешении идентификаторов, используя разделители POSIX ( / ), сохраняя при этом объём в Windows. С другой стороны, Rollup по умолчанию оставляет разрешённые пути нетронутыми, поэтому разрешённые идентификаторы имеют разделители win32 ( \ ) в Windows. Однако плагины Rollup используют внутреннюю функцию утилиты normalizePath из @rollup/pluginutils, которая преобразует разделители в POSIX перед выполнением сравнений. Это означает, что когда эти плагины используются в Vite, шаблоны конфигурации include и exclude, а также другие аналогичные пути для сравнений разрешённых идентификаторов работают корректно.

Таким образом, для плагинов Vite, при сравнении путей с разрешёнными идентификаторами важно сначала нормализовать пути, чтобы использовать разделители POSIX. Эквивалентная функция утилиты normalizePath экспортируется из модуля vite.

js
import { normalizePath } from 'vite'

normalizePath('foo\\bar') // 'foo/bar'
normalizePath('foo/bar') // 'foo/bar'

Фильтрация, шаблон include/exclude

Vite предоставляет функцию createFilter из @rollup/pluginutils, чтобы побудить специфичные для Vite плагины и интеграции использовать стандартный шаблон фильтрации include/exclude, который также используется в Vite Core.

Фильтры хуков

Rolldown ввёл функцию фильтрации хуков, чтобы уменьшить накладные расходы на взаимодействие между средами выполнения Rust и JavaScript. Эта функция позволяет плагинам указывать шаблоны, определяющие, когда должны вызываться хуки, улучшая производительность за счёт избежания ненужных вызовов.

Это также поддерживается в Rollup 4.38.0+ и Vite 6.3.0+. Чтобы сделать ваш плагин обратно совместимым со старыми версиями, убедитесь, что вы также запускаете фильтр внутри обработчиков хуков.

js
export default function myPlugin() {
  const jsFileRegex = /\.js$/

  return {
    name: 'my-plugin',
    // Пример: вызывать transform только для .js файлов
    transform: {
      filter: {
        id: jsFileRegex,
      },
      handler(code, id) {
        // Дополнительная проверка для обратной совместимости
        if (!jsFileRegex.test(id)) return null

        return {
          code: transformCode(code),
          map: null,
        }
      },
    },
  }
}

СОВЕТ

@rolldown/pluginutils экспортирует некоторые утилиты для фильтров хуков, такие как exactRegex и prefixRegex. Они также переэкспортируются из rolldown/filter для удобства.

Сведения о карте импортов чанков

Экспериментальная функция

Эта функция является экспериментальной и в будущем может измениться.

Когда включён параметр build.chunkImportMap, инструкции импорта в сгенерированных чанках будут использовать уникальный идентификатор каждого чанка вместо пути к файлу.

Чтобы получить соответствие между идентификатором чанка и путём к файлу, можно обратиться к карте импортов, добавленной в сборку, в хуке generateBundle или writeBundle. Карта импортов получает имя, указанное в параметре build.rolldownOptions.experimental.chunkImportMap.fileName (по умолчанию — importmap.json).

ts
function accessImportMap() {
  let config: ResolvedConfig
  return {
    name: 'access-import-map',
    configResolved(resolvedConfig) {
      config = resolvedConfig
    },
    generateBundle(options, bundle) {
      const chunkImportMap =
        config.build.rolldownOptions.experimental?.chunkImportMap
      if (chunkImportMap) {
        const importMapFilename =
          typeof chunkImportMap === 'object' && chunkImportMap.fileName
            ? chunkImportMap.fileName
            : 'importmap.json'
        const importMap = bundle[importMapFilename]! as OutputAsset
        const mapping = JSON.parse(importMap.source).imports
        console.log(mapping)
        // { "./entry.hash1.js": "./entry.hash2.js" }
      }
    },
  }
}

Связь клиент-сервер

Начиная с Vite 2.9, мы предоставляем некоторые утилиты для плагинов, чтобы помочь в обработке связи с клиентами.

От сервера к клиенту

На стороне плагина мы можем использовать server.ws.send, чтобы транслировать события клиенту:

js
// vite.config.js
export default defineConfig({
  plugins: [
    {
      // ...
      configureServer(server) {
        server.ws.on('connection', () => {
          server.ws.send('my:greetings', { msg: 'привет' })
        })
      },
    },
  ],
})

ПРИМЕЧАНИЕ

Мы рекомендуем всегда добавлять префикс к именам ваших событий, чтобы избежать конфликтов с другими плагинами.

На стороне клиента используйте hot.on, чтобы слушать события:

ts
// сторона клиента
if (import.meta.
hot
) {
import.meta.
hot
.
on
('my:greetings', (
data
) => {
console
.
log
(
data
.msg) // привет
}) }

От клиента к серверу

Чтобы отправить события от клиента к серверу, мы можем использовать hot.send:

ts
// сторона клиента
if (import.meta.hot) {
  import.meta.hot.send('my:from-client', { msg: 'Привет!' })
}

Затем используйте server.ws.on и слушайте события на стороне сервера:

js
// vite.config.js
export default defineConfig({
  plugins: [
    {
      // ...
      configureServer(server) {
        server.ws.on('my:from-client', (data, client) => {
          console.log('Сообщение от клиента:', data.msg) // Привет!
          // отвечаем только клиенту (если необходимо)
          client.send('my:ack', { msg: 'Привет! Я получил ваше сообщение!' })
        })
      },
    },
  ],
})

TypeScript для пользовательских событий

Возможно типизировать пользовательские события, расширяя интерфейс CustomEventMap:

ts
// events.d.ts
import 'vite/types/customEvent'

declare module 'vite/types/customEvent' {
  interface CustomEventMap {
    'custom:foo': { msg: string }
    // 'event-key': payload
  }
}