Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

init task. closes #19

  • Loading branch information...
commit f2f99f8fd330bc899366d0e876b8ffdab51671c7 1 parent abe4656
Mickael Daniel authored
1  .gitignore
View
@@ -4,3 +4,4 @@ test/fixtures/h5bp
npm-debug.log
test/custom
docs/_site
+tasks/init/h5bp/root
25 bin/h5bp
View
@@ -1,21 +1,28 @@
#!/usr/bin/env node
var fs = require('fs'),
join = require('path').join,
- help = join(__dirname, 'help.txt');
+ help = join(__dirname, 'help.txt'),
+ cli = require('grunt/lib/grunt/cli');
-var cmds = process.argv.slice(2),
- opts = {};
+// register this plugin to grunt npm tasks
+var grunt = require('grunt').npmTasks(join(__dirname, '../')),
+ opts = cli.options,
+ cmds = cli.tasks,
+ route = cmds.join(' ').trim('');
// custom help, on `h5bp help`
-if(cmds[0] === 'help') {
- if(cmds.length === 1) return fs.createReadStream(help).pipe(process.stdout);
- process.argv = process.argv.slice(0, 2).concat([cmds.join(':')]);
+if(/^help/.test(route)) {
+ if(/^help$/.test(route)) return fs.createReadStream(help).pipe(process.stdout);
+ cli.tasks = cmds.join(':');
}
-if(cmds[0] === '--version') {
+if(opts.version) {
console.log('h5bp v%s', require('../package.json').version);
- opts.version = true;
+}
+
+if(/^init$/.test(route)) {
+ cli.tasks = 'init:h5bp';
}
// the grunt cli
-require('grunt').npmTasks(join(__dirname, '../')).cli(opts);
+cli(opts);
53 lib/utils/fetch.js
View
@@ -0,0 +1,53 @@
+var fs = require('fs'),
+ path = require('path'),
+ zlib = require('zlib'),
+ request = require('request'),
+ tar = require('tar');
+
+// Check if we're behind some kind of proxy.
+var proxy = process.env.http_proxy || process.env.HTTP_PROXY ||
+ process.env.https_proxy || process.env.HTTPS_PROXY || '';
+
+// heavily based on npm's util/untar.js file
+module.exports = function fetch(tarball, target, cb) {
+ var r = request.defaults({ proxy: proxy }),
+ now = +new Date;
+
+ var log = this.log
+ .subhead('Fetching ' + tarball)
+ .writeln('This might take a few moment');
+
+ // tarball untar opts
+ var extractOpts = { type: 'Directory', path: target, strip: 1 };
+
+ // remote request --> zlib.Unzip() --> untar into h5bp/root
+ var req = r.get(tarball).on('error', cb);
+
+ req.on('data', function() { log.write('.'); }).on('end', function() {
+ log.ok().writeln();
+ log.ok('Done in ' + (+new Date - now) / 1000 + 's.');
+ });
+
+ req
+ // first gzip
+ .pipe(zlib.Unzip())
+ .on('error', function(err) {
+ console.error('unzip error', err);
+ cb(err);
+ })
+ // then tar extract into h5bp/root
+ .pipe(tar.Extract(extractOpts))
+ .on('entry', function(entry) {
+ log.write('.');
+ entry.props.uid = entry.uid = 501;
+ entry.props.gid = entry.gid = 20;
+ })
+ .on('error', function(err) {
+ console.error('untar error', err);
+ cb(err);
+ })
+ .on('close', function() {
+ log.writeln().ok('Done in ' + extractOpts.path).writeln();
+ cb();
+ });
+};
8 lib/utils/index.js
View
@@ -31,6 +31,14 @@ utils.__defineGetter__('ncp', function () {
return require('ncp').ncp;
});
+//
+// Wrapper to `require('./fetch')`, internal tarball helper using
+// mikeal/request, zlib and isaacs/tar.
+//
+utils.__defineGetter__('fetch', function () {
+ return require('./fetch');
+});
+
// **extend** a given object with the util module definition, taking care
// of not triggering the getters. Doing so with _.extend makes the module
// to be required right away.
4 package.json
View
@@ -20,7 +20,9 @@
"serve": "~1.0.3",
"grunt": "~0.3.8",
"socket.io": "~0.9.5",
- "grunt-help": "~0.1.1"
+ "grunt-help": "~0.1.1",
+ "request": "~2.9.200",
+ "tar": "~0.1.13"
},
"scripts": {
"install": "node scripts/install.js",
335 tasks/init/h5bp.js
View
@@ -0,0 +1,335 @@
+
+var fs = require('fs'),
+ path = require('path'),
+ utils = require('../../').utils;
+
+var h5bp = module.exports;
+
+// Basic template description.
+h5bp.description = 'Init a new html5-boilerplate project.';
+
+// Template-specific notes to be displayed before question prompts.
+h5bp.notes = fs.readFileSync(path.join(__dirname, 'h5bp/notes.txt'), 'utf8');
+
+
+// Any existing file or directory matching this wildcard will cause a warning.
+h5bp.warnOn = '*';
+
+// the "prompts steps"
+h5bp.steps = 'project setup files gruntfile'.split(' ');
+
+// The actual init template.
+h5bp.template = function(grunt, init, done) {
+ h5bp.grunt = grunt;
+
+ // setup custom prompt
+ h5bp.customPrompt();
+
+ (function run(step) {
+ if(!step) return h5bp.end(init, h5bp.props, done);
+
+ h5bp[step](function(err, props) {
+ if(err) {
+ grunt.log.error(err);
+ return done(false);
+ }
+
+ if(step === 'project') h5bp.props = props;
+ else h5bp.props[step] = props;
+ run(h5bp.steps.shift());
+ });
+ })(h5bp.steps.shift())
+
+};
+
+
+//
+// Prompts steps
+//
+// _ project info
+// - default setup
+// - rewrite of specific files
+//
+
+// **project** prompts and collects info on the project to create (name,
+// description, etc.)
+h5bp.project = function project(cb) {
+ var grunt = this.grunt;
+ var exists = path.existsSync(path.join(__dirname, 'h5bp/root/index.html'));
+
+ var prompts = 'name description version repository homepage ';
+ prompts += 'licenses author_name author_email author_url ';
+ prompts += exists ? 'force_update' : '';
+
+ h5bp.prompt(prompts.trim().split(' '), function(err, props) {
+ if(/n/i.test(props.force_update) && exists) return cb(null, props);
+ var url = 'https://github.com/h5bp/html5-boilerplate/tarball/master';
+ utils.fetch.call(grunt, url, path.join(__dirname, 'h5bp/root'), function(err) {
+ if(err) return cb(err);
+ cb(null, props);
+ });
+ });
+};
+
+// **setup** prompts and collects info on the project layout to use,
+// default is standard html5-boilerplate project.
+h5bp.setup = function setup(cb) {
+ h5bp.prompt(['layout'], cb);
+};
+
+// **files** prompts and collects info on very specific file rewrites,
+// in case the layout entered is the `custom` one.
+h5bp.files = function files(cb) {
+ var grunt = this.grunt,
+ setup = this.props.setup,
+ layout = setup.layout;
+
+ if(/d/i.test(layout)) return cb();
+
+ var prompts = /c/i.test(layout) ? ['css/', 'js/', 'img/'] :
+ /s/i.test(layout) ? this.filePrompts() :
+ [];
+
+ h5bp.prompt(prompts, cb);
+};
+
+// **gruntfile** Inits a new gruntfile, based on built-in init gruntfile
+// template, plus specific-to-this-plugin properties. The gruntfile
+// generated should be mapping the path that depens on previous prompts
+// steps.
+h5bp.gruntfile = function(cb) {
+ var grunt = this.grunt;
+ grunt.helper('prompt', {}, [
+ // Prompt for these values.
+ {
+ name: 'dom',
+ message: 'Is the DOM involved in ANY way?',
+ default: 'Y/n',
+ warning: 'Yes: QUnit unit tests + JSHint "browser" globals. No: Nodeunit unit tests.'
+ },
+ {
+ name: 'min_concat',
+ message: 'Will files be concatenated or minified?',
+ default: 'Y/n',
+ warning: 'Yes: min + concat tasks. No: nothing to see here.'
+ },
+ {
+ name: 'package_json',
+ message: 'Will you have a package.json file?',
+ default: 'Y/n',
+ warning: 'This changes how filenames are determined and banners are generated.'
+ },
+
+ {
+ name: 'staging',
+ message: 'What is the intermediate/ directory for the build script?',
+ default: 'intermediate/',
+ warning: 'This changes where the files are copied with the mkdirs task.'
+ },
+ {
+ name: 'output',
+ message: 'What it is the final build output directory?',
+ default: 'publish/',
+ warning: 'The final optimized version of your website will be there.'
+ },
+ {
+ name: 'css_dir',
+ message: 'What is the CSS directory?',
+ default: 'css/',
+ warning: 'This is used in the css task, every css files under that directory ' +
+ 'is concatanated into one file and pass through requirejs optimizer.'
+ },
+ {
+ name: 'js_dir',
+ message: 'What is the JS directory?',
+ default: 'js/',
+ warning: 'This is used in the concat, min and rev task, every js files under that directory ' +
+ 'is concatanated into one file and compressed via uglifyjs.'
+ },
+ {
+ name: 'img_dir',
+ message: 'What is the IMG directory?',
+ default: 'img/',
+ warning: 'This is used in the rev task.'
+ }
+ ], function(err, props) {
+ props.dom = /y/i.test(props.dom);
+ props.min_concat = /y/i.test(props.min_concat);
+ props.package_json = /y/i.test(props.package_json);
+ props.test_task = props.dom ? 'qunit' : 'test';
+ props.file_name = '<%= pkg.name %>';
+
+ // Guess at some directories, if they exist.
+ props.test_dir = 'test';
+
+ // jQuery is default in h5bp setup!
+ props.jquery = true;
+
+ // normalize some of the dirs path
+ props.js_dir = props.js_dir.replace(/\/$/, '');
+ props.css_dir = props.css_dir.replace(/\/$/, '');
+ props.img_dir = props.img_dir.replace(/\/$/, '');
+ props.output = props.output.replace(/\/$/, '');
+ props.staging = props.staging.replace(/\/$/, '');
+
+ cb(null, props);
+ });
+};
+
+// **end** completes the creation process.
+h5bp.end = function end(init, props, cb) {
+ var grunt = this.grunt;
+
+ // custom renames
+ init.renames = h5bp.renames(init, props);
+
+ // Files to copy (and process).
+ var files = init.filesToCopy(props);
+
+ // Add properly-named license files.
+ init.addLicenseFiles(files, props.licenses);
+
+ // Actually copy (and process) files.
+ init.copyAndProcess(files, props);
+
+ // Generate package.json file.
+ props.dependencies = {
+ 'node-build-script': 'http://nodeload.github.com/h5bp/node-build-script/tarball/dev'
+ };
+
+ init.writePackageJSON('package.json', props);
+
+ // special copy and process for the gruntfile
+ init.copy(path.join(__dirname, 'h5bp/gruntfile.js'), 'grunt.js', {
+ process: function(contents) {
+ var data = grunt.utils._.extend({}, props, props.gruntfile);
+ return grunt.template.process(contents, data, 'init');
+ }
+ });
+
+
+ // All done!
+ cb();
+};
+
+
+// **customPrompt** is an helper for convenience reading of prompt.txt
+// file, configuring defaults grunt prompts for further usage
+h5bp.customPrompt = function() {
+ var grunt = this.grunt,
+ opts = grunt.helper('prompt_for_obj'),
+ custom = grunt.file.read(path.join(__dirname, 'h5bp/prompts.txt')).trim(),
+ matcher = /^\[\?\]\s?([^\(]+)\(([^\)]+)\)\s*\|\s([\w\d\-_\/]+)/,
+ lf = grunt.utils.linefeed;
+
+ var lines = custom.split(grunt.utils.linefeed);
+ this.prompts = lines.map(function(line, i) {
+ // trim blank line and non [?] prompt like line
+ if(!line || !/^\[\?\]/.test(line)) return;
+
+ // return a meaningful object
+ var m = (line.match(matcher) || []),
+ opt = /\[[A-Z]\]/,
+ msg = '',
+ ok = false;
+
+ var prompt = {
+ message: m[1].trim(),
+ default: m[2].trim(),
+ name: m[3].trim(),
+ };
+
+ if(/^»/.test(lines[i + 1])) {
+ // print additional info
+ prompt.help = lines.slice(i + 1).filter(function(l) {
+ ok = ok || /^\[/.test(l);
+ return !ok;
+ }).map(function(l) {
+ return l.replace(/^»(\s)(\w)/, '$1$2');
+ });
+ }
+
+ // if the default has [S]ome, [K]ind of defauls like this, build a
+ // sanitize handler
+ if(opt.test(line)) prompt.validator = function(value, next) {
+ var flags = m[2].match(/\[[A-Z]\]/g).map(function(m) {
+ return m.replace(/\[|\]/g, '');
+ }).join('');
+
+ next(new RegExp('^[' + flags + ']$', 'i').test(value));
+ };
+
+ return prompt;
+ });
+
+ this.prompts = this.prompts.filter(function(p) {
+ return p;
+ });
+
+ // actually register these custom prompts to grunt
+ this.prompts.forEach(function(prompt) {
+ opts[prompt.name] = prompt;
+ });
+};
+
+
+// **prompt** convenience wrapper to grunt.helper('prompt')
+h5bp.prompt = function(prompts, cb) {
+ var grunt = this.grunt;
+ if(!prompts || !prompts.length) return cb();
+ prompts = prompts.map(function(p) {
+ return grunt.helper('prompt_for', p);
+ });
+
+ grunt.helper('prompt', prompts, cb);
+};
+
+// **filePrompts** builds an array of prompts object, for each files in
+// the root repository.
+h5bp.filePrompts = function() {
+ var root = root = path.join(__dirname, 'h5bp/root'),
+ files = this.grunt.file.expandFiles(path.join(root, '**')),
+ opts = this.grunt.helper('prompt_for_obj');
+
+ files = files.map(function(f) {
+ var name = f.replace(root, '').replace(/^(\/)|(\\)/g, '');
+ opts[name] = {
+ name: name,
+ message: name,
+ default: name
+ };
+
+ return name;
+ });
+
+ return files;
+};
+
+// **renames** wrapper to grunt's rename feature, dealing with specific
+// directory mappings.
+h5bp.renames = function(init, props) {
+ var files = props.files || {},
+ grunt = this.grunt,
+ root = path.join(__dirname, 'h5bp/root/');
+
+ Object.keys(files).forEach(function(file) {
+ var dest = files[file],
+ ignores = ['none', 'nill', 'nil', 'false', 'null'],
+ falsy = !!~ignores.indexOf(dest);
+
+ // handle our ignores values
+ if(falsy) files[file] = false;
+
+ // handle directory like name
+ if(file.slice(-1) === '/') {
+ grunt.file.expandFiles({ dot: true }, path.join(root, file, '**')).forEach(function(filepath) {
+ filepath = filepath.replace(root, '').replace(/^(\/)|(\\)/g);
+ var dest = files[file];
+ dest = dest.slice(-1) === '/' ? dest : dest + '/';
+ files[filepath] = filepath.replace(file, dest);
+ });
+ }
+ });
+
+ return this.grunt.utils._.extend({}, init.renames, files);
+};
91 tasks/init/h5bp/gruntfile.js
View
@@ -0,0 +1,91 @@
+var h5bp = require('node-build-script');
+
+module.exports = function(grunt) {
+
+ // extend the grunt.utils object with h5bp's utilities, wrapping require
+ // calls to utility libs (rimraf, ncp, mkdirp) as lazy-loaded getters.
+ h5bp.utils.extend(grunt.utils);
+
+ // Project configuration.
+ grunt.initConfig({{% if (min_concat) { if (package_json) { %}
+ pkg: '<json:package.json>',
+ meta: {
+ banner: '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' +
+ '<%= grunt.template.today("yyyy-mm-dd") %>\n' +
+ '<%= pkg.homepage ? "* " + pkg.homepage + "\n" : "" %>' +
+ '* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' +
+ ' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */'
+ },{% } else { %}
+ meta: {
+ version: '0.1.0',
+ banner: '/*! PROJECT_NAME - v<%= meta.version %> - ' +
+ '<%= grunt.template.today("yyyy-mm-dd") %>\n' +
+ '* http://PROJECT_WEBSITE/\n' +
+ '* Copyright (c) <%= grunt.template.today("yyyy") %> ' +
+ 'YOUR_NAME; Licensed MIT */'
+ },{% } } %}
+ lint: {
+ files: ['grunt.js', '{%= js_dir %}/**/*.js', '{%= test_dir %}/**/*.js']
+ },{% if (dom) { %}
+ qunit: {
+ files: ['{%= test_dir %}/**/*.html']
+ },{% } else { %}
+ test: {
+ files: ['{%= test_dir %}/**/*.js']
+ },{% } %}{% if (min_concat) { %}
+ concat: {
+ '{%= staging %}/dist/{%= name %}-{%= version %}.js': ['js/**/*.js']
+ },
+ min: {
+ '{%= output %}/dist/{%= name %}-{%= version %}.js': ['{%= staging %}/dist/{%= name %}-{% version %}.min.js']
+ },{% } %}
+ watch: {
+ files: '<config:lint.files>',
+ tasks: 'lint {%= test_task %}'
+ },
+
+ // h5bp plugin task confit
+ staging: '{%= staging %}',
+ output: '{%= output %}',
+ exclude: '.git* build/** node_modules/** grunt.js package.json *.md'.split(' '),
+ mkdirs: {
+ staging: '<config:exclude>',
+ output: '<config:exclude>'
+ },
+ css: {
+ '{%= output %}/css/style.css': ['{%= css_dir %}/**/*.css']
+ },
+ usemin: {
+ files: ['{%= output %}/**/*.html']
+ },
+ rev: {
+ js: '{%= js_dir %}/**/*.js',
+ css: '{%= css_dir %}/**/*.css',
+ img: '{%= img_dir %}/**'
+ },
+
+ jshint: {
+ options: {
+ curly: true,
+ eqeqeq: true,
+ immed: true,
+ latedef: true,
+ newcap: true,
+ noarg: true,
+ sub: true,
+ undef: true,
+ boss: true,
+ eqnull: true{% if (dom) { %},
+ browser: true{% } %}
+ },
+ globals: {{% if (jquery) { %}
+ jQuery: true
+ {% } %}}
+ }{% if (min_concat) { %},
+ uglify: {}{% } %}
+ });
+
+ // Default task.
+ grunt.registerTask('default', 'clean mkdirs concat css min rev usemin');
+
+};
22 tasks/init/h5bp/notes.txt
View
@@ -0,0 +1,22 @@
+The root folder will be created the first time the init task is run with
+`h5bp` template (eg. `grunt init:h5bp`) by downloading latest version of
+html5-boilerplate.
+
+The resulting output depends on the few question grunt asks during the
+process. This includes some path rewrites (like renaming the
+`css/style.css` file to something else).
+
+Simply keep pressing enter for the default h5bp layout.
+
+There's three "step" of prompts:
+
+- project: Basic project configuration (name, description, version, ...)
+- layout: [D]efault, [C]ustom, [S]illy
+- files: Depends on layout value, series of prompts for specific
+ file / directory renames
+- gruntfile: Gruntfile creation
+
+This template tries to guess file and directory paths, but you will most likely
+need to edit the generated grunt.js file before running grunt. If you run grunt
+after generating grunt.js, and grunt exits with errors, edit the grunt.js file!
+
22 tasks/init/h5bp/prompts.txt
View
@@ -0,0 +1,22 @@
+
+[?] Do you need to force an update on master repo? (y/N) | force_update
+[?] Which layout ? ([D]efault, [C]ustom, [S]illy) | layout
+» [D]efault: Standard html5-boilerplate layout
+
+» [C]ustom: Specific build of html5-boilerplate. A series of prompt allows
+ explicit file rewrites for common files and directories.
+
+» [S]illy: A "silly" build will prompt for every file in the h5bp repository.
+
+[?] CSS directory (css/) | css/
+» You can change here the basic layout of the project you're about to
+create. The defaults values will create a standars h5bp project, but you
+might want to go for something different like:
+
+ js/ → javascritps/
+ css/ → stylesheets/
+ img/ → images/
+
+[?] Image directory (img/) | img/
+[?] JavaScript directory (js/) | js/
+
109 tasks/init/h5bp/readme.md
View
@@ -0,0 +1,109 @@
+**grunt init template for html5-boilerplate**
+
+---
+
+The root folder will be created the first time the init task is run with
+`h5bp` template (eg. `grunt init:h5bp`).
+
+The resulting output depends on the few question grunt asks during the
+process. This includes some path rewrites (like renaming the
+`css/style.css` file to something else).
+
+Simply keep pressing enter for the default h5bp layout.
+
+## Options
+
+## Steps
+
+### Project
+
+```sh
+Please answer the following:
+[?] Project name (foo)
+[?] Description (The best project ever.)
+[?] Version (0.1.0)
+[?] Project git repository (git://github.com/USER/REPO.git)
+[?] Project homepage (https://github.com/USER/REPO)
+[?] Licenses (MIT)
+[?] Author name (USER_NAME)
+[?] Author email (USER_EMAIL)
+[?] Author url (none)
+```
+
+### Layout
+
+```sh
+Please answer the following:
+help: » [D]efault: Standard html5-boilerplate layout
+help:
+help: » [C]ustom: Specific build of html5-boilerplate. A series of prompt allows
+help: explicit file rewrites for common files and directories.
+help:
+help: » [S]illy: A "silly" build will prompt for every file in the h5bp repository.
+help:
+[?] Which layout ? ([D]efault, [C]ustom, [S]illy) c
+[?] Do you need to make any changes to the above before continuing?
+```
+
+### Files
+
+Only if `layout=custom`
+
+```sh
+Please answer the following:
+Please answer the following:
+help: You can change here the basic layout of the project you're about to
+help: create. The defaults values will create a standars h5bp project, but you
+help: might want to go for something different like:
+help:
+help: js/ → javascritps/
+help: css/ → stylesheets/
+help: img/ → images/
+help:
+[?] CSS directory (css/)
+[?] JavaScript directory (js/)
+[?] Image directory (img/)
+[?] Do you need to make any changes to the above before continuing? (y/N)
+```
+
+Only if `layout=silly`
+```sh
+Please answer the following:
+Please answer the following:
+[?] 404.html (404.html)
+[?] apple-touch-icon-114x114-precomposed.png (apple-touch-icon-114x114-precomposed.png)
+[?] apple-touch-icon-144x144-precomposed.png (apple-touch-icon-144x144-precomposed.png)
+[?] apple-touch-icon-57x57-precomposed.png (apple-touch-icon-57x57-precomposed.png)
+[?] apple-touch-icon-72x72-precomposed.png (apple-touch-icon-72x72-precomposed.png)
+[?] apple-touch-icon-precomposed.png (apple-touch-icon-precomposed.png)
+[?] apple-touch-icon.png (apple-touch-icon.png)
+[?] crossdomain.xml (crossdomain.xml)
+[?] css/style.css (css/style.css)
+[?] favicon.ico (favicon.ico)
+[?] grunt.js (grunt.js)
+[?] humans.txt (humans.txt)
+[?] index.html (index.html)
+[?] js/libs/jquery-1.7.2.js (js/libs/jquery-1.7.2.js)
+[?] js/libs/jquery-1.7.2.min.js (js/libs/jquery-1.7.2.min.js)
+[?] js/libs/modernizr-2.5.3.min.js (js/libs/modernizr-2.5.3.min.js)
+[?] js/plugins.js (js/plugins.js)
+[?] js/script.js (js/script.js)
+[?] readme.md (readme.md)
+[?] robots.txt (robots.txt)
+[?] Do you need to make any changes to the above before continuing? (y/N)
+```
+
+### gruntfile
+
+```sh
+Please answer the following:
+[?] Is the DOM involved in ANY way? (Y/n)
+[?] Will files be concatenated or minified? (Y/n)
+[?] Will you have a package.json file? (Y/n)
+[?] What is the intermediate/ directory for the build script? (intermediate/)
+[?] What it is the final build output directory? (publish/)
+[?] What is the CSS directory? (css/)
+[?] What is the JS directory? (js/)
+[?] What is the IMG directory? (img/)
+[?] Do you need to make any changes to the above before continuing? (y/N)
+```
5 tasks/support/css.js
View
@@ -37,10 +37,11 @@ module.exports = function(grunt) {
//
task.registerHelper('mincss', function(files, o) {
o = o || {};
- return files ? files.map(function(filepath) {
+ files = grunt.file.expandFiles(files);
+ return files.map(function(filepath) {
var content = file.read(filepath);
return o.nocompress ? content : cleanCSS.process(content);
- }).join("") : "";
+ }).join('');
});
// **rjs:optimize:css** is an helper using rjs to optimize a single file,
2  tasks/support/misc.js
View
@@ -24,7 +24,7 @@ module.exports = function(grunt) {
cb = this.async();
// support for #3. Append the staging / output directories to the list of .ignore files
- ignores = ignores.concat([join(config('staging') + '/**'), join(config('output') + '/**')]);
+ ignores = ignores.concat([path.join(config('staging') + '/**'), path.join(config('output') + '/**')]);
log
.writeln('Copying into ' + dirname)
Please sign in to comment.
Something went wrong with that request. Please try again.