Skip to content
This repository has been archived by the owner on Oct 8, 2021. It is now read-only.

Commit

Permalink
quick port of grunt for qunit and phantom build
Browse files Browse the repository at this point in the history
  • Loading branch information
johnbender committed May 23, 2012
1 parent 6e8cf9c commit ec4c3a8
Show file tree
Hide file tree
Showing 11 changed files with 685 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .gitignore
Expand Up @@ -13,3 +13,9 @@ tmp/

# branch preview
branches

# node build dependencies
node_modules

# phantom junit output
build/test-results/
124 changes: 124 additions & 0 deletions build/config.js
@@ -0,0 +1,124 @@
var fs = require( 'fs' ),
path = require( 'path' ),
child_process = require( 'child_process' ),
glob = require( 'glob-whatev' );

module.exports = function( grunt ) {
var global = {
dirs : {
output: 'compiled',
temp: 'tmp'
},

files: {
license: 'LICENSE-INFO.txt'
},

names: {
base: 'jquery.mobile',
// this will change for the deploy target to include version information
root: 'jquery.mobile',
structure: 'jquery.mobile.structure',
theme: 'jquery.mobile.theme'
},

// other version information is added via the asyncConfig helper that
// depends on git commands (eg ver.min, ver.header)
ver: {
official: grunt.file.read( 'version.txt' ).replace(/\n/, ''),
min: "/*! jQuery Mobile v<%= build_sha %> jquerymobile.com | jquery.org/license !*/"
},

shas: {},

helpers: {
appendFrom: function( output, input, filter ) {
var inputString = fs.readFileSync(input).toString();

this.append( output, inputString, filter );
},

append: function( output, input, filter ) {
var id = fs.openSync(output, 'a+');

input = filter ? filter(input) : input;

fs.writeSync( id, input );
fs.closeSync( id );
},

minify: function( opts ) {
var max = grunt.file.read( opts.input ),
min = opts.minCallback(max);

// add the min header into the minified file, and then the min css
grunt.file.write( opts.output, opts.header );
this.append( opts.output, min );

grunt.helper( "min_max_info", min, max );
},

// NOTE cargo culting my way to the top :(
rmdirRecursive: function(dir) {
if( !path.existsSync(dir) ) {
return;
}

var list = fs.readdirSync(dir);
for(var i = 0; i < list.length; i++) {
var filename = path.join(dir, list[i]);
var stat = fs.statSync(filename);

if(filename == "." || filename == "..") {
// pass these files
} else if(stat.isDirectory()) {
// rmdir recursively
this.rmdirRecursive(filename);
} else {
// rm fiilename
fs.unlinkSync(filename);
}
}
fs.rmdirSync(dir);
},

asyncConfig: function( callback ) {
child_process.exec( 'git log -1 --format=format:"Git Build: SHA1: %H <> Date: %cd"', function( err, stdout, stderr ){
global.shas.build_sha = stdout;
global.ver.min = grunt.template.process( global.ver.min, global.shas );

child_process.exec( 'git log -1 --format=format:"%H"', function( err, stdout, stderr ) {
global.shas.head_sha = stdout;

// NOTE not using a template here because the Makefile depends on the v@VERSION
global.ver.header = grunt.file.read( global.files.license )
.replace(/v@VERSION/, global.shas.build_sha );
callback( global );
});
});
}
}
};

grunt.registerTask( 'test_config', 'glob all the test files', function() {
var done = this.async(), test_paths, server_paths = [];

test_paths = glob.glob( 'tests/unit/*/' );
test_paths = test_paths.concat( glob.glob('tests/unit/**/*-tests.html') );
test_paths.forEach( function( file_path ) {
var final_path = process.env.ROOT_DOMAIN + file_path;

// if no test path is defined or if the path matches that specified in the env
// add it to the config
if( !process.env.TEST_PATH || file_path.indexOf(process.env.TEST_PATH) >= 0 ) {
server_paths.push( final_path );
}
});

grunt.config.set( 'qunit', { all: server_paths });

done();
});

grunt.config.set( 'global', global );
};
10 changes: 10 additions & 0 deletions build/tasks/clean.js
@@ -0,0 +1,10 @@
var fs = require( 'fs' );

module.exports = function( grunt ) {
var config = grunt.config.get( 'global' );

grunt.registerTask( 'clean', 'ensure the output directory is present', function() {
config.helpers.rmdirRecursive( config.dirs.output );
config.helpers.rmdirRecursive( config.dirs.temp );
});
};
116 changes: 116 additions & 0 deletions build/tasks/css.js
@@ -0,0 +1,116 @@
var requirejs = require( 'requirejs' ),
path = require( 'path' ),
fs = require( 'fs' ),
sqwish = require ( 'sqwish' ),
util = require( 'util' );

