Create a gulpfile and write gulp tasks using TypeScript

Are you migrating code from javascript to typescript, or writing a new app using typescript, but don’t know how to write gulp tasks in typescript? Then this article is for you.

There are some caveats in writing gulp tasks in typescript. First of all when you run “gulp” in command line by default it tries to work only with gulpfile.js file, and there is no support of gulpfile.ts or typescript at all. And how do we solve it? We need to compile our gulpfile.ts to the gulpfile.js using typescript compiler. That is a solution. But what if typescript compilation is a part of the gulp tasks process? This may be a problem, because you cannot run gulp tasks until you compile a typescript code, which can be compiled only after you run a gulp task. Recursion, hah? This article answers you how to handle this problem.

Also since we are using typescript we have a nice ability to use true OOP classes, encapsulation, inheritance and all other wonderful features. So, you may ask yourself how do I combine these awesome features when I write gulp tasks? How do I write my gulp tasks using classes? The answer is to use gulpclass package that allows you to write a beautiful class-based tasks without headache.

Before we start you’ll need to install required packages.

npm install typescript --save-dev
npm install gulpclass --save-dev

Next step is to create a typescript file where you’ll define gulp tasks. For example let’s create a gulpclass.ts file.

note that you can call it as you wish — for example you can call it gulpfile.ts, but in the case if you call it gulpfile.ts make sure that you are using outDir in typescript compiler options, because otherwise compiler will override gulpfile.js that you’ll need to create later.

In gulpclass.ts file you need to create a class and put @Gulpclass decorator on it. Each method in class that you mark with @Task decorator will be a gulp task. For example lets create a gulp class with one task that will clean everything inside of our “dist” directory. We are gonna use npm’s del package, so you’ll need to install it:

npm install del --save-dev

Now lets put some code into gulpclass.ts file:

import {Gulpclass, Task} from "gulpclass/Decorators";

let gulp = require("gulp");
let del = require("del");

@Gulpclass()
export class Gulpfile {

@Task()
clean(cb: Function) {
return del(["./dist/**"], cb);
}

}

Right now we created a gulp task named “clean” that will clean contents of the “dist” directory.

Next step is to create a gulpfile.js . Right, you still need this file because this is the only way gulp can understand that you have registered tasks. Remember that gulp itself is not working with typescript, it supports only javascript and gulp tasks written in javascript must be in gulpfile.js file.

But if gulp can only understand javascript, then how do we tell him about our tasks in gulpclass.ts? There is a trick. Just put this code into gulpfile.js:

eval(require("typescript").transpile(require("fs").readFileSync("./gulpclass.ts").toString()));

This trick does following:

  • reads the typescript code (containing gulp tasks) from typescript file
  • tells typescript compiler to compile our typescript code read from the file
  • typescript compiler returns us compiled javascript code in a string
  • we dynamically execute this compiled code in a current gulpfile.js file

And everything will work.

There are multiple ways how you can make your typescript code working. This approach is useful because it allows you to run gulp tasks without pre-compiling typescript code. If you don’t understand the process — no worries, simply use this code in all your project’s gulpfile.js files.

Now you can simply run task:

gulp clean

Task will execute and clean “dist” directory contents. The name of the task is automatically read from the class’s method name.

If you want to specify a custom name you can do it by specifying it in the first argument of the @Task decorator:

import {Gulpclass, Task} from "gulpclass/Decorators";

let gulp = require("gulp");
let del = require("del");

@Gulpclass()
export class Gulpfile {

@Task("clean-dist")
clean(cb: Function) {
return del(["./dist/**"], cb);
}

}

Now you can run task this way:

gulp clean-dist

Lets create more tasks and create a default task:

import {Gulpclass, Task} from "gulpclass/Decorators";

let gulp = require("gulp");
let del = require("del");

@Gulpclass()
export class Gulpfile {

@Task("clean-dist")
clean(cb: Function) {
return del(["./dist/**"], cb);
}
    @Task()
copyScripts() {
return gulp.src("./src/**/*.js")
.pipe(gulp.dest("./dist/**/*.js"));
}
    @Task()
copyStyles() {
return gulp.src("./src/**/*.css")
.pipe(gulp.dest("./dist/**/*.css"));
}
    @Task()
default() {
return ["copyScripts", "copyStyles"];
}
}

Now 4 gulp tasks are available for you:

  • gulp — runs default task which copies scripts and styles in parallel
  • gulp clean-dist — cleans “dist” directory
  • gulp copyScripts — copies all scripts from “src” directory to “dist”
  • gulp copyStyles — copies all styles from “src” directory to “dist”

Thats it. At this point you should be available to use gulp as you usually do, but this time using Typescript instead of Javascript.

Additionally gulpclass provides you ability to create tasks that can run in sequence. By default when you are using gulp it runs tasks in parallel, but sometimes when tasks are depend of each other you need to run tasks in sequence. To achieve this task gulpclass is using run-sequence and encapsulates it in a simple decorator called @SequenceTask.

In our gulpclass.ts we want to make first clean and only after clean is finished we want to copy scripts and styles in parallel. Here is updated code to achieve this:

import {Gulpclass, Task} from "gulpclass/Decorators";

let gulp = require("gulp");
let del = require("del");

@Gulpclass()
export class Gulpfile {

@Task("clean-dist")
clean(cb: Function) {
return del(["./dist/**"], cb);
}
    @Task()
copyScripts() {
return gulp.src("./src/**/*.js")
.pipe(gulp.dest("./dist/**/*.js"));
}
    @Task()
copyStyles() {
return gulp.src("./src/**/*.css")
.pipe(gulp.dest("./dist/**/*.css"));
}
    @SequenceTask()
default() {
return ["clean-dist", ["copyScripts", "copyStyles"]];
}
}

Don’t hesitate to add github stars to gulpclass project and share with community.