sake v0.1.32
SAKÉ
Stitch from Rake
This package contains Saké, a JavaScript build program that runs in node with capabilities similar to ruby's Rake, and with some extra Stitch tasks for building JavaScript, CSS, HTML, and other sundry files for web development.
Saké has the following features:
- Sakefiles (Saké’s version of Rakefiles) are completely defined in standard JavaScript (or CoffeeScript, for those who want an even more Rake-like feel).
- Flexible FileLists that act like arrays but know about manipulating file names and paths.
- Standard
clean
andclobber
tasks - Handling of Synchronous and Asynchronous tasks.
- Many utility methods for handling common build tasks (rm, rm_rf, mkdir, mkdir_p, sh, cat, etc...)
- Stitch a set of utility methods that help build packages of JavaScript, CSS, HTML, etc...
Installation
Install with npm
Download and install with the following:
npm install -g sake
Saké Command-Line Usage
% sake [options] [task ...] [env=variable ...]
Saké will look within the current directory, and all parent directories, for the first /^[sS]akefile(\.(js|coffee))?$/
it can find, run that file, and then invoke the task passed on the command-line. If no task is given, it will try to invoke the task named default
.
If additional arguments in the form of [VARIABLE_NAME]=[VALUE]
are given on the command-line, Saké will set an environment variable VARIABLE_NAME
with its value the JSON parsed value of VALUE
(or a plain string, if it fails to JSON parse cleanly). These will then be accessible through the node's process.env[ironment]
namespace.
Sake Command-Line Options
-f, --sakefile PATH Specify PATH to Sakefile to run instead of searching for one.
-T, --tasks List tasks with descriptions and exit.
-P, --prerequisites List tasks and their prerequisites and exit.
-d, --debug Enable additional debugging output.
-v, --verbose Log messages to standard output.
-V, --version Print the version of sake and exit.
-h, --help Print this help information and exit.
Stitch Specific Options
-o, --outfile PATH Save Stitch output to file PATH.
-F, --force If outputing to a file, overwrite any existing file.
-N, --no-minify Set Stitch minification flag to false.
--stitch-temp-dir PATH Directory to use for temporary files
Sakefile Usage
Within a Sakefile
, Saké's methods are exported to the global scope, so you can invoke them directly:
task("taskname", ["prereq1", "prereq2"], function (t) {
// task action...
});
or, the equivalent in a Sakefile.coffee
:
task "taskname", ["prereq1", "prereq2"], (t)->
// task action...
Within another node module you can require("sake")
and access the methods on the exported object:
var sake = require("sake");
sake.task("taskname", ["prereq1", "prereq2"], function (t) {
// task action...
});
The remainder of this documentation will assume that we are calling the methods from within a Sakefile
.
Defining Tasks
The various task methods take one, or more, of the following arguments:
taskname
:string
-- naming the taskprerequisites
: an optionalarray
ofstring
task names,FileLists
, orfunctions
that return a task name, anarray
, or aFileList
. You can also pass aFileList
in directly forprerequisites
.action
: an optionalfunction
that will be called when the task is invoked.
All task methods return the task instance.
If a task is already defined, it will be augmented by the additional arguments. So, this:
task("one", ["othertask"], function (t) {
// do action one...
});
task("one", function (t) {
// do action two...
});
task("othertask");
Would result in a task "othertask" with no prerequisites, and no action, and a task "one" with "othertask" as a prerequisite and the two functions as its actions.
Note how the dependent task was defined after it was required as a prerequisite. Task prerequisites are not resolved until the task is invoked. This leads to flexibility in how to compose your tasks and prerequisite tasks.
File Tasks
File tasks are created with the (appropriately named) file
method. File tasks, however, are only triggered if the file doesn't exist, or the modification time of any of its prerequisites is newer than itself.
file("path/to/some/file", function (t) {
cp("other/path", t.name);
});
The above task would only be triggered if path/to/some/file
did not exist.
The following:
file("combined/file/path", ["pathA", "pathB", "pathC"], function (t) {
write(t.name, cat(t.prerequisites), "utf8");
});
would be triggered if path/to/some/file
did not exist, or its modification time was earlier than any of its prerequisites (pathA
, pathB
, or pathC
).
Directory Tasks
Directory tasks, created with the directory
method, are tasks that will only be called if they do not exist. A task will be created for the named directory (and for all directories along the way) with the action of creating the directory.
Directory tasks do not take any prerequisites
or an action
when first defined, however, they may be augmented with such after they are created:
directory("dir/path/to/create");
task("dir/path/to/create", ["othertask"], action (t) {
//... do stuff
});
File Create Tasks
A file create task is a file task, that when used as a prerequisite, will be needed if, and only if, the file has not been created. Once created, it is not re-triggered if any of its prerequisites are newer, nor does it trigger any rebuilds of tasks that depend on it whenever the file is updated.
fileCreate("file/path/to/create.ext", ["pathA", "pathB"], function (t) {
// create file...
});
(A)Synchronicity and Tasks
In Saké all task actions are assumed to be synchronous. However, many things in node require asynchronous callbacks. You can indicate that a task action is asynchronous by calling the tasks's, or the global Task
class', startAsyc
method when starting the task action, and the clearAsync
method when it is complete. i.e:
task("asynctask", function (t) {
t.startAsync(); // or, Task.startAsync()
sh("some long running shell command", function (err, stdout, stderr) {
// do stuff...
t.clearAsync(); // or, Task.clearAsync()
});
});
Alternatively, you can use the atask
method to add an asynchronous task action. This will automatically set the async flag for that action. However, your task must still clear it when it is done. i.e:
atask("longtask", function (t) {
sh("some long running shell command", function (err, stdout, stderr) {
t.clearAsync(); // or, Task.clearAsync()
});
});
File Lists
FileLists are lists (an Array
) of files.
new FileList("*.scss");
Would contain all the files with a ".scss" extension in the top-level directory of your project.
You can use FileLists pretty much like an Array
. You can iterate them (with forEach, filter, reduce
, etc...), concat
them, splice
them, and you get back a new FileList object.
To add files, or glob patterns to them, use the #include
method:
var fl = new FileList("*.scss");
fl.include("core.css", "reset.css", "*.css");
You can also exlucude
files by Glob pattern, Regular Expression
pattern, or by use of a function
that takes the file path as an argument and returns a truthy
value to exclude a file.
// Exclude by RegExp
fl.exclude(/^dev-.*\.css/);
// Exclude by Glob pattern
fl.exclude("dev-*.css");
// Exclude by function
fl.exclude(function (path) {
return FS.statSync(path).mtime.getTime() < (Date.now() - 60 * 60 * 1000);
});
To get to the actual items of the FileList, use the #items
property, or the #toArray
method, to get a plain array back. You can also use the #get
or #set
methods to retrieve or set an item.
FileLists are lazy, in that the actual file paths are not determined from the include and exclude patterns until the individual items are requested. This allows you to define a FileList and incrementally add patterns to it in the Sakefile file. The FileList paths will not be resolved until the task that uses it as a prerequisite actually asks for the final paths.
FileList Utility Properties & Methods
FileList#existing
Will return a new FileList
with all of the files that actually exist.
FileList#notExisting
Will return a new FileList
all of the files that do not exist.
FileList#extension(ext)
Returns a new FileList
with all paths that match the given extension.
fl.extension(".scss").forEach(function (path) {
//...
});
FileList#grep(pattern)
Get a FileList
of all the files that match the given pattern
. pattern
can be a plain String
, a Glob
pattern, a RegExp
, or a function
.
FileList#clearExcludes()
Clear all exclude patterns/functions.
FileList#clearIncludes()
Clear all include patterns.
FileList#add()
Alias for #include
Saké Utility Functions
Saké defines a few utility functions to make life a little easier in an asynchronous world. Most of these are just wrappers for node
's File System (require("fs")
) utility methods.
mkdir(dirpath, mode="755")
mkdir_p(dirpath, mode="755"])
Create the dirpath
directory, if it doesn't already exist. mkdir_p
will create all intermediate directories as needed.
rm(path, path1, ..., pathN)
rm_rf(path, path1, ..., pathN)
Remove one or more paths from the file system. rm_rf
will remove directories and their contents.
cp(from, to)
Copy a file from from
path to to
path.
mv(from, to)
Move a file from from
path to to
path.
ln(from, to)
Create a hard link from from
path to to
path.
ln_s(from, to)
Create a symlink from from
path to to
path.
cat(path, path1, ..., pathN)
Synchronously read all supplied paths and return their contents as a string. If an argument is an Array
it will be expanded and those paths will be read.
read(path, enc)
Synchronously read the supplied file path. Returns a buffer
, or a string
if enc
is given.
write(path, data, enc, mode="w")
Synchronously write the data
to the supplied file path
. data
should be a buffer
or a string
if enc
is given. mode
is a string
of either "w", for over write, or "a" for append.
sh(cmd, success, failure)
Execute shell cmd
. On success the success
handler will be called, on error, the failure
function.
This method is asynchronous, and if used in a task, one should call Task.startAsync
or the task#startAsync
to indicate that the task is asynchronous. Clear the asynchronous flag by calling Task.clearAsync
, or the task#clearAsync
method in the success
or failure
handler.
Stitch Usage
stitch
provides various methods and core tasks to help define tasks that enable bundling of resources for web-development. (It's also where the S in Saké comes from.)
stitch(namespace, function)
Define a stitch configuration. If namespace
is omitted, it defaults to "default".
The first argument to the function
will be a reference to the current stitch
driver; in addition, the this
context of the function will be set to the stitch configuration driver.
stitch.aliasType("text/stylesheet", "scss");
stitch(function (cfg) {
cfg.bundle("core", function (core) {
core.javascript(function () {
core.add("src/js/core.js");
});
core.stylesheet(function () {
this.add("src/css/core.scss");
this.add("src/css/reset.scss");
});
});
this.bundle("sub-module", function (sub) {
sub.include("core");
this.js("src/js/sub-module.js");
this.scss("src/css/sub-module.scss");
});
});
or the equivalent CoffeeScript:
stitch.aliasType "text/stylesheet", "scss"
stitch (cfg)->
cfg.bundle "core", (core)->
core.javascript ->
core.add "src/js/core.js"
core.stylesheet ->
@add "src/css/core.scss"
@add "src/css/reset.scss"
@bundle "sub-module", (sub)->
sub.include "core"
@js "src/js/sub-module.js"
@scss "src/css/sub-module.scss"
Types
Bundles
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago