@useavalon/avalon 0.1.5 → 0.1.7

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 (39) hide show
  1. package/package.json +31 -58
  2. package/src/build/prop-extractors/index.ts +11 -11
  3. package/src/build/prop-extractors/lit.ts +1 -1
  4. package/src/build/prop-extractors/qwik.ts +2 -2
  5. package/src/build/prop-extractors/solid.ts +1 -1
  6. package/src/build/prop-extractors/svelte.ts +1 -1
  7. package/src/schemas/routing.ts +2 -2
  8. package/src/vite-plugin/nitro-integration.ts +1 -1
  9. package/src/vite-plugin/plugin.ts +20 -16
  10. package/src/build/README.md +0 -310
  11. package/src/client/tests/css-hmr-handler.test.ts +0 -360
  12. package/src/client/tests/framework-adapter.test.ts +0 -519
  13. package/src/client/tests/hmr-coordinator.test.ts +0 -176
  14. package/src/client/tests/hydration-option-parsing.test.ts +0 -107
  15. package/src/client/tests/lit-adapter.test.ts +0 -427
  16. package/src/client/tests/preact-adapter.test.ts +0 -353
  17. package/src/client/tests/qwik-adapter.test.ts +0 -343
  18. package/src/client/tests/react-adapter.test.ts +0 -317
  19. package/src/client/tests/solid-adapter.test.ts +0 -396
  20. package/src/client/tests/svelte-adapter.test.ts +0 -387
  21. package/src/client/tests/vue-adapter.test.ts +0 -407
  22. package/src/components/tests/component-analyzer.test.ts +0 -96
  23. package/src/components/tests/component-detection.test.ts +0 -347
  24. package/src/components/tests/persistent-islands.test.ts +0 -398
  25. package/src/core/components/tests/enhanced-framework-detector.test.ts +0 -577
  26. package/src/core/components/tests/framework-registry.test.ts +0 -465
  27. package/src/core/integrations/README.md +0 -282
  28. package/src/core/layout/tests/enhanced-layout-resolver.test.ts +0 -477
  29. package/src/core/layout/tests/layout-cache-optimization.test.ts +0 -149
  30. package/src/core/layout/tests/layout-composer.test.ts +0 -486
  31. package/src/core/layout/tests/layout-data-loader.test.ts +0 -443
  32. package/src/core/layout/tests/layout-discovery.test.ts +0 -253
  33. package/src/core/layout/tests/layout-matcher.test.ts +0 -480
  34. package/src/core/modules/tests/framework-module-resolver.test.ts +0 -263
  35. package/src/core/modules/tests/module-resolution-integration.test.ts +0 -117
  36. package/src/islands/discovery/tests/island-discovery.test.ts +0 -881
  37. package/src/middleware/__tests__/discovery.test.ts +0 -107
  38. package/src/types/tests/layout-types.test.ts +0 -197
  39. package/src/vite-plugin/tests/image-optimization.test.ts +0 -54
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@useavalon/avalon",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "Multi-framework islands architecture for the modern web",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -14,6 +14,7 @@
14
14
  "exports": {
15
15
  ".": "./mod.ts",
16
16
  "./client": "./src/client/components.ts",
17
+ "./islands/framework-detection": "./src/islands/framework-detection.ts",
17
18
  "./middleware": "./src/middleware/index.ts",
18
19
  "./nitro/renderer": "./src/nitro/renderer.ts",
19
20
  "./nitro/types": "./src/nitro/types.ts",
@@ -26,64 +27,36 @@
26
27
  "types": ["./src/types/index.d.ts"]
27
28
  }
28
29
  },
29
- "files": ["mod.ts", "src/**/*.ts", "src/**/*.tsx", "src/**/*.js", "src/**/*.d.ts", "README.md"],
30
+ "files": ["mod.ts", "src/**/*.ts", "src/**/*.tsx", "src/**/*.js", "src/**/*.d.ts", "!src/**/*.test.ts", "!src/**/tests/**", "!src/**/__tests__/**", "!src/**/README.md", "README.md"],
30
31
  "devDependencies": {
31
32
  "@types/mime-types": "^3.0.1"
32
33
  },
