CLI plugins
Written for Titanium SDK 13.4.0 and later
A CLI plugin is JavaScript the CLI loads and lets subscribe to build events. It changes the build, not the app: generating a file before compilation, injecting a value, uploading an artifact afterwards.
Alloy is one. plugins/ti.alloy/hooks/alloy.js in an Alloy project is a hook
that compiles app/ into Resources/ before every build - which is why an
Alloy project needs ti.alloy in tiapp.xml and is otherwise a Classic
project.
The shape of one
// plugins/ti.example/hooks/stamp.js
exports.cliVersion = '>=3.X';
exports.version = '1.0.0';
exports.init = (logger, config, cli, appc) => {
cli.on('build.pre.compile', {
priority: 1000,
post(builder, done) {
logger.info(`building ${builder.tiapp.name} ${builder.tiapp.version}`);
done();
},
});
};
init is called once with the logger, the CLI config, the CLI itself, and the
node-appc helpers. cliVersion is a range the plugin needs, and a plugin
whose range does not match is skipped rather than crashing the build.
A hook subscribes with pre or post, and must call done() - the build
waits. A hook that forgets it hangs with no error, which is the failure mode to
recognise.
priority orders hooks against each other; the default is 1000.
Where they are found
| Location | Scope |
|---|---|
<project>/plugins/<id>/hooks/ |
That project |
paths.hooks in CLI config |
That machine |
The SDK's own cli/hooks/ |
Everything |
Declare a project plugin in tiapp.xml:
<plugins>
<plugin version="1.0">ti.example</plugin>
</plugins>
Add a machine-wide path with CLI configuration:
ti config paths.hooks --append ~/titanium-hooks
A machine-wide hook changes builds for every project on that machine and for nobody else, so a build stops being reproducible from the repository alone. Use the project location unless you specifically want the opposite.
Useful events
| Event | When |
|---|---|
build.pre.construct |
Before the builder is set up |
build.pre.compile |
Before compilation. Where generated code goes |
build.post.compile |
After compilation, before packaging |
build.finalize |
The build is done |
cli:pre-execute |
Before any command runs |
cli:post-execute |
After it finishes |
The build events carry the builder, which is where tiapp, the project
directory and the resolved options are. Read it rather than re-parsing
tiapp.xml.
Platform builders emit their own more specific events too. --debug prints the
events as they fire, which is the practical way to find the one you want.
Alloy's own hook file
For work tied to Alloy's compile rather than the CLI's build, app/alloy.jmk
is simpler and does not need a plugin. See
Alloy configuration.
Keep them cheap
A hook runs on every build, including the rebuild you do twenty times an hour.
Anything slow belongs behind a check that skips it when there is nothing to do,
or in a production-only branch.
Next
Back to building apps, or the CLI reference for the commands these hook into.