@useavalon/avalon 0.1.0
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 +54 -0
- package/mod.ts +301 -0
- package/package.json +85 -0
- package/src/build/README.md +310 -0
- package/src/build/integration-bundler-plugin.ts +116 -0
- package/src/build/integration-config.ts +168 -0
- package/src/build/integration-detection-plugin.ts +117 -0
- package/src/build/integration-resolver-plugin.ts +90 -0
- package/src/build/island-manifest.ts +269 -0
- package/src/build/island-types-generator.ts +476 -0
- package/src/build/mdx-island-transform.ts +464 -0
- package/src/build/mdx-plugin.ts +98 -0
- package/src/build/page-island-transform.ts +598 -0
- package/src/build/prop-extractors/index.ts +21 -0
- package/src/build/prop-extractors/lit.ts +140 -0
- package/src/build/prop-extractors/qwik.ts +16 -0
- package/src/build/prop-extractors/solid.ts +125 -0
- package/src/build/prop-extractors/svelte.ts +194 -0
- package/src/build/prop-extractors/vue.ts +111 -0
- package/src/build/sidecar-file-manager.ts +104 -0
- package/src/build/sidecar-renderer.ts +30 -0
- package/src/client/adapters/index.ts +13 -0
- package/src/client/adapters/lit-adapter.ts +654 -0
- package/src/client/adapters/preact-adapter.ts +331 -0
- package/src/client/adapters/qwik-adapter.ts +345 -0
- package/src/client/adapters/react-adapter.ts +353 -0
- package/src/client/adapters/solid-adapter.ts +451 -0
- package/src/client/adapters/svelte-adapter.ts +524 -0
- package/src/client/adapters/vue-adapter.ts +467 -0
- package/src/client/components.ts +35 -0
- package/src/client/css-hmr-handler.ts +344 -0
- package/src/client/framework-adapter.ts +462 -0
- package/src/client/hmr-coordinator.ts +396 -0
- package/src/client/hmr-error-overlay.js +533 -0
- package/src/client/main.js +816 -0
- package/src/client/tests/css-hmr-handler.test.ts +360 -0
- package/src/client/tests/framework-adapter.test.ts +519 -0
- package/src/client/tests/hmr-coordinator.test.ts +176 -0
- package/src/client/tests/hydration-option-parsing.test.ts +107 -0
- package/src/client/tests/lit-adapter.test.ts +427 -0
- package/src/client/tests/preact-adapter.test.ts +353 -0
- package/src/client/tests/qwik-adapter.test.ts +343 -0
- package/src/client/tests/react-adapter.test.ts +317 -0
- package/src/client/tests/solid-adapter.test.ts +396 -0
- package/src/client/tests/svelte-adapter.test.ts +387 -0
- package/src/client/tests/vue-adapter.test.ts +407 -0
- package/src/client/types/framework-runtime.d.ts +68 -0
- package/src/client/types/vite-hmr.d.ts +46 -0
- package/src/client/types/vite-virtual-modules.d.ts +60 -0
- package/src/components/Image.tsx +123 -0
- package/src/components/IslandErrorBoundary.tsx +145 -0
- package/src/components/LayoutDataErrorBoundary.tsx +141 -0
- package/src/components/LayoutErrorBoundary.tsx +127 -0
- package/src/components/PersistentIsland.tsx +52 -0
- package/src/components/StreamingErrorBoundary.tsx +233 -0
- package/src/components/StreamingLayout.tsx +538 -0
- package/src/components/tests/component-analyzer.test.ts +96 -0
- package/src/components/tests/component-detection.test.ts +347 -0
- package/src/components/tests/persistent-islands.test.ts +398 -0
- package/src/core/components/component-analyzer.ts +192 -0
- package/src/core/components/component-detection.ts +508 -0
- package/src/core/components/enhanced-framework-detector.ts +500 -0
- package/src/core/components/framework-registry.ts +563 -0
- package/src/core/components/tests/enhanced-framework-detector.test.ts +577 -0
- package/src/core/components/tests/framework-registry.test.ts +465 -0
- package/src/core/content/mdx-processor.ts +46 -0
- package/src/core/integrations/README.md +282 -0
- package/src/core/integrations/index.ts +19 -0
- package/src/core/integrations/loader.ts +125 -0
- package/src/core/integrations/registry.ts +195 -0
- package/src/core/islands/island-persistence.ts +325 -0
- package/src/core/islands/island-state-serializer.ts +258 -0
- package/src/core/islands/persistent-island-context.tsx +80 -0
- package/src/core/islands/use-persistent-state.ts +68 -0
- package/src/core/layout/enhanced-layout-resolver.ts +322 -0
- package/src/core/layout/layout-cache-manager.ts +485 -0
- package/src/core/layout/layout-composer.ts +357 -0
- package/src/core/layout/layout-data-loader.ts +516 -0
- package/src/core/layout/layout-discovery.ts +243 -0
- package/src/core/layout/layout-matcher.ts +299 -0
- package/src/core/layout/layout-types.ts +110 -0
- package/src/core/layout/tests/enhanced-layout-resolver.test.ts +477 -0
- package/src/core/layout/tests/layout-cache-optimization.test.ts +149 -0
- package/src/core/layout/tests/layout-composer.test.ts +486 -0
- package/src/core/layout/tests/layout-data-loader.test.ts +443 -0
- package/src/core/layout/tests/layout-discovery.test.ts +253 -0
- package/src/core/layout/tests/layout-matcher.test.ts +480 -0
- package/src/core/modules/framework-module-resolver.ts +273 -0
- package/src/core/modules/tests/framework-module-resolver.test.ts +263 -0
- package/src/core/modules/tests/module-resolution-integration.test.ts +117 -0
- package/src/islands/component-analysis.ts +213 -0
- package/src/islands/css-utils.ts +565 -0
- package/src/islands/discovery/index.ts +80 -0
- package/src/islands/discovery/registry.ts +340 -0
- package/src/islands/discovery/resolver.ts +477 -0
- package/src/islands/discovery/scanner.ts +386 -0
- package/src/islands/discovery/tests/island-discovery.test.ts +881 -0
- package/src/islands/discovery/types.ts +117 -0
- package/src/islands/discovery/validator.ts +544 -0
- package/src/islands/discovery/watcher.ts +368 -0
- package/src/islands/framework-detection.ts +428 -0
- package/src/islands/integration-loader.ts +490 -0
- package/src/islands/island.tsx +565 -0
- package/src/islands/render-cache.ts +550 -0
- package/src/islands/types.ts +80 -0
- package/src/islands/universal-css-collector.ts +157 -0
- package/src/islands/universal-head-collector.ts +137 -0
- package/src/layout-system.d.ts +592 -0
- package/src/layout-system.ts +218 -0
- package/src/middleware/__tests__/discovery.test.ts +107 -0
- package/src/middleware/discovery.ts +268 -0
- package/src/middleware/executor.ts +315 -0
- package/src/middleware/index.ts +76 -0
- package/src/middleware/types.ts +99 -0
- package/src/nitro/build-config.ts +576 -0
- package/src/nitro/config.ts +483 -0
- package/src/nitro/error-handler.ts +636 -0
- package/src/nitro/index.ts +173 -0
- package/src/nitro/island-manifest.ts +584 -0
- package/src/nitro/middleware-adapter.ts +260 -0
- package/src/nitro/renderer.ts +1458 -0
- package/src/nitro/route-discovery.ts +439 -0
- package/src/nitro/types.ts +321 -0
- package/src/render/collect-css.ts +198 -0
- package/src/render/error-pages.ts +79 -0
- package/src/render/isolated-ssr-renderer.ts +654 -0
- package/src/render/ssr.ts +1030 -0
- package/src/schemas/api.ts +30 -0
- package/src/schemas/core.ts +64 -0
- package/src/schemas/index.ts +212 -0
- package/src/schemas/layout.ts +279 -0
- package/src/schemas/routing/index.ts +38 -0
- package/src/schemas/routing.ts +376 -0
- package/src/types/as-island.ts +20 -0
- package/src/types/image.d.ts +106 -0
- package/src/types/index.d.ts +22 -0
- package/src/types/island-jsx.d.ts +33 -0
- package/src/types/island-prop.d.ts +20 -0
- package/src/types/layout.ts +285 -0
- package/src/types/mdx.d.ts +6 -0
- package/src/types/routing.ts +555 -0
- package/src/types/tests/layout-types.test.ts +197 -0
- package/src/types/types.ts +5 -0
- package/src/types/urlpattern.d.ts +49 -0
- package/src/types/vite-env.d.ts +11 -0
- package/src/utils/dev-logger.ts +299 -0
- package/src/utils/fs.ts +151 -0
- package/src/vite-plugin/auto-discover.ts +551 -0
- package/src/vite-plugin/config.ts +266 -0
- package/src/vite-plugin/errors.ts +127 -0
- package/src/vite-plugin/image-optimization.ts +151 -0
- package/src/vite-plugin/integration-activator.ts +126 -0
- package/src/vite-plugin/island-sidecar-plugin.ts +176 -0
- package/src/vite-plugin/module-discovery.ts +189 -0
- package/src/vite-plugin/nitro-integration.ts +1334 -0
- package/src/vite-plugin/plugin.ts +329 -0
- package/src/vite-plugin/tests/image-optimization.test.ts +54 -0
- package/src/vite-plugin/types.ts +327 -0
- package/src/vite-plugin/validation.ts +228 -0
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
# Avalon Build System
|
|
2
|
+
|
|
3
|
+
This directory contains the build system components for Avalon, including integration detection, bundling, and optimization.
|
|
4
|
+
|
|
5
|
+
## Components
|
|
6
|
+
|
|
7
|
+
### Integration Detection (`integration-detection-plugin.ts`)
|
|
8
|
+
|
|
9
|
+
Automatically detects which framework integrations are used in your project by:
|
|
10
|
+
- Scanning file extensions (`.vue`, `.svelte`)
|
|
11
|
+
- Analyzing imports in TSX/JSX files
|
|
12
|
+
- Detecting framework-specific patterns
|
|
13
|
+
|
|
14
|
+
**Usage:**
|
|
15
|
+
```typescript
|
|
16
|
+
import { detectUsedIntegrations, getRequiredIntegrations } from './integration-detection-plugin.ts';
|
|
17
|
+
|
|
18
|
+
const detected = await detectUsedIntegrations();
|
|
19
|
+
const required = getRequiredIntegrations(detected);
|
|
20
|
+
// required = ['preact', 'vue', 'solid', 'svelte']
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Integration Resolver (`integration-resolver-plugin.ts`)
|
|
24
|
+
|
|
25
|
+
Resolves `@useavalon/integration-*` imports to actual file paths:
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
// Import resolution
|
|
29
|
+
'@useavalon/integration-preact' → 'src/integrations/preact/mod.ts'
|
|
30
|
+
'@useavalon/integration-preact/server' → 'src/integrations/preact/server/renderer.ts'
|
|
31
|
+
'@useavalon/integration-preact/client' → 'src/integrations/preact/client/index.ts'
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**Usage:**
|
|
35
|
+
```typescript
|
|
36
|
+
import { integrationResolverPlugin, createIntegrationAliases } from './integration-resolver-plugin.ts';
|
|
37
|
+
|
|
38
|
+
// In Vite config
|
|
39
|
+
plugins: [
|
|
40
|
+
integrationResolverPlugin(),
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
// Or use aliases
|
|
44
|
+
resolve: {
|
|
45
|
+
alias: createIntegrationAliases(),
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Integration Bundler (`integration-bundler-plugin.ts`)
|
|
50
|
+
|
|
51
|
+
Handles bundling of integration packages for both client and SSR builds:
|
|
52
|
+
|
|
53
|
+
**Usage:**
|
|
54
|
+
```typescript
|
|
55
|
+
import { integrationBundlerPlugin } from './integration-bundler-plugin.ts';
|
|
56
|
+
|
|
57
|
+
// Client build
|
|
58
|
+
plugins: [
|
|
59
|
+
integrationBundlerPlugin({
|
|
60
|
+
integrations: ['preact', 'vue'],
|
|
61
|
+
ssr: false
|
|
62
|
+
}),
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
// SSR build
|
|
66
|
+
plugins: [
|
|
67
|
+
integrationBundlerPlugin({
|
|
68
|
+
integrations: ['preact', 'vue'],
|
|
69
|
+
ssr: true
|
|
70
|
+
}),
|
|
71
|
+
]
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Integration Config (`integration-config.ts`)
|
|
75
|
+
|
|
76
|
+
Centralized configuration for all framework integrations:
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
export interface IntegrationBuildConfig {
|
|
80
|
+
name: string;
|
|
81
|
+
extensions: string[];
|
|
82
|
+
optimizeDeps: string[];
|
|
83
|
+
ssrExternal: string[];
|
|
84
|
+
ssrNoExternal: string[];
|
|
85
|
+
requiresPlugin: boolean;
|
|
86
|
+
pluginPackage?: string;
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**Usage:**
|
|
91
|
+
```typescript
|
|
92
|
+
import {
|
|
93
|
+
getIntegrationBuildConfig,
|
|
94
|
+
getOptimizeDepsForIntegrations,
|
|
95
|
+
getSSRNoExternalForIntegrations
|
|
96
|
+
} from './integration-config.ts';
|
|
97
|
+
|
|
98
|
+
const config = getIntegrationBuildConfig('preact');
|
|
99
|
+
const optimizeDeps = getOptimizeDepsForIntegrations(['preact', 'vue']);
|
|
100
|
+
const ssrNoExternal = getSSRNoExternalForIntegrations(['preact', 'vue']);
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Island Manifest (`island-manifest.ts`)
|
|
104
|
+
|
|
105
|
+
Generates a manifest of all islands with their framework types and bundle paths:
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
export interface IslandManifest {
|
|
109
|
+
islands: Record<string, IslandEntry>;
|
|
110
|
+
version: string;
|
|
111
|
+
buildTime: number;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export interface IslandEntry {
|
|
115
|
+
src: string;
|
|
116
|
+
bundle: string;
|
|
117
|
+
hash: string;
|
|
118
|
+
framework: 'preact' | 'solid' | 'vue' | 'svelte' | 'vanilla';
|
|
119
|
+
deps: string[];
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
**Usage:**
|
|
124
|
+
```typescript
|
|
125
|
+
import { generateIslandManifest, loadIslandManifest } from './island-manifest.ts';
|
|
126
|
+
|
|
127
|
+
// During build
|
|
128
|
+
const manifest = await generateIslandManifest();
|
|
129
|
+
await Deno.writeTextFile('dist/island-manifest.json', JSON.stringify(manifest));
|
|
130
|
+
|
|
131
|
+
// At runtime
|
|
132
|
+
const manifest = await loadIslandManifest();
|
|
133
|
+
const bundlePath = getIslandBundlePath('/islands/Counter.tsx', manifest);
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### MDX Plugin (`mdx-plugin.ts`)
|
|
137
|
+
|
|
138
|
+
Handles MDX file processing with support for framework components.
|
|
139
|
+
|
|
140
|
+
## Build Configurations
|
|
141
|
+
|
|
142
|
+
### Main Build (`vite.config.ts`)
|
|
143
|
+
|
|
144
|
+
Client-side build configuration:
|
|
145
|
+
- Detects used integrations
|
|
146
|
+
- Bundles client hydration code
|
|
147
|
+
- Optimizes dependencies
|
|
148
|
+
- Includes island bundles
|
|
149
|
+
|
|
150
|
+
### SSR Build (`vite.ssr.config.ts`)
|
|
151
|
+
|
|
152
|
+
Server-side rendering build configuration:
|
|
153
|
+
- Bundles SSR rendering code
|
|
154
|
+
- Includes island SSR bundles
|
|
155
|
+
- Configures SSR externals
|
|
156
|
+
- Outputs to `dist/ssr/`
|
|
157
|
+
|
|
158
|
+
## Build Process
|
|
159
|
+
|
|
160
|
+
The build process is orchestrated by `build.ts`:
|
|
161
|
+
|
|
162
|
+
1. **Integration Detection**: Scan project to detect frameworks
|
|
163
|
+
2. **Manifest Generation**: Create island manifest
|
|
164
|
+
3. **Client Build**: Bundle client code with Vite
|
|
165
|
+
4. **SSR Build**: Bundle SSR code with Vite SSR config
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
deno run --allow-all build.ts
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Tree Shaking
|
|
172
|
+
|
|
173
|
+
The build system automatically tree-shakes unused integrations:
|
|
174
|
+
|
|
175
|
+
- Only detected integrations are bundled
|
|
176
|
+
- Framework dependencies are excluded if not used
|
|
177
|
+
- Vite plugins are only loaded for used frameworks
|
|
178
|
+
|
|
179
|
+
**Example:**
|
|
180
|
+
```
|
|
181
|
+
Project uses: Preact, Vue
|
|
182
|
+
Build includes: preact integration, vue integration
|
|
183
|
+
Build excludes: solid integration, svelte integration
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## Testing
|
|
187
|
+
|
|
188
|
+
Test integration detection:
|
|
189
|
+
```bash
|
|
190
|
+
deno run --allow-read test-integration-detection.ts
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Expected output:
|
|
194
|
+
```
|
|
195
|
+
🔍 Testing integration detection...
|
|
196
|
+
|
|
197
|
+
Detected integrations:
|
|
198
|
+
Preact: ✅
|
|
199
|
+
Vue: ✅
|
|
200
|
+
Solid: ✅
|
|
201
|
+
Svelte: ✅
|
|
202
|
+
|
|
203
|
+
Required integrations: preact, vue, solid, svelte
|
|
204
|
+
|
|
205
|
+
✅ Integration detection test complete!
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Adding a New Integration
|
|
209
|
+
|
|
210
|
+
To add support for a new framework:
|
|
211
|
+
|
|
212
|
+
1. **Create Integration Package**
|
|
213
|
+
```
|
|
214
|
+
src/integrations/[framework]/
|
|
215
|
+
├── mod.ts
|
|
216
|
+
├── server/
|
|
217
|
+
│ └── renderer.ts
|
|
218
|
+
├── client/
|
|
219
|
+
│ └── index.ts
|
|
220
|
+
└── types.ts
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
2. **Add Build Configuration**
|
|
224
|
+
```typescript
|
|
225
|
+
// In integration-config.ts
|
|
226
|
+
export const INTEGRATION_BUILD_CONFIGS = {
|
|
227
|
+
// ...
|
|
228
|
+
myframework: {
|
|
229
|
+
name: 'myframework',
|
|
230
|
+
extensions: ['.myext'],
|
|
231
|
+
optimizeDeps: ['myframework'],
|
|
232
|
+
ssrExternal: [],
|
|
233
|
+
ssrNoExternal: ['myframework'],
|
|
234
|
+
requiresPlugin: true,
|
|
235
|
+
pluginPackage: 'vite-plugin-myframework',
|
|
236
|
+
},
|
|
237
|
+
};
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
3. **Update Detection Logic**
|
|
241
|
+
```typescript
|
|
242
|
+
// In integration-detection-plugin.ts
|
|
243
|
+
export async function detectUsedIntegrations() {
|
|
244
|
+
const result = {
|
|
245
|
+
// ...
|
|
246
|
+
myframework: false,
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
// Add detection logic
|
|
250
|
+
if (entry.name.endsWith('.myext')) {
|
|
251
|
+
result.myframework = true;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return result;
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
4. **Add Resolver Aliases**
|
|
259
|
+
```typescript
|
|
260
|
+
// In integration-resolver-plugin.ts
|
|
261
|
+
export function createIntegrationAliases() {
|
|
262
|
+
return {
|
|
263
|
+
// ...
|
|
264
|
+
'@useavalon/integration-myframework': resolve(cwd, 'src/integrations/myframework/mod.ts'),
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
## Performance
|
|
270
|
+
|
|
271
|
+
### Build Time Impact
|
|
272
|
+
|
|
273
|
+
- Integration detection: ~10-50ms
|
|
274
|
+
- Plugin initialization: ~5-20ms per integration
|
|
275
|
+
- Total overhead: <100ms for typical projects
|
|
276
|
+
|
|
277
|
+
### Bundle Size Impact
|
|
278
|
+
|
|
279
|
+
Per-integration overhead (gzipped):
|
|
280
|
+
- Preact: ~4KB (client) + ~8KB (server)
|
|
281
|
+
- Vue: ~10KB (client) + ~15KB (server)
|
|
282
|
+
- Solid: ~7KB (client) + ~10KB (server)
|
|
283
|
+
- Svelte: ~5KB (client) + ~12KB (server)
|
|
284
|
+
|
|
285
|
+
## Troubleshooting
|
|
286
|
+
|
|
287
|
+
### Integration Not Detected
|
|
288
|
+
|
|
289
|
+
Check:
|
|
290
|
+
1. File extensions match integration config
|
|
291
|
+
2. Files are in scanned directories
|
|
292
|
+
3. Imports use correct framework packages
|
|
293
|
+
|
|
294
|
+
### Build Errors
|
|
295
|
+
|
|
296
|
+
Common issues:
|
|
297
|
+
- Missing Vite plugin: Install required plugin
|
|
298
|
+
- Module resolution: Check integration aliases
|
|
299
|
+
- SSR errors: Verify SSR noExternal config
|
|
300
|
+
|
|
301
|
+
### Bundle Size
|
|
302
|
+
|
|
303
|
+
To optimize:
|
|
304
|
+
1. Remove unused framework imports
|
|
305
|
+
2. Verify tree-shaking is working
|
|
306
|
+
3. Check that only used integrations are bundled
|
|
307
|
+
|
|
308
|
+
## Documentation
|
|
309
|
+
|
|
310
|
+
See [docs/build-system-integrations.md](../../docs/build-system-integrations.md) for detailed documentation.
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import type { Plugin } from 'vite';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
import { getOptimizeDepsForIntegrations, getSSRNoExternalForIntegrations } from './integration-config.ts';
|
|
4
|
+
|
|
5
|
+
export interface IntegrationBundlerOptions {
|
|
6
|
+
/** Integrations to include in the build */
|
|
7
|
+
integrations: string[];
|
|
8
|
+
/** Whether to bundle for SSR */
|
|
9
|
+
ssr?: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Vite plugin to bundle integration packages
|
|
14
|
+
* Ensures integration server and client code is properly bundled
|
|
15
|
+
*/
|
|
16
|
+
export function integrationBundlerPlugin(options: IntegrationBundlerOptions): Plugin {
|
|
17
|
+
const { integrations, ssr = false } = options;
|
|
18
|
+
const cwd = process.cwd();
|
|
19
|
+
|
|
20
|
+
return {
|
|
21
|
+
name: 'avalon:integration-bundler',
|
|
22
|
+
enforce: 'post',
|
|
23
|
+
|
|
24
|
+
config(config) {
|
|
25
|
+
// Add integration entry points to the build
|
|
26
|
+
const entries: Record<string, string> = {};
|
|
27
|
+
|
|
28
|
+
for (const framework of integrations) {
|
|
29
|
+
if (ssr) {
|
|
30
|
+
// SSR build: include server-side integration code
|
|
31
|
+
entries[`integrations/${framework}/server`] = resolve(
|
|
32
|
+
cwd,
|
|
33
|
+
`packages/integrations/${framework}/server/renderer.ts`
|
|
34
|
+
);
|
|
35
|
+
} else {
|
|
36
|
+
// Client build: include client-side integration code
|
|
37
|
+
entries[`integrations/${framework}/client`] = resolve(
|
|
38
|
+
cwd,
|
|
39
|
+
`packages/integrations/${framework}/client/index.ts`
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Merge with existing rolldown input
|
|
45
|
+
const existingInput = config.build?.rolldownOptions?.input || {};
|
|
46
|
+
const mergedInput = typeof existingInput === 'string'
|
|
47
|
+
? { main: existingInput, ...entries }
|
|
48
|
+
: { ...existingInput, ...entries };
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
build: {
|
|
52
|
+
rolldownOptions: {
|
|
53
|
+
input: mergedInput,
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Get external dependencies for integration bundling
|
|
65
|
+
* These should not be bundled but loaded from node_modules
|
|
66
|
+
*/
|
|
67
|
+
export function getIntegrationExternals(framework: string, ssr: boolean) {
|
|
68
|
+
const externals: string[] = [];
|
|
69
|
+
|
|
70
|
+
// Framework-specific externals
|
|
71
|
+
switch (framework) {
|
|
72
|
+
case 'preact':
|
|
73
|
+
if (!ssr) {
|
|
74
|
+
// Client-side: preact should be bundled for hydration
|
|
75
|
+
return [];
|
|
76
|
+
}
|
|
77
|
+
// SSR: keep preact external if needed
|
|
78
|
+
externals.push('preact', 'preact/hooks', 'preact-render-to-string');
|
|
79
|
+
break;
|
|
80
|
+
|
|
81
|
+
case 'vue':
|
|
82
|
+
if (ssr) {
|
|
83
|
+
// SSR: Vue server renderer should be external
|
|
84
|
+
externals.push('vue', 'vue/server-renderer', '@vue/server-renderer', '@vue/shared');
|
|
85
|
+
}
|
|
86
|
+
break;
|
|
87
|
+
|
|
88
|
+
case 'solid':
|
|
89
|
+
if (ssr) {
|
|
90
|
+
externals.push('solid-js', 'solid-js/web');
|
|
91
|
+
}
|
|
92
|
+
break;
|
|
93
|
+
|
|
94
|
+
case 'svelte':
|
|
95
|
+
if (ssr) {
|
|
96
|
+
externals.push('svelte', 'svelte/server', 'svelte/compiler', 'svelte/internal');
|
|
97
|
+
}
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return externals;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Configure optimization for integration dependencies
|
|
106
|
+
*/
|
|
107
|
+
export function getIntegrationOptimizeDeps(integrations: string[]) {
|
|
108
|
+
return getOptimizeDepsForIntegrations(integrations);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Get SSR noExternal packages for integrations
|
|
113
|
+
*/
|
|
114
|
+
export function getIntegrationSSRNoExternal(integrations: string[]) {
|
|
115
|
+
return getSSRNoExternalForIntegrations(integrations);
|
|
116
|
+
}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration configuration for build system
|
|
3
|
+
* Defines how each integration should be bundled and optimized
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface IntegrationBuildConfig {
|
|
7
|
+
/** Framework name */
|
|
8
|
+
name: string;
|
|
9
|
+
/** File extensions this integration handles */
|
|
10
|
+
extensions: string[];
|
|
11
|
+
/** NPM packages that should be optimized for this integration */
|
|
12
|
+
optimizeDeps: string[];
|
|
13
|
+
/** NPM packages that should be external in SSR builds */
|
|
14
|
+
ssrExternal: string[];
|
|
15
|
+
/** NPM packages that should NOT be external in SSR builds */
|
|
16
|
+
ssrNoExternal: string[];
|
|
17
|
+
/** Whether this integration requires a Vite plugin */
|
|
18
|
+
requiresPlugin: boolean;
|
|
19
|
+
/** Plugin package name (if requiresPlugin is true) */
|
|
20
|
+
pluginPackage?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Build configuration for all supported integrations
|
|
25
|
+
*/
|
|
26
|
+
export const INTEGRATION_BUILD_CONFIGS: Record<string, IntegrationBuildConfig> = {
|
|
27
|
+
preact: {
|
|
28
|
+
name: 'preact',
|
|
29
|
+
extensions: ['.tsx', '.jsx'],
|
|
30
|
+
optimizeDeps: [
|
|
31
|
+
'preact',
|
|
32
|
+
'preact/hooks',
|
|
33
|
+
'preact/jsx-runtime',
|
|
34
|
+
'preact/jsx-dev-runtime',
|
|
35
|
+
],
|
|
36
|
+
ssrExternal: [],
|
|
37
|
+
ssrNoExternal: ['preact', 'preact-render-to-string'],
|
|
38
|
+
requiresPlugin: false,
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
vue: {
|
|
42
|
+
name: 'vue',
|
|
43
|
+
extensions: ['.vue'],
|
|
44
|
+
optimizeDeps: ['vue'],
|
|
45
|
+
ssrExternal: [],
|
|
46
|
+
ssrNoExternal: ['vue', '@vue/server-renderer', '@vue/shared'],
|
|
47
|
+
requiresPlugin: true,
|
|
48
|
+
pluginPackage: '@vitejs/plugin-vue',
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
solid: {
|
|
52
|
+
name: 'solid',
|
|
53
|
+
extensions: ['.tsx', '.jsx'],
|
|
54
|
+
optimizeDeps: [
|
|
55
|
+
'solid-js',
|
|
56
|
+
'solid-js/web',
|
|
57
|
+
'solid-js/store',
|
|
58
|
+
],
|
|
59
|
+
ssrExternal: [],
|
|
60
|
+
ssrNoExternal: ['solid-js', 'solid-js/web', 'solid-js/store'],
|
|
61
|
+
requiresPlugin: true,
|
|
62
|
+
pluginPackage: 'vite-plugin-solid',
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
svelte: {
|
|
66
|
+
name: 'svelte',
|
|
67
|
+
extensions: ['.svelte'],
|
|
68
|
+
optimizeDeps: [
|
|
69
|
+
'svelte',
|
|
70
|
+
'svelte/internal',
|
|
71
|
+
'svelte/store',
|
|
72
|
+
'svelte/animate',
|
|
73
|
+
'svelte/easing',
|
|
74
|
+
'svelte/motion',
|
|
75
|
+
'svelte/transition',
|
|
76
|
+
],
|
|
77
|
+
ssrExternal: [],
|
|
78
|
+
ssrNoExternal: ['svelte', 'svelte/server', 'svelte/internal', 'svelte/store'],
|
|
79
|
+
requiresPlugin: true,
|
|
80
|
+
pluginPackage: '@sveltejs/vite-plugin-svelte',
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
react: {
|
|
84
|
+
name: 'react',
|
|
85
|
+
extensions: ['.jsx', '.tsx'],
|
|
86
|
+
optimizeDeps: [
|
|
87
|
+
'react',
|
|
88
|
+
'react/jsx-runtime',
|
|
89
|
+
'react/jsx-dev-runtime',
|
|
90
|
+
'react-dom',
|
|
91
|
+
'react-dom/client',
|
|
92
|
+
],
|
|
93
|
+
ssrExternal: [],
|
|
94
|
+
ssrNoExternal: ['react', 'react-dom', 'react-dom/server'],
|
|
95
|
+
requiresPlugin: true,
|
|
96
|
+
pluginPackage: '@vitejs/plugin-react',
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
lit: {
|
|
100
|
+
name: 'lit',
|
|
101
|
+
extensions: ['.ts', '.js'],
|
|
102
|
+
optimizeDeps: [
|
|
103
|
+
'lit',
|
|
104
|
+
'lit/decorators.js',
|
|
105
|
+
'lit/directives/class-map.js',
|
|
106
|
+
'lit/directives/style-map.js',
|
|
107
|
+
'@lit/reactive-element',
|
|
108
|
+
],
|
|
109
|
+
ssrExternal: [],
|
|
110
|
+
ssrNoExternal: ['lit', '@lit-labs/ssr', '@lit/reactive-element', 'lit-html'],
|
|
111
|
+
requiresPlugin: false,
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Get build configuration for a specific integration
|
|
117
|
+
*/
|
|
118
|
+
export function getIntegrationBuildConfig(framework: string) {
|
|
119
|
+
return INTEGRATION_BUILD_CONFIGS[framework];
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Get all optimize deps for given integrations
|
|
124
|
+
*/
|
|
125
|
+
export function getOptimizeDepsForIntegrations(integrations: string[]) {
|
|
126
|
+
const deps = new Set<string>();
|
|
127
|
+
|
|
128
|
+
for (const integration of integrations) {
|
|
129
|
+
const config = INTEGRATION_BUILD_CONFIGS[integration];
|
|
130
|
+
if (config) {
|
|
131
|
+
config.optimizeDeps.forEach(dep => deps.add(dep));
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return Array.from(deps);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Get SSR noExternal packages for given integrations
|
|
140
|
+
*/
|
|
141
|
+
export function getSSRNoExternalForIntegrations(integrations: string[]) {
|
|
142
|
+
const packages = new Set<string>();
|
|
143
|
+
|
|
144
|
+
for (const integration of integrations) {
|
|
145
|
+
const config = INTEGRATION_BUILD_CONFIGS[integration];
|
|
146
|
+
if (config) {
|
|
147
|
+
config.ssrNoExternal.forEach(pkg => packages.add(pkg));
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return Array.from(packages);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Check if an integration requires a Vite plugin
|
|
156
|
+
*/
|
|
157
|
+
export function integrationRequiresPlugin(framework: string) {
|
|
158
|
+
const config = INTEGRATION_BUILD_CONFIGS[framework];
|
|
159
|
+
return config?.requiresPlugin ?? false;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Get plugin package name for an integration
|
|
164
|
+
*/
|
|
165
|
+
export function getIntegrationPluginPackage(framework: string) {
|
|
166
|
+
const config = INTEGRATION_BUILD_CONFIGS[framework];
|
|
167
|
+
return config?.pluginPackage;
|
|
168
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import type { Plugin } from 'vite';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
import { readdir, readFile } from 'node:fs/promises';
|
|
4
|
+
|
|
5
|
+
export interface IntegrationDetectionResult {
|
|
6
|
+
preact: boolean;
|
|
7
|
+
vue: boolean;
|
|
8
|
+
solid: boolean;
|
|
9
|
+
svelte: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Vite plugin to detect which framework integrations are used in the project
|
|
14
|
+
* This enables tree-shaking of unused integrations
|
|
15
|
+
*/
|
|
16
|
+
export function integrationDetectionPlugin(): Plugin {
|
|
17
|
+
let detectedIntegrations: IntegrationDetectionResult | null = null;
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
name: 'avalon:integration-detection',
|
|
21
|
+
enforce: 'pre',
|
|
22
|
+
|
|
23
|
+
async buildStart() {
|
|
24
|
+
// Detect integrations during build start
|
|
25
|
+
detectedIntegrations = await detectUsedIntegrations();
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
resolveId(id: string) {
|
|
29
|
+
// Handle integration imports
|
|
30
|
+
if (id.startsWith('@useavalon/integration-')) {
|
|
31
|
+
const framework = id.replace('@useavalon/integration-', '').split('/')[0];
|
|
32
|
+
|
|
33
|
+
// Check if this integration is used
|
|
34
|
+
if (detectedIntegrations && !detectedIntegrations[framework as keyof IntegrationDetectionResult]) {
|
|
35
|
+
console.warn(`⚠️ Integration ${framework} is imported but not detected in project files`);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Resolve to the actual integration path
|
|
39
|
+
const integrationPath = resolve(process.cwd(), `packages/integrations/${framework}/mod.ts`);
|
|
40
|
+
return integrationPath;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return null;
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
transform(_code: string, id: string) {
|
|
47
|
+
// Track integration usage in island files
|
|
48
|
+
if (id.includes('/islands/') || id.includes('/components/')) {
|
|
49
|
+
// This helps with dynamic detection during development
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return null;
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Detect which framework integrations are actually used in the project
|
|
60
|
+
*/
|
|
61
|
+
export async function detectUsedIntegrations() {
|
|
62
|
+
const result: IntegrationDetectionResult = {
|
|
63
|
+
preact: false,
|
|
64
|
+
vue: false,
|
|
65
|
+
solid: false,
|
|
66
|
+
svelte: false,
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const searchDirs = ['islands', 'components', 'src/islands', 'src/components'];
|
|
70
|
+
const cwd = process.cwd();
|
|
71
|
+
|
|
72
|
+
for (const dir of searchDirs) {
|
|
73
|
+
try {
|
|
74
|
+
const dirPath = resolve(cwd, dir);
|
|
75
|
+
const entries = await readdir(dirPath, { withFileTypes: true });
|
|
76
|
+
for (const entry of entries) {
|
|
77
|
+
if (!entry.isFile()) continue;
|
|
78
|
+
|
|
79
|
+
// Check file extensions
|
|
80
|
+
if (entry.name.endsWith('.vue')) {
|
|
81
|
+
result.vue = true;
|
|
82
|
+
} else if (entry.name.endsWith('.svelte')) {
|
|
83
|
+
result.svelte = true;
|
|
84
|
+
} else if (entry.name.endsWith('.tsx') || entry.name.endsWith('.jsx')) {
|
|
85
|
+
// Read file content to detect framework
|
|
86
|
+
const filePath = resolve(dirPath, entry.name);
|
|
87
|
+
const content = await readFile(filePath, 'utf-8');
|
|
88
|
+
|
|
89
|
+
if (content.includes('solid-js')) {
|
|
90
|
+
result.solid = true;
|
|
91
|
+
} else {
|
|
92
|
+
// Default to Preact for JSX/TSX files
|
|
93
|
+
result.preact = true;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
} catch {
|
|
98
|
+
// Directory doesn't exist, continue
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return result;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Get list of integration packages that should be included in the build
|
|
107
|
+
*/
|
|
108
|
+
export function getRequiredIntegrations(detected: IntegrationDetectionResult) {
|
|
109
|
+
const integrations: string[] = [];
|
|
110
|
+
|
|
111
|
+
if (detected.preact) integrations.push('preact');
|
|
112
|
+
if (detected.vue) integrations.push('vue');
|
|
113
|
+
if (detected.solid) integrations.push('solid');
|
|
114
|
+
if (detected.svelte) integrations.push('svelte');
|
|
115
|
+
|
|
116
|
+
return integrations;
|
|
117
|
+
}
|