Параметр resolve.extensions в конфигурации Vite
управляет списком расширений файлов, которые система автоматически
пытается определить при импорте модулей без явного указания
расширения.
По умолчанию Vite поддерживает распространённые расширения JavaScript, TypeScript и модулей:
resolve: {
extensions: ['.mjs', '.js', '.mts', '.ts', '.jsx', '.tsx', '.json']
}
Механизм работает аналогично поведению Node.js и Webpack: если в коде указан импорт без расширения, Vite перебирает список расширений по порядку и пытается найти подходящий файл.
Пример:
import App from './App'
Во время обработки Vite последовательно проверяет:
./App.mjs
./App.js
./App.mts
./App.ts
./App.jsx
./App.tsx
./App.json
Первый найденный файл используется как результат импорта.
Конфигурация задаётся в vite.config.js:
import { defineConfig } from 'vite'
export default defineConfig({
resolve: {
extensions: ['.js', '.ts', '.jsx', '.tsx']
}
})
После этого Vite будет искать только указанные расширения.
Автоматическое определение расширений влияет на:
import Button from './Button'
Если существует файл:
Button.jsx
то Vite автоматически подключит его.
import Button from './Button.jsx'
В этом случае resolve.extensions уже не используется,
потому что путь указан полностью.
Порядок элементов внутри массива критически важен.
Пример:
resolve: {
extensions: ['.ts', '.js']
}
При наличии двух файлов:
utils.ts
utils.js
и импорте:
import utils from './utils'
Vite выберет:
utils.ts
Потому что .ts находится раньше.
Частая проблема крупных проектов:
Button.js
Button.ts
Button.jsx
Button.tsx
При коротком импорте:
import Button from './Button'
результат зависит только от порядка в extensions.
Это может вызывать:
Для React-проектов обычно используются:
resolve: {
extensions: ['.js', '.jsx', '.ts', '.tsx']
}
Если проект использует React + TypeScript:
Component.tsx
то импорт:
import Component from './Component'
будет успешно работать только при наличии .tsx в списке
расширений.
Для Vue-файлов:
Component.vue
можно добавить:
resolve: {
extensions: ['.js', '.ts', '.vue']
}
Теперь станет возможным:
import Component from './Component'
вместо:
import Component from './Component.vue'
Для Vue-проектов рекомендуется указывать .vue явно:
import Component from './Component.vue'
Причины:
Vite позволяет добавлять нестандартные расширения.
Пример:
resolve: {
extensions: ['.js', '.custom']
}
Теперь импорт:
import module from './example'
может разрешаться в:
example.custom
Подобная схема применяется:
.tsПри настройке:
resolve: {
extensions: ['.ts', '.js']
}
можно писать:
import api from './api'
вместо:
import api from './api.ts'
В обычном Node.js ESM требуется явное указание расширений:
import './file.js'
Но Vite использует собственную систему обработки модулей, поэтому разрешает сокращённые импорты.
tsconfig.json также содержит настройки разрешения
модулей:
{
"compilerOptions": {
"moduleResolution": "bundler"
}
}
Однако TypeScript и Vite работают независимо.
Даже если TypeScript успешно проверяет импорт, Vite может не найти
файл при неправильном resolve.extensions.
Каждый импорт без расширения инициирует последовательный поиск файлов.
Пример:
extensions: [
'.js',
'.jsx',
'.ts',
'.tsx',
'.vue',
'.json',
'.mjs',
'.mts'
]
Для одного импорта Vite может выполнить множество проверок файловой системы.
В проектах с тысячами импортов:
Оптимальный подход:
resolve: {
extensions: ['.ts', '.tsx', '.js']
}
Следует избегать:
Webpack традиционно активно использует
resolve.extensions.
Типичная конфигурация:
resolve: {
extensions: ['.js', '.jsx', '.ts', '.tsx']
}
В Vite философия немного отличается.
Рекомендуется:
Особенно это касается:
.vue;.css;.scss;.svg;.json.import Header from './Header'
Плюсы:
Минусы:
import Header from './Header.tsx'
Преимущества:
resolve.extensions участвует и при поиске индексных
файлов.
Пример:
import utils from './utils'
Vite проверит:
utils.js
utils.ts
utils/index.js
utils/index.ts
в зависимости от конфигурации.
resolve: {
alias: {
'@': '/src'
},
extensions: ['.js', '.ts']
}
Импорт:
import api from '@/services/api'
будет автоматически разрешён в:
/src/services/api.ts
или:
/src/services/api.js
Некоторые IDE хуже работают с неявными расширениями.
Возможные проблемы:
Особенно это проявляется:
В SSR-проектах особенно важно избегать неоднозначности.
Например:
api.server.ts
api.client.ts
api.ts
Неявный импорт:
import api from './api'
может привести к загрузке неправильной версии.
Во многих современных проектах используется минимальная конфигурация:
resolve: {
extensions: ['.js', '.ts']
}
или вообще значение по умолчанию.
resolve.extensionsНастройка действительно полезна при:
Изменение параметра не требуется, если:
Конфигурация:
resolve: {
extensions: ['.js']
}
Импорт:
import App from './App'
Файл:
App.tsx
Результат:
Failed to resolve import "./App"
extensions: ['.js', '.ts']
При наличии:
config.js
config.ts
будет выбран config.js, даже если ожидался
TypeScript-файл.
extensions: [
'.js',
'.jsx',
'.ts',
'.tsx',
'.vue',
'.mjs',
'.mts',
'.json',
'.custom'
]
Подобные конфигурации ухудшают производительность и усложняют сопровождение.
import { defineConfig } from 'vite'
export default defineConfig({
resolve: {
extensions: [
'.ts',
'.tsx',
'.js',
'.jsx'
]
}
})
src/
├── components/
│ ├── Button.tsx
│ └── Modal.jsx
├── utils/
│ └── api.ts
import Button from './components/Button'
import Modal from './components/Modal'
import api from './utils/api'
Все модули будут корректно разрешены без явного указания расширений.
extensions: ['.ts', '.tsx', '.js']
extensions: ['.tsx', '.ts', '.jsx', '.js']
Чаще используется явное указание:
import App from './App.vue'
Для библиотек рекомендуется: