In a bare-bones environment, any change to a TypeScript file means that we need to reissue the tsc command from the command line every time we wish to compile our project. Obviously, it is going to be very tedious to have to switch to the command prompt and manually compile our project every time we have made a change. Fortunately, the TypeScript compiler provides the --watch option that will run a background task to monitor files for changes, and automatically recompile them when a change is detected. From the command line, we can run the following:
tsc --watch
Here, we have invoked the TypeScript compiler with the --watch option, which will then start the compilation step in watch mode. As and when we modify .ts files in our project directory, the compilation step will re-execute, and report any errors found.
If we have a more complicated build process that compiles our project, for example, and then needs to uglify the resulting JavaScript, we can use an automated task runner such as Grunt or Gulp. As an example of this process, let's replicate the --watch option by using Grunt to automatically invoke the tsc compiler when a file is saved. Gulp is a very similar task runner to Grunt, and, in certain circumstances, can perform steps faster than Grunt. Grunt, however, has a simpler syntax for configuration, and so we will use it in this section to introduce the concept of automated task runners.
Grunt runs in a Node environment, and therefore needs to be installed as an npm dependency of our project. To install Grunt, we will first need to create a packages.json file in the base directory of the project that will list all of the npm package dependencies that we may need. To create this packages.json file, open up a command prompt, navigate to the base directory of your project, and then simply type the following:
npm init
Then follow the prompts. You can pretty much leave all of the options as their defaults, and always go back to edit the packages.json file that is created from this step, should you need to tweak any changes.
Now that we have a packages.json file created, we can install Grunt. Grunt has two components that need to be installed independently. Firstly, we need to install the Grunt command-line interface that allows us to run Grunt from the command line. This can be accomplished as follows:
npm install -g grunt-cli
The second component is to install the Grunt files within our project directory:
npm install grunt --save-dev
The --save-dev option will install a local version of Grunt in the project directory. This is done so that multiple projects on your machine can use different versions of Grunt. We will also need the grunt-exec package, as well as the grunt-contrib-watch package installed for the project. These can be installed with the following commands:
npm install grunt-exec --save-dev
npm install grunt-contrib-watch --save-dev
Lastly, we will need a GruntFile.js. Using an editor, create a new file, save it as GruntFile.js, and enter the following JavaScript. Note that we are creating a JavaScript file here, not a TypeScript file. You can find a copy of this file in the sample source code that accompanies this chapter:
module.exports = function (grunt) {
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-exec');
grunt.initConfig( {
pkg: grunt.file.readJSON('package.json'),
watch : {
files : ['**/*.ts'],
tasks : ['exec:run_tsc']
},
exec: {
run_tsc: { cmd : 'tsc'}
}
});
grunt.registerTask('default', ['watch']);
};
This GruntFile.js contains a simple function to initialize the Grunt environment, and specify the commands to run. The first two lines of the function are loading grunt-contrib-watch and grunt-exec as npm tasks. We then call initConfig to configure the tasks to run. This configuration section has a pkg property, a watch property, and an exec property. The pkg property is used to load the package.json file that we created earlier as part of the npm init step.
The watch property has two sub-properties. The files property specifies a matching algorithm for Grunt to identify which files to watch for. In this case, it is set to find any .ts files within our entire source tree. The tasks array specifies that we should kick off the exec:run_tsc command once a file has changed. Finally, we call grunt.registerTask, specifying that the default task is to watch for file changes.
We can now run grunt from the command line, as follows:
grunt
As can be seen from the command line output, Grunt is running the watch task, and is waiting for changes to any .ts files, as follows:
Running "watch" task
Waiting...
Open up any TypeScript file, make a small change (add a space or something), and then hit Ctrl+S to save the file. Now, check back on the output from the Grunt command line. You should see something like the following:
>> File "hellogrunt.ts" changed.
Running "exec:run_tsc" (exec) task
Done, without errors.
Completed in 1.866s at Fri Jul 20 2018 22:22:52 GMT+0800 (AWST) - Waiting...
This command line output is confirmation that the Grunt watch task has identified that the hellogrunt.ts file has changed, run the exec:run_tsc task, and is waiting for the next file to change. We should now also see a hellogrunt.js file in the same directory as our Typescript file.