module.exports = function( grunt ) {
var config = grunt.config.get( 'global' ),
regularFile = path.join( config.dirs.output, config.names.root ),
structureFile = path.join( config.dirs.output, config.names.structure ),
themeFile = path.join( config.dirs.output, config.names.theme ),
helpers = config.helpers;

grunt.config.set( 'css', {
theme: process.env.THEME || 'default',

require: {
all: {
cssIn: 'css/themes/default/jquery.mobile.css',
optimizeCss: 'standard.keepComments.keepLines',
baseUrl: '.',
out: regularFile + '.compiled.css'
},

structure: {
cssIn: 'css/structure/jquery.mobile.structure.css',
out: structureFile + '.compiled.css'
}
}
});

grunt.registerTask( 'css_without_deps', 'compile and minify the css', function() {
var done = this.async(),
theme = grunt.config.get( 'css' ).theme,
require = grunt.config.get( 'css' ).require;

helpers.asyncConfig(function( config ) {
// pull the includes together using require js
requirejs.optimize( require.all );

// dump the versioned header into the normal css file
grunt.file.write( regularFile + '.css', config.ver.header );

// add the compiled css to the normal css file
helpers.appendFrom( regularFile + '.css', require.all.out );

helpers.minify({
output: regularFile + '.min.css',
input: regularFile + '.css',
header: config.ver.min,
minCallback: function( unminified ) {
return sqwish.minify( unminified, false );
}
});

// pull the includes together using require js
requirejs.optimize( require.structure );

// dump the versioned header into the structure css file
grunt.file.write( structureFile + '.css', config.ver.header );

// add the compiled css to the normal css file
helpers.appendFrom( structureFile + '.css', require.all.out );

// add the min header into the minified file
grunt.file.write( structureFile + '.min.css', config.ver.min );

// minify the structure css
helpers.minify({
output: structureFile + '.min.css',
input: structureFile + '.css',
header: config.ver.min,
minCallback: function( unminified ) {
return sqwish.minify( unminified, false );
}
});

// dump the versioned header into the theme css file
grunt.file.write( themeFile + '.css', config.ver.header );

// dump the theme css into the theme css file
helpers.appendFrom( themeFile + '.css', 'css/themes/default/jquery.mobile.theme.css' );

// minify the theme css
helpers.minify({
output: themeFile + '.min.css',
input: themeFile + '.css',
header: config.ver.min,
minCallback: function( unminified ) {
return sqwish.minify( unminified, false );
}
});

// remove the requirejs compile output
fs.unlink( require.all.out );
fs.unlink( require.structure.out );

// copy images directory
var imagesPath = path.join( config.dirs.output, 'images' ), fileCount = 0;

grunt.file.mkdir( imagesPath );
grunt.file.recurse( path.join('css', 'themes', theme, 'images'), function( full, root, sub, filename ) {

fileCount++;
var is = fs.createReadStream( full );
var os = fs.createWriteStream( path.join(imagesPath, filename) );
util.pump(is, os, function() {
fileCount--;
if( fileCount == 0 ) { done(); }
});
});
});
});

grunt.registerTask( 'css', 'custom_init css_without_deps' );
};
11 changes: 11 additions & 0 deletions build/tasks/custom_init.js
@@ -0,0 +1,11 @@
var fs = require( 'fs' ), path = require( 'path' );

module.exports = function( grunt ) {
var config = grunt.config.get( 'global' );
// TODO having issues overriding default init task
grunt.registerTask( 'custom_init', 'ensure the output directory is present', function() {
if( !path.existsSync(config.dirs.output) ) {
fs.mkdirSync( config.dirs.output );
}
});
};
63 changes: 63 additions & 0 deletions build/tasks/js.js
@@ -0,0 +1,63 @@
var requirejs = require( 'requirejs' ),
path = require( 'path' ),
fs = require( 'fs' );

module.exports = function( grunt ) {
var config = grunt.config.get( 'global' ),
outputFile = path.join( config.dirs.output, config.names.root ),
helpers = config.helpers;

grunt.config.set( 'js', {
require: {
baseUrl: 'js',
name: 'jquery.mobile',
exclude:[
'jquery',
'../external/requirejs/order',
'../external/requirejs/depend',
'../external/requirejs/text',
'../external/requirejs/text!../version.txt'
],
out: outputFile + '.compiled.js',
pragmasOnSave: { jqmBuildExclude: true },
wrap: { startFile: 'build/wrap.start', endFile: 'build/wrap.end' },
findNestedDependencies: true,
skipModuleInsertion: true,
optimize: 'none'
}
});

grunt.registerTask( 'js_without_deps', 'compile and minify the js', function() {
var done = this.async(), require = grunt.config.get( 'js' ).require;

helpers.asyncConfig(function( config ) {
// pull the includes together using require js
requirejs.optimize( require );

// dump the versioned header into the normal js file
grunt.file.write( outputFile + '.js', config.ver.header );

// add the compiled js to the normal js file, replace the version tag
// with the contents from version.txt
helpers.appendFrom( outputFile + '.js', require.out, function( fileContents ) {
return fileContents.replace( /__version__/, '"' + config.ver.official + '"' );
});

helpers.minify({
output: outputFile + '.min.js',
input: outputFile + '.js',
header: config.ver.min,
minCallback: function( unminified ) {
return grunt.helper( 'uglify', unminified, {});
}
});

// remove the requirejs compile output
fs.unlink( require.out );
done();
});
});

// NOTE custom dasks don't accept dependencies so we alias
grunt.registerTask( 'js', 'custom_init js_without_deps' );
};

0 comments on commit ec4c3a8

Please sign in to comment.