@eventuras/vite-config 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +171 -0
- package/package.json +37 -0
- package/src/base.ts +16 -0
- package/src/externals.ts +45 -0
- package/src/next-lib.ts +36 -0
- package/src/react-lib.ts +239 -0
- package/src/vanilla-lib.ts +90 -0
package/README.md
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# @eventuras/vite-config
|
|
2
|
+
|
|
3
|
+
Shared Vite configurations for Eventuras monorepo libraries.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This package provides reusable Vite configuration presets for different types of libraries in the Eventuras monorepo. It helps maintain consistency, reduces duplication, and makes it easier to update build configurations across all libraries.
|
|
8
|
+
|
|
9
|
+
## Presets
|
|
10
|
+
|
|
11
|
+
### Vanilla Library (`vanilla-lib`)
|
|
12
|
+
|
|
13
|
+
For plain TypeScript libraries without React.
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
// vite.config.ts
|
|
17
|
+
import { defineVanillaLibConfig } from '@eventuras/vite-config/vanilla-lib';
|
|
18
|
+
import { resolve } from 'path';
|
|
19
|
+
|
|
20
|
+
export default defineVanillaLibConfig({
|
|
21
|
+
entry: 'src/index.ts',
|
|
22
|
+
name: 'MyLibrary',
|
|
23
|
+
external: ['some-external-dep'],
|
|
24
|
+
});
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### React Library (`react-lib`)
|
|
28
|
+
|
|
29
|
+
For React component libraries and utilities.
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
// vite.config.ts
|
|
33
|
+
import { defineReactLibConfig } from '@eventuras/vite-config/react-lib';
|
|
34
|
+
import { resolve } from 'path';
|
|
35
|
+
|
|
36
|
+
export default defineReactLibConfig({
|
|
37
|
+
entry: 'src/index.ts',
|
|
38
|
+
// Or use glob for multiple entry points:
|
|
39
|
+
// entry: 'src/**/index.ts',
|
|
40
|
+
external: ['@eventuras/ratio-ui'],
|
|
41
|
+
tailwind: true, // Enable Tailwind CSS
|
|
42
|
+
preserveModules: true, // Keep source structure in dist
|
|
43
|
+
useSWC: false, // Use Babel (default) or SWC for React transform
|
|
44
|
+
});
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**Features:**
|
|
48
|
+
- React plugin (Babel or SWC)
|
|
49
|
+
- TypeScript declaration generation
|
|
50
|
+
- Optional Tailwind CSS support
|
|
51
|
+
- 'use client' directive preservation for RSC
|
|
52
|
+
- Configurable module preservation
|
|
53
|
+
- Auto-excludes test files and stories from types
|
|
54
|
+
|
|
55
|
+
### Next.js Library (`next-lib`)
|
|
56
|
+
|
|
57
|
+
For React libraries compatible with Next.js (includes Next.js externals).
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
// vite.config.ts
|
|
61
|
+
import { defineNextLibConfig } from '@eventuras/vite-config/next-lib';
|
|
62
|
+
import { resolve } from 'path';
|
|
63
|
+
|
|
64
|
+
export default defineNextLibConfig({
|
|
65
|
+
entry: {
|
|
66
|
+
'Image/index': resolve(__dirname, 'src/Image/index.ts'),
|
|
67
|
+
'Link/index': resolve(__dirname, 'src/Link/index.ts'),
|
|
68
|
+
index: resolve(__dirname, 'src/index.ts'),
|
|
69
|
+
},
|
|
70
|
+
external: ['@eventuras/ratio-ui'],
|
|
71
|
+
tailwind: true,
|
|
72
|
+
});
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**Features:**
|
|
76
|
+
- All React library features
|
|
77
|
+
- Next.js externals (next, next/image, next/link, etc.)
|
|
78
|
+
- Always preserves 'use client' directives
|
|
79
|
+
|
|
80
|
+
## Configuration Options
|
|
81
|
+
|
|
82
|
+
### Common Options
|
|
83
|
+
|
|
84
|
+
All presets support these options:
|
|
85
|
+
|
|
86
|
+
- **`entry`**: Library entry point(s)
|
|
87
|
+
- String: `'src/index.ts'`
|
|
88
|
+
- Object: `{ index: 'src/index.ts', utils: 'src/utils.ts' }`
|
|
89
|
+
- Glob (React only): `'src/**/index.ts'`
|
|
90
|
+
|
|
91
|
+
- **`external`**: Additional dependencies to exclude from bundle
|
|
92
|
+
- Array of strings or RegExp patterns
|
|
93
|
+
- Common externals (react, next) are already included
|
|
94
|
+
|
|
95
|
+
- **`viteConfig`**: Additional Vite config to merge
|
|
96
|
+
|
|
97
|
+
### React-Specific Options
|
|
98
|
+
|
|
99
|
+
- **`tailwind`**: Enable Tailwind CSS support (default: `false`)
|
|
100
|
+
- **`preserveModules`**: Keep source structure in output (default: `true`)
|
|
101
|
+
- **`preserveUseClientDirectives`**: Preserve 'use client' for RSC (default: `true`)
|
|
102
|
+
- **`useSWC`**: Use SWC instead of Babel (default: `false`)
|
|
103
|
+
- **`dts`**: TypeScript declaration options
|
|
104
|
+
- `entryRoot`: Source root (default: `'src'`)
|
|
105
|
+
- `outDir`: Output directory (default: `'dist'`)
|
|
106
|
+
- `rollupTypes`: Bundle types into single file (default: `false`)
|
|
107
|
+
|
|
108
|
+
## Migration Guide
|
|
109
|
+
|
|
110
|
+
### Before (duplicated config in each library)
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
// libs/my-lib/vite.config.ts
|
|
114
|
+
import react from '@vitejs/plugin-react';
|
|
115
|
+
import { resolve } from 'path';
|
|
116
|
+
import { defineConfig } from 'vite';
|
|
117
|
+
import dts from 'vite-plugin-dts';
|
|
118
|
+
|
|
119
|
+
export default defineConfig({
|
|
120
|
+
plugins: [
|
|
121
|
+
react(),
|
|
122
|
+
dts({
|
|
123
|
+
include: ['src/**/*'],
|
|
124
|
+
exclude: ['src/**/*.stories.tsx'],
|
|
125
|
+
}),
|
|
126
|
+
],
|
|
127
|
+
build: {
|
|
128
|
+
lib: {
|
|
129
|
+
entry: resolve(__dirname, 'src/index.ts'),
|
|
130
|
+
formats: ['es'],
|
|
131
|
+
},
|
|
132
|
+
rollupOptions: {
|
|
133
|
+
external: ['react', 'react-dom', 'react/jsx-runtime'],
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### After (using shared config)
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
// libs/my-lib/vite.config.ts
|
|
143
|
+
import { defineReactLibConfig } from '@eventuras/vite-config/react-lib';
|
|
144
|
+
|
|
145
|
+
export default defineReactLibConfig({
|
|
146
|
+
entry: 'src/index.ts',
|
|
147
|
+
});
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Best Practices
|
|
151
|
+
|
|
152
|
+
1. **Use the most specific preset**: If building for Next.js, use `next-lib` instead of `react-lib`
|
|
153
|
+
2. **Only specify what's different**: The presets have sensible defaults
|
|
154
|
+
3. **Use glob patterns for multi-entry libraries**: `entry: 'src/**/index.ts'`
|
|
155
|
+
4. **Enable SWC for faster builds**: `useSWC: true` (in development)
|
|
156
|
+
5. **Keep modules preserved**: `preserveModules: true` for better tree-shaking
|
|
157
|
+
|
|
158
|
+
## Troubleshooting
|
|
159
|
+
|
|
160
|
+
### Types not generated
|
|
161
|
+
- Check that your TypeScript files are in `src/`
|
|
162
|
+
- Ensure test files use `.test.ts` or `.spec.ts` extensions
|
|
163
|
+
- Check `dts.entryRoot` and `dts.outDir` options
|
|
164
|
+
|
|
165
|
+
### 'use client' directives missing
|
|
166
|
+
- Ensure `preserveUseClientDirectives: true` (default for Next.js)
|
|
167
|
+
- Check that source files have 'use client' at the top
|
|
168
|
+
|
|
169
|
+
### Build errors with Next.js
|
|
170
|
+
- Use `next-lib` preset instead of `react-lib`
|
|
171
|
+
- Check that Next.js packages are in `external` array
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@eventuras/vite-config",
|
|
3
|
+
"version": "0.2.2",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/losol/origo.git",
|
|
8
|
+
"directory": "config/vite-config"
|
|
9
|
+
},
|
|
10
|
+
"type": "module",
|
|
11
|
+
"exports": {
|
|
12
|
+
"./base": "./src/base.ts",
|
|
13
|
+
"./react-lib": "./src/react-lib.ts",
|
|
14
|
+
"./vanilla-lib": "./src/vanilla-lib.ts",
|
|
15
|
+
"./next-lib": "./src/next-lib.ts"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"src"
|
|
19
|
+
],
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@tailwindcss/vite": "^4.3.2",
|
|
22
|
+
"@vitejs/plugin-react": "^6.0.3",
|
|
23
|
+
"@vitejs/plugin-react-swc": "^4.3.0",
|
|
24
|
+
"glob": "^13.0.6",
|
|
25
|
+
"vite-plugin-dts": "^5.0.3"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"typescript": "^6.0.2",
|
|
29
|
+
"vite": "^8.1.0"
|
|
30
|
+
},
|
|
31
|
+
"peerDependencies": {
|
|
32
|
+
"vite": "^7.0.0 || ^8.0.0"
|
|
33
|
+
},
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public"
|
|
36
|
+
}
|
|
37
|
+
}
|
package/src/base.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { defineConfig, type UserConfig } from 'vite';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Base Vite configuration with common defaults for all Eventuras packages.
|
|
5
|
+
*/
|
|
6
|
+
export function defineBaseConfig(config: UserConfig = {}): UserConfig {
|
|
7
|
+
return defineConfig({
|
|
8
|
+
...config,
|
|
9
|
+
build: {
|
|
10
|
+
...config.build,
|
|
11
|
+
// Common build optimizations
|
|
12
|
+
minify: false, // Libraries should not be minified
|
|
13
|
+
sourcemap: true, // Always generate sourcemaps for debugging
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
}
|
package/src/externals.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { builtinModules } from 'node:module';
|
|
3
|
+
import { resolve } from 'node:path';
|
|
4
|
+
|
|
5
|
+
interface PackageJson {
|
|
6
|
+
dependencies?: Record<string, string>;
|
|
7
|
+
peerDependencies?: Record<string, string>;
|
|
8
|
+
optionalDependencies?: Record<string, string>;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Reads the consumer package's package.json and returns RegExp patterns that
|
|
13
|
+
* mark every runtime dependency (and its subpaths) as external.
|
|
14
|
+
*
|
|
15
|
+
* Bundling runtime deps into a library is harmful: it duplicates code, breaks
|
|
16
|
+
* `instanceof` checks across module boundaries (the consumer's class identity
|
|
17
|
+
* differs from the bundled copy), and inflates installed size. Consumers
|
|
18
|
+
* already install these deps via the lib's own package.json.
|
|
19
|
+
*/
|
|
20
|
+
export function getRuntimeDependencyExternals(cwd: string = process.cwd()): RegExp[] {
|
|
21
|
+
const pkgPath = resolve(cwd, 'package.json');
|
|
22
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf8')) as PackageJson;
|
|
23
|
+
|
|
24
|
+
const names = [
|
|
25
|
+
...Object.keys(pkg.dependencies ?? {}),
|
|
26
|
+
...Object.keys(pkg.peerDependencies ?? {}),
|
|
27
|
+
...Object.keys(pkg.optionalDependencies ?? {}),
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
return names.map(name => new RegExp(`^${escapeRegex(name)}(/.*)?$`));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Externalize Node built-ins in both forms — `node:fs` (always matched by the
|
|
35
|
+
* regex) and the bare `fs` form (matched against the explicit list, since the
|
|
36
|
+
* names overlap with userland packages and can't be regex-distinguished).
|
|
37
|
+
*/
|
|
38
|
+
export const NODE_BUILTINS_EXTERNAL: (string | RegExp)[] = [
|
|
39
|
+
/^node:/,
|
|
40
|
+
...builtinModules,
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
function escapeRegex(s: string): string {
|
|
44
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
45
|
+
}
|
package/src/next-lib.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { UserConfig } from 'vite';
|
|
2
|
+
import { defineReactLibConfig, type ReactLibConfig } from './react-lib.ts';
|
|
3
|
+
|
|
4
|
+
export interface NextLibConfig extends Omit<ReactLibConfig, 'external'> {
|
|
5
|
+
/**
|
|
6
|
+
* Additional external dependencies beyond the Next.js defaults and the
|
|
7
|
+
* package.json auto-externalization (via the underlying React preset).
|
|
8
|
+
*/
|
|
9
|
+
external?: (string | RegExp)[];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Vite configuration preset for Next.js-compatible React libraries.
|
|
14
|
+
* Extends the React library config with Next.js-specific externals and defaults.
|
|
15
|
+
*/
|
|
16
|
+
export function defineNextLibConfig(config: NextLibConfig): UserConfig {
|
|
17
|
+
const { external = [], ...reactConfig } = config;
|
|
18
|
+
|
|
19
|
+
// Next.js externals - include all next/* paths to avoid bundling internal modules
|
|
20
|
+
const nextExternals = [
|
|
21
|
+
'next',
|
|
22
|
+
'next/image',
|
|
23
|
+
'next/link',
|
|
24
|
+
'next/navigation',
|
|
25
|
+
'next/router',
|
|
26
|
+
'next/headers',
|
|
27
|
+
/^next\//, // Externalize all next/* imports
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
return defineReactLibConfig({
|
|
31
|
+
...reactConfig,
|
|
32
|
+
external: [...nextExternals, ...external],
|
|
33
|
+
// Next.js libraries should always preserve client directives
|
|
34
|
+
preserveUseClientDirectives: true,
|
|
35
|
+
});
|
|
36
|
+
}
|
package/src/react-lib.ts
ADDED
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { defineConfig, type UserConfig } from 'vite';
|
|
2
|
+
import react from '@vitejs/plugin-react';
|
|
3
|
+
import tailwindcss from '@tailwindcss/vite';
|
|
4
|
+
import dts from 'vite-plugin-dts';
|
|
5
|
+
import { resolve } from 'node:path';
|
|
6
|
+
import { glob } from 'glob';
|
|
7
|
+
import fs from 'node:fs';
|
|
8
|
+
|
|
9
|
+
import { getRuntimeDependencyExternals, NODE_BUILTINS_EXTERNAL } from './externals.ts';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Plugin to preserve 'use client' directives in React Server Components.
|
|
13
|
+
* This ensures client-side code is properly marked when building for Next.js.
|
|
14
|
+
*/
|
|
15
|
+
function preserveUseClient() {
|
|
16
|
+
return {
|
|
17
|
+
name: 'preserve-use-client',
|
|
18
|
+
enforce: 'post' as const,
|
|
19
|
+
generateBundle(_options: any, bundle: any) {
|
|
20
|
+
for (const [_fileName, chunk] of Object.entries(bundle)) {
|
|
21
|
+
if ((chunk as any).type === 'chunk') {
|
|
22
|
+
const chunkData = chunk as any;
|
|
23
|
+
// Check if any source module had 'use client'
|
|
24
|
+
const hasClientDirective = chunkData.moduleIds?.some((id: string) => {
|
|
25
|
+
try {
|
|
26
|
+
const content = fs.readFileSync(id, 'utf-8');
|
|
27
|
+
// Remove leading comments to check for 'use client'
|
|
28
|
+
const withoutComments = content
|
|
29
|
+
.replace(/^(\s*\/\/.*\n)+/, '')
|
|
30
|
+
.replace(/^(\s*\/\*[\s\S]*?\*\/\s*)/, '');
|
|
31
|
+
return (
|
|
32
|
+
withoutComments.trimStart().startsWith("'use client'") ||
|
|
33
|
+
withoutComments.trimStart().startsWith('"use client"')
|
|
34
|
+
);
|
|
35
|
+
} catch {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
if (hasClientDirective) {
|
|
41
|
+
const codeStart = chunkData.code.trimStart();
|
|
42
|
+
if (!codeStart.startsWith("'use client'") && !codeStart.startsWith('"use client"')) {
|
|
43
|
+
chunkData.code = `'use client';\n${chunkData.code}`;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface ReactLibConfig {
|
|
53
|
+
/**
|
|
54
|
+
* Library entry point(s). Can be:
|
|
55
|
+
* - A string path: 'src/index.ts'
|
|
56
|
+
* - An object with multiple entries: { index: 'src/index.ts', utils: 'src/utils.ts' }
|
|
57
|
+
* - A glob pattern: 'src/** /index.ts' (auto-discovers multiple entry points)
|
|
58
|
+
*/
|
|
59
|
+
entry: string | Record<string, string>;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Additional external dependencies to exclude from the bundle, on top of the
|
|
63
|
+
* runtime deps read from the consumer's package.json and the React core
|
|
64
|
+
* externals. Pass `false` to opt out of package.json auto-externalization.
|
|
65
|
+
*/
|
|
66
|
+
external?: (string | RegExp)[] | false;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Enable Tailwind CSS support via @tailwindcss/vite plugin.
|
|
70
|
+
* @default false
|
|
71
|
+
*/
|
|
72
|
+
tailwind?: boolean;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Preserve module structure in output.
|
|
76
|
+
* When true, creates a dist structure mirroring src structure.
|
|
77
|
+
* When false, bundles everything into fewer files.
|
|
78
|
+
* @default true
|
|
79
|
+
*/
|
|
80
|
+
preserveModules?: boolean;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Enable 'use client' directive preservation for Next.js React Server Components.
|
|
84
|
+
* @default true
|
|
85
|
+
*/
|
|
86
|
+
preserveUseClientDirectives?: boolean;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Use SWC instead of Babel for React transformation (faster builds).
|
|
90
|
+
* @default false
|
|
91
|
+
*/
|
|
92
|
+
useSWC?: boolean;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* TypeScript declaration options.
|
|
96
|
+
*/
|
|
97
|
+
dts?: {
|
|
98
|
+
/**
|
|
99
|
+
* Entry root for DTS generation.
|
|
100
|
+
* @default 'src'
|
|
101
|
+
*/
|
|
102
|
+
entryRoot?: string;
|
|
103
|
+
/**
|
|
104
|
+
* Output directory for .d.ts files.
|
|
105
|
+
* @default 'dist'
|
|
106
|
+
*/
|
|
107
|
+
outDir?: string;
|
|
108
|
+
/**
|
|
109
|
+
* Roll up types into a single .d.ts file.
|
|
110
|
+
* @default false
|
|
111
|
+
*/
|
|
112
|
+
rollupTypes?: boolean;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Additional Vite configuration to merge.
|
|
117
|
+
*/
|
|
118
|
+
viteConfig?: UserConfig;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Vite configuration preset for React libraries.
|
|
123
|
+
* Includes React plugin, TypeScript declarations, and common React externals.
|
|
124
|
+
*/
|
|
125
|
+
export function defineReactLibConfig(config: ReactLibConfig): UserConfig {
|
|
126
|
+
const {
|
|
127
|
+
entry,
|
|
128
|
+
external,
|
|
129
|
+
tailwind = false,
|
|
130
|
+
preserveModules = true,
|
|
131
|
+
preserveUseClientDirectives = true,
|
|
132
|
+
useSWC = false,
|
|
133
|
+
dts: dtsOptions = {},
|
|
134
|
+
viteConfig = {},
|
|
135
|
+
} = config;
|
|
136
|
+
|
|
137
|
+
const autoExternals =
|
|
138
|
+
external === false ? [] : getRuntimeDependencyExternals();
|
|
139
|
+
const userExternals = Array.isArray(external) ? external : [];
|
|
140
|
+
|
|
141
|
+
// Determine entry points
|
|
142
|
+
let entryPoints: string | string[] | Record<string, string>;
|
|
143
|
+
if (typeof entry === 'string' && entry.includes('*')) {
|
|
144
|
+
entryPoints = glob.sync(resolve(process.cwd(), entry));
|
|
145
|
+
} else if (typeof entry === 'string') {
|
|
146
|
+
entryPoints = resolve(process.cwd(), entry);
|
|
147
|
+
} else {
|
|
148
|
+
entryPoints = entry;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Common React externals
|
|
152
|
+
const reactExternals = ['react', 'react-dom', 'react/jsx-runtime'];
|
|
153
|
+
|
|
154
|
+
const plugins: any[] = [];
|
|
155
|
+
|
|
156
|
+
// Add React plugin (SWC or standard)
|
|
157
|
+
if (useSWC) {
|
|
158
|
+
// Dynamically import SWC plugin only when needed
|
|
159
|
+
const reactSwc = require('@vitejs/plugin-react-swc').default;
|
|
160
|
+
plugins.push(reactSwc());
|
|
161
|
+
} else {
|
|
162
|
+
plugins.push(react());
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Add Tailwind if enabled
|
|
166
|
+
if (tailwind) {
|
|
167
|
+
plugins.push(tailwindcss());
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Add DTS plugin
|
|
171
|
+
plugins.push(
|
|
172
|
+
dts({
|
|
173
|
+
entryRoot: dtsOptions.entryRoot || 'src',
|
|
174
|
+
outDir: dtsOptions.outDir || 'dist',
|
|
175
|
+
include: ['src/**/*'],
|
|
176
|
+
exclude: ['**/*.test.ts', '**/*.test.tsx', '**/*.spec.ts', '**/*.spec.tsx', '**/*.stories.tsx'],
|
|
177
|
+
copyDtsFiles: true,
|
|
178
|
+
rollupTypes: dtsOptions.rollupTypes || false,
|
|
179
|
+
})
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
// Add use client preservation if enabled
|
|
183
|
+
if (preserveUseClientDirectives) {
|
|
184
|
+
plugins.push(preserveUseClient());
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Add custom plugins from viteConfig
|
|
188
|
+
if (viteConfig.plugins) {
|
|
189
|
+
plugins.push(...viteConfig.plugins);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return defineConfig({
|
|
193
|
+
plugins,
|
|
194
|
+
resolve: {
|
|
195
|
+
alias: {
|
|
196
|
+
'@': resolve(process.cwd(), './src'),
|
|
197
|
+
...viteConfig.resolve?.alias,
|
|
198
|
+
},
|
|
199
|
+
...viteConfig.resolve,
|
|
200
|
+
},
|
|
201
|
+
build: {
|
|
202
|
+
minify: false,
|
|
203
|
+
sourcemap: true,
|
|
204
|
+
lib: {
|
|
205
|
+
entry: entryPoints,
|
|
206
|
+
formats: ['es'],
|
|
207
|
+
},
|
|
208
|
+
rollupOptions: {
|
|
209
|
+
...viteConfig.build?.rollupOptions,
|
|
210
|
+
external: [
|
|
211
|
+
...reactExternals,
|
|
212
|
+
...autoExternals,
|
|
213
|
+
...NODE_BUILTINS_EXTERNAL,
|
|
214
|
+
...userExternals,
|
|
215
|
+
],
|
|
216
|
+
output: {
|
|
217
|
+
preserveModules,
|
|
218
|
+
...(preserveModules && {
|
|
219
|
+
preserveModulesRoot: 'src',
|
|
220
|
+
entryFileNames: '[name].js',
|
|
221
|
+
}),
|
|
222
|
+
...viteConfig.build?.rollupOptions?.output,
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
// Spread other build options from viteConfig except lib and rollupOptions
|
|
226
|
+
...Object.fromEntries(
|
|
227
|
+
Object.entries(viteConfig.build || {}).filter(
|
|
228
|
+
([key]) => key !== 'lib' && key !== 'rollupOptions'
|
|
229
|
+
)
|
|
230
|
+
),
|
|
231
|
+
},
|
|
232
|
+
// Spread other viteConfig options except build, plugins, and resolve
|
|
233
|
+
...Object.fromEntries(
|
|
234
|
+
Object.entries(viteConfig).filter(
|
|
235
|
+
([key]) => key !== 'build' && key !== 'plugins' && key !== 'resolve'
|
|
236
|
+
)
|
|
237
|
+
),
|
|
238
|
+
});
|
|
239
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { defineConfig, type UserConfig } from 'vite';
|
|
2
|
+
import dts from 'vite-plugin-dts';
|
|
3
|
+
import { resolve } from 'node:path';
|
|
4
|
+
|
|
5
|
+
import { getRuntimeDependencyExternals, NODE_BUILTINS_EXTERNAL } from './externals.ts';
|
|
6
|
+
|
|
7
|
+
export interface VanillaLibConfig {
|
|
8
|
+
/**
|
|
9
|
+
* Library entry point(s). Can be a string or an object with multiple entries.
|
|
10
|
+
* @example 'src/index.ts'
|
|
11
|
+
* @example { index: 'src/index.ts', utils: 'src/utils.ts' }
|
|
12
|
+
*/
|
|
13
|
+
entry: string | Record<string, string>;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Library name for UMD builds (optional).
|
|
17
|
+
*/
|
|
18
|
+
name?: string;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Additional external dependencies to exclude from the bundle, on top of the
|
|
22
|
+
* runtime deps read from the consumer's package.json. Pass `false` to opt out
|
|
23
|
+
* of the package.json auto-externalization (rarely what you want).
|
|
24
|
+
*/
|
|
25
|
+
external?: (string | RegExp)[] | false;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Additional Vite configuration to merge.
|
|
29
|
+
*/
|
|
30
|
+
viteConfig?: UserConfig;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Vite configuration preset for vanilla TypeScript libraries.
|
|
35
|
+
*
|
|
36
|
+
* Defaults that matter for libraries:
|
|
37
|
+
* - All runtime deps (dependencies + peerDependencies + optionalDependencies)
|
|
38
|
+
* are externalized so consumers get one copy from their node_modules instead
|
|
39
|
+
* of inlined+mangled copies inside the published bundle.
|
|
40
|
+
* - Minification is OFF — consumers minify their own bundle, and unminified
|
|
41
|
+
* output preserves class names (so `instanceof` and stack traces work).
|
|
42
|
+
* - Sourcemaps ON for debuggable consumer stack traces.
|
|
43
|
+
*/
|
|
44
|
+
export function defineVanillaLibConfig(config: VanillaLibConfig): UserConfig {
|
|
45
|
+
const { entry, name, external, viteConfig = {} } = config;
|
|
46
|
+
|
|
47
|
+
const autoExternals =
|
|
48
|
+
external === false ? [] : getRuntimeDependencyExternals();
|
|
49
|
+
const userExternals = Array.isArray(external) ? external : [];
|
|
50
|
+
|
|
51
|
+
return defineConfig({
|
|
52
|
+
plugins: [
|
|
53
|
+
dts({
|
|
54
|
+
include: ['src/**/*'],
|
|
55
|
+
exclude: ['**/*.test.ts', '**/*.test.tsx', '**/*.spec.ts', '**/*.spec.tsx'],
|
|
56
|
+
}),
|
|
57
|
+
...(viteConfig.plugins || []),
|
|
58
|
+
],
|
|
59
|
+
build: {
|
|
60
|
+
minify: false,
|
|
61
|
+
sourcemap: true,
|
|
62
|
+
lib: {
|
|
63
|
+
entry: typeof entry === 'string' ? resolve(process.cwd(), entry) : entry,
|
|
64
|
+
...(name && { name }),
|
|
65
|
+
formats: ['es'],
|
|
66
|
+
fileName: (_format, entryName) => `${entryName}.js`,
|
|
67
|
+
},
|
|
68
|
+
rollupOptions: {
|
|
69
|
+
...viteConfig.build?.rollupOptions,
|
|
70
|
+
external: [...autoExternals, ...NODE_BUILTINS_EXTERNAL, ...userExternals],
|
|
71
|
+
output: {
|
|
72
|
+
preserveModules: false,
|
|
73
|
+
...viteConfig.build?.rollupOptions?.output,
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
// Spread other build options from viteConfig except lib and rollupOptions
|
|
77
|
+
...Object.fromEntries(
|
|
78
|
+
Object.entries(viteConfig.build || {}).filter(
|
|
79
|
+
([key]) => key !== 'lib' && key !== 'rollupOptions'
|
|
80
|
+
)
|
|
81
|
+
),
|
|
82
|
+
},
|
|
83
|
+
// Spread other viteConfig options except build and plugins
|
|
84
|
+
...Object.fromEntries(
|
|
85
|
+
Object.entries(viteConfig).filter(
|
|
86
|
+
([key]) => key !== 'build' && key !== 'plugins'
|
|
87
|
+
)
|
|
88
|
+
),
|
|
89
|
+
});
|
|
90
|
+
}
|