-
Notifications
You must be signed in to change notification settings - Fork 4
Creating a Simple Source Bundle & Compiling it
In this tutorial we are going to create a source JBB Bundle (.jbbsrc) with some simple resources and then use gulp-jbb
to compile it into a binary bundle. We are also going to create a profile-loader
for the simple profile we created in the Encoding & Decoding User Objects tutorial, in order to load such objects from file.
You will need Node.js 3.0 installed. Then you will need to install a few more packages:
npm install jbb gulp gulp-jbb
You should also get the profile-encode.js
, profile-decode.js
and specs.yaml
from the previous tutorial.
Before we can start working in our source bundle we will need to make sure that the compiler is aware of how to load the resources we are going to specify. For this purpose we are going to create a profile-loader
, that completes the profile we defined in the previous tutorial.
The boilerplate code for the profile-loader.js
is the following:
module.exports = {
// Initialize
initialize: function( callback, specs ) {
callback();
},
// Load an object based on given specs
'load': function( loadClass, loadSpecs, name, callback ) {
}
}
It's quite straightforward: The initialize
function is called once the source bundle specifications are loaded and load
is called every time the compiler needs to load a resource. We are going to work on the load
function.
The arguments of this function are the following:
-
loadClass
(string) : The name of the resource class the user requested. -
loadSpecs
(any) : The specifications passed to the loader class by the user. -
name
(string) : The name of the resource in the bundle. -
callback
(function) : Afunction( string error, object objects )
that should be called by the loader when the resource is ready.
For example, in our simple profile we have two objects: Objects.User
and Objects.Color
. Therefore the load function should look something like this:
module.exports = {
// Load an object based on given specs
'load': function( loadClass, loadSpecs, name, callback ) {
if (loadClass == "Objects.User") {
// Load a user
} else if (loadClass == "Objects.Color") {
// Load a color
}
}
}
The loadSpecs
property can be a string, and object or an array, depending on what the user passed. Usually it's a string and is the URL to the file that contains the object. For our example, we are going to load the object fields from simple JSON files. Like the following:
{
"name": "Bob",
"age": 42,
"color": [ 128, 128, 255 ]
}
We are going to use fs.readFile
to load our file and JSON.parse
to parse it:
fs.readFile( loadSpecs, function(err, data) {
if (err) {
callback(err, null);
return;
}
// Parse JSON
var data = JSON.parse(data);
});
Then we are going to create the object instance and prepare it for storing it in the bundle. Since a load
function can populate an arbitrary number of resources in the bundle we start by creating an object that will carry all the new objects:
var objects = {};
The property name
provide us with the hint for the name of the resource. Usually we are just creating a key with the given name were we store our object, but some other kind of loader might use this as a prefix (for instance name+'/texture'
, name+'/mesh'
etc).
objects[name] = new Objects.User(
data['name'], data['age'],
new Objects.Color(
data['color'][0],
data['color'][1],
data['color'][2]
)
);
We will then call the callback
function to let JBB compiler know that we are ready.
callback( null, objects );
Finally, we must return true
in the code branches that we have handled the user's request to let the compiler know that our profile supports this type:
'load': function( loadClass, loadSpecs, name, callback ) {
if (loadClass == "Objects.User") {
// Load a user
fs.readFile( loadSpecs, function(err, data) {
if (err) {
callback(err, null);
return;
}
// Parse JSON
var data = JSON.parse(data);
// Create object
var objects = {};
objects[name] = new Objects.User(
data['name'], data['age'],
new Objects.Color(
data['color'][0],
data['color'][1],
data['color'][2]
)
);
// Call back
callback( null, objects );
return true;
});
} else if (loadClass == "Objects.Color") {
// Load a color
fs.readFile( loadSpecs, function(err, data) {
if (err) {
callback(err, null);
return;
}
// Parse JSON
var data = JSON.parse(data);
// Create object
var objects = {};
objects[name] = new Objects.Color(
data['color'][0],
data['color'][1],
data['color'][2]
);
// Call back
callback( null, objects );
return true;
});
}
}
The source bundle is a directory that contains all of our resources and an index file called bundle.json
. Let's start by creating our 'users' bundle:
~$ mkdir users.jbbsrc
Also create a new file called bundle.json
inside the folder with the following contents:
{
"name": "users",
"exports": {
}
}
The bare minimum requirements for a source bundle is the name
of the bundle and an exports
section were we are going to define the resources this bundle exports. You can refer to the bundle.json Reference if you want more information regarding the syntax of this file.
The exports
section has the following general:
"exports": {
"<Loader Class>": {
"<Resrouce Name>": <Loader Specs>,
...
}
}
According to the profile-loader
we created in the previous step we have two loader classes: Objects.User
and Objects.Color
that use the path to the file as loader specifications. This means that in order to load two users from the file we will specify:
{
"name": "users",
"exports": {
"Objects.User": {
"mike": "mike.json",
"bob": "bob.json"
}
}
}
The files mike.json
and bob.json
must be located in the bundle directory and their path is relevant to the folder. So let's create them:
For bob.json
:
{
"name": "Bob Doe",
"age": 46,
"color": [ 170, 187, 204 ]
}
For mike.json
:
{
"name": "Mike Johanson",
"age": 36,
"color": [ 19, 255, 69 ]
}
And now we are ready to compile our bundle.
To compile the bundle we are going to use the gulp-jbb
plug-in for gulp. This way it's very easy to integrate this process to your existing build process.
Let's start by creating the following gulpfile.js
:
var gulp = require('gulp');
var jbb = require('gulp-jbb');
// Compile source bundle
gulp.task('default', function() {
return gulp
.src([ "users.jbbsrc" ])
.pipe(jbb({
profile: "."
}))
.pipe(gulp.dest('.'));
});
The profile
option in the jbb()
pipe instructs JBB to use the profile from our working directory. The profile is the directory were the profile-encode
, profile-decode
and profile-load
scripts are located.
We can now compile our source bundle using gulp
:
~$ gulp
[10:51:40] Using gulpfile ~/gulpfile.js
[10:51:40] Starting 'default'...
[10:51:40] Finished 'default' after 53 ms
~$ ls
-rwxr-xr-x 1 user staff 136B Jun 6 10:45 users.jbb