@useavalon/vue 0.1.7 → 0.1.9
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 +42 -42
- package/dist/client/hydration.js +1 -76
- package/dist/server/renderer.js +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,42 +1,42 @@
|
|
|
1
|
-
# @useavalon/vue
|
|
2
|
-
|
|
3
|
-
Vue 3 integration for [Avalon](https://useavalon.dev). Server-side rendering and client-side hydration for Vue Single File Components as islands.
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
- Vue 3 with Composition API and `<script setup>`
|
|
8
|
-
- Server-side rendering via `@vue/server-renderer`
|
|
9
|
-
- Scoped CSS extraction from SFCs
|
|
10
|
-
- All hydration strategies (`on:client`, `on:visible`, `on:idle`, `on:interaction`)
|
|
11
|
-
|
|
12
|
-
## Usage
|
|
13
|
-
|
|
14
|
-
```vue
|
|
15
|
-
<!-- components/Counter.vue -->
|
|
16
|
-
<script setup>
|
|
17
|
-
import { ref } from 'vue';
|
|
18
|
-
const count = ref(0);
|
|
19
|
-
</script>
|
|
20
|
-
|
|
21
|
-
<template>
|
|
22
|
-
<button @click="count++">Count: {{ count }}</button>
|
|
23
|
-
</template>
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
```tsx
|
|
27
|
-
// pages/index.tsx
|
|
28
|
-
import Counter from '../components/Counter.vue';
|
|
29
|
-
|
|
30
|
-
export default function Home() {
|
|
31
|
-
return <Counter island={{ condition: 'on:visible' }} />;
|
|
32
|
-
}
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
## Links
|
|
36
|
-
|
|
37
|
-
- [Documentation](https://useavalon.dev/docs/frameworks/vue)
|
|
38
|
-
- [GitHub](https://github.com/useAvalon/Avalon)
|
|
39
|
-
|
|
40
|
-
## License
|
|
41
|
-
|
|
42
|
-
MIT
|
|
1
|
+
# @useavalon/vue
|
|
2
|
+
|
|
3
|
+
Vue 3 integration for [Avalon](https://useavalon.dev). Server-side rendering and client-side hydration for Vue Single File Components as islands.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Vue 3 with Composition API and `<script setup>`
|
|
8
|
+
- Server-side rendering via `@vue/server-renderer`
|
|
9
|
+
- Scoped CSS extraction from SFCs
|
|
10
|
+
- All hydration strategies (`on:client`, `on:visible`, `on:idle`, `on:interaction`)
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
```vue
|
|
15
|
+
<!-- components/Counter.vue -->
|
|
16
|
+
<script setup>
|
|
17
|
+
import { ref } from 'vue';
|
|
18
|
+
const count = ref(0);
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<template>
|
|
22
|
+
<button @click="count++">Count: {{ count }}</button>
|
|
23
|
+
</template>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
```tsx
|
|
27
|
+
// pages/index.tsx
|
|
28
|
+
import Counter from '../components/Counter.vue';
|
|
29
|
+
|
|
30
|
+
export default function Home() {
|
|
31
|
+
return <Counter island={{ condition: 'on:visible' }} />;
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Links
|
|
36
|
+
|
|
37
|
+
- [Documentation](https://useavalon.dev/docs/frameworks/vue)
|
|
38
|
+
- [GitHub](https://github.com/useAvalon/Avalon)
|
|
39
|
+
|
|
40
|
+
## License
|
|
41
|
+
|
|
42
|
+
MIT
|
package/dist/client/hydration.js
CHANGED
|
@@ -1,76 +1 @@
|
|
|
1
|
-
import{
|
|
2
|
-
import { createApp } from 'vue';
|
|
3
|
-
|
|
4
|
-
// Auto-hydrate all Vue islands
|
|
5
|
-
document.querySelectorAll('[data-framework="vue"]').forEach(async (el) => {
|
|
6
|
-
const src = el.getAttribute('data-src');
|
|
7
|
-
const propsJson = el.getAttribute('data-props') || '{}';
|
|
8
|
-
const condition = el.getAttribute('data-condition') || 'on:client';
|
|
9
|
-
|
|
10
|
-
// Check hydration condition
|
|
11
|
-
if (!shouldHydrate(el, condition)) {
|
|
12
|
-
return;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
try {
|
|
16
|
-
// Dynamic import the component
|
|
17
|
-
const module = await import(src);
|
|
18
|
-
const Component = module.default || module;
|
|
19
|
-
|
|
20
|
-
// Parse props
|
|
21
|
-
const props = JSON.parse(propsJson);
|
|
22
|
-
|
|
23
|
-
// Create and mount Vue app
|
|
24
|
-
const app = createApp(Component, props);
|
|
25
|
-
app.mount(el, true);
|
|
26
|
-
} catch (error) {
|
|
27
|
-
console.error('Failed to hydrate Vue island:', error);
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
function shouldHydrate(element, condition) {
|
|
32
|
-
if (!condition || condition === 'on:client') {
|
|
33
|
-
return true;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (condition === 'on:visible') {
|
|
37
|
-
return new Promise((resolve) => {
|
|
38
|
-
const observer = new IntersectionObserver((entries) => {
|
|
39
|
-
if (entries[0].isIntersecting) {
|
|
40
|
-
observer.disconnect();
|
|
41
|
-
resolve(true);
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
observer.observe(element);
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (condition === 'on:interaction') {
|
|
49
|
-
return new Promise((resolve) => {
|
|
50
|
-
const events = ['click', 'mouseenter', 'focusin', 'touchstart'];
|
|
51
|
-
const handler = () => {
|
|
52
|
-
events.forEach(e => element.removeEventListener(e, handler));
|
|
53
|
-
resolve(true);
|
|
54
|
-
};
|
|
55
|
-
events.forEach(e => element.addEventListener(e, handler, { once: true }));
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if (condition === 'on:idle') {
|
|
60
|
-
return new Promise((resolve) => {
|
|
61
|
-
if ('requestIdleCallback' in window) {
|
|
62
|
-
requestIdleCallback(() => resolve(true));
|
|
63
|
-
} else {
|
|
64
|
-
setTimeout(() => resolve(true), 200);
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (condition.startsWith('media:')) {
|
|
70
|
-
const query = condition.slice(6);
|
|
71
|
-
return window.matchMedia(query).matches;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
return true;
|
|
75
|
-
}
|
|
76
|
-
`}
|
|
1
|
+
import{createSSRApp as e}from"vue";export function hydrate(t,n,r={}){try{e(n,r).mount(t)}catch(e){throw console.error(`Vue hydration failed:`,e),e}}export function getHydrationScript(){return``}
|
package/dist/server/renderer.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{resolveIslandPath as e}from"@useavalon/avalon/islands/framework-detection";import{toImportSpecifier as t}from"@useavalon/core/utils";import{createSSRApp as n}from"vue";import{renderToString as r}from"vue/server-renderer";import{extractCSS as i}from"./css-extractor.js";export async function render(e){let{component:t,props:a={},src:s,condition:c=`on:client`,ssrOnly:l=!1}=e;try{let e=t||await o(s),u=await r(n(e,a)),d=e.__scopeId,f=``;if(d)try{f=await i(s,{scopeId:d})}catch{}return{html:u,css:f||void 0,scopeId:d||void 0,hydrationData:{src:s,props:a,framework:`vue`,condition:c,ssrOnly:l}}}catch(e){throw Error(`Vue SSR rendering failed: ${e}`)}}async function o(n){if(process.env.NODE_ENV!==`production`&&globalThis.__viteDevServer){let t=globalThis.__viteDevServer,r=await e(n),i=await t.ssrLoadModule(r);return i.default||i}let r=await import(t(n.replace(`/islands/`,`/dist/ssr/islands/`).replace(`.vue`,`.js`)));return r.default||r}export function getComponentMetadata(e){return typeof e==`object`&&e?{name:e.name||`Anonymous`,type:`component`,hasSetup:`setup`in e,hasTemplate:`template`in e,hasRender:`render`in e}:{type:typeof e}}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@useavalon/vue",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"description": "Vue integration for Avalon islands architecture",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -36,8 +36,8 @@
|
|
|
36
36
|
"README.md"
|
|
37
37
|
],
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@useavalon/avalon": "
|
|
40
|
-
"@useavalon/core": "
|
|
39
|
+
"@useavalon/avalon": "^0.1.71",
|
|
40
|
+
"@useavalon/core": "^0.1.7",
|
|
41
41
|
"@vitejs/plugin-vue": "^5.2.4"
|
|
42
42
|
},
|
|
43
43
|
"peerDependencies": {
|