Using TypeScript and Gulp for CRM Client side scripting

Business Rules and real time workflows have reduced the necessity to write Javascript in Microsoft CRM for really simple use cases. Once the requirements are a bit more complex and client side scripting seems the right choice, you can try using TypeScript.

Pre-requisites

  1. Install Node
  2. Globally install gulp by typing “npm install gulp -g” into the command prompt
  3. Globally install TypeScript compiler by typing “npm install typescript -g” in command prompt.
  4. Install VSCode

package.json

{
  "devDependencies": {
    "babel-core": "^5.8.25",
    "del": "^2.0.2",
    "gulp": "^3.9.0",
    "gulp-babel": "^5.3.0",
    "gulp-load-plugins": "^1.0.0",
    "gulp-size": "^2.0.0",
    "gulp-sourcemaps": "^1.6.0",
    "gulp-tsc": "^1.1.1",
    "gulp-uglify": "^1.4.2"
  },
  "engines": {
    "node": ">=0.10.0"
  },
  "private": true
}

Once you download the repo from https://github.com/rajyraman/crm-client-scripts/tree/master/typescript run “node install” inside the typescript folder from command prompt. This will bring across the required node modules.

The below is the config file for gulp.

import gulp from 'gulp';
import del from 'del';
import gulpLoadPlugins from 'gulp-load-plugins';
import source from 'vinyl-source-stream';
import buffer from 'vinyl-buffer';
import glob from 'glob';
import es from 'event-stream';

const $ = gulpLoadPlugins();

gulp.task('build', ['clean'], ()=> {
    glob('src/**/**form.ts', function(err, files) {
        var tasks = files.map(function(entry) {
            let fileName = entry.substr(entry.lastIndexOf('/')+1).replace('.ts','.bundle.js');
            return gulp.src([entry])
                .pipe($.tsc({keepTree: false, out: fileName}))
                .pipe(buffer())
                .pipe($.sourcemaps.init({loadMaps: true}))
                .pipe($.uglify({preserveComments: 'some'}))
                .pipe($.sourcemaps.write())
                .pipe(gulp.dest('build'));
            });
        return es.merge.apply(null, tasks);
    });
    gulp.watch(['src/**/*.ts'], ['build']);
});

// Clean output directory
gulp.task('clean', cb => del(['.tmp', 'build/*', '!build/.git'], {dot: true}, cb));

gulp.task('default', ['build']);

In this build file, I make these assumptions:

  1. Scripts for each entity are stored in a separate folder
  2. The main entity script is suffixed with .form

Since the dependant files are always included via the triple slash reference comment on all the “.form.ts” files, TypeScript compiler will package up the output Javascript file with all the required dependencies.

There is also a gulp watch in the build task, so that any changes you make to the TypeScript files, triggers the build task and hence the compiled Javascript files will always be in sync with the TypeScript files. In order to start build, just type “gulp” in the command prompt from the folder containing the gulp.babel.js and the default task should take care of the rest.

TypeScript Definitions

Dave Berry has published the tsd files for CRM Client side development. There are so many good reasons to use TypeScript, and Intellisense is one of the top items in my list. There are community published tsds for other popular libraries and so you are not losing any thing by switching to TypeScript.

Head to the TypeScript playground to quickly familiarise yourself with the features and see how your TypeScript code is compiled into Javascript. Here is a quick comparison on couple of the common ones, in terms of CRM development with Dave Berry’s tsd files.

Javascript Typescript
Xrm.Page.getAttribute(‘[NAME]’).setValue(‘hello’) Xrm.Page.getAttribute(‘[NAME]’).setValue(‘hello’)
Xrm.Page.getControl(‘[NAME]’).setDisabled(false) Xrm.Page.getControl(‘[NAME]’).setDisabled(false)
Xrm.Page.getAttribute(‘[NAME]’).setValue([{id: ‘[ID]’, name: ‘[NAME]’, entityType: ‘[TYPE]’}]) Xrm.Page.getAttribute(‘[NAME]’).setValue([{id: ‘[ID]’, name: ‘[NAME]’, entityType: ‘[TYPE]’}])
Xrm.Page.getAttribute(‘[NAME]’).setValue(new Date()); Xrm.Page.getAttribute(‘[NAME]’).setValue(new Date());

These are the valid types for attributes types as per the tsd:

  1. NumberAttribute
  2. StringAttribute
  3. EnumAttribute (for Optionsets and bool)
  4. DateAttribute
  5. LookupAttribute

These are the valid control types as per the tsd:

  1. StandardControl
  2. GridControl
  3. FramedControl
  4. SilverlightControl

Why should you use TypeScript

Types is a polarizing topic. Some prefer dynamically typed language, while some prefer strongly typed. With ever increasing Javascript adoption, there is a growing opinion that types are a good thing. TypeScript still compiles into Javascript, but uses typing to improve developer productivity. It also adds some additional features that are not in Javascript. These are some of the advantages:

  1. Intellisense
  2. Compilation stage catches the obvious errors arising due to types
  3. Generics
  4. Modules (available in ES6 as well)
  5. Classes (available in ES6 as well)
  6. Union Types
  7. Microsoft product – great tooling support with VSCode and Visual Studio
  8. Open source

Screenshots

VSCode

output

Final notes

I have also added a sample project on how to do this with ES6, Babel and Browserify. You can refer https://github.com/rajyraman/crm-client-scripts/tree/master/es2015 for this, if you still want to use just Javascript.

EDIT (11/05/16): TypeScript has now published an official recipe for using Gulp, Browserify and Babel with TypeScript. Please refer http://www.typescriptlang.org/docs/handbook/gulp.html

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s