33
- "dependencies": {
34
- "@useavalon/core": "0.1.0",
35
- "@mdx-js/react": "^3.0.0",
36
- "@mdx-js/rollup": "^3.0.0",
37
- "@types/mdx": "^2.0.0",
38
- "consola": "^3.4.2",
39
- "cookie-es": "^2.0.0",
40
- "croner": "^10.0.1",
41
- "crossws": "^0.4.3",
42
- "db0": "^0.3.4",
43
- "defu": "^6.1.4",
44
- "destr": "^2.0.5",
45
- "error-stack-parser-es": "^1.0.5",
46
- "get-port-please": "^3.2.0",
47
- "h3": "^2.0.1-rc.16",
48
- "hast-util-to-text": "^4.0.0",
49
- "hookable": "^6.0.1",
50
- "jiti": "^2.6.1",
51
- "kleur": "^4.1.5",
52
- "lowlight": "^3.1.0",
53
- "marked": "^17.0.4",
54
- "mime-types": "^3.0.2",
55
- "nf3": "^0.3.11",
56
- "nitro": "3.0.1-alpha.2",
57
- "ofetch": "^2.0.0-alpha.3",
58
- "ohash": "^2.0.11",
59
- "oxc-minify": "^0.117.0",
60
- "oxc-transform": "^0.117.0",
61
- "preact": "10.28.4",
62
- "preact-render-to-string": "6.6.6",
63
- "rehype-highlight": "^7.0.0",
64
- "remark-frontmatter": "^5.0.0",
65
- "remark-gfm": "^4.0.0",
66
- "remark-mdx-frontmatter": "^5.0.0",
67
- "rendu": "^0.0.7",
68
- "rolldown": "^1.0.0-rc.8",
69
- "rollup": "^4.55.0",
70
- "rou3": "^0.8.1",
71
- "scule": "^1.3.0",
72
- "srvx": "^0.11.9",
73
- "std-env": "^3.9.0",
74
- "supports-color": "^10.2.2",
75
- "typescript": "5.9.3",
76
- "ufo": "^1.6.3",
77
- "unctx": "^2.4.1",
78
- "undici": "^7.18.2",
79
- "unenv": "^2.0.0-rc.24",
80
- "unified": "^11.0.0",
81
- "unstorage": "^2.0.0-alpha.5",
82
- "vite": "8.0.0",
83
- "vite-imagetools": "^7.0.5",
84
- "xml2js": "^0.6.2",
85
- "youch": "^4.1.0-beta.13",
86
- "youch-core": "^0.3.3",
87
- "zod": "4.3.6"
88
- }
34
+ "peerDependencies": {
35
+ "vite": "^8.0.0",
36
+ "nitro": "^3.0.0-alpha.0",
37
+ "vite-imagetools": "^7.0.0"
38
+ },
39
+ "peerDependenciesMeta": {
40
+ "nitro": {
41
+ "optional": true
42
+ },
43
+ "vite-imagetools": {
44
+ "optional": true
45
+ }
46
+ },
47
+ "dependencies": {
48
+ "@useavalon/core": "^0.1.1",
49
+ "@mdx-js/rollup": "^3.0.0",
50
+ "h3": "^2.0.1-rc.16",
51
+ "marked": "^17.0.4",
52
+ "oxc-transform": "^0.117.0",
53
+ "preact": "10.28.4",
54
+ "preact-render-to-string": "6.6.6",
55
+ "rehype-highlight": "^7.0.0",
56
+ "remark-frontmatter": "^5.0.0",
57
+ "remark-gfm": "^4.0.0",
58
+ "remark-mdx-frontmatter": "^5.0.0",
59
+ "unified": "^11.0.0",
60
+ "zod": "4.3.6"
61
+ }
89
62
  }
@@ -1,15 +1,15 @@
1
- export { type PropExtractionResult, FALLBACK_PROPS, extractVueProps } from "./vue";
2
- export { extractSvelteProps } from "./svelte";
3
- export { extractLitProps } from "./lit";
4
- export { extractSolidProps } from "./solid";
5
- export { extractQwikProps } from "./qwik";
1
+ export { type PropExtractionResult, FALLBACK_PROPS, extractVueProps } from "./vue.ts";
2
+ export { extractSvelteProps } from "./svelte.ts";
3
+ export { extractLitProps } from "./lit.ts";
4
+ export { extractSolidProps } from "./solid.ts";
5
+ export { extractQwikProps } from "./qwik.ts";
6
6
 
7
- import type { PropExtractionResult } from "./vue";
8
- import { extractVueProps } from "./vue";
9
- import { extractSvelteProps } from "./svelte";
10
- import { extractLitProps } from "./lit";
11
- import { extractSolidProps } from "./solid";
12
- import { extractQwikProps } from "./qwik";
7
+ import type { PropExtractionResult } from "./vue.ts";
8
+ import { extractVueProps } from "./vue.ts";
9
+ import { extractSvelteProps } from "./svelte.ts";
10
+ import { extractLitProps } from "./lit.ts";
11
+ import { extractSolidProps } from "./solid.ts";
12
+ import { extractQwikProps } from "./qwik.ts";
13
13
 
14
14
  /** Maps framework name to its prop extractor function */
