node package manager

tilt

Minimalist, ES6 based, developer-friendly web framework for node.

tilt

wip

Minimalist, ES6 based, developer-friendly web framework for node.

Inspired by Play Framework and Sails / Trails, Tilt aims to be a lightweight framework to quickly develop new nodejs application using a set of common tools that works well together.

  • Routers / Controllers tilt-router Standard ES6 Class defines the mapping between URLs pattern and request handlers
  • Views tilt-react-views Views are built using React Components through res.render() method
  • Models Models are ES6 Class that extends tilt.Model to offer a thin abstraction on top of Sequelize.
  • Modular architecture Glob patterns are used to load Controllers, Models and configure directories. Supports multiple Views, assets and static directories allowing any kind of file structure.
  • Asset pipeline tilt-assets implements a basic Asset pipeline for any /assets/*.{js,css} URLs. JS files are compiled down to ES6 using Browserify with Babelify transform. CSS files are processed by PostCSS and autoprefixer plugin.

wip: todo

git clone https://github.com/mklabs/tilt.git
cd tilt

# Run babel / test on source changes
npm run watch

# Start example app
npm start
  • npm start to start the server. It'll run babel once before and use nodemon to restart the server if needed.
  • npm run watch will recompile and relaunch the tests.

The lib/ folder is where sources are, the src/ folder are where generated sources are.

var path = require('path');
var tilt = require('tilt');
 
var app = tilt();
 
app
  // Controllers, default: app/controllers/* 
  .controllers(path.join(__dirname, 'app/controllers/*'))
 
  // Same for models 
  .models(path.join(__dirname, 'app/models/*'))
 
  // Views directories, default: app/views/ (must end with a "/") 
  .views(path.join(__dirname, 'app/views/'))
 
 
  // Static / public directories, default: app/public/ 
  .static(path.join(__dirname, 'app/public/'))
 
  // Assets directories, default: disabled 
  .assets(path.join(__dirname, 'app/assets/'))
 
  // Custom middlewares 
  .use(require('morgan')('dev'));
 
  // Start the server 
  .start(function(err) {
    if (err) throw err;
    console.log('Server started');
  });

app/controllers/main.js

Controllers (or Routers) are standard ES6 Class that inherits from tilt.Controller.

They implement a routes hash that defines the mapping between URLs pattern and class methods / request handlers.

req and res are standard node HTTP request and response.

var Controller = require('tilt').Controller;
 
class Router extends Controller {
  get routes() {
    return {
      '/': 'index'
    };
  }
 
  index(req, res) {
    return res.render('index', { name: 'Title!' });
  }
}
 
module.exports = Router;

app/views/index.jsx

res.render(filename, { ... }) is used to render React components and serve the resulting HTML.

React JSX views are automatically transpiled by Babel when the framework requires them.

import React from 'react';
 
class HelloMessage extends React.Component {
  render() {
    return (<div>Hello {this.props.name}</div>);
  }
}
 
module.exports = HelloMessage;

app/models/user.js

Models inherits from tilt.Model to provide a thin abstraction on top of Sequelize.

Both attributes and options getters maps the sequelize.define('name', {attributes}, {options}) equivalent.

  • attributes Specifiy the Model schema (Model Definition)
  • options Specifiy the Model options

Most of Sequelize Model API is available on tilt.Model instances.

var tilt = require('tilt');
 
class User extends tilt.Model {
  get attributes() {
    return {
      username: tilt.Sequelize.STRING,
      birthday: tilt.Sequelize.DATE
    };
  }
 
  get options() {}
}
 
module.exports = User;

Then used like so:

create(req, res, next) {
  var user = new User({
    username: 'foobar',
    birthday: new Date()
  }, this.db);
 
  user.save()
    .catch(next)
    .then(() => {
      res.end('User saved');
    });
}

Renders 404 html.

request(this.app.server)
  .get('/blah')
  .expect('Content-Type', 'text/html')
  .expect(404)
  .end(done);

Renders homepage.

request(this.app.server)
  .get('/')
  .expect('Content-Type', 'text/html')
  .expect(/Bonjour Title/)
  .end(done);

Renders /home.

request(this.app.server)
  .get('/home')
  .expect(/Response from/)
  .end(done);

Renders 404 html.

request(this.app.server)
  .get('/blah')
  .expect('Content-Type', 'text/html')
  .expect(404)
  .end(done);

Renders homepage.

request(this.app.server)
  .get('/')
  .expect('Content-Type', 'text/html')
  .expect(/Hello Bob/)
  .end(done);

Renders /profile.

request(this.app.server)
  .get('/profile')
  .expect(/Response from profile module/)
  .end(done);

Renders /profile/template.

request(this.app.server)
  .get('/profile/template')
  .expect(/Response from profile module using a React view/)
  .end(done);

Renders /assets/main.js.

request(this.app.server)
  .get('/assets/main.js')
  .expect('Content-Type', 'application/javascript')
  .expect(/classCallCheck/)
  .expect(/return App/)
  .end(done);

Renders /assets/main.css.

request(this.app.server)
  .get('/assets/main.css')
  .expect('Content-Type', 'text/css')
  .expect(/display: flex/)
  .expect(/display: -webkit-box/)
  .end(done);

Defines a sequelize instance.

var User = class extends tilt.Model {
  get attributes() {
    return {
      username: tilt.Sequelize.STRING,
      birthday: tilt.Sequelize.DATE
    };
  }
  get options() {}
}
var user = new User({
  username: 'John Doe',
  birthday: new Date()
}, this.app.db);
assert.ok(user.sequelize);
// Sequelize API 
assert.equal(typeof user.find, 'function');
assert.equal(typeof user.findById, 'function');
``