Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 453 lines (354 sloc) 19.181 kb
0493335e »
2011-09-21 Work in progress.
1 # grunt
ab62e0f3 »
2011-10-14 Documenting some stuff. I have lots more to write.
2 Grunt is a command line build tool for JavaScript projects.
469bda80 »
2012-01-10 Updating Readme. Lots more to write, but it's a start.
3
4 As of now, grunt has the following predefined tasks:
ab62e0f3 »
2011-10-14 Documenting some stuff. I have lots more to write.
5
6 * **concat** - Concatenate files.
bdc9798d »
2012-02-03 Updating readme with version changes.
7 * **init** - Generate project scaffolding from a predefined template.
469bda80 »
2012-01-10 Updating Readme. Lots more to write, but it's a start.
8 * **lint** - Validate files with [JSHint][jshint].
9 * **min** - Minify files with [UglifyJS][uglify].
10 * **test** - Run unit tests with [nodeunit][nodeunit].
bdc9798d »
2012-02-03 Updating readme with version changes.
11 * **qunit** - Run [QUnit][qunit] unit tests in a headless [PhantomJS][phantom] instance.
12 * **server** - Start a static web server.
469bda80 »
2012-01-10 Updating Readme. Lots more to write, but it's a start.
13 * **watch** - Run predefined tasks whenever watched files change.
ab62e0f3 »
2011-10-14 Documenting some stuff. I have lots more to write.
14
bdc9798d »
2012-02-03 Updating readme with version changes.
15 _(My TODO list includes more "project scaffolding" templates among other things)_
0350043e »
2012-01-10 More readme tweaks.
16
469bda80 »
2012-01-10 Updating Readme. Lots more to write, but it's a start.
17 And in addition to the predefined tasks, you can define your own.
ab62e0f3 »
2011-10-14 Documenting some stuff. I have lots more to write.
18
ce76143f »
2012-01-11 Updated readme to mention that it's in beta and that feedback and sug…
19 [issues]: https://github.com/cowboy/grunt/issues
20
3506314f »
2012-01-22 Updated readme, going to bump the version and publish. As soon as I m…
21 [concat]: https://github.com/cowboy/grunt/blob/master/tasks/concat.js
22 [init]: https://github.com/cowboy/grunt/blob/master/tasks/init.js
23 [init-nodejs]: https://github.com/cowboy/grunt/blob/master/tasks/init/node.js
24 [init-nodedir]: https://github.com/cowboy/grunt/blob/master/tasks/init/node
25 [lint]: https://github.com/cowboy/grunt/blob/master/tasks/lint.js
26 [min]: https://github.com/cowboy/grunt/blob/master/tasks/min.js
27 [test]: https://github.com/cowboy/grunt/blob/master/tasks/test.js
28 [misc]: https://github.com/cowboy/grunt/blob/master/tasks/misc.js
29 [tasks]: https://github.com/cowboy/grunt/tree/master/tasks
99e6cf65 »
2012-01-10 More readme tweaks.
30 [gruntfile]: https://github.com/cowboy/grunt/blob/master/grunt.js
b996cd31 »
2011-10-14 Added cloning / install instructions to readme. For the few, brave gu…
31
469bda80 »
2012-01-10 Updating Readme. Lots more to write, but it's a start.
32 [node]: http://nodejs.org/
33 [npm]: http://npmjs.org/
34 [jshint]: http://www.jshint.com/
35 [uglify]: https://github.com/mishoo/UglifyJS/
36 [nodeunit]: https://github.com/caolan/nodeunit
bdc9798d »
2012-02-03 Updating readme with version changes.
37 [qunit]: http://docs.jquery.com/QUnit
38 [phantom]: http://www.phantomjs.org/
b996cd31 »
2011-10-14 Added cloning / install instructions to readme. For the few, brave gu…
39
469bda80 »
2012-01-10 Updating Readme. Lots more to write, but it's a start.
40 ## Why does grunt exist?
41 Doing all this stuff manually is a total pain, and building all this stuff into a gigantic Makefile / Jakefile / Cakefile / Rakefile / ?akefile that's maintained across all my projects was also becoming a total pain. Since I always found myself performing the same tasks over and over again, for every project, it made sense to build a task-based build tool.
42
43 Being primarily a JavaScript developer, I decided to use [Node.js][node] and [npm][npm] because the dependencies I most care about ([JSHint][jshint] and [UglifyJS][uglify]) were already npm modules. That being said, while Node.js was designed to support highly-concurrent asynchronous-IO-driven web servers, it was clearly NOT designed to make command-line build tools. But none of that matters, because grunt works. Just install it and see.
b996cd31 »
2011-10-14 Added cloning / install instructions to readme. For the few, brave gu…
44
469bda80 »
2012-01-10 Updating Readme. Lots more to write, but it's a start.
45 ## Installing grunt
ce76143f »
2012-01-11 Updated readme to mention that it's in beta and that feedback and sug…
46
5437bd58 »
2012-01-11 Minor readme tweaks.
47 _Grunt is currently in beta. While I'm already using it on multiple projects, it might have a minor issue or two. And things might change before its final release, based on your feedback. Please try it out in a project, and [make suggestions][issues] or [report bugs][issues]!_
ce76143f »
2012-01-11 Updated readme to mention that it's in beta and that feedback and sug…
48
469bda80 »
2012-01-10 Updating Readme. Lots more to write, but it's a start.
49 Grunt is available as an [npm][npm] module. If you install grunt globally via `npm install -g grunt`, it will be available for use in all of your projects.
ab62e0f3 »
2011-10-14 Documenting some stuff. I have lots more to write.
50
ce76143f »
2012-01-11 Updated readme to mention that it's in beta and that feedback and sug…
51 Once grunt has been installed, you can type `grunt --help` at the command line for more information. And if you want to see grunt "grunt" itself, cd into grunt's directory and type `grunt` (in Windows, you might need to run it as `grunt.cmd`).
ab62e0f3 »
2011-10-14 Documenting some stuff. I have lots more to write.
52
469bda80 »
2012-01-10 Updating Readme. Lots more to write, but it's a start.
53 ## The config file, aka "gruntfile"
54 When run, grunt looks in the current directory for a file named `grunt.js`, and if not found, continues looking in parent directories until found. The gruntfile is typically placed in the root of your project repository, and is a valid JavaScript file comprised of two parts: [project configuration](#config), and [tasks](#tasks) / [helpers](#helpers).
55
56 <div id="config"></div>
57 ## Project configuration
58 Each grunt task relies on configuration information defined in a single `config.init()` call in the gruntfile. Usually, this information is specified in task-named sub-properties of a main configuration object. It's not as complicated as it sounds.
59
60 For example, this simple configuration would define a list of files to be linted when the task "lint:files" was run on the command line like this: `grunt lint:files`.
61
62 ```javascript
63 config.init({
64 lint: {
65 files: ['lib/*.js', 'test/*.js', 'grunt.js']
66 }
67 });
68 ```
ab62e0f3 »
2011-10-14 Documenting some stuff. I have lots more to write.
69
469bda80 »
2012-01-10 Updating Readme. Lots more to write, but it's a start.
70 Also note that because the "lint" task is a [basic task](#tasks_basic), you can also run _all_ lint sub-tasks with just `grunt lint`.
ab62e0f3 »
2011-10-14 Documenting some stuff. I have lots more to write.
71
469bda80 »
2012-01-10 Updating Readme. Lots more to write, but it's a start.
72 You can store any arbitrary information inside of the configuration object, and as long as it doesn't conflict with a property one of your tasks is using, it will be ignored.
ab62e0f3 »
2011-10-14 Documenting some stuff. I have lots more to write.
73
74 ```javascript
75 config.init({
76 // Generic project information used by some helpers and tasks.
77 meta: {},
78 // Lists of files to be concatenated, used by the "concat" task.
79 concat: {},
80 // Lists of files to be minififed with UglifyJS, used by the "min" task.
81 min: {},
82 // Lists of files to be unit tested with Nodeunit, used by the "test" task.
83 test: {},
84 // Lists of files to be linted with JSHint, used by the "lint" task.
85 lint: {},
86 // Global configuration options for JSHint.
87 jshint: {},
88 // Global configuration options for UglifyJS.
89 uglify: {}
90 });
91 ```
92
51a4be7b »
2012-01-11 I guess I'll release it on npm now.
93 Take a look at grunt's own [grunt.js gruntfile][gruntfile] or [javascript-hooker's gruntfile](https://github.com/cowboy/javascript-hooker/blob/master/grunt.js) or [glob-whatev's gruntfile](https://github.com/cowboy/node-glob-whatev/blob/master/grunt.js) for a few examples.
0350043e »
2012-01-10 More readme tweaks.
94
469bda80 »
2012-01-10 Updating Readme. Lots more to write, but it's a start.
95 _Note: you don't need to specify configuration settings for tasks that you don't use._
96
97 <div id="tasks"></div>
98 ## Tasks
99 Tasks are the things you do most often, like [concat][concat], [lint][lint], [min][min] or [test][test] files. Every time grunt is run, one or more tasks must be specified, which tells grunt what you want it to do. Note that if you don't specify a task, but a task named "default" has been defined, that task will run (unsurprisingly) by default.
100
99e6cf65 »
2012-01-10 More readme tweaks.
101 _You should probably create a ["default" task][gruntfile] in your gruntfile._
469bda80 »
2012-01-10 Updating Readme. Lots more to write, but it's a start.
102
103 Tasks can be created in a few ways.
ab62e0f3 »
2011-10-14 Documenting some stuff. I have lots more to write.
104
469bda80 »
2012-01-10 Updating Readme. Lots more to write, but it's a start.
105 <div id="tasks_alias"></div>
106 ### Alias tasks
ab62e0f3 »
2011-10-14 Documenting some stuff. I have lots more to write.
107
108 ```javascript
469bda80 »
2012-01-10 Updating Readme. Lots more to write, but it's a start.
109 task.registerTask(taskName, [description, ] taskList);
ab62e0f3 »
2011-10-14 Documenting some stuff. I have lots more to write.
110 ```
111
469bda80 »
2012-01-10 Updating Readme. Lots more to write, but it's a start.
112 _Note that the description is optional. If omitted, a useful description will be added for you automatically._
ab62e0f3 »
2011-10-14 Documenting some stuff. I have lots more to write.
113
99e6cf65 »
2012-01-10 More readme tweaks.
114 The following example defines a task named "theworks" that, when run, actually runs the "lint:files" "test:files" "concat" "min" tasks, in-order. so instead of typing `grunt lint:files test:files concat min` at the command line, you can just type `grunt theworks`. If this task were named "default" instead of "theworks" it would be run by default whenever `grunt` was executed without specifying tasks.
b9428965 »
2011-10-14 More documentation.
115
116 ```javascript
469bda80 »
2012-01-10 Updating Readme. Lots more to write, but it's a start.
117 task.registerTask('theworks', 'lint:files test:files concat min');
b9428965 »
2011-10-14 More documentation.
118 ```
ab62e0f3 »
2011-10-14 Documenting some stuff. I have lots more to write.
119
469bda80 »
2012-01-10 Updating Readme. Lots more to write, but it's a start.
120 <div id="tasks_basic"></div>
121 ### Basic tasks
122 A basic task is a task that implicitly iterates over all of its configuration sub-properties if no sub-task is specified. For example, in the following, while `grunt lint:test` or `grunt lint:lib` will lint only those specific files, `grunt lint` will run the "test", "lib" and "grunt" sub-tasks for you, automatically. It's convenient.
ab62e0f3 »
2011-10-14 Documenting some stuff. I have lots more to write.
123
124 ```javascript
469bda80 »
2012-01-10 Updating Readme. Lots more to write, but it's a start.
125 config.init({
126 lint: {
127 test: ['test/*.js'],
128 lib: ['lib/*.js'],
129 grunt: ['grunt.js']
130 }
131 });
ab62e0f3 »
2011-10-14 Documenting some stuff. I have lots more to write.
132 ```
133
469bda80 »
2012-01-10 Updating Readme. Lots more to write, but it's a start.
134 While it's probably more useful for you to check out the JavaScript source of the [concat][concat], [lint][lint], [min][min] or [test][test] tasks, this is how you'd define a Basic task:
ab62e0f3 »
2011-10-14 Documenting some stuff. I have lots more to write.
135
136 ```javascript
469bda80 »
2012-01-10 Updating Readme. Lots more to write, but it's a start.
137 task.registerBasicTask('log', 'This task logs something.', function(data, name) {
138 // data === the value of the config sub-prop
139 // name === the name of the config sub-prop
140
141 log.writeln(data);
142
143 if (failureOfSomeKind) { return false; }
144 log.writeln('Your success message.');
145 });
ab62e0f3 »
2011-10-14 Documenting some stuff. I have lots more to write.
146 ```
147
469bda80 »
2012-01-10 Updating Readme. Lots more to write, but it's a start.
148 <div id="tasks_custom"></div>
149 ### Custom tasks
ab62e0f3 »
2011-10-14 Documenting some stuff. I have lots more to write.
150
3506314f »
2012-01-22 Updated readme, going to bump the version and publish. As soon as I m…
151 You can go crazy with tasks, though. They don't have to be basic. If your tasks don't follow the "basic task" structure, use a custom task.
ab62e0f3 »
2011-10-14 Documenting some stuff. I have lots more to write.
152
153 ```javascript
b9428965 »
2011-10-14 More documentation.
154 task.registerTask('default', 'My "default" task description.', function() {
155 log.writeln('Currently running the "default" task.');
ab62e0f3 »
2011-10-14 Documenting some stuff. I have lots more to write.
156 });
157 ```
158
159 Inside a task, you can run other tasks.
160
161 ```javascript
162 task.registerTask('foo', 'My "foo" task.', function() {
99e6cf65 »
2012-01-10 More readme tweaks.
163 // Enqueue "bar" and "baz" tasks, to run after 'foo' finishes, in-order.
b9428965 »
2011-10-14 More documentation.
164 task.run('bar baz');
99e6cf65 »
2012-01-10 More readme tweaks.
165 // Or:
166 task.run(['bar', 'baz']);
ab62e0f3 »
2011-10-14 Documenting some stuff. I have lots more to write.
167 });
168 ```
169
170 Tasks can be asynchronous.
171
172 ```javascript
173 task.registerTask('async', 'My "foo" task.', function() {
174 // Force task into async mode and grab a handle to the "done" function.
175 var done = this.async();
176 // Run some sync stuff.
177 log.writeln('Processing task...');
178 // And some async stuff.
179 setTimeout(function() {
180 log.writeln('All done!');
181 done();
182 }, 1000);
183 });
184 ```
185
186 Tasks can access their own name and arguments.
187
188 ```javascript
189 task.registerTask('foo', 'My "foo" task.', function(a, b) {
b9428965 »
2011-10-14 More documentation.
190 log.writeln(this.name, a, b);
191 });
192
193 // Usage:
194 // grunt foo foo:bar
195 // logs: "foo", undefined, undefined
196 // logs: "foo", "bar", undefined
197 // grunt foo:bar:baz
198 // logs: "foo", "bar", "baz"
199 ```
200
469bda80 »
2012-01-10 Updating Readme. Lots more to write, but it's a start.
201 Tasks can fail if any errors were logged.
99e6cf65 »
2012-01-10 More readme tweaks.
202
469bda80 »
2012-01-10 Updating Readme. Lots more to write, but it's a start.
203 ```javascript
204 task.registerTask('foo', 'My "foo" task.', function() {
205 if (someError) {
206 log.error('This is an error message.');
207 }
208
209 // Fail task if errors were logged.
210 if (task.hadErrors()) { return false; }
211
212 log.writeln('This is the success message');
213 });
214 ```
215
3506314f »
2012-01-22 Updated readme, going to bump the version and publish. As soon as I m…
216 When tasks fail, all subsequent tasks will be aborted unless `--force` was specified.
b9428965 »
2011-10-14 More documentation.
217
218 ```javascript
219 task.registerTask('foo', 'My "foo" task.', function() {
220 // Fail synchronously.
221 return false;
ab62e0f3 »
2011-10-14 Documenting some stuff. I have lots more to write.
222 });
223
b9428965 »
2011-10-14 More documentation.
224 task.registerTask('bar', 'My "bar" task.', function() {
225 var done = this.async();
226 setTimeout(function() {
227 // Fail asynchronously.
228 done(false);
229 }, 1000);
230 });
231 ```
232
233 Tasks can be dependent on the successful execution of other tasks. Note that `task.requires` won't actually RUN the other task. It'll just check to see that it has run and not failed.
234
235 ```javascript
236 task.registerTask('foo', 'My "foo" task.', function() {
237 return false;
238 });
239
240 task.registerTask('bar', 'My "bar" task.', function() {
241 // Fail task if "foo" task failed or never ran.
242 task.requires('foo');
469bda80 »
2012-01-10 Updating Readme. Lots more to write, but it's a start.
243 // This code executes if the "foo" task ran successfully.
244 log.writeln('Hello, world.');
b9428965 »
2011-10-14 More documentation.
245 });
246
247 // Usage:
248 // grunt foo bar
249 // doesn't log, because foo failed.
250 // grunt bar
251 // doesn't log, because foo never ran.
252 ```
253
254 Tasks can fail if required configuration properties don't exist.
255
256 ```javascript
257 task.registerTask('foo', 'My "foo" task.', function() {
258 // Fail task if "meta.name" config prop is missing.
259 config.requires('meta.name');
469bda80 »
2012-01-10 Updating Readme. Lots more to write, but it's a start.
260 // Also fails if "meta.name" config prop is missing.
261 config.requires(['meta', 'name']);
b9428965 »
2011-10-14 More documentation.
262 // Log... conditionally.
263 log.writeln('This will only log if meta.name is defined in the config.');
264 });
265 ```
266
267 Tasks can access configuration properties.
268
269 ```javascript
270 task.registerTask('foo', 'My "foo" task.', function() {
271 // Log the property value. Returns null if the property is undefined.
272 log.writeln('The meta.name property is: ' + config('meta.name'));
469bda80 »
2012-01-10 Updating Readme. Lots more to write, but it's a start.
273 // Also logs the property value. Returns null if the property is undefined.
274 log.writeln('The meta.name property is: ' + config(['meta', 'name']));
b9428965 »
2011-10-14 More documentation.
275 });
ab62e0f3 »
2011-10-14 Documenting some stuff. I have lots more to write.
276 ```
277
278 Look at the [built-in tasks][tasks] for more examples.
279
280 ## Helpers
99e6cf65 »
2012-01-10 More readme tweaks.
281 Helpers are just utility functions, exposed through the `task` global variable, so that they can be used by tasks in other files.
282
283 It's not much more complex than this:
284
285 ```javascript
286 task.registerHelper('foo', function(a, b) {
287 return a + b;
288 });
ab62e0f3 »
2011-10-14 Documenting some stuff. I have lots more to write.
289
99e6cf65 »
2012-01-10 More readme tweaks.
290 task.helper('foo', 2, 3) // 5
291 ```
292
293 For example, in the [min][min] task, the majority of the actual minification work is done in an [uglify][min] helper, so that other tasks can utilize that code if they need to.
294
295 ## Directives
296 Directives are essentially string placeholders for helper functions, specified as values in the [configuration object](#config). It's not as crazy as it sounds.
ab62e0f3 »
2011-10-14 Documenting some stuff. I have lots more to write.
297
99e6cf65 »
2012-01-10 More readme tweaks.
298 A good example of directives would be the `<json:package.json>` and `<config:lint.files>` directives in grunt's own [grunt.js gruntfile][gruntfile]. Or the `<banner>` and `<file_strip_banner:lib/hooker.js>` directives in [javascript-hooker's gruntfile](https://github.com/cowboy/javascript-hooker/blob/master/grunt.js).
ab62e0f3 »
2011-10-14 Documenting some stuff. I have lots more to write.
299
99e6cf65 »
2012-01-10 More readme tweaks.
300 In brief, when a directive like `<foo>` is encountered, the `foo` helper is executed, and its return value is used. If `<foo:bar:baz>` is encountered, the `foo` helper is executed, with arguments `"bar"` and `"baz"` passed in, and its return value is used.
ab62e0f3 »
2011-10-14 Documenting some stuff. I have lots more to write.
301
99e6cf65 »
2012-01-10 More readme tweaks.
302 Some of the built-in directives:
ab62e0f3 »
2011-10-14 Documenting some stuff. I have lots more to write.
303
99e6cf65 »
2012-01-10 More readme tweaks.
304 * `<config:prop.subprop>` - expand to the prop.subprop config property. Great for DRYing up file lists.
305 * `<json:file.json>` - expand to the object parsed from file.json (a valid JSON file).
306 * `<banner>` - the string in config property `meta.banner`, parsed via [handlebars][misc].
307 * `<banner:prop.subprop>` - same as above, but using a custom config property.
308 * `<file_strip_banner:file.js>` - expand to the given file, with any leading /*...*/ banner stripped.
ab62e0f3 »
2011-10-14 Documenting some stuff. I have lots more to write.
309
99e6cf65 »
2012-01-10 More readme tweaks.
310 Can you guess what these directives do? They're from grunt's own [grunt.js gruntfile][gruntfile].
ab62e0f3 »
2011-10-14 Documenting some stuff. I have lots more to write.
311
99e6cf65 »
2012-01-10 More readme tweaks.
312 ```javascript
313 config.init({
314 pkg: '<json:package.json>',
315 lint: {
3506314f »
2012-01-22 Updated readme, going to bump the version and publish. As soon as I m…
316 files: ['grunt.js', 'lib/**/*.js', 'tasks/*.js', 'test/**/*.js']
99e6cf65 »
2012-01-10 More readme tweaks.
317 },
318 watch: {
319 files: '<config:lint.files>',
320 tasks: 'default'
321 }
322 });
323 ```
324
325 ## Global Variables
326 In an effort to make things easier, there are a lot of global variables.
327
51a4be7b »
2012-01-11 I guess I'll release it on npm now.
328 * `underscore` - [Underscore.js](http://underscorejs.org/)
99e6cf65 »
2012-01-10 More readme tweaks.
329 * `util` - miscellaneous utilities
330 * `task` - the entire task interface
331 * `file` - glob expansion, file reading, writing, directory traversing
332 * `fail` - more serious than error logging, `fail.warn` and `fail.fatal` will halt everything
333 * `config` - reading values from the grunt configuration
334 * `option` - reading values from the command-line options
371e622a »
2012-01-10 More readme tweaks.
335 * `log` - don't use `console.log`, use `log.writeln` instead! [More info on log](#logging).
336 * `verbose` - just like `log`, but only logs if `--verbose` was specified. [More info on verbose](#logging).
99e6cf65 »
2012-01-10 More readme tweaks.
337
371e622a »
2012-01-10 More readme tweaks.
338 Unfortunately, I haven't documented everything yet. Fortunately, the source is open and browsable. Have fun!
339
340 <div id="logging"></div>
341 ## Logging
342 I wanted grunt to look pretty. As such, there are a LOT of logging methods, and a few useful patterns:
343
344 Note, all of the methods that actually log something are chainable.
345
346 * `log.write(msg)` - log msg, with no trailing newline
347 * `log.writeln(msg)` - log msg, with trailing newline
348 * `log.error(msg)` - if msg is omitted, logs ERROR in red, otherwise logs: >> msg, with trailing newline
349 * `log.ok(msg)` - if msg is omitted, logs OK in green, otherwise logs: >> msg, with trailing newline
350 * `log.subhead(msg)` - logs msg in bold, with trailing newline
351 * `log.writeflags(obj, prefix)` - logs a list of obj properties (good for debugging flags)
352 * `log.wordlist(arr)` - returns a comma-separated list of array items
353 * `log.verbose` - contains all methods of `log` but only logs if `--verbose` was specified.
354 * `log.notverbose` - contains all methods of `log` but only logs if `--verbose` wasn't specified.
355 * `log.verbose.or` - reference to `log.notverbose`
356 * `log.notverbose.or` - reference to `log.verbose`
357
358 There are a few other methods, but you shouldn't use them in your tasks or helpers, so they've been omitted.
359
360 A common pattern is to only log when in `--verbose` mode OR if an error occurs, like so:
361
362 ```javascript
363 task.registerHelper('something', function(arg) {
364 var result;
365 var msg = 'Doing something...';
366 verbose.write(msg);
367 try {
368 result = doSomethingThatThrowsAnExceptionOnError(arg);
369 // Success!
370 verbose.ok();
371 return result;
372 } catch(e) {
373 // Something went wrong.
374 verbose.or.write(msg).error().error(e.message);
375 fail.warn('Something went wrong.', 50);
376 }
377 });
378 ```
379
380 An explanation of the above code:
381
382 1. `verbose.write(msg);` logs the message (no newline), but only in `--verbose` mode.
383 2. `verbose.ok();` logs OK in green, with a newline.
384 3. `verbose.or.write(msg).error().error(e.message);` does a few things:
385 1. `verbose.or.write(msg)` logs the message (no newline) if not in `--verbose` mode, and returns the `notverbose` object.
386 2. `.error()` logs ERROR in red, with a newline, and returns the `notverbose` object.
387 3. `.error(e.message);` logs the actual error message (and returns the `notverbose` object).
388 4. `fail.warn('Something went wrong.', 50);` logs a warning in bright yellow, existing grunt with exit code 50, unless `--force` was specified.
389
390 You can write crazy logging chains, omg!
391
392 <div id="exit_codes"></div>
393 ## Exit Codes
394
395 * `1` - Generic error.
396 * `2` - Config file not found.
397 * `3` - Generic task failed.
398 * `10` - Uglify-JS error.
399 * `11` - Banner generation error.
400 * `20` - Init error.
55163289 »
2012-02-02 Updating erroneous Nodeunit/QUnit exit code documentation.
401 * `91-99` - Nodeunit/QUnit errors.
371e622a »
2012-01-10 More readme tweaks.
402
403 <div id="examples"></div>
99e6cf65 »
2012-01-10 More readme tweaks.
404 ## Examples
469bda80 »
2012-01-10 Updating Readme. Lots more to write, but it's a start.
405 In this example, you don't want to run `grunt lint concat` every time you need to process your code, because "dist/output.js" will be linted before it's created!
406
407 You should really do `grunt lint:beforeconcat concat lint:afterconcat`.
408
409 ```javascript
410 config.init({
411 // When the "concat:dist/output.js" task is run, the specified "foo.js" and
412 // "bar.js" files will be concatenated in-order and saved to the "output.js"
413 // output file. Because the "concat" task is a Basic task, when it is run
414 // without an argument, all sub-tasks will automatically be run.
415 concat: {
416 'dist/output.js': ['src/foo.js', 'src/bar.js']
417 },
418 lint: {
419 // When the "lint:beforeconcat" task is run, the specified "foo.js" and
420 // "bar.js" files will be linted with JSHint. The same follows for the
421 // "lint:afterconcat" task. Because the "lint" task is a Basic task, when
422 // it is run without an argument, all sub-tasks will automatically be run.
423 beforeconcat: ['src/foo.js', 'src/bar.js'],
424 afterconcat: ['dist/output.js']
425 }
426 });
427 ```
428
429 And to make your workflow easier, create an [Alias Task](#tasks_alias):
430
431 ```javascript
432 task.registerTask('default', 'lint:beforeconcat concat lint:afterconcat');
433 ```
5aad12e6 »
2012-01-07 MIT license is fine. GPL license is redundant.
434
371e622a »
2012-01-10 More readme tweaks.
435 _(more examples coming... soon)_
436
99e6cf65 »
2012-01-10 More readme tweaks.
437 ## Contributing
438 Fork, tweak, and make pull requests.. but you'd better successfully `grunt` it first, or I'm not even looking.
439
5aad12e6 »
2012-01-07 MIT license is fine. GPL license is redundant.
440 ## Release History
ab934581 »
2012-01-22 Removed handlebars, strip_banner tweaks.
441 _(Until v1.0.0, this will only be updated when major or breaking changes are made)_
51a4be7b »
2012-01-11 I guess I'll release it on npm now.
442
bdc9798d »
2012-02-03 Updating readme with version changes.
443 * 2012/02/03 - v0.2.14 - Added a server task (which starts a static webserver for your tasks). The qunit task now uses PhantomJS instead of Zombie.js (4768 of 4971 jQuery unit test pass, neat), and supports both file wildcards as well as http:// or https:// urls. (static webserver, anyone?). Grunt should no longer "hang" when done.
c33969c8 »
2012-01-29 Bumping version to v0.2.5, publishing to npm.
444 * 2012/01/29 - v0.2.5 - Added a "qunit" task as well as an init "jquery" template (as of now, there are also "node" and "commonjs" init templates).
8438292d »
2012-01-22 Minor readme tweak.
445 * 2012/01/22 - v0.2.1 - Removed handlebars, templates are universally handled by underscore now. Changed init task template tags from <% %> to {% %}. Banners beginning with /*! will no longer be stripped.
446 * 2012/01/22 - v0.2.0 - Added "init" task with a sample template, reworked a lot of code. Hopefully it's backwards-compatible.
447 * 2012/01/11 - v0.1.0 - Initial release.
5aad12e6 »
2012-01-07 MIT license is fine. GPL license is redundant.
448
449 ## License
450 Copyright (c) 2012 "Cowboy" Ben Alman
451 Licensed under the MIT license.
452 <http://benalman.com/about/license/>
Something went wrong with that request. Please try again.