Created
June 6, 2013 14:26
-
-
Save millermedeiros/5721901 to your computer and use it in GitHub Desktop.
node.js build script using commander and shelljs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var DIST_FOLDER = '../site/public'; | |
// ---- | |
// more references: | |
// https://gist.github.com/millermedeiros/2640928 | |
// https://gist.github.com/millermedeiros/4724047 | |
var _cli = require('commander'), | |
_requirejs = require('requirejs'), | |
_path = require('path'), | |
_fs = require('fs'), | |
_shell = require('shelljs'); | |
// --- | |
_cli | |
.command('js') | |
.description('optimize JS files. combine into fewer files to improve load performance') | |
.action(optimizeJS); | |
_cli | |
.command('css') | |
.description('compile Sass files into CSS') | |
.action(compileSass); | |
_cli | |
.command('deploy') | |
.description('optimize JS, compile SASS, copy all assets to the "./site" folder') | |
.action(deploy); | |
_cli.parse(process.argv); | |
// ---- | |
function rjs(opts, cb){ | |
var defaultSettings = { | |
logLevel: 1, | |
// optimize: 'none', | |
baseUrl: 'scripts', | |
mainConfigFile : 'scripts/main.js', | |
paths: { | |
// TODO: load jquery from CDN | |
'jquery': 'lib/jquery/jquery' | |
} | |
}; | |
for(var key in opts) { | |
defaultSettings[key] = opts[key]; | |
} | |
_requirejs.optimize(defaultSettings, cb); | |
} | |
function optimizeJS(cb){ | |
rjs({ | |
name: 'main', | |
out: 'scripts/main.min.js', | |
stubModules: [ | |
'text', | |
'hbs' | |
], | |
include: [ | |
// map is loaded dynamically to avoid loading gmaps before needed | |
'widgets/map/Map', | |
'widgets/map/HotelMarker', | |
'widgets/map/LocationMarker', | |
'widgets/hotelpicker/Marker', | |
'booking/entry/LocationMarker', | |
// TODO: sub-sections should probably be loaded dynamically | |
'booking/entry/entry', | |
'booking/confirm/confirm', | |
'property/entry/entry', | |
'property/city/city', | |
'property/explore/explore' | |
], | |
// exclude: [ ], | |
onBuildWrite : function(moduleName, path, content){ | |
// replace handlebars with the runtime version (which is many times | |
// smaller) | |
if (moduleName === 'Handlebars') { | |
content = _fs.readFileSync('scripts/lib/handlebars.runtime.js').toString(); | |
content = content.replace(/(define\()(function)/, '$1"Handlebars", $2'); | |
} | |
return content; | |
} | |
}, cb); | |
} | |
// --- | |
function compileSass(){ | |
if (! _shell.which('compass') ) { | |
console.error('this build script requires "compass" to be installed globally. http://compass-style.org/install/'); | |
process.exit(1); | |
} | |
_shell.exec('compass compile .'); | |
} | |
// --- | |
function deploy(){ | |
var assetsDir = _path.join(DIST_FOLDER, 'assets'); | |
var tempDir = _path.join(DIST_FOLDER, 'temp'); | |
_shell.mkdir('-p', assetsDir); | |
_shell.mkdir('-p', tempDir); | |
compileSass(); | |
optimizeJS(function(){ | |
// purge old files | |
_shell.rm('-Rf', _path.join(assetsDir, 'styles')); | |
_shell.rm('-Rf', _path.join(assetsDir, 'js')); | |
_shell.rm('-Rf', _path.join(assetsDir, 'img')); | |
_shell.rm('-Rf', _path.join(assetsDir, 'webfonts')); | |
_shell.rm('-Rf', _path.join(tempDir, 'content')); | |
// --- | |
_shell.cp('-R', 'img', assetsDir); | |
_shell.cp('-R', 'webfonts', assetsDir); | |
_shell.cp('-R', 'content', tempDir); | |
var jsDir = _path.join(assetsDir, 'js'); | |
_shell.mkdir('-p', jsDir); | |
// TODO: minify requirejs | |
_shell.cp('scripts/lib/require/require.js', _path.join(jsDir, 'require.js')); | |
_shell.cp('scripts/main.min.js', _path.join(jsDir, 'main.js')); | |
// need to keep same depth to avoid issues with webfonts/image paths | |
var cssDir = _path.join(assetsDir, 'styles/css'); | |
_shell.mkdir('-p', cssDir); | |
_shell.cp('styles/css/*', cssDir); | |
}); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I wrote this build script yesterday for a project in less than 20 minutes. I don't think it would be any simpler to write it with a tool like grunt, and if the build needs to be more complex in the future I can easily augment/refactor it.
Grunt is not all bad since you can still write plain JavaScript inside the tasks, but if you are writing plain JS why tie yourself to a single task runner?
It's a shame to see so many useful tools tied to a single task runner for no real benefit... Grunt and any other similar tool should not need to exist since we already have dozens of argument parsers.
PS: the build script above could be refactored to avoid duplications but I won't do it until it is needed, 160 LOC is pretty easy to manage - verbosity is not always a bad thing.