15
15
  export const EXTRACTOR_MAP: Record<string, (source: string) => PropExtractionResult> = {
@@ -1,4 +1,4 @@
1
- import { FALLBACK_PROPS, type PropExtractionResult } from "./vue";
1
+ import { FALLBACK_PROPS, type PropExtractionResult } from "./vue.ts";
2
2
 
3
3
  /** Mapping from Lit type constructors to TypeScript type strings */
4
4
  const LIT_TYPE_MAP: Record<string, string> = {
@@ -1,5 +1,5 @@
1
- import type { PropExtractionResult } from "./vue";
2
- import { FALLBACK_PROPS } from "./vue";
1
+ import type { PropExtractionResult } from "./vue.ts";
2
+ import { FALLBACK_PROPS } from "./vue.ts";
3
3
 
4
4
  /**
5
5
  * Extract props type from a Qwik component file.
@@ -1,4 +1,4 @@
1
- import { FALLBACK_PROPS, type PropExtractionResult } from "./vue";
1
+ import { FALLBACK_PROPS, type PropExtractionResult } from "./vue.ts";
2
2
 
3
3
  /**
4
4
  * Extract props from a Solid component source string.
@@ -1,4 +1,4 @@
1
- import { FALLBACK_PROPS, type PropExtractionResult } from "./vue";
1
+ import { FALLBACK_PROPS, type PropExtractionResult } from "./vue.ts";
2
2
 
3
3
  /**
4
4
  * Extract props from a Svelte component source string.
@@ -362,7 +362,7 @@ export type {
362
362
  ValidRoutePattern,
363
363
  ValidRouteExtension,
364
364
  PageComponentProps,
365
- } from '../types/routing';
365
+ } from '../types/routing.ts';
366
366
 
367
367
  export {
368
368
  isValidRouteParams,
@@ -373,4 +373,4 @@ export {
373
373
  createTypedMetadataGenerator,
374
374
  createTypedPageLoader,
375
375
  createTypedApiHandler,
376
- } from '../types/routing';
376
+ } from '../types/routing.ts';
@@ -43,7 +43,7 @@ function resolveAvalonPackagePath(relativePath: string): string {
43
43
  * Resolves the absolute path to a file inside an @useavalon/<name> integration package.
44
44
  */
45
45
  function resolveIntegrationPackagePath(name: string, relativePath: string): string {
46
- const require = createRequire(import.meta.url);
46
+ const require = createRequire(join(process.cwd(), 'package.json'));
47
47
  const modEntry = require.resolve(`@useavalon/${name}`);
48
48
  const pkgRoot = dirname(modEntry);
49
49
  return join(pkgRoot, relativePath);
@@ -269,14 +269,12 @@ export async function avalon(config?: AvalonPluginConfig): Promise<PluginOption[
269
269
  }
270
270
 
271
271
  // Resolve /@useavalon/*/client virtual imports used by main.js
272
- const integrationClientMap: Record<string, string | null> = {};
273
- for (const name of ['preact', 'react', 'vue', 'svelte', 'solid', 'lit', 'qwik']) {
274
- try {
275
- integrationClientMap[`/@useavalon/${name}/client`] = require.resolve(`@useavalon/${name}/client`);
276
- } catch {
277
- integrationClientMap[`/@useavalon/${name}/client`] = null;
278
- }
279
- }
272
+ // These are resolved dynamically in the resolveId hook using Vite's resolver
273
+ const integrationClientIds = new Set(
274
+ ['preact', 'react', 'vue', 'svelte', 'solid', 'lit', 'qwik'].map(
275
+ name => `/@useavalon/${name}/client`
276
+ )
277
+ );
280
278
 
281
279
  // The main Avalon plugin
282
280
  const avalonPlugin: Plugin = {
@@ -309,27 +307,33 @@ export async function avalon(config?: AvalonPluginConfig): Promise<PluginOption[
309
307
  checkDirectoriesExist(resolvedConfig, resolvedViteConfig.root);
310
308
  },
311
309
 
312
- resolveId(id: string) {
310
+ async resolveId(id: string) {
313
311
  if (id === "/src/client/main.js" && clientMainResolved) {
314
312
  return clientMainResolved;
315
313
  }
316
- if (id in integrationClientMap && integrationClientMap[id]) {
317
- return integrationClientMap[id];
314
+ // /@useavalon/*/client resolve through Vite's pipeline so it finds
315
+ // workspace-linked or npm-installed integration packages from the
316
+ // consuming project's node_modules, not from avalon's own context.
317
+ if (integrationClientIds.has(id)) {
318
+ const packageId = id.slice(1); // strip leading /
319
+ const resolved = await this.resolve(packageId);
320
+ return resolved?.id ?? null;
318
321
  }
319
322
  return null;
320
323
  },
321
324
 
322
325
  async transform(code: string, id: string) {
323
- // Vite 8's OXC transform applies the project's jsx config to ALL .ts files,
324
- // including those in node_modules/@useavalon. OXC rejects jsx options for
325
- // plain .ts files. Strip TypeScript ourselves for @useavalon packages so
326
- // Vite's built-in OXC doesn't need to touch them.
326
+ // Vite 8's built-in OXC plugin returns { moduleType: "js" } so the dev
327
+ // server knows the output is JavaScript. Because we exclude @useavalon
328
+ // packages from that plugin (via oxc.exclude), we must strip TypeScript
329
+ // ourselves AND set moduleType so the browser receives valid JS.
327
330
  if (id.includes('node_modules/@useavalon/') && /\.tsx?$/.test(id)) {
328
331
  const { transform: oxcTransform } = await import('oxc-transform');
329
332
  const result = await oxcTransform(id, code, {
333
+ sourcemap: true,
330
334
  typescript: { onlyRemoveTypeImports: false },
331
335
  });
332
- return { code: result.code, map: result.map };
336
+ return { code: result.code, map: result.map, moduleType: 'js' };
333
337
  }
334
338
  },
335
339
 
@@ -1,310 +0,0 @@
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.