DocsFramework differences

Vue

Nexy renders Vue 3 single-file components on the server, then Vue takes them over in the browser. Pages, layouts, islands and actions are the same in every framework: this page covers setup, then the parts that differ from the shared contracts.

Mode nexyconfig.py Pages are Vue is
Server (default) useCSR = False .nexy files islands inside those pages
Client useCSR = True .vue files the whole page, with layouts and a client router

With the modular router, Vue components are islands inside the .nexy views a controller returns: there is no page file and no client router.

Start a project

nx new my-app --template web-fbr-vue
nx new my-app --template web-modular-vue

The template is a server-mode project with Vue islands. Run nx new my-app without a template to answer the prompts instead: the router, the project type, whether to use client-side routing, then the framework.

Enable Vue in an existing project

nexyconfig.py
from nexy.core.models import NexyConfigModelfrom nexy.frontend import vue  class NexyConfig(NexyConfigModel):    useFF = vue()    useAliases = {"@": "src"}
vite.config.ts
import { defineConfig } from "vite";import vue from "@vitejs/plugin-vue";import nexy from "./__nexy__/vite"; export default defineConfig({  plugins: [nexy(), vue()],  customLogger: nexy.log(),});

nx new writes this file; Nexy writes __nexy__/vite.ts itself, so do not edit it.

Package Version nx new writes
vue ^3.5.33
@vitejs/plugin-vue ^6.0.0

Rules

  • One framework per project. useFF takes exactly one framework; useFF = [vue(), react()] stops the server at startup.
  • One component per file. A .vue file exports its component as default; the name you import it under is only the tag you write.
  • Components live outside src/routes/, usually in src/components/, so they are not pages.
  • A server-mode project has no .vue page, and a client-mode project has no .nexy page: Nexy refuses to start and names the file. See modes.
  • Components live in src/components/, and a view imports them as islands.

Pages

In client mode (useCSR = True), a page is a .vue file.

Page component

The page is the component defined by the <script setup> block.

src/routes/index.vue
<template>  <h1>Hello</h1></template>

Dynamic segments

URL parameters reach the page as props. You can declare them using defineProps:

src/routes/blog/[slug].vue
<script setup lang="ts">defineProps<{ slug: string }>();</script> <template>  <h1>{{ slug }}</h1></template>

Alternatively, use the useParams hook from @nexy/client in any component.

Layouts

Implementation

The root layout defines the document shell. Nested layouts wrap the content in their default slot.

src/routes/layout.vue
<template>  <html>    <body>      <header>My app</header>      <main><slot /></main>    </body>  </html></template>

Islands

In server mode, a Vue component imported into a .nexy file is an island.

Importing

Import components in the frontmatter of the .nexy file:

src/routes/index.nexy
---from "@/components/Counter.vue" import Counter---<Counter start=3 />
src/apps/home_view.nexy
---from "@/components/Counter.vue" import Counter---<Counter start=3 />

Hydration directives

Use the directive prop to control when the island hydrates:

  • client:load (default): immediately
  • client:idle: when the browser is idle
  • client:visible: when it scrolls into view
  • client:media: when the media query matches

Actions and navigation

Calling actions

Use the useAction hook to manage the state of an action call. In Vue, the returned state (pending, data, error) are computed refs.

<script setup lang="ts">import { ref } from "vue";import { useAction } from "@nexy/client";import { add_todo } from "@nexy/actions"; const title = ref("");const { run, pending, error, data } = useAction(add_todo, {  onSuccess: () => (title.value = ""),});</script> <template>  <form @submit.prevent="run({ title })">    <input v-model="title" />    <button :disabled="pending">Add</button>  </form></template>

Use the Link component for client-side transitions:

<template>  <Link href="/about" active-class="active">About</Link></template>

For programmatic navigation, use the useRouter hook:

import { useRouter } from "@nexy/client"; const router = useRouter();router.push("/dashboard");

URL access

All location hooks return computed refs:

  • usePathname(): current path
  • useParams(): dynamic segments
  • useSearchParams(): query string
  • useLocation(): full location object

Next steps

  • Views: compare the formats a page can use
  • Frontend: Vite and the client build

Edit on GitHub

Enter opens the result, Esc closes.