Getting started
Your first page
A page is made of a controller method that returns data and a ReactVue component that shows it.
The controller
Put @View() on a handler with the name of the page it should render, and return your data as a plain object.
// src/app.controller.ts
import { Controller, Get } from '@nestjs/common'
import { View } from 'nestjs-mvc'
@Controller()
export class AppController {
@Get()
@View('Home')
home() {
return { name: 'Ada' }
}
}
The page
The name Home points to frontend/pages/Home.tsxfrontend/pages/Home.vue, and the object you returned comes in as props.
// frontend/pages/Home.tsx
export default function Home({ name }: { name: string }) {
return <h1>Hello, {name}</h1>
}
<!-- frontend/pages/Home.vue -->
<script setup lang="ts">
defineProps<{ name: string }>()
</script>
<template>
<h1>Hello, {{ name }}</h1>
</template>
Open http://localhost:3000 and you'll see "Hello, Ada".
Folders
Page names can include folders, so @View('Users/Show') renders frontend/pages/Users/Show.tsxfrontend/pages/Users/Show.vue. Most apps end up with a folder per controller:
frontend/pages/
Home.tsx
Users/
Index.tsx
Show.tsx
frontend/pages/
Home.vue
Users/
Index.vue
Show.vue
Using services
It's still a normal NestJS controller, so you can inject services, read route params and use pipes like you always do.
@Controller('users')
export class UsersController {
constructor(private readonly users: UsersService) {}
@Get(':id')
@View('Users/Show')
async show(@Param('id', ParseIntPipe) id: number) {
const user = await this.users.findOne(id)
return { user: { id: user.id, name: user.name } }
}
}
Only return what the page needs
Everything you return ends up in the browser. So pick the fields you want to show, rather than returning a whole database entity that might have a password hash in it.
What happens
On the first visit the server sends a full HTML page with your data in it, and your page takes over in the browser from there.
When someone clicks a link after that, the browser asks the same controller for just the data and swaps the page in place. You get that without writing anything extra, and the next page shows how links work.