[How To] Integrate your Typescript resource to your /resources folder


As a strict Typescript developer you often want to keep your source files clean. However you do not want to bother with the bundled files.

This topic will teach you how to use gulp with FiveM to compile .ts files to the resources directory.


Requirements:

  • NodeJs v9+
  • Basic Typescript and Javascript knowledge

Let’s start:

Place yourself on the resources folder level.
Create a src directory where your source files will live: mkdir src.
Create a fresh resource folder: mkdir src/[essential]/ilog.
Create a client and a server sub directory: mkdir src/[essential]/ilog/client src/[essential]/ilog/server.
Create a __resource.lua file with this content:

server_scripts {
    "server/server_main.js"
}

client_scripts {
    "client/client_main.js"
}

The tree should looks like this:

Code your resource

Develop your resource under client and/or server as you usually did in Lua/Js.
You can create as many sub-folder ans .ts as you want.

How to build the whole thing?

If you didn’t initiate a npm package, please do npm init on the top level, so the package.json will live beside src and resources.

Now on the same place, create a gulpfile.js file: touch gulpfile.js
Note: gulp is a toolkit for automating painful or time-consuming tasks in your development .

Type the following: npm i --save-dev gulp gulp-typescript merge-stream gulp-concat, it will install out dependencies.

Let’s import the dependencies in the gulpfile.js:

const gulp = require("gulp");
const ts = require("gulp-typescript");
const fs = require("fs");
const path = require("path");
const merge = require("merge-stream");
const concat = require("gulp-concat");

Now, we’ll create our “resource list”, for instance we just have one:

let folders = ["[essential]/ilog", "mySuperResource2"];

Note that we use the path taken from src.

Our build task:

gulp.task("build", function() {
  let tasks = [];

  // For each resource path in folder:
  folders.map(el => {
    // If there's a server folder
    if (fs.existsSync(path.join("src", el, "server"))) {
      tasks.push(
        gulp
          .src(`src/${escapeBracketPath(el)}/server/**/*.ts`)
          .pipe(
            ts({
              noImplicitAny: true,
              module: "commonjs"
            })
          )
          .pipe(concat("main_server.js"))
          .pipe(gulp.dest(`resources/${el}/server/`))
      );
    }
    // If there's a client folder
    if (fs.existsSync(path.join("src", el, "client"))) {
      tasks.push(
        gulp
          .src(`src/${escapeBracketPath(el)}/client/**/*.ts`)
          .pipe(
            ts({
              noImplicitAny: true,
              module: "system",
              outFile: "client_main.js"
            })
          )
          .pipe(concat("main_client.js"))
          .pipe(gulp.dest(`resources/${el}/client/`))
      );
    }
    // Copy the __resource.lua
    tasks.push(
      gulp
        .src(`src/${escapeBracketPath(el)}/__resource.lua`)
        .pipe(gulp.dest(`resources/`))
    );
  });

  // Merge all steams together
  return merge(tasks);
});

Note: since gulp.src() use node-glob, we do need to escape our [ ] in the path, here is one solution I made:

// [essential]/ilog -> [[]essential]/ilog
// [essential]/[essential]/ilog -> [[]essential]/[[]essential]/ilog
const escapeBracketPath = path =>
  path
    .split("[")
    .map((val, i) => (i != 0 ? `[]${val}` : val))
    .join("[");

Execute it

  1. You can install gulp globally and directly use gulp build
  2. You can edit package.json:
"scripts": {
  "test": "echo \"Error: no test specified\" && exit 1",
  "build": "gulp build"
}

and now you’re able to launch the build task with this: npm run build.

If the build succeed (no Ts compile error) you should now see your resource under resources:

I hope this will help you to be a STRONG Typescript developer.

5 Likes

Yo, this is cool and all, but I’m getting an error of Cannot set values on exports on the server and System is not defined on the client, if you can help resolve these, that would be great :smiley:

FYI: I’m using imports to split my code into multiple files, then want to gulp to a single file.
https://cdn.mrv.dog/ss/Code_6Z0rMIFC9v.png

Use globalThis/global