This is very probably the dullest title for a blog post I've ever come up with. Read on though folks - it's definitely going to pick up...
I wrote last year about my first usage of Gulp in an ASP.Net project. I used Gulp to replace the Web Optimization functionality that is due to disappear when ASP.Net v5 ships. What I came up with was an approach that provided pretty much the same functionality; raw source in debug mode, bundling + minification in release mode.
- Each time you fired up the app the following sequence of events would happen: - jQuery would load (purely there to simplify the making of various startup AJAX calls)
- the page would make an AJAX call to the server to load various startup data, including whether the app is running in debug or release mode
- Depending on the result of the startup data either the debug or release package manifest would be loaded.
- For each entry in the package manifest
linktags would be created and added to the document. These would generate further requests to the server to load the resources.
Quite a lot going on here isn't there? Accordingly, initial startup time was slower than you might hope. 2. The "F" word: FOUC. Flash Of Unstyled Content - whilst all the hard work of the page load was going on (before the CSS had been loaded) the page would look rather ... bare. Not a terrible thing but none too slick either. 3. The gulpfile built both the debug and the release package each time it was run. This meant the gulp task generally did double the work that it needed to do.
I wanted to see if I could tackle these issues. I've recently been watching John Papa's excellent Pluralsight course on Gulp and picked up a number of useful tips. With that in hand let's see what we can come up with...
The main issue with the approach I've been using is the dynamic loading. It makes the app slower and more complicated. So the obvious solution is to have my gulpfile inject scripts and css into the template. To that end it's wiredep & gulp-inject to the rescue!
gulp-inject (as the name suggests) is used to inject
link tags into source code. I'm using Bower as my client side package manager and so I'm going to use wiredep to determine the vendor scripts I need. It will determine what packages my app is using from looking at my
bower.json, and give me a list of file paths in dependency order (which I can then pass on to gulp-inject in combination with my own app script files). This means I don't have to think about ordering bower dependencies myself and I no longer need to separately maintain a list of these files within my gulpfile.
So, let's get the launch page (
index.html) ready for gulp-inject:
The important thing to notice here are the
<!-- inject:css --> and
<!-- inject:js --> injection placeholders. It's here that our script and style tags will be injected into the template. You'll notice that jQuery is not being injected - and that's because I've opted to use a CDN for jQuery and then only fallback to serving jQuery myself if the CDN fails.
The other thing to notice here is that our launch page has become oh so much simpler in comparison with the dynamic loading approach. Which is fab.
Now before we start looking at our gulpfile I want to split out the configuration into a standalone file called gulpfile.config.js:
Now to the meat of the matter - let me present the gulpfile:
That's a big old lump of code. So let's go through this a task by task...
build folder so we have a clean slate to build into.
Copy across all files that are needed to allow the page to "boot" / startup. At present this is only jQuery and images.
This is the magic. This picks up the launch page (
link tags into the page and writing it to the
build folder. Either the original source code or the bundled / minified equivalent will be used depending on whether it's debug or release.
Here we collect up the following:
- and we use our template files to construct a
templates.jsfile to prime the Angular template cache
If it's the scripts-debug task we copy all these files into the
build/debug folder. If it's the scripts-release task we also bundle, minify and strip the TypeScript out too and copy into the
Here we collect up the following:
- the Bower specified CSS files
- our own app CSS
If it's the styles-debug task we copy all these files into the
build/debug folder. If it's the styles-release task we also bundle and minify and copy into the
Whether it's the debug or the release build we copy across the font-awesome assets and place them in a location which works for the associated CSS (as the CSS will depend upon font-awesome).
build-debug and build-release (as their name suggests) either perform a build for release or a build for debug. If you remember, the web optimization library in ASP.Net serves up the raw code ("debug" code) if the
compilation debug flag in the
web.config is set to
true. If it is set to
false then we get the bundled and minified code ("release" code) instead. Our default task tries its best to emulate this behaviour by doing a very blunt regex against the
web.config. Simply, if it can match
<compilation debug="true" then it runs the debug build. Otherwise, the release build. It could be more elegant but there's a dearth of XML readers on npm that support synchronous parsing (which you kinda need for this scenario).
What I intend to do soon is switch from using the web.config to drive the gulp build to using the approach outlined here. Namely plugging the build directly into Visual Studio's build process and using the type of build there.
Hopefully what I've written here makes it fairly clear how to use Gulp to directly inject scripts and styles directly into your HTML. If you want to look directly at the source then check out the Proverb.Web folder in this repo.