Skip to Content
Manual Install 🚧

Manual Install

Create a Next.js project with App Router and TypeScript

npx create-next-app my-app --ts --app --src-dir
cd my-app

The src directory is optional but recommended, as it keeps the root directory clean.

Install “vovk” and “vovk-client”

npm i vovk vovk-client

Create an empty config file (optional)

Create vovk.config.mjs at the root of the project with the following content:

vovk.config.mjs
// @ts-check /** @type {import('vovk').VovkConfig} */ const vovkConfig = {}; export default vovkConfig;

Install a validation library and enable client-side validation

For Zod validation on the server side and Ajv on the client side, install the following packages:

npm i zod vovk-zod vovk-ajv

Modify the validateOnClient import in your config file to enable client-side validation:

vovk.config.mjs
// @ts-check /** @type {import('vovk').VovkConfig} */ const vovkConfig = { outputConfig: { imports: { validateOnClient: 'vovk-ajv', }, }, }; export default vovkConfig;

Read more about validation.

Update the “dev” script and create a “prebuild” NPM script

There are two ways to run Vovk.ts and the Next.js server concurrently: explicitly and implicitly. The explicit way is to install the concurrently package and run both scripts with it, which requires the PORT variable to be set. The implicit way is to have the Vovk.ts CLI run the Next.js server itself. In this case, vovk-cli will assign the port automatically.

The prebuild script will run vovk generate before next build to generate the client library before building the Next.js app.

Install concurrently:

npm i -D concurrently

Update the “dev” script in package.json:

"scripts": { "build": "next build", "dev": "PORT=3000 concurrently 'vovk dev' 'next dev' --kill-others", "prebuild": "vovk generate" }

Enable decorators

In your tsconfig.json, set "experimentalDecorators" to true.

{ "compilerOptions": { "experimentalDecorators": true // ... } }

Create a controller

Create HelloController.ts at /src/modules/hello/ with a same-named static class.

src/modules/hello/HelloController.ts
import { get, prefix } from 'vovk'; @prefix('greetings') // prefix is optional export default class HelloController { @get('greeting') static getHello() { return { greeting: 'Hello, World!' }; } }

Create a root segment

Create the root segment /src/app/api/[[…vovk]]/route.ts, where [[…vovk]] is a folder name indicating what the Next.js documentation calls an “Optional Catch-all Segment”  (the slug can be any valid slug, such as [[…mySlug]]).

In the code below, HelloRPC indicates the name of the generated RPC module, and HelloController is the controller module created above.

src/app/api/[[...vovk]]/route.ts
import { initSegment } from 'vovk'; import HelloController from '../modules/hello/HelloController'; const controllers = { HelloRPC: HelloController }; // export types that are inferred by the client export type Controllers = typeof controllers; // export Next.js route handlers export const { GET, POST, PUT, DELETE } = initSegment({ controllers });

Run “vovk dev”

Run npm run dev to start Vovk.ts and Next.js concurrently.

npm run dev

Navigate to http://localhost:3000/api/greetings/greeting  to see the result.

Create a React component

Now that the client is generated, you can safely import your client library from vovk-client.

src/app/page.tsx
'use client'; import { useState } from 'react'; import { HelloRPC } from 'vovk-client'; import type { VovkReturnType } from 'vovk'; export default function MyComponent() { const [serverResponse, setServerResponse] = useState<VovkReturnType<typeof HelloController.getHello>>(); return ( <> <button onClick={async () => { const response = await HelloController.getHello(); setServerResponse(response); }} > Get Greeting from Server </button> <div>{serverResponse?.greeting}</div> </> ); }

Open http://localhost:3000  to see the result.

ℹ️

Note that if you’re using VSCode, you’ll probably need to restart the TS server  each time you add a new controller class to your app. Changing the controller list is the only case when you may need to restart the TS server manually; other changes, such as adding new methods or changing validation, will be picked up automatically.

Last updated on