This is second part of my Getting Back to Visual Studio-post. With Visual Studio 2015 and MVC 6 the Microsoft team have given the front end some extra attention. Web essentials ditching the Sass, Less, Coffeescript compiler in favor for Gulp/Grunt and the new folder structure is evidence of that.

Normally if you make for example a Laravel-project you'll have the front end preprocessor stuff in a Resources-folder and compile that to the app folder. Or if you make a theme to Wordpress or Ghost you'll probably have a src-folder and compile it to the theme-folder. This workflow will be a lot easier to mimic with the release of MVC 6.

But right now we are working with MVC 4 (or possibly 5). And Umbraco has it's own way to structure front end files so this is how to set it up my way:

I like to work with Gulp and Sass. If you prefer Grunt and/or less; you'll probably know how to write the corresponding code snippets.

Since my last post Visual Studio RC is released and when installing i noticed you could select Web Essentials to be included. Otherwise, be sure to install the version of Web Essentials that matches your version of Visual Studio. Right click on your project and add a package.json file. Below you can see the my whole package-file and the packages we are going to work with.

{
  "name": "package",
  "version": "1.0.0",
  "private": true,
  "devDependencies": {
    "gulp": "~3.8.11",
    "gulp-load-plugins": "~0.10.0",
    "browser-sync": "~2.7.2",
    "wiredep": "~2.2.2", 
    "gulp-sass": "~2.0.1",
    "gulp-sourcemaps": "~1.5.2",
    "gulp-autoprefixer": "~2.3.0",
    "gulp-csso": "~1.0.0",
    "gulp-uglify": "~1.2.0",
    "gulp-notify": "~2.2.0",
    "gulp-clean": "~0.3.1",
    "gulp-concat": "~2.5.2",
    "gulp-jshint": "~1.10.0",
    "gulp-useref": "~1.1.2",
    "gulp-strip-debug": "~1.0.2",
    "gulp-rename": "~1.2.2",
    "gulp-bower": "~0.0.10",
    "gulp-filter": "~2.0.2",
    "main-bower-files": "~2.8.0",
    "gulp-if": "~1.2.5"
  }
}

The Gist (May be more up to date)

If you try to add a package yourself you'll notice that there are some pretty sweet IntelliSense going on. Specially nice is that it searches the latest version and gives explanation to what the tilde (~) and the caret (^) means. As you can see i prefer the tilde. That only upgrades to the latest minor release. That way i have to make a conscious choice to upgrade and nothing will brake because of an update of library.

The Gulpfile

Add a gulpfile.js to the root of your project. And start by loading the plugins:

// Load plugins
var gulp = require('gulp'),  
    $ = require('gulp-load-plugins')(),
    browserSync = require('browser-sync'),
    reload = browserSync.reload;

gulp-load-plugins loads all plugins in our package file. With Browsersync we can start up a proxy server that refreshes on save.

Next we want a task to process our sass styles:

// Sass
gulp.task('sass:dev', function () {

    // Sass to css
    // Sourcemap
    // Prefix for latest browsers
    // Put .css in /css root

    return gulp.src('css/sass/main.scss')

        .pipe($.sourcemaps.init())
        .pipe($.sass().on('error', $.sass.logError))
            .pipe($.sourcemaps.write()) // Bug Workaround (https://github.com/dlmanning/gulp-sass/issues/106#issuecomment-60977513)
            .pipe($.sourcemaps.init({ loadMaps: true }))
        .pipe($.autoprefixer())
        .pipe($.sourcemaps.write())
        .pipe(gulp.dest('css'))
        .pipe(reload({ stream: true }));
});

As you can see i have all my sass files in css/sass/. I have seen other Umbracians structure it like this and it seems fitting. Projects i work on i usually don't need more than one bundled CSS for the whole site. So this folder structure suits me pretty well.

Sourcemaps: There is a bug with a nasty workaround. Hopefully fixed soon! This works for now.

Autoprefixer: The autoprefixer is nice. Doesn't bloat the dev code and you can easily change what browsers to support globally.

Destination: We put our new bundled CSS in the CSS root. We don't need to clear anything. Just write over the older one. This works fine because we haven't added any cache busting plugin that versions the CSS. If we want to add that we need another folder structure. We'd need to have the bundled and minified CSS in its own folder. Cause we want to still be able to add CSS though the admin system. Specially if we want to add a CSS file for a tinyMCE Editor in the admin.

Sass For Production

