aurelia-nw Part 2
This is the second post regarding creating a nw.js (node-webkit) app with Aurelia. The first post can be found here In this followup post, we will make our aurelia-nw app and its build process production ready. The completed source code is available on GitHub.
I have taken the project where
we left off in the previous post (view source here),
and I added the content from the Aurelia demo project.
I made some minor changes such as using LESS for my styles, moving the styles
folder inside the src
folder, and
updating the gulp tasks respectively.
The updated project can now be found here, and it is the starting point for this post.
Creating a Production Release
Goals:
- Minify and uglify all Javascript
- Minify all HTML/CSS
- Use semver to manage versioning
- Ensure various production values are set (i.e
toolbar: false
in our nw manifest properties) - Isolate all release builds from the rest of the codebase, then use node-webkit-builder to compile
Release Arguments
In order to differentiate between a normal (development) build and a release build, I’ll use
yargs so that we can do something along the lines of gulp build --release
.
I’ll also use gulp-bump to increase the app’s version. After installing
those packages (npm install yargs gulp-bump --save-dev
), add a args.js
file in the gulp
folder.
gulp\args.js
:
var yargs = require('yargs');
var argv = yargs.argv,
validBumpTypes = "major|minor|patch|prerelease".split("|"),
bump = (argv.bump || 'patch').toLowerCase(),
isRelease = argv.release ? true : false;
if (validBumpTypes.indexOf(bump) === -1) {
throw new Error('Unrecognized bump "' + bump + '".');
}
module.exports = {
bump: bump,
isRelease: isRelease
};
Minification
In each of the (relevant)gulp tasks, I will require gulp\args
to determine if the build is a release build. Using
gulp-if, I will either run the task for release or development.
If it is a release build, then all output will be directed to a dist
folder. Once it is there, I’ll use
node-webkit-builder to compile it.
I won’t go into each library that is used for minification and uglification - they are pretty standard.
Here is the project after these modifications have been made. Running gulp build --release
will produce
a dist
folder with the same structure as the build
folder, but everything will be minified/uglified.
Versioning
When I build a production release, I would like the version of the app to be increased using semver. Let’s add a gulp task for that.
gulp\tasks\prepare-release.js
:
var gulp = require('gulp'),
runSequence = require('run-sequence'),
args = require('../args'),
paths = require('../paths'),
bump = require('gulp-bump');
gulp.task('prepare-release', function(done){
return runSequence(
'build',
'bump-version',
done
);
});
gulp.task('bump-version', function () {
return gulp.src('./package.json')
.pipe(bump({type: args.bump})) //major|minor|patch|prerelease
.pipe(gulp.dest('./'))
.pipe(gulp.dest(paths.dist));
});
This can be called like so: gulp prepare-release --release --bump minor
Prepping the Dist Folder
I want to call node-webkit-builder’s build()
on the dist
folder, and I want it
to look something like this:
|-- app
|-- app.js
|-- app.html
|-- etc..
|-- content
|--styles
|-- jspm_packages
|-- node_modules
|-- index.html
|-- config.js
|-- package.json
A gulp task can be added to simply copy index.html, config.js, and package.json; but I don’t want to copy all of the node modules and jspm packages. I only want to include the packages that are being used - after all, most of the node packages are used for development only. Let’s add a gulp task for that.
gulp.task('npm-dependencies', function(){
var buffer, packages, keys;
buffer = fs.readFileSync('./package.json');
packages = JSON.parse(buffer.toString());
keys = [];
for (var key in packages.dependencies) {
keys.push('./node_modules/' + key + '/**/*');
}
return gulp.src(keys, {base: './'})
.pipe(gulp.dest(paths.dist));
});
Miscellaneous Production Values
When I release the app, I want some of the NW.js manifest properties to be changed (mainly the display of the toolbar and the frame). I’ll add a gulp task and use gulp-json-editor to do this.
gulp.task('prep-nw-properties', function () {
return gulp.src(paths.dist + 'package.json')
.pipe(jeditor(function (json) {
json.window.toolbar = false;
json.window.frame = false;
return json;
}))
.pipe(gulp.dest(paths.dist));
});
Building
Once the dist
folder is prepped, I’ll build it with node-webkit-builder.
gulp.task('build-release', ['prepare-release'], function(cb){
var nw = new NwBuilder(config.nwBuilderConfig);
nw.on('log', gutil.log);
nw.build(cb);
return nw;
});
That’s it! At this point, we have a ready-to-release production build alongside a development build.
Running gulp build-release --release
will produce binaries for each platform that was supplied in a
release
folder in the project’s root.
It’s not perfect right now, but it is effective. I’ll dive into some of the those imperfections in a future post.
Here is the source for the project at this point.