Механизм разрешения модулей в Webpack позволяет импортировать файлы
без указания полного имени файла. За это отвечает свойство
resolve.extensions.
Без настройки:
import Button from './Button'
Webpack не сможет определить, какой именно файл требуется загрузить:
Button.js
Button.jsx
Button.ts
Button.vue
Button.json
Список расширений из resolve.extensions задаёт порядок,
в котором Webpack будет искать подходящие файлы.
Базовая конфигурация:
module.exports = {
resolve: {
extensions: ['.js']
}
}
Теперь импорт:
import sum from './math/sum'
будет автоматически преобразован в:
./math/sum.js
При импорте:
import App from './App'
Webpack начинает последовательно проверять расширения:
extensions: ['.js', '.json']
Алгоритм:
./App.js
./App.json
Если файл найден — поиск прекращается.
Если файл отсутствует — Webpack переходит к следующему расширению.
Webpack автоматически использует несколько встроенных расширений:
['.js', '.json', '.wasm']
Это означает, что даже без настройки можно импортировать:
import data from './data'
при наличии файла:
data.json
или:
data.js
Чаще всего конфигурация выглядит так:
module.exports = {
resolve: {
extensions: ['.js', '.jsx', '.ts', '.tsx']
}
}
Теперь Webpack поддерживает импорты:
import App from './App'
для файлов:
App.js
App.jsx
App.ts
App.tsx
Порядок расширений критически важен.
Пример:
extensions: ['.ts', '.js']
При импорте:
import api from './api'
Webpack сначала ищет:
api.ts
и только потом:
api.js
Если существуют оба файла:
api.ts
api.js
будет выбран именно api.ts.
Изменение порядка полностью меняет результат.
Неверный порядок расширений может приводить к:
Опасный пример:
extensions: ['.test.js', '.js']
Импорт:
import utils from './utils'
может неожиданно подключить:
utils.test.js
вместо:
utils.js
...Webpack 5 поддерживает специальный оператор:
'...'
Он позволяет сохранить стандартные расширения Webpack.
Пример:
module.exports = {
resolve: {
extensions: ['.ts', '.tsx', '...']
}
}
Webpack объединит:
['.ts', '.tsx', '.js', '.json', '.wasm']
Без ... стандартные расширения полностью заменяются.
Конфигурация:
extensions: ['.ts']
отключает:
.js
.json
.wasm
Теперь импорт:
import data from './data'
не найдёт:
data.json
Для TypeScript обычно используется:
resolve: {
extensions: ['.ts', '.tsx', '.js']
}
или:
resolve: {
extensions: ['.ts', '.tsx', '...']
}
Причины:
Для React-проектов:
resolve: {
extensions: ['.js', '.jsx']
}
или:
resolve: {
extensions: ['.tsx', '.ts', '.jsx', '.js']
}
Это позволяет писать:
import Header from './components/Header'
вместо:
import Header from './components/Header.jsx'
.vueVue-компоненты обычно подключаются так:
resolve: {
extensions: ['.js', '.vue']
}
Импорт:
import App from './App'
найдёт:
App.vue
.tsAngular-проекты почти всегда используют:
resolve: {
extensions: ['.ts', '.js']
}
Поскольку большая часть кода написана на TypeScript, .ts
располагается первым.
Для Svelte:
resolve: {
extensions: ['.mjs', '.js', '.svelte']
}
Современные проекты часто используют:
resolve: {
extensions: ['.mjs', '.js']
}
Файл .mjs обозначает полноценный ESM-модуль.
Webpack умеет импортировать JSON напрямую:
import config from './config'
Если присутствует:
config.json
Webpack автоматически загрузит JSON-файл.
Это работает благодаря расширению .json.
Импорт без расширения:
import api from './api'
выглядит компактнее.
Но при большом количестве одинаковых имён может возникать неоднозначность:
api.js
api.ts
api.mock.js
api.test.js
В крупных проектах иногда предпочитают явные расширения:
import api from './api.ts'
Каждое расширение увеличивает количество проверок файловой системы.
Конфигурация:
extensions: [
'.ts',
'.tsx',
'.js',
'.jsx',
'.json',
'.vue',
'.mjs'
]
заставляет Webpack выполнять множество проверок.
При импорте:
import App from './App'
Webpack может последовательно проверять:
App.ts
App.tsx
App.js
App.jsx
App.json
App.vue
App.mjs
На больших проектах это влияет на скорость сборки.
Хорошая практика — оставлять только реально используемые расширения.
Плохо:
extensions: [
'.js',
'.jsx',
'.ts',
'.tsx',
'.vue',
'.json',
'.mjs',
'.coffee'
]
если половина из них не используется.
Лучше:
extensions: ['.ts', '.tsx', '.js']
resolve.aliasextensions работает совместно с алиасами.
Конфигурация:
resolve: {
alias: {
'@': path.resolve(__dirname, 'src')
},
extensions: ['.js', '.ts']
}
Импорт:
import Button from '@/components/Button'
будет проверять:
src/components/Button.js
src/components/Button.ts
mainFilesWebpack умеет автоматически искать индексные файлы.
Конфигурация:
resolve: {
mainFiles: ['index'],
extensions: ['.js', '.ts']
}
Импорт:
import utils from './utils'
может привести к поиску:
utils/index.js
utils/index.ts
fullySpecifiedВ ESM-режиме Webpack может требовать полные пути:
import utils from './utils.js'
Опция:
resolve: {
fullySpecified: false
}
разрешает использовать:
import utils from './utils'
вместе с extensions.
При работе Babel и Webpack важно синхронизировать расширения.
Webpack:
resolve: {
extensions: ['.js', '.jsx']
}
Babel:
test: /\.(js|jsx)$/
Если Webpack поддерживает .jsx, а Babel — нет, файл
будет найден, но не обработан транспилятором.
ESLint также должен понимать используемые расширения.
Пример настройки:
settings: {
'import/resolver': {
node: {
extensions: ['.js', '.jsx', '.ts', '.tsx']
}
}
}
Иначе линтер может ошибочно считать импорт несуществующим.
Jest имеет собственный механизм резолвинга модулей.
Обычно настройки синхронизируют:
moduleFileExtensions: ['js', 'jsx', 'ts', 'tsx']
Несовпадение между Jest и Webpack приводит к ошибкам тестирования.
tsconfig.jsonTypeScript также хранит список расширений.
Webpack:
extensions: ['.ts', '.tsx', '.js']
TypeScript:
{
"compilerOptions": {
"allowJs": true
}
}
Важно поддерживать согласованность всей инфраструктуры проекта.
Неправильно:
extensions: ['js']
Правильно:
extensions: ['.js']
Неправильно:
extensions: ['.ts']
если проект использует JSON.
Правильно:
extensions: ['.ts', '...']
Избыточные расширения:
extensions: [
'.js',
'.jsx',
'.ts',
'.tsx',
'.json',
'.vue',
'.mjs',
'.cjs',
'.coffee'
]
ухудшают производительность.
Опасная структура:
Button.js
Button.ts
Button.jsx
Импорт:
import Button from './Button'
становится зависимым от порядка extensions.
resolve: {
extensions: ['.js', '...']
}
resolve: {
extensions: ['.jsx', '.js', '...']
}
resolve: {
extensions: ['.tsx', '.ts', '.jsx', '.js', '...']
}
resolve: {
extensions: ['.vue', '.js', '...']
}
resolve: {
extensions: ['.mjs', '.js', '.json']
}
При импорте:
import module from './module'
Webpack:
extensions.mainFiles.Из-за большого количества файлов механизм резолвинга считается одной из наиболее нагруженных частей сборки.
Webpack кэширует результаты поиска модулей.
Если файл уже был найден как:
Button.tsx
Webpack повторно использует результат без повторного перебора расширений.
Это особенно важно в больших monorepo-проектах.
enhanced-resolveWebpack использует библиотеку enhanced-resolve.
Именно она:
Свойство extensions является частью этого механизма.
Node.js и Webpack работают по-разному.
Node.js ESM:
import './utils.js'
обычно требует полного расширения.
Webpack способен автоматически дополнять расширения через
resolve.extensions.
Это упрощает разработку, но создаёт различия между средами выполнения.
Явные расширения полезны:
Пример:
import Button from './Button.tsx'
resolve.extensions максимально полезен:
Без него импорты становятся значительно длиннее:
import Header from './components/Header/Header.jsx'
вместо:
import Header from './components/Header/Header'