buddy(1)
buddy(1) is a build tool for js/css/html projects. It helps you manage third-party dependencies (optional add-on), compiles source code from higher order js/css/html languages (CoffeeScript/LiveScript/Handlebars/Stylus/Less/Jade/Twig), automatically wraps js files in module definitions, statically resolves module dependencies, and concatenates (and optionally compresses) all souces into a single file for more efficient delivery to the browser.
Current version: 0.12.4 [See Change Log for more details]
Features
- Allows you to write js modules without the module boilerplate (similar to Node.js)
- Resolves js module dependencies automatically
- Supports efficient lazy runtime evaluation by storing js modules as strings
- Resolves all relative dependencies on deploy
- Compiles CoffeeScript, LiveScript, Handlebars, Stylus, Less, Twig, and Jade source files
- Concatenates js modules into a single file
- Runs js and css code through linters to check for syntax errors
- Watches for source changes and builds automatically
- Serves static files from specified directory on specified port
- Refreshes connected browsers after each change
- Inlines css
@imports
automatically - Supports execution of a test script after each build
- [Add-on] Copies packages from GitHub to your project
- [Add-on] Copies assets from a local destination to your project
Installation
To avoid running buddy(1) directly as a global command, and thus avoid versioning problems across different projects, it is highly recommended that you instead install the separate buddy-cli command line interface system-wide:
$ npm -g install buddy-cli
...then create a package.json file for each project, locally installing buddy as a devDependency:
{
"name": "myproject",
"description": "This is my web project",
"version": "0.1.0",
"devDependencies": {
"buddy": "0.12.0"
}
}
$ cd path/to/project
$ npm install
Usage
Usage: buddy [options] <command> [path/to/package.json or path/to/buddy.js or path/to/buddy.json]>
Commands:
init set up a basic buddy project
install [config] install dependencies
build [config] build js and css sources
watch [config] watch js and css source files and build changes
deploy [config] build compressed js and css sources
ls list all previously created files and directories
clean remove all previously created files and directories
Options:
-h, --help output usage information
-V, --version output the version number
-c, --compress compress output for production deployment
-l, --lint check output for syntax and logic errors
-r, --reload reload all connected live-reload clients on file change during watch
-s, --serve create a webserver to serve static files during watch
-t, --test run test command on build completion
-L, --lazy convert js modules for lazy evaluation
-v, --verbose print all messages for debugging
Examples
See buddy-dependencies for install
command examples.
Generate www/main.js
by concatenating and modularizing all dependencies in src
or libs/js
referenced in src/main.js
:
package.json
{
"name": "myproject",
"description": "This is my web project",
"version": "0.1.0",
"dependencies": {
"simple-browser-require": "*"
},
"devDependencies": {
"buddy": "0.12.0"
},
"buddy": {
"build": {
"js": {
"sources": ["src", "libs/js"],
"targets": [
{
"input": "src/main.js",
"output": "www/main.js"
}
]
}
}
}
}
$ buddy build
Generate www/main.js
with references to dependencies installed via npm:
package.json
{
"name": "myproject",
"description": "This is my web project",
"version": "0.1.0",
"dependencies": {
"simple-browser-require": "*"
"underscore": "1.4.4"
},
"devDependencies": {
"buddy": "0.12.0"
},
"buddy": {
"build": {
"js": {
"sources": ["src"],
"targets": [
{
"input": "src/main.js",
"output": "www/main.js"
}
]
}
}
}
}
$ buddy build
First compile all CoffeeScript files in libs/src/coffee
, then generate www/main.js
by concatenating and modularizing all dependencies referenced in 'src/main.js':
package.json
{
"name": "myproject",
"description": "This is my web project",
"version": "0.1.0",
"dependencies": {
"simple-browser-require": "*"
},
"devDependencies": {
"buddy": "0.12.0"
},
"buddy": {
"build": {
"js": {
"sources": ["src", "libs/js", "libs/src/coffee"],
"targets": [
{
"input": "libs/src/coffee",
"output": "libs/js"
},
{
"input": "src/main.js",
"output": "www/main.js"
}
]
}
}
}
}
$ buddy build
Generate www/main.js
and an additional widget www/widget.js
using shared sources (avoid duplicating dependencies):
package.json
{
"name": "myproject",
"description": "This is my web project",
"version": "0.1.0",
"dependencies": {
"simple-browser-require": "*"
},
"devDependencies": {
"buddy": "0.12.0"
},
"buddy": {
"build": {
"js": {
"sources": ["src", "libs/js"],
"targets": [
{
"input": "src/main.js",
"output": "www/main.js",
"targets": [
{
"input": "src/widget.js",
"output": "www/widget.js"
}
]
}
]
}
}
}
}
$ buddy build
Compile a CoffeeScript project for Node.js, skipping module wrapping and concatenation:
package.json
{
"name": "myproject",
"description": "This is my server project",
"version": "0.1.0",
"devDependencies": {
"buddy": "0.12.0"
},
"buddy": {
"build": {
"js": {
"sources": ["src/coffee"],
"targets": [
{
"input": "src/coffee",
"output": "js",
"modular": false
}
]
}
}
}
}
$ buddy build
Start a basic web server and refresh the browser (using the Live-Reload browser plugin) after each build triggered by source file changes:
package.json
{
"name": "myproject",
"description": "This is my web project",
"version": "0.1.0",
"devDependencies": {
"buddy": "0.12.0"
},
"buddy": {
"settings": {
"server": {
"directory": "www",
"port": 8080
}
}
}
}
$ buddy watch -rs
Configuration
Complete annotated buddy.js
configuration file:
exports.build = {
js: {
sources: ['a/coffeescript/source/directory', 'a/js/source/directory'],
targets: [
{
input: 'a/coffeescript/or/js/file',
output: 'a/js/file/or/directory',
output_compressed: 'a/js/file/or/directory',
targets: [
{
input: 'a/coffeescript/or/js/file',
output: 'a/js/file/or/directory'
}
]
},
{
input: 'a/coffeescript/or/js/directory',
output: 'a/js/directory',
modular: false
}
]
},
css: {
sources: ['a/stylus/directory', 'a/less/directory', 'a/css/directory'],
targets: [
{
input: 'a/stylus/less/or/css/file',
output: 'a/css/file/or/directory'
},
{
input: 'a/stylus/less/or/css/directory',
output: 'a/css/directory'
}
]
}
}
exports.dependencies = {
'a/vendor/directory': {
sources: [
'popeindustries/browser-require',
'library@version'
],
output: 'a/js/file'
},
'a/source/directory': {
sources: [
'username/repo',
'username/repo#a/file/or/directory|another/file/or/directory',
'../a/file/or/directory'
]
}
}
exports.settings = {
test: 'command --flags',
server: {
directory: 'a/project/directory',
port: 8000
}
}
Concepts
BUILD
Project Root: The directory from which all paths resolve to. Determined by location of the configuration file.
Sources: An array of directories from which all referenced files are retrieved from. Note: A js module's id is derived from it's relative path to it's source directory.
Targets: Objects that specify the input and output files or directories for each build. Targets are built in sequence, allowing builds to be chained together. Note: A js target can also have nested child targets, ensuring that dependencies are not duplicated across related builds.
Target parameters:
-
input: file or directory to build. If js (or equivalent) file, all dependencies referenced will be concatenated together for output.
If directory, all compileable files will be compiled, wrapped in module definitions (js), and output to individual js/css files.
-
output: file or directory to output to.
-
targets: a nested target that prevents the duplication of source code with it's parent target.
-
modular: a flag to prevent js files from being wrapped with a module definition.
-
output_compressed: an alternate file or directory to use for compressed output.
MODULES
Each js file is wrapped in a module declaration based on the file's location. Dependencies are determined by the use of require()
statements:
var lib = require('./my/lib');
var SomeClass = require('../someclass');
var util = require('utils/util');
lib.doSomething();
var something = new SomeClass();
util.log('hey');
Specifying a module's public behaviour is achieved by decorating an exports
object:
var myModuleVar = 'my module';
exports.myModuleMethod = function() {
return myModuleVar;
};
...or overwriting the exports
object completely:
function MyModule() {
this.myVar = 'my instance var';
};
MyModule.prototype.myMethod = function() {
return this.myVar;
};
module.exports = MyModule;
Each module is provided with a module
, exports
, and require
reference.
When require()
-ing a module, keep in mind that the module id is resolved based on the following rules:
- packages begin at the root folder specified in build > js > sources:
'Users/alex/project/src/package/main.js' > 'package/main'
- uppercase filenames are converted to lowercase module ids:
'my/package/Class.js' > 'my/package/class'
See node.js modules for more info on modules.
NOTE: require
boilerplate needs to be included in the browser to enable module loading. It's recommended to install
a library like popeindustries/browser-require (npm: simple-browser-require).
DEPENDENCIES
See buddy-dependencies.
License
(The MIT License)
Copyright (c) 2011-2013 Pope-Industries <alex@pope-industries.com>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.