Skip to content

TypeScript setup

The TypeScript plugin API is the npm package @vespura/vmenu-plugin, with its types included. The rest of the API is on Making a plugin. The TypeScript example is a complete project to copy.

npm install @vespura/vmenu-plugin@<your vMenu version> --save-exact

The package version always matches the vMenu Enhanced release it belongs to. Pin it to the vMenu your server runs, and raise it when you update vMenu.

Import from Used by
@vespura/vmenu-plugin/client your client script
@vespura/vmenu-plugin/server your server script

The package ships ES modules, and FiveM loads plain scripts. Bundle each half into one file with esbuild, or any bundler you like:

import { build } from 'esbuild';
const shared = { bundle: true, format: 'iife', target: 'es2020' };
await build({ ...shared, entryPoints: ['src/client.ts'], platform: 'browser', outfile: 'dist/client.js' });
await build({ ...shared, entryPoints: ['src/server.ts'], platform: 'node', outfile: 'dist/server.js' });

The plugin API ends up inside both files, so the resource needs nothing else at runtime, and start order does not matter. Since the output is a plain script, use .then() at the top level rather than a top level await.

fx_version 'cerulean'
games { 'gta5' }
client_script 'dist/client.js'
server_script 'dist/server.js'

Everything on the JavaScript setup page applies, with imports in place of the global vMenu object:

import { Gate, Text, VMenuPlugin } from '@vespura/vmenu-plugin/client';
import { ServerPluginDeclaration, VMenuServer } from '@vespura/vmenu-plugin/server';

Every row type has its own class, such as PluginCheckbox or PluginList, so instanceof narrows a row you got back from a key press or a filter. The options for each add method are typed too, so your editor tells you which ones a row takes.