SyntaxHighlighter

Wednesday, December 2, 2015

SharePoint + TypeScript + Angular + Gulp + Visual Studio 2015 + more

I have been playing with Angular, Node and Gulp frameworks for a while mostly with WebStorm IDE and recently started using TypeScript and I love it. To learn and understand how these framework will integrate with SharePoint solution, I created simple Web Part farm project which does nothing at the moment, except few text boxes binding with Angular. WebStorm does not support SharePoint Solution, but luckily the recent release of Visual Studio 2015 has built-in support for Node, Task Runner and Bower. You can also add Task Runner support in Visual Studio 2013 by installing this plugin.

This post is about my learning experience integrating all these technologies together with SharePoint, Visual Studio and Gulp workflows. Here is the list of tools/frameworks I used:

Node – JavaScript runtime engine
Angular – JavaScript framework
jQuery – JavaScript framework
Gulp – Automation and build workflow (install global only)
Typescript – Built-in support in VS.NET 2015. Other version requires WebEssentials
TSD – DefinitelyType definition for Typescript repository.
Bower – Front-end optimized framework/libraries package manager. VS.NET 2015 has built-in support for Bower.
NPM – Node package manager (comes with Node)
Git – required by NPM and Bower

You can open link for instructions to install on your environment.


Step 1 – Create SharePoint Project


Create empty SharePoint 2013 project and added SharePoint Project Item: EmpDir_Module. This is the folder where we will be generating compiled/bundled/minified typescript file and other JavaScript files which we will be deploying to SharePoint. You can create dummy placeholder files and include it in Elements.xml or once files are copied (by Step 6) you can use "Include in Project" and update Elements.xml.


Step 2 – Setup


I assume all tools are installed and ready to go. First we need to initialize *.json files which contains references to files dependencies with versions installed, which can be used by other developers to bring in all dependencies.

Open Command Prompt, navigate to root Project directory and run following commands. I tried running this command from Visual Studio Package Manager Console but it hanged. These commands will ask series of questions to initialize *.json file.

$ npm init
- this command creates package.json file
$ bower init
- this command creates bower.json file
$ tsd init
- this command creates tsd.json and folder “typings”


Step 3 – Install Dependencies


Once we have all the *.json files, we can begin installing dependencies for our project. We can run these command either from external command prompt of Visual Studio Package Manager Console window.

$ npm install --save-dev gulp
- install gulp for the project and save as DEV dependency in package.json
$ npm install --save-dev gulp-concat gulp-print gulp-rename gulp-sequence gulp-typescript -uglify run-sequence
- install gulp plugins and save as DEV dependency in package.json

* Note : npm installs all components under “node_modules” folder in root.

$ bower install jquery angular --save
- install jquery and angular framework and save dependency in bower.json

* Note : bower installs all components under “bower_components” folder in root.

$ tsd install jquery angular --save
- install jquery and angular DefinitelyTyped definitions and save dependency in tsd.json

* Note : tsd installs all components under “typings” folder in root.

* Note : --save switch will record dependency as minimum required and if latest version available, will download the latest build. If you want to stick to any version, you can use --save-exact switch.


Step 4 – Write code


Before you start writing Typescript files, it’s better to decide the project folder structure. There is awesome Angular style guide compiled by John Papa here. As we are not going to deploy *.ts (typescript files) to SharePoint, I prefer to keep those files away in a separate folder. Here is how my project folder structure looks like:


I have created folder: “App” which contains typescripts source and compiled JavaScript files under “TScripts” and “compiled” folders. I have not included “bower_components”, “node_modules” and its contents to the project, as we are not deploying these files. We do need files from “bower_components” and will see how to deploy those as Module. I added “typings” folder, as I sometimes open *.d.ts files to see method signature or interface description. In Visual Studio you can select any method on typescript file and hit F12 will take you to method definition in *.d.ts file. Pretty handy.

I will not discuss about writing angular in Typescript, as that is a huge topic in itself. Pluralsight has several trainings on this subject.

Typescript file naming convention is for a reason we will see when we go to Gulp section. The naming convention will come handy during bundling and order of files.


