Алиасы на внутренние пакеты
Алиасы в конфигурации Vite используются для упрощения импорта модулей, особенно в монорепозиториях и проектах с внутренними пакетами. При правильной настройке они позволяют избавиться от длинных относительных путей, ускоряют разработку и делают архитектуру более предсказуемой.
### Внутренние пакеты в монорепозитории
В проектах с несколькими пакетами (monorepo, pnpm workspaces, yarn workspaces) структура часто выглядит следующим образом:
```
repo/
packages/
ui/
utils/
api/
apps/
web/
```
Каждый пакет имеет собственный `package.json`, но при разработке возникает задача: как удобно импортировать один пакет в другой без сложных относительных путей и без публикации в npm.
Типичная проблема без алиасов:
```js
import { formatDate } from '../. ./. ./. ./packages/utils/src/date/formatDate'
```
Такие импорты ухудшают читаемость и усложняют рефакторинг.
### Механизм alias в Vite
Vite предоставляет встроенную поддержку алиасов через поле `resolve.alias` в конфигурации:
```js
import { defineConfig } from 'vite'
import path from 'path'
export default defineConfig({
resolve: {
alias: {
'@utils': path.resolve(__dirname, 'packages/utils/src'),
'@ui': path.resolve(__dirname, 'packages/ui/src'),
'@api': path.resolve(__dirname, 'packages/api/src')
}
}
})
```
Теперь импорт упрощается:
```js
import { formatDate } from '@utils/date/formatDate'
```
### Алиасы для внутренних пакетов в монорепозитории
В случае workspace-архитектуры более правильный подход — отражать структуру пакетов:
```js
resolve: {
alias: {
'@utils': path.resolve(__dirname, '../utils/src'),
'@ui': path.resolve(__dirname, '../ui/src')
}
}
```
Важно учитывать, что алиасы должны указывать именно на исходный код, а не на собранные файлы (`dist`). Это позволяет использовать HMR (Hot Module Replacement) и ускоряет разработку.
### Согласование с TypeScript
Если используется TypeScript, одного `resolve.alias` недостаточно. Необходимо синхронизировать пути с `tsconfig.json`:
```json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@utils/*": ["../packages/utils/src/*"],
"@ui/*": ["../packages/ui/src/*"]
}
}
}
```
Несоответствие между Vite и TypeScript приводит к ошибкам: редактор будет считать импорт валидным, но сборщик — нет, или наоборот.
### Использование vite-tsconfig-paths
В монорепозиториях часто применяется плагин, который устраняет дублирование конфигурации:
```bash
npm install vite-tsconfig-paths -D
```
Конфигурация:
```js
import tsconfigPaths from 'vite-tsconfig-paths'
export default defineConfig({
plugins: [tsconfigPaths()]
})
```
Теперь `paths` из `tsconfig.json` автоматически применяются в Vite без ручного дублирования `alias`.
### Алиасы и оптимизация зависимостей
Vite предварительно бандлит зависимости через `optimizeDeps`. При работе с внутренними пакетами важно учитывать, что:
* пакеты из workspace могут не попадать в pre-bundling автоматически
* иногда требуется явно указать их в `optimizeDeps.include`
```js
export default defineConfig({
optimizeDeps: {
include: ['@utils', '@ui']
}
})
```
Если этого не сделать, возможны проблемы с холодным стартом или некорректная работа ESM/CJS интеропа.
### Разделение алиасов для dev и build
В сложных проектах требуется различное поведение в dev и production. Например, в dev используется исходный код, а в build — собранные артефакты:
```js
export default defineConfig(({ mode }) => {
const isProd = mode === 'production'
return {
resolve: {
alias: {
'@utils': isProd
? path.resolve(__dirname, 'dist/utils')
: path.resolve(__dirname, '../utils/src')
}
}
}
})
```
Такой подход применяется редко, но полезен при строгой изоляции пакетов.
### Алиасы и SSR
При серверном рендеринге (SSR) алиасы должны быть идентичны на клиенте и сервере. Несовпадение путей приводит к ошибкам гидратации.
```js
export default defineConfig({
ssr: {
noExternal: ['@utils', '@ui']
}
})
```
Если внутренние пакеты содержат ESM-код, важно избегать их внешней обработки как зависимостей node_modules.
### Типичные ошибки при настройке
Распространённые проблемы:
* указание пути на `dist`, а не на `src`
* отсутствие синхронизации с `tsconfig.json`
* использование алиасов без учёта монорепозитория
* конфликт одинаковых alias в разных пакетах
* отсутствие поддержки в тестовых раннерах (Vitest, Jest)
### Алиасы и тестирование
При использовании Vitest важно дублировать конфигурацию Vite:
```js
import { defineConfig } from 'vitest/config'
export default defineConfig({
resolve: {
alias: {
'@utils': path.resolve(__dirname, '../utils/src')
}
}
})
```
Иначе тесты могут использовать реальные относительные пути, отличающиеся от продакшн-сборки.
### Архитектурное значение алиасов
Алиасы в Vite — не просто синтаксический сахар. В монорепозиториях они выполняют роль слоя абстракции между пакетами:
* скрывают физическую структуру файлов
* уменьшают связанность между модулями
* позволяют реорганизовывать код без массового рефакторинга импортов
* обеспечивают единый стиль импорта во всех приложениях
При грамотной настройке алиасы становятся частью архитектурного контракта проекта, а не просто конфигурацией сборщика.