Режим build.lib предназначен для сборки библиотек, SDK,
UI-компонентов, утилит и других переиспользуемых пакетов. В отличие от
стандартной сборки приложения, библиотечный режим ориентирован не на
генерацию HTML-страниц, а на создание универсального JavaScript-пакета,
который может использоваться в других проектах.
При использовании build.lib Vite переключается на
специализированный режим Rollup-сборки:
index.html;es, cjs,
umd, iife.build.libМинимальная конфигурация выглядит следующим образом:
// vite.config.js
import { defineConfig } from 'vite'
import path from 'path'
export default defineConfig({
build: {
lib: {
entry: path.resolve(__dirname, 'src/index.js'),
name: 'MyLibrary',
fileName: 'my-library'
}
}
})
build.libentryТочка входа библиотеки.
lib: {
entry: 'src/index.js'
}
Именно этот файл становится основным экспортом всей библиотеки.
Пример:
// src/index.js
export { Button } from './components/Button'
export { Modal } from './components/Modal'
export { formatDate } from './utils/date'
nameИмя глобальной переменной для форматов umd и
iife.
lib: {
name: 'MyLibrary'
}
После подключения UMD-сборки библиотека станет доступна:
<script src="my-library.umd.js"></script>
<script>
MyLibrary.Button
</script>
Для формата es параметр не используется.
fileNameИмя выходных файлов.
lib: {
fileName: 'my-library'
}
Результат:
dist/
├── my-library.js
├── my-library.umd.cjs
└── style.css
Можно использовать функцию:
fileName: (format) => `my-library.${format}.js`
Результат:
my-library.es.js
my-library.cjs.js
esСовременный стандарт ES Modules.
build: {
lib: {
formats: ['es']
}
}
Результат:
import { Button } from 'my-library'
Особенности:
cjsCommonJS-модули для Node.js.
formats: ['cjs']
Использование:
const lib = require('my-library')
Подходит для:
umdУниверсальный формат.
formats: ['umd']
Поддерживает:
<script>;Пример подключения:
<script src="my-library.umd.js"></script>
iifeСамовызывающаяся функция.
formats: ['iife']
Используется для:
Наиболее распространённый вариант:
build: {
lib: {
entry: 'src/index.js',
name: 'MyLibrary',
formats: ['es', 'cjs', 'umd']
}
}
Результат:
dist/
├── my-library.js
├── my-library.cjs
└── my-library.umd.cjs
externalКритически важная часть библиотечной сборки.
Если библиотека использует Vue, React или
другие крупные зависимости, их обычно исключают из бандла.
build: {
lib: {
entry: 'src/index.js',
name: 'MyLibrary'
},
rollupOptions: {
external: ['vue']
}
}
Теперь vue не попадёт в итоговый bundle.
При использовании external для umd
требуется указать глобальные переменные.
rollupOptions: {
external: ['vue'],
output: {
globals: {
vue: 'Vue'
}
}
}
Без этого UMD-сборка не сможет получить зависимость в браузере.
import { defineConfig } from 'vite'
import path from 'path'
export default defineConfig({
build: {
lib: {
entry: path.resolve(__dirname, 'src/index.js'),
name: 'MyLibrary',
fileName: (format) => `my-library.${format}.js`,
formats: ['es', 'umd']
},
rollupOptions: {
external: ['vue'],
output: {
globals: {
vue: 'Vue'
}
}
}
}
})
Типичная структура проекта:
project/
├── src/
│ ├── components/
│ ├── composables/
│ ├── utils/
│ └── index.js
├── dist/
├── package.json
└── vite.config.js
export { Button }
export { Modal }
Использование:
import { Button } from 'my-library'
export default MyLibrary
Использование:
import MyLibrary from 'my-library'
Vite автоматически извлекает CSS.
Пример:
import './style.css'
Результат:
dist/
├── my-library.js
└── style.css
Иногда требуется единый CSS-файл.
build: {
cssCodeSplit: false
}
Vite сам не генерирует .d.ts.
Обычно используется vite-plugin-dts.
npm install vite-plugin-dts -D
import dts from 'vite-plugin-dts'
export default defineConfig({
plugins: [
dts()
]
})
Результат:
dist/
├── index.d.ts
├── my-library.js
└── style.css
preserveModulesПозволяет сохранять структуру модулей.
rollupOptions: {
output: {
preserveModules: true
}
}
Результат:
dist/
├── components/
├── utils/
└── index.js
Одно из главных преимуществ ES Modules.
export default {
Button,
Modal,
Table
}
Bundler сложнее удалять неиспользуемый код.
export { Button }
export { Modal }
export { Table }
Такой подход улучшает tree-shaking.
Vite поддерживает multi-entry libraries.
lib: {
entry: {
index: 'src/index.js',
utils: 'src/utils/index.js',
components: 'src/components/index.js'
}
}
Результат:
dist/
├── index.js
├── utils.js
└── components.js
resolve: {
alias: {
'@': path.resolve(__dirname, 'src')
}
}
Пример:
import { Button } from '@/components/Button'
По умолчанию используется esbuild.
build: {
minify: true
}
Можно использовать terser.
npm install terser -D
build: {
minify: 'terser'
}
Полезно при отладке.
build: {
sourcemap: true
}
Результат:
my-library.js.map
Современные npm-пакеты используют exports.
package.json{
"name": "my-library",
"type": "module",
"main": "./dist/my-library.cjs.js",
"module": "./dist/my-library.es.js",
"exports": {
".": {
"import": "./dist/my-library.es.js",
"require": "./dist/my-library.cjs.js"
}
}
}
Для корректного tree-shaking:
{
"sideEffects": false
}
Если имеются CSS-импорты:
{
"sideEffects": [
"*.css"
]
}
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
build: {
lib: {
entry: 'src/index.js',
name: 'MyUILibrary'
},
rollupOptions: {
external: ['vue'],
output: {
globals: {
vue: 'Vue'
}
}
}
}
})
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
build: {
lib: {
entry: 'src/index.jsx',
name: 'MyReactLibrary'
},
rollupOptions: {
external: ['react', 'react-dom'],
output: {
globals: {
react: 'React',
'react-dom': 'ReactDOM'
}
}
}
}
})
Ошибка:
external: []
Результат:
Ошибка:
window.addEventListener(...)
Проблема:
Безопасный вариант:
if (typeof window !== 'undefined') {
window.addEventListener(...)
}
main
в package.jsonОшибка:
{
"main": "index.js"
}
Файл отсутствует после сборки.
Правильно:
{
"main": "./dist/my-library.cjs.js"
}
Обычно библиотеку тестируют через:
npm pack
или:
npm link
Также часто создают отдельный playground-проект:
playground/
где проверяется:
{
"files": [
"dist"
]
}
{
"scripts": {
"build": "vite build",
"dev": "vite",
"preview": "vite preview"
}
}
emptyOutDirbuild: {
emptyOutDir: true
}
Перед каждой сборкой каталог dist очищается.
Для библиотек обычно не требуется:
build: {
manifest: false
}
rollupOptions: {
output: {
assetFileNames: 'assets/[name].[ext]'
}
}
output: {
chunkFileNames: 'chunks/[name].js'
}
Лимит inline-файлов:
build: {
assetsInlineLimit: 4096
}
Для универсальных библиотек важно избегать:
window;document;SSR-совместимость особенно важна для:
Основные методы:
external;import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import dts from 'vite-plugin-dts'
import path from 'path'
export default defineConfig({
plugins: [
vue(),
dts()
],
resolve: {
alias: {
'@': path.resolve(__dirname, './src')
}
},
build: {
sourcemap: true,
cssCodeSplit: false,
lib: {
entry: path.resolve(__dirname, 'src/index.js'),
name: 'MyUILibrary',
formats: ['es', 'umd'],
fileName: (format) => `my-ui-library.${format}.js`
},
rollupOptions: {
external: ['vue'],
output: {
globals: {
vue: 'Vue'
},
assetFileNames: 'assets/[name].[ext]',
chunkFileNames: 'chunks/[name].js'
}
}
}
})