view.json

Intro

First, I'd like to apologize if the number of options here are a bit overwhelming.

I really want great support for seamlessly using the same code in Node and in the browser. This hasn't really been done in other frameworks* so the terminology and options available are new.

Basically, you can do these things:

  • Build a static file with just views and run it in the browser (single file build)
  • Take a source json file and run in in Node (on the fly conversion)
  • Extend a source json file view, and run the result in both Node and in the browser (Node and browser interop)
  • Advanced mode (e.g. manually building and packaging CommonJS files)

(*) A few frameworks like Derby and Meteor have done this, but they use a custom server to share code between Node and the browser, making it impossible to take your views and use them without also running the server. view.json does static file builds which are self-contained static file builds that work anywhere. This means that you don't need Node or a specific server for the views to work. This is mostly based on stuff I learned while working on gluejs, a CommonJS build system I wrote.

Static builds

Single file build (browser)

Compile a view into a view.js file:

viewjson --singlefile /path/to/input.json

This constructs a single file build:

  • includes the runtime in the same file
  • exports the runtime
  • exports each view in input.json file

The single file build can be served to the browser by any server (e.g. nginx, Apache).

Alternatively, you can use .singlefile(filename, options) which does the same thing as the viewjson command but from inside Node.

If you want to do your own packaging, you can use .compile() to generate all the views, and then use a different system for combining them into a package. See "Generating separate view files" below.

On the fly conversion (Node)

This is the recommended way if you want to actually run views inside Node.

Input JSON files are directly converted into JS objects rather than being written to disk and the evaluated from there.

Inside Node, the easiest way to interact with views is to use the on-the-fly conversion:

var AppView = require('view-json').convert('./app.json', 'AppView');

AppView.prototype.foo = function() {
  // ...
};

module.exports = AppView;

Rendering under Node

Under Node, there is one additional complication: we can have more than one active document and more than one global scope, since it would not make much sense to render each view in it's own process.

In essence, it must be possible to sandbox view instances to a particular global environment, consisting of:

  • the event registration function
  • the DOM state
  • the app-specific globals (via resolve())

These are all contained in the runtime.

Extending view prototypes (Node and browser interop)

Compile with extensions:

viewjson --singlefile /path/to/input.json \
 --include /path/to/extensions/ \
 --main /path/to/main

Additionally:

  • each file in extensions is included in the build
  • if the extensions use vjson.convert(__dirname + '/collection.json', 'TodoListView') to fetch, then that works in the result file
  • exports are defined by the main file

Generating separate view files

This is not usually required, since on the fly conversion is much more seamless and guarantees that the view prototypes are up to date.

If you really want to avoid on the fly conversion, you can do the same thing in two steps. First, statically convert the files, using compile rather than convert:

var views = vjson.compile(__dirname + '/collection.json');

views.forEach(function(className, txt) {
  fs.writeFile(__dirname+'/output/'+className+'.js',
    txt + 'module.exports = '+className +';');
});

Note how each view is appended with a module.exports statement.

You can then use the regular require() on each file without invoking on the fly conversion.

Compiler API

.compile(filename, item)
.singlefile(filename, options)
.convert(filename, item)