@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.
Files changed (159) hide show
  1. package/README.md +54 -0
  2. package/mod.ts +301 -0
  3. package/package.json +85 -0
  4. package/src/build/README.md +310 -0
  5. package/src/build/integration-bundler-plugin.ts +116 -0
  6. package/src/build/integration-config.ts +168 -0
  7. package/src/build/integration-detection-plugin.ts +117 -0
  8. package/src/build/integration-resolver-plugin.ts +90 -0
  9. package/src/build/island-manifest.ts +269 -0
  10. package/src/build/island-types-generator.ts +476 -0
  11. package/src/build/mdx-island-transform.ts +464 -0
  12. package/src/build/mdx-plugin.ts +98 -0
  13. package/src/build/page-island-transform.ts +598 -0
  14. package/src/build/prop-extractors/index.ts +21 -0
  15. package/src/build/prop-extractors/lit.ts +140 -0
  16. package/src/build/prop-extractors/qwik.ts +16 -0
  17. package/src/build/prop-extractors/solid.ts +125 -0
  18. package/src/build/prop-extractors/svelte.ts +194 -0
  19. package/src/build/prop-extractors/vue.ts +111 -0
  20. package/src/build/sidecar-file-manager.ts +104 -0
  21. package/src/build/sidecar-renderer.ts +30 -0
  22. package/src/client/adapters/index.ts +13 -0
  23. package/src/client/adapters/lit-adapter.ts +654 -0
  24. package/src/client/adapters/preact-adapter.ts +331 -0
  25. package/src/client/adapters/qwik-adapter.ts +345 -0
  26. package/src/client/adapters/react-adapter.ts +353 -0
  27. package/src/client/adapters/solid-adapter.ts +451 -0
  28. package/src/client/adapters/svelte-adapter.ts +524 -0
  29. package/src/client/adapters/vue-adapter.ts +467 -0
  30. package/src/client/components.ts +35 -0
  31. package/src/client/css-hmr-handler.ts +344 -0
  32. package/src/client/framework-adapter.ts +462 -0
  33. package/src/client/hmr-coordinator.ts +396 -0
  34. package/src/client/hmr-error-overlay.js +533 -0
  35. package/src/client/main.js +816 -0
  36. package/src/client/tests/css-hmr-handler.test.ts +360 -0
  37. package/src/client/tests/framework-adapter.test.ts +519 -0
  38. package/src/client/tests/hmr-coordinator.test.ts +176 -0
  39. package/src/client/tests/hydration-option-parsing.test.ts +107 -0
  40. package/src/client/tests/lit-adapter.test.ts +427 -0
  41. package/src/client/tests/preact-adapter.test.ts +353 -0
  42. package/src/client/tests/qwik-adapter.test.ts +343 -0
  43. package/src/client/tests/react-adapter.test.ts +317 -0
  44. package/src/client/tests/solid-adapter.test.ts +396 -0
  45. package/src/client/tests/svelte-adapter.test.ts +387 -0
  46. package/src/client/tests/vue-adapter.test.ts +407 -0
  47. package/src/client/types/framework-runtime.d.ts +68 -0
  48. package/src/client/types/vite-hmr.d.ts +46 -0
  49. package/src/client/types/vite-virtual-modules.d.ts +60 -0
  50. package/src/components/Image.tsx +123 -0
  51. package/src/components/IslandErrorBoundary.tsx +145 -0
  52. package/src/components/LayoutDataErrorBoundary.tsx +141 -0
  53. package/src/components/LayoutErrorBoundary.tsx +127 -0
  54. package/src/components/PersistentIsland.tsx +52 -0
  55. package/src/components/StreamingErrorBoundary.tsx +233 -0
  56. package/src/components/StreamingLayout.tsx +538 -0
  57. package/src/components/tests/component-analyzer.test.ts +96 -0
  58. package/src/components/tests/component-detection.test.ts +347 -0
  59. package/src/components/tests/persistent-islands.test.ts +398 -0
  60. package/src/core/components/component-analyzer.ts +192 -0
  61. package/src/core/components/component-detection.ts +508 -0
  62. package/src/core/components/enhanced-framework-detector.ts +500 -0
  63. package/src/core/components/framework-registry.ts +563 -0
  64. package/src/core/components/tests/enhanced-framework-detector.test.ts +577 -0
  65. package/src/core/components/tests/framework-registry.test.ts +465 -0
  66. package/src/core/content/mdx-processor.ts +46 -0
  67. package/src/core/integrations/README.md +282 -0
  68. package/src/core/integrations/index.ts +19 -0
  69. package/src/core/integrations/loader.ts +125 -0
  70. package/src/core/integrations/registry.ts +195 -0
  71. package/src/core/islands/island-persistence.ts +325 -0
  72. package/src/core/islands/island-state-serializer.ts +258 -0
  73. package/src/core/islands/persistent-island-context.tsx +80 -0
  74. package/src/core/islands/use-persistent-state.ts +68 -0
  75. package/src/core/layout/enhanced-layout-resolver.ts +322 -0
  76. package/src/core/layout/layout-cache-manager.ts +485 -0
  77. package/src/core/layout/layout-composer.ts +357 -0
  78. package/src/core/layout/layout-data-loader.ts +516 -0
  79. package/src/core/layout/layout-discovery.ts +243 -0
  80. package/src/core/layout/layout-matcher.ts +299 -0
  81. package/src/core/layout/layout-types.ts +110 -0
  82. package/src/core/layout/tests/enhanced-layout-resolver.test.ts +477 -0
  83. package/src/core/layout/tests/layout-cache-optimization.test.ts +149 -0
  84. package/src/core/layout/tests/layout-composer.test.ts +486 -0
  85. package/src/core/layout/tests/layout-data-loader.test.ts +443 -0
  86. package/src/core/layout/tests/layout-discovery.test.ts +253 -0
  87. package/src/core/layout/tests/layout-matcher.test.ts +480 -0
  88. package/src/core/modules/framework-module-resolver.ts +273 -0
  89. package/src/core/modules/tests/framework-module-resolver.test.ts +263 -0
  90. package/src/core/modules/tests/module-resolution-integration.test.ts +117 -0
  91. package/src/islands/component-analysis.ts +213 -0
  92. package/src/islands/css-utils.ts +565 -0
  93. package/src/islands/discovery/index.ts +80 -0
  94. package/src/islands/discovery/registry.ts +340 -0
  95. package/src/islands/discovery/resolver.ts +477 -0
  96. package/src/islands/discovery/scanner.ts +386 -0
  97. package/src/islands/discovery/tests/island-discovery.test.ts +881 -0
  98. package/src/islands/discovery/types.ts +117 -0
  99. package/src/islands/discovery/validator.ts +544 -0
  100. package/src/islands/discovery/watcher.ts +368 -0
  101. package/src/islands/framework-detection.ts +428 -0
  102. package/src/islands/integration-loader.ts +490 -0
  103. package/src/islands/island.tsx +565 -0
  104. package/src/islands/render-cache.ts +550 -0
  105. package/src/islands/types.ts +80 -0
  106. package/src/islands/universal-css-collector.ts +157 -0
  107. package/src/islands/universal-head-collector.ts +137 -0
  108. package/src/layout-system.d.ts +592 -0
  109. package/src/layout-system.ts +218 -0
  110. package/src/middleware/__tests__/discovery.test.ts +107 -0
  111. package/src/middleware/discovery.ts +268 -0
  112. package/src/middleware/executor.ts +315 -0
  113. package/src/middleware/index.ts +76 -0
  114. package/src/middleware/types.ts +99 -0
  115. package/src/nitro/build-config.ts +576 -0
  116. package/src/nitro/config.ts +483 -0
  117. package/src/nitro/error-handler.ts +636 -0
  118. package/src/nitro/index.ts +173 -0
  119. package/src/nitro/island-manifest.ts +584 -0
  120. package/src/nitro/middleware-adapter.ts +260 -0
  121. package/src/nitro/renderer.ts +1458 -0
  122. package/src/nitro/route-discovery.ts +439 -0
  123. package/src/nitro/types.ts +321 -0
  124. package/src/render/collect-css.ts +198 -0
  125. package/src/render/error-pages.ts +79 -0
  126. package/src/render/isolated-ssr-renderer.ts +654 -0
  127. package/src/render/ssr.ts +1030 -0
  128. package/src/schemas/api.ts +30 -0
  129. package/src/schemas/core.ts +64 -0
  130. package/src/schemas/index.ts +212 -0
  131. package/src/schemas/layout.ts +279 -0
  132. package/src/schemas/routing/index.ts +38 -0
  133. package/src/schemas/routing.ts +376 -0
  134. package/src/types/as-island.ts +20 -0
  135. package/src/types/image.d.ts +106 -0
  136. package/src/types/index.d.ts +22 -0
  137. package/src/types/island-jsx.d.ts +33 -0
  138. package/src/types/island-prop.d.ts +20 -0
  139. package/src/types/layout.ts +285 -0
  140. package/src/types/mdx.d.ts +6 -0
  141. package/src/types/routing.ts +555 -0
  142. package/src/types/tests/layout-types.test.ts +197 -0
  143. package/src/types/types.ts +5 -0
  144. package/src/types/urlpattern.d.ts +49 -0
  145. package/src/types/vite-env.d.ts +11 -0
  146. package/src/utils/dev-logger.ts +299 -0
  147. package/src/utils/fs.ts +151 -0
  148. package/src/vite-plugin/auto-discover.ts +551 -0
  149. package/src/vite-plugin/config.ts +266 -0
  150. package/src/vite-plugin/errors.ts +127 -0
  151. package/src/vite-plugin/image-optimization.ts +151 -0
  152. package/src/vite-plugin/integration-activator.ts +126 -0
  153. package/src/vite-plugin/island-sidecar-plugin.ts +176 -0
  154. package/src/vite-plugin/module-discovery.ts +189 -0
  155. package/src/vite-plugin/nitro-integration.ts +1334 -0
  156. package/src/vite-plugin/plugin.ts +329 -0
  157. package/src/vite-plugin/tests/image-optimization.test.ts +54 -0
  158. package/src/vite-plugin/types.ts +327 -0
  159. 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
+ }