Параметр build.rollupOptions в конфигурации Vite
предоставляет прямой доступ к настройкам сборщика Rollup. Несмотря на то
что Vite скрывает большую часть низкоуровневой конфигурации, внутри
production-сборки используется именно Rollup, поэтому через
rollupOptions можно:
Базовый пример:
import { defineConfig } from 'vite'
export default defineConfig({
build: {
rollupOptions: {
}
}
})
rollupOptionsОбъект rollupOptions поддерживает практически все
параметры Rollup:
export default defineConfig({
build: {
rollupOptions: {
input,
output,
plugins,
external,
treeshake,
preserveEntrySignatures,
onwarn
}
}
})
Наиболее важными являются:
| Параметр | Назначение |
|---|---|
input |
Точки входа |
output |
Настройка выходных файлов |
plugins |
Rollup-плагины |
external |
Исключение зависимостей из бандла |
treeshake |
Управление tree shaking |
onwarn |
Перехват предупреждений |
manualChunks |
Ручное разделение чанков |
inputПо умолчанию Vite использует index.html как entry
point.
Эквивалент:
rollupOptions: {
input: 'index.html'
}
Многовходовая архитектура используется в:
Пример:
import { defineConfig } from 'vite'
import { resolve } from 'path'
export default defineConfig({
build: {
rollupOptions: {
input: {
main: resolve(__dirname, 'index.html'),
admin: resolve(__dirname, 'admin.html'),
dashboard: resolve(__dirname, 'dashboard.html')
}
}
}
})
После сборки каждая HTML-страница получит собственный набор ресурсов.
Иногда требуется собирать не HTML, а JS-модуль.
Пример:
rollupOptions: {
input: 'src/main.js'
}
Подобный подход применяется:
outputРаздел output отвечает за структуру итоговой сборки.
rollupOptions: {
output: {
dir: 'dist',
format: 'es'
}
}
По умолчанию Vite генерирует файлы с hash:
assets/index-a1b2c3.js
Настройка:
rollupOptions: {
output: {
entryFileNames: 'js/[name].js',
chunkFileNames: 'js/[name].js',
assetFileNames: 'assets/[name].[ext]'
}
}
Результат:
dist/
├── js/
│ ├── main.js
│ └── vendor.js
└── assets/
└── logo.svg
Для production почти всегда нужен hash.
Пример:
output: {
entryFileNames: 'js/[name]-[hash].js',
chunkFileNames: 'js/[name]-[hash].js',
assetFileNames: 'assets/[name]-[hash].[ext]'
}
Можно сортировать ресурсы автоматически.
Пример:
output: {
assetFileNames(assetInfo) {
const ext = assetInfo.name.split('.').pop()
if (/png|jpg|svg|gif/.test(ext)) {
return 'images/[name]-[hash].[ext]'
}
if (/css/.test(ext)) {
return 'css/[name]-[hash].[ext]'
}
return 'assets/[name]-[hash].[ext]'
}
}
Результат:
dist/
├── images/
├── css/
└── assets/
Rollup поддерживает различные форматы модулей.
output: {
format: 'es'
}
Современный стандарт JavaScript-модулей.
output: {
format: 'cjs'
}
Используется в Node.js.
output: {
format: 'umd',
name: 'MyLibrary'
}
Подходит для подключения через <script>.
output: {
format: 'iife',
name: 'App'
}
Создаёт самовызывающийся bundle.
manualChunksОдна из важнейших возможностей Rollup.
manualChunks позволяет:
output: {
manualChunks: {
vendor: ['vue']
}
}
Будет создан отдельный chunk:
vendor.js
output: {
manualChunks: {
vue: ['vue'],
charts: ['chart.js'],
editor: ['quill']
}
}
Очень распространённая практика:
output: {
manualChunks(id) {
if (id.includes('node_modules')) {
return 'vendor'
}
}
}
Более гибкий вариант:
output: {
manualChunks(id) {
if (id.includes('node_modules')) {
return id
.split('node_modules/')[1]
.split('/')[0]
}
}
}
Результат:
react.js
lodash.js
axios.js
externalПараметр external запрещает Rollup включать модуль в
bundle.
rollupOptions: {
external: ['vue']
}
Vue не попадёт в итоговую сборку.
Типичные случаи:
При UMD/IIFE требуется указать глобальное имя:
output: {
globals: {
vue: 'Vue'
}
}
Полный пример:
rollupOptions: {
external: ['vue'],
output: {
globals: {
vue: 'Vue'
}
}
}
Vite поддерживает Rollup-плагины напрямую.
import legacy from '@vitejs/plugin-legacy'
export default defineConfig({
plugins: [
legacy()
]
})
Но существуют случаи, когда нужен именно Rollup-plugin:
import strip from '@rollup/plugin-strip'
export default defineConfig({
build: {
rollupOptions: {
plugins: [
strip({
debugger: true
})
]
}
}
})
| Плагин | Назначение |
|---|---|
@rollup/plugin-alias |
Алиасы |
@rollup/plugin-replace |
Замена значений |
@rollup/plugin-strip |
Удаление debugger |
@rollup/plugin-inject |
Автоимпорт |
rollup-plugin-visualizer |
Анализ bundle |
@rollup/plugin-commonjs |
CommonJS поддержка |
Очень полезный инструмент.
Установка:
npm install rollup-plugin-visualizer --save-dev
Конфигурация:
import { visualizer } from 'rollup-plugin-visualizer'
export default defineConfig({
build: {
rollupOptions: {
plugins: [
visualizer({
open: true
})
]
}
}
})
После сборки откроется интерактивная карта bundle.
Rollup обладает одним из лучших механизмов tree shaking.
rollupOptions: {
treeshake: true
}
rollupOptions: {
treeshake: {
moduleSideEffects: false,
propertyReadSideEffects: false,
tryCatchDeoptimization: false
}
}
moduleSideEffectsУказывает, имеет ли модуль побочные эффекты.
treeshake: {
moduleSideEffects: false
}
Rollup сможет агрессивнее удалять код.
onwarnПозволяет перехватывать предупреждения Rollup.
rollupOptions: {
onwarn(warning, warn) {
if (warning.code === 'CIRCULAR_DEPENDENCY') {
return
}
warn(warning)
}
}
preserveModulesПозволяет сохранять файловую структуру.
output: {
preserveModules: true
}
Вместо одного bundle:
dist/
├── utils/
├── components/
└── services/
Типичные сценарии:
Vite поддерживает режим библиотечной сборки.
export default defineConfig({
build: {
lib: {
entry: 'src/index.js',
name: 'MyLib',
fileName: 'my-lib'
},
rollupOptions: {
external: ['vue'],
output: {
globals: {
vue: 'Vue'
}
}
}
}
})
build: {
lib: {
entry: 'src/index.js',
name: 'MyLib',
formats: ['es', 'umd', 'cjs']
}
}
Rollup корректно обрабатывает:
const module = await import('./module.js')
Каждый dynamic import создаёт отдельный chunk.
Пример:
const AdminPanel = () => import('./AdminPanel.js')
После сборки:
admin-panel.js
Позволяет объединять dynamic imports в один файл.
output: {
inlineDynamicImports: true
}
Нельзя использовать:
Rollup позволяет гибко управлять sourcemap.
output: {
sourcemap: true
}
build: {
sourcemap: 'hidden'
}
Карта будет создана без ссылки внутри JS-файла.
Пример production-конфигурации:
import { defineConfig } from 'vite'
export default defineConfig({
build: {
sourcemap: false,
rollupOptions: {
output: {
entryFileNames: 'js/[name]-[hash].js',
chunkFileNames: 'js/[name]-[hash].js',
assetFileNames(assetInfo) {
const ext = assetInfo.name
.split('.')
.pop()
if (/css/.test(ext)) {
return 'css/[name]-[hash].[ext]'
}
if (/png|jpg|svg|gif/.test(ext)) {
return 'images/[name]-[hash].[ext]'
}
return 'assets/[name]-[hash].[ext]'
},
manualChunks(id) {
if (id.includes('node_modules')) {
return 'vendor'
}
}
}
}
}
})
manualChunksНеправильное разделение может вызвать:
externalЕсли исключить зависимость ошибочно:
external: ['react']
но не подключить React отдельно, приложение сломается.
Не все Rollup-плагины корректно работают с Vite.
Причины:
Подходит:
manualChunks(id) {
if (id.includes('node_modules')) {
return 'vendor'
}
}
Критически важны:
external
globals
formats
preserveModules
Рекомендуется:
Полезны:
preserveModules
external
import { defineConfig } from 'vite'
import { visualizer } from 'rollup-plugin-visualizer'
export default defineConfig({
build: {
sourcemap: false,
rollupOptions: {
external: ['vue'],
plugins: [
visualizer()
],
output: {
format: 'es',
globals: {
vue: 'Vue'
},
entryFileNames: 'js/[name]-[hash].js',
chunkFileNames: 'js/[name]-[hash].js',
assetFileNames: 'assets/[name]-[hash].[ext]',
manualChunks(id) {
if (id.includes('node_modules')) {
return 'vendor'
}
}
},
treeshake: {
moduleSideEffects: false
},
onwarn(warning, warn) {
if (warning.code === 'CIRCULAR_DEPENDENCY') {
return
}
warn(warning)
}
}
}
})