gulp.task('sass:prod', function () {

    // Sass to css
    // No sourcemap
    // Prefix for latest browsers
    // Put .css in /css root

    return gulp.src('css/sass/main.scss')

      .pipe($.sass({
          outputStyle: 'compressed',
          precision: 10, // Default 5
          onError: console.error.bind(console, 'Sass error:')
      }))
      .pipe($.autoprefixer())
      .pipe(gulp.dest('css'));
});

Main difference is that we skip the sourcemap.

CSS and Javascript For Production

gulp.task('production', ['sass:prod', 'fonts'], function () {

  var assets = $.useref.assets({ searchPath: ['.'] });

  return gulp.src('Views/*.cshtml')
      .pipe(assets)
      .pipe($.if('*.js', $.uglify()))
      .pipe($.if('*.js', $.stripDebug()))
      .pipe($.if('*.css', $.csso()))
      .pipe(assets.restore())
      .pipe($.useref())
      .pipe(gulp.dest('dist'));
});

We run the production sass before this so we get the latest CSS without sourcemaps (['sass:prod']). Useref helps us concatinate the files and CSSO/Uglify helps us minifying the files. stripDebug() strips away things like console.log(). Life saver.

Since we're (i'm) not working with a "dist"-folder i do a midway compromise. I export only the files altered in the optimization stage to a dist folder. I can then just copy over that folder over the old one on a staging or production server.

Bower Components

Add a bower.json file to the root of the project. I usually start of with a bower containing Modernizr, JQuery and NormalizeCSS.

{
    "name": "bower",
    "license": "Apache-2.0",
    "private": true,
    "dependencies": {
        "modernizr": "~2.8.3",
        "jquery": "~2.1.4",
        "normalize.css": "~3.0.3",
        "jquery-smooth-scroll": "~1.5.5",
        "Font-Awesome": "~4.3.0"
    }
}

When saving this file it'll fetch your front end libraries just like the node packages. But they comes with a lot of folders and can be a bit messy. Wiredep can help us with this. We define with comments in CSHTML where we want our dependencies:

<html>  
<head>  
  <!-- bower:css -->
  <!-- endbower -->
</head>  
<body>  
  <!-- bower:js -->
  <!-- endbower -->
</body>  
</html>  

And even cooler! We can watch the bower file with gulp watch and if we ad a dependency and save our CSHTML files will update itself. This is how that task could look like:

gulp.task('wiredep', function () {

    var wiredep = require('wiredep').stream;

    gulp.src('css/sass/*.scss')
      .pipe(wiredep(({
          ignorePath: /^(\.\.\/)+/
      })))
      .pipe(gulp.dest('css/sass'));

    gulp.src('Views/**/*.cshtml')
      .pipe(wiredep(({
          ignorePath: /^(\.\.\/)*\.\./
      })))
      .pipe(gulp.dest('Views'));
});

The regular expression is because we have everything in the root. It corrects the path. If we run this, we'll notice that Modernizr will be inserted in the bottom. Modernizr belongs in the head! Just move it manually and the next time wiredep runs it'll see that Modernizr is already in the document and not add it again. Good enough.

Let's tie this gulp file together with a init task that starts the proxy and all watches. Don't forget to enter the right port on the proxy.

gulp.task('initialize', ['sass:dev'], function () {

    // Init watch and browsersync on build

    browserSync.init({

        proxy: 'http://localhost:55107/'
    });

    // Watch .scss files
    gulp.watch('css/sass/**/*.scss', ['sass:dev']);

    // Watch .js files
    gulp.watch('scripts/**/*.js', function () {
        browserSync.reload();
    });

    // Watch HTML
    gulp.watch('Views/**/*.cshtml', function () {
        browserSync.reload();
    });

    // Watch Bower for new Libraries
    gulp.watch('bower.json', ['wiredep', function () {
        browserSync.reload();
    }]);

});

First argument is what to watch and second is an array of tasks that will execute on change. A cool thing with Web Essentials is that you can bind tasks to events. The reason i called the task initialize is because i want it to run when i build my project. From Tools; choose Task Runner Explorer. From there you can see all your Gulp Tasks. Right click init and bind it to before build. Why not after? Cause if there is something wrong with the gulpfile it will stop and not fire up a server that contains errors. Cool stuff!

You can find my whole gulpfile in this Gist.

The handsome model with the Gulp/Umbraco bevarage is the Dart nerd Emil Persson.