Step 5 – Write Gulp Workflow


This is where all magic happens. Create a new JavaScript file: “gulpfile.js” in the root and copy/paste content below:
/// <binding BeforeBuild='default' />
/**
 * Created by Javed on 8/15/2015.
 */
'use strict';

var gulp = require('gulp'),
    gprint = require('gulp-print'),
    runSequence = require('run-sequence'),
    ts = require('gulp-typescript'),
    bundle = require('gulp-concat'),
    minify = require('gulp-uglify'),
    rename = require('gulp-rename');

var paths = {
    "TSSrc": 'App/TScripts/',
    "JSCompiled": 'App/compiled/',
    "JSDest": 'EmpDir_Module',
    "BowerSrc": "bower_components/"
}

var config = {
    "TypeScriptFiles": [
        paths.TSSrc + '**.ts'
    ],
    "BowerFiles": [
        paths.BowerSrc + 'jquery/dist/jquery.min.js',
        paths.BowerSrc + 'angular/angular.min.js'
    ],
    "BundleSrc": [
        paths.JSCompiled + '*.module.js',
        paths.JSCompiled + '*.config.js',
        paths.JSCompiled + '*.run.js',
        paths.JSCompiled + '*.constant.js',
        paths.JSCompiled + '*.directive.js',
        paths.JSCompiled + '*.service.js',
        paths.JSCompiled + '*.controller.js'
    ],
    "BundleFileName": "ed.bundle.js",
    "MinifyFileName": "ed.bundle.min.js"
}

gulp.task('compile', function () {
    var tsc = gulp
        .src(config.TypeScriptFiles)
        .pipe(gprint())
        .pipe(ts({ "noImplicitAny": true, "removeComments": true }));

    return tsc.js.pipe(gulp.dest(paths.JSCompiled));
});

gulp.task('bower', function () {
    return gulp
        .src(config.BowerFiles)
        .pipe(gprint())
        .pipe(gulp.dest(paths.JSDest));
});

gulp.task('prod_build', function() {
    return gulp
        .src(config.BundleSrc)
        .pipe(bundle(config.BundleFileName))
        .pipe(gprint())
        //.pipe(rename(config.MinifyFileName))
        //.pipe(minify())
        .pipe(gulp.dest(paths.JSDest));
});

gulp.task('default', function () {
    runSequence('compile', 'bower', 'prod_build');
});

You can read more on Gulp here. I will explain in brief about gulpfile.js and each task.

As gulpfile.js is plain JavaScript file, you can define your own variable and functions. I have defined 2 variables “paths” and “config” objects with property for source, destination or file name which we will be using in gulp tasks. I found this approach to be better than hard coding paths in tasks definition itself.

Compile task:
  1. Grab all *.ts files under “App/TScripts” folder
  2. Compile to JavaScript
  3. Copy output to “App/compiled” folder
Bower task:
  1. Grab bower_component files like jquery, angular
  2. Copy to SharePoint module folder “EmpDir_Module”
Prod_Build task:
  1. Grab all compiled JavaScript from “App/compiled” folder in same order as defined in config.BundleSrc array
  2. Conact all files and save “ed.bundle.js”
  3. Rename file to “ed.bundle.min.js”
  4. Minify/uglify this file
  5. Copy to SharePoint module folder “EmpDir_Module”   
Default task:
  1. Run all tasks in sequence.
* Note : When default task in defined executing “gulp” command with no parameter runs default task. You can run individual task by executing “gulp bower” from command line or VS Package Manager Console.


Step 6 – Attaching Gulp task with Visual Studio build event


The last step. Open Task Runner from View > Other Windows > Task Runner Explorer. You should see Gulpfile.js node with all task names. Right click on any task and select Bindings to attach to any build event. See the screenshot below, where default task is attached to Before Build event.


* Note : While in development mode, you can write new task "dev_build" and instead of copying to Module folder, you can map Style Library or any other library (where you are deploying your .js files) and copy to this mapped location. No need to deploy WSP package :)

This concludes the long post. Hope this help someone.

Thanks,
-Javed

4 comments: