npm init capri my-capri-site -- -e vue
This will download and install capri-js/capri/examples/vue.
You can view a deployed version of the demo on GitHub pages, including the preview SPA.
The client entry file is a regular vue single page app:
// src/main.tsx
import { createApp } from "vue";
import App from "./App.vue";
import createRouter from "./router.js";
const app = createApp(App);
app.use(createRouter());
app.mount("#app");
// src/main.server.tsx
import { createSSRApp } from "vue";
import { renderToString } from "vue/server-renderer";
import App from "./App.vue";
import createRouter from "./router.js";
export async function render(url: string) {
const app = createSSRApp(App);
const router = createRouter();
app.use(router);
router.push(url);
await router.isReady();
const { matched } = router.currentRoute.value;
if (matched.length) {
const html = await renderToString(app);
return {
"#app": html,
};
}
}
you can define interactive islands by naming your components *.island.vue
:
// src/Counter.island.vue
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
props: {
start: Number,
},
data() {
return {
count: this.start ?? 0,
};
},
});
</script>
<template>
<div>
<button @click="count--">-</button>
<span>{{ count }}</span>
<button @click="count++">+</button>
</div>
</template>
<style scoped>
div {
display: inline-flex;
gap: 0.5em;
}
</style>
You can export an options
object in the module context to hydrate an island
as soon as a media query matches. The following example will hydrate once the
viewport width gets below 700px:
<script lang="ts">
export const options = {
media: "(max-width:500px)",
};
</script>
<script setup lang="ts">
import { ref, onMounted } from "vue";
const content = ref(
"Resize your browser below 500px to hydrate this island."
);
onMounted(() => {
content.value = "The island has been hydrated.";
});
</script>
<template>
<div class="box">{{ content }}</div>
</template>
Vue components can load data by awaiting a promise in their setup script:
// src/Profile.tsx
<script setup lang="ts">
async function fetchUser() {
const res = await fetch("https://api.example.com/user");
return res.json();
}
const user = await fetchUser();
</script>
<template>
<span>{{ user.name }}</span>
</template>