Wednesday, December 31, 2014

Gulp is the Wild West

TL;DR This post described how I implemented asset processing with Gulp in a .NET project.

enter image description here

I am working on a .NET web application using Nancy in the backend and AngularJS in the frontend.
I decided to use a frontend-build based on Gulp. Frontend builds based on Grunt or Gulp have a lot of momentum right now, and this seems a better option for me than some .NET based tools like Cassette or SquishIt

By the way: if you have a node based frontend build you can run it on each Azure deployment like described here.

My requirements were the following:

  • For development the project should be runnable from VisualStudio without having to trigger a frontend build. That means that all the frontend assets have to be present at development time and referenced from my .cshtml files.
  • For release the frontend assets should be processed (concatenated, minified, revisioned …) by a frontend build. This build also needed to manipulate the .cshtml files, since they must reference the processed assets.

I started with gulp-usemin:

gulp.task("usemin", function() {
    return gulp.src("./Views/*.cshtml")
            js: [ngAnnotate(), uglify(), rev()]


This was nice and easy and worked well … until I had some more requirements …

The problem:
With gulp-usemin you have not access to the stream in a pipeline. So you are limited to list some tasks that should be performed. If you want to do something more fancy, you are out of luck. In my case I wanted to add the output of angular template cache to my main js file after it has been concatenated and minified…
In my case I wanted to append another JavaScript file that contains my angular templates (generated with gulp-angular-templatecache)

So I started looking for another solution… thats where I discovered that I am in the Wild Wild West: gulp-usemin2, gulp-spa, gulp-asset-transform, gulp-inject, gulp-rev-replace, gulp-useref, gulp-rev-all, gulp-rev-collector … all seem somehow to do something similar, documentation is minimalistic and you can waste a big amount of time to find the right plugin combination that works for you.

I ended up with the following combination of plugins:

var gulp = require("gulp");
var ngAnnotate = require("gulp-ng-annotate");
var templateCache = require("gulp-angular-templatecache");
var uglify = require("gulp-uglify");
var addsrc = require("gulp-add-src");
var concat = require("gulp-concat");
var rev = require("gulp-rev");
var minifyCSS = require("gulp-minify-css");
var useref = require("gulp-useref");
var filter = require("gulp-filter");
var revReplace = require("gulp-rev-replace");
var order = require("gulp-order");

gulp.task("angular-templates", function(){
    return gulp.src(TEMPLATES_SOURCES)
        .pipe(templateCache(TEMPLATES_JS, {module: "moonwalk", root: TEMPLATES_ROOT}))

gulp.task("release-assets", ["angular-templates"], function() {
    var assets = useref.assets();
    var jsFilter = filter("**/*.js");
    var moonwalkFilter = filter("**/" + MOONWALK_JS);
    var cssFilter = filter("**/*.css");

    return gulp.src("./Content/**/*.cshtml")
        .pipe(assets)               // Concatenate with gulp-useref
        .pipe(ngAnnotate())         // Process javascript sources to add dependency injection annotations
        .pipe(uglify())             // Minify javascript sources
        .pipe(minifyCSS())          // Minify CSS sources
        .pipe(moonwalkFilter)       // Filter the moonwalk.js source file, which is generated above by useref
        .pipe(addsrc("Temp/" + TEMPLATES_JS))// Add the templates.js to the stream, which is generated by a seperate task
        .pipe(order(["**/" + MOONWALK_JS, "*.js"]))// Order stream, so that templates.js is appended to moonwalk.js (needed, since templates depend on the angular module)
        .pipe(concat(MOONWALK_JS))// Concat the existing moonwalk.js and the templates.js into moonwalk.js
        .pipe(rev())                // Rename the concatenated files
        .pipe(useref())             // Replace the original references in the cshtml with the concatenated and processed resources by usemin
        .pipe(revReplace({replaceInExtensions:[".cshtml"]}))         // Replace the usemin generated resources with the reved resources

And by the way: This thread about running tasks synchronously is representative for Gulp (final verdict: “This will be fixed in gulp 4”) … welcome in the wild wild west!

Sunday, December 21, 2014

Weekend Reader, Week 51

IMG 0221

Rob Ashton speaks at the .NET user group

I never met Rob, but I think he is a very interesting character in the programming space.

His episode as a “journeyman programmer” is mind blowing and I suggest to every enterprise programmer to have a look at it: "The software journeyman's guide to being homeless and jobless.” (or if you have a plural sight subscription you can watch the production: Change it Up where Rob Conery does an extensive interview with Rob).

Rob will be speaking on January 7th in Bern and on January 8th in Luzern about "Frameworkless development with NPM and React” - a very interesting topic in my opinion. And of course not at all related to .NET programming :-). So I hope to see some non .NET programmers at the event...

While we are at it, here are some further interesting posts of Rob Ashton:


Software engineering in practice

Very nice presentation by Marc Hofer about Agile software development.


Which Silicon Valley company has the best intern perks?

So the myths are true, there are companies that do a lot for their employees ...


From Open (Unlimited) to Minimum Vacation Policy

… perks are not without problems:

Netflix has it, Virgin has it: Unlimited vacation policy … but not everything that shines is gold:

The cause was intended to be noble, as we didn't want to get into the way of people taking time off as much time as they need to recharge.[…] Two years later, this idea turned out to be a failure, and we're changing our vacation policy.


Letter To A Young Programmer Considering A Startup

Startups are not that sexy any more according to:

A startup job is the new office job. Startup culture is the new corporate culture.

Here is also a recent production of Swiss radio SRF about the “disillusion of startups” (in German): Start-up-Firmen: Der Traum vom nächsten Facebook


The State of JavaScript in 2015

The JavaScript world seems to be entering a crisis of churn rate. Frameworks and technologies are being pushed out and burned through at an unsustainable speed.


More developer tidbits:


Friday, December 19, 2014

Presentation: Java & JavaScript - Best Friends?


Last week I was invited again to give a talk at the annual developer day of Swiss Railways (SBB).

As every year the conference was a great event with many great sessions and interesting discussions during the breaks.

My talk was about how JavaScript can fit into a Java ecosystem.

Tuesday, December 2, 2014

There is something about JavaScript - My Slides from the Choose Forum 2014

I was very honored that I was invited to speak at the Choose Forum 2014 along with Michael FeathersErik Doernenburg and Adam Tornhill.
These were the slides for my talk “There is something about JavaScript”:

Related Posts Plugin for WordPress, Blogger...