DEV Community

Cover image for FiveM x TypeScript
Justin Martin
Justin Martin

Posted on • Edited on

FiveM x TypeScript

FiveM is a modification for Grand Theft Auto V enabling you to play multiplayer on customized dedicated servers, powered by Cfx.re.

When you develop a FiveM server, you can create resource. Theses resources can be write in multiple langage Lua, C# and JavaScript. In this article we are going to see how to build a resource using TypeScript

Type :

For typing our code, we will use two packages provided by CFX.re the company behind FiveM

  • @citizenfx/client
  • @citizenfx/server

These packages provided types for each native method usable inside client-side or server-side code.

tsconfig.json

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "moduleResolution": "Bundler",
    // Location
    "outDir": "./dist",
    // Other
    "types": ["@citizenfx/client", "@types/node"],
    "lib": ["ES2020"],
    "strict": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "skipLibCheck": true
  },
  "include": ["src/**/*.ts"],
  "exclude": ["**/node_modules", "**/.test.ts"]
}

Enter fullscreen mode Exit fullscreen mode

Bundle :

After the compilation of .ts files, you will have to create a bundle which going to be loaded and ran by FiveM server. Indeed, FiveM only allows require of native node.js package like path, fs, …

To do it, we use the tool named rollup, it’s a JavaScript module bundler based on plugin system. I also explored other tools like vite, rspack, but it’s too complicated. An other tool which offers good performance will be turbopack a tool behind next bundling but it still inside next for the moment.

rollup.config.mjs

import typescript from "@rollup/plugin-typescript";
import commonjs from "@rollup/plugin-commonjs";
import resolve from "@rollup/plugin-node-resolve";

export default {
  input: "src/index.ts",
  output: {
    dir: "dist",
    format: "cjs",
    sourcemap: false,
  },
  plugins: [resolve(), typescript(), commonjs()],
};
Enter fullscreen mode Exit fullscreen mode

package.json :

{
  ...
  "devDependencies": {
    "@citizenfx/client": "2.0.9282-1",
    "@rollup/plugin-commonjs": "^26.0.1",
    "@rollup/plugin-node-resolve": "^15.2.3",
    "@rollup/plugin-typescript": "^11.1.6",
    "@types/node": "^20.14.12",
    "rollup": "^4.20.0",
    "tslib": "^2.6.3",
    "typescript": "^5.5.4"
  },
  ...
}
Enter fullscreen mode Exit fullscreen mode

Exemple

init.ts

import { join } from "path"

export const init = () => {
    console.log("inited", join(".", "init.js"));
}
Enter fullscreen mode Exit fullscreen mode

index.ts

import { init } from "./init"

on("onResourceStart", async (resName: string) => {
  if (resName === GetCurrentResourceName()) {
    init();
  }
});
Enter fullscreen mode Exit fullscreen mode

After running rollup -c, you will have only one file :

'use strict';

var path = require('path');

const init = () => {
    console.log("inited", path.join(".", "init.js"));
};

on("onResourceStart", async (resName) => {
    if (resName === GetCurrentResourceName()) {
        init();
    }
});

Enter fullscreen mode Exit fullscreen mode

Top comments (0)