Vain is a view-first middleware and simplistic templating engine for Node.js / Express
applications. Inspired by the Lift Framework, vain gives you the building
blocks for a clean separation between view concerns and logic concerns. Using vain, you can register
some sets of functions to certain names, such as "page-title", then use
data-vain attributes in
your markup to invoke the function on that HTML element and its children.
If you want to see it in action, you can look at the code in my vain-test repository. Check out app.js for the good stuff.
Vain is ideally integrated by using the vain router. The vain router will search for HTML files in your views
folder that matches the path the user is trying to access. If one is found, it will run the HTML template through
vain and send the output to the browser. So, for example, if the user is trying to access the URL "/admin/users"
and you configured the vain router to use "views" as its
viewsFolder, then it will look for the HTML file
"views/admin/users.html" and render it, processing any
data-vain attributes it finds, then return that result
to the client.
Such a configuration would be accomplished by adding the following lines to your app.js in your express app:
You can also use vain in conjunction with another template engine, such as jade! In this configuration, we instruct vain to consider jade files as templates and run them through jade before running them through the regular vain renderer.
After you have vain integrated into your stack, you'll want to register snippets. Some notes on snippets:
thiskeyword is bound to the current element you're rendering.
- They take three arguments:
- A jQuery object
- A hash of parameters, which will consist of any parameters passed in from the markup and
responsewhich are the express request and response objects, respectively.
finishedcallback which should be invoked when the snippet is done doing its thing.
- A jQuery object
So, let's start by registering a snippet named "page-title" that changes the title of a page to something meaningful.
Congrats! That's all that is required to register a snippet with vain. Now, let's look at using it.
Assuming you have integrated vain with your application using one of the options above. Using it is as simple as making a change to your markup. Let's take the following markup:
Now, we want the title tag above to be run against our "page-title" snippet. To do that, all we
need to do is to add a
data-vain attribute with the name of our snippet to the element.
Then, in the response that actually appears to the user we'll get "Welcome to vain." in the page title. You can also pass in parameters to snippets. For example, if you had a snippet that did localization, you may want to pass in the localization key associated with a particular tag.
My Awesome Header
The snippet is able to check its
snippetParameters for the
key value and make decisions about
what to do based on that value. You can also use multiple parameters by using an ampersand.
In the above example the
snippetParameters will contain "2" at "a", "3" at key "b", and 1 at
Vain API Documentation
Vain exposes the following methods:
- registerSnippet(snippetName, snippetFunction) - Register a snippet in the global snippet registry.
- unregisterSnippet(snippetName) - Unregister a global snippet.
- render(input, options, fn) - Render the
input(a string) by finding all data-vain invocations and executing the relevant snippets. The
fncallback will be invoked with the result upon completion. The following elements are supported in
- snippets - An object literal of snippet names to functions that only apply for this render invocation.
- renderFile(path, options, fn) - Exactly the same as render, except that it operates on a file path.
- renderFileWith(preprocessor) - Generates a rendering function that first runs templates through the
preprocessorspecified, then runs them through vain. The
preprocessorabove may be a string name of the module to include or an actual instance of the renderer module that you want to preprocess with.
- router(viewsFolder, viewsExtensions) - The vain router, which will work for any HTML file under your
viewsFolderspecified when you create the router. You can additionally specify what extension(s) should be used for templates. You can specify a single extension as a string or specify multiple extensions with an array. If left unspecified, it will default to just checking for files with an html extension. This should be the last router in the chain.
Who am I?
My name is Matt Farmer. I'm a Software Engineer in Atlanta, GA, hacking on things for Elemica by day, and hacking on my own things for Crazy Goat Creative by night. You can read my thoughts on my blog, Farmdawg Nation, and follow my 140-character mindstream, @farmdawgnation.