UNPKG

genji

Version:

Writing reusable, modular and flexible node.js applications made easy.

265 lines (183 loc) 6.99 kB
Site ==== **Site** is the organizer for your applications. And using **Site** is the recommended way to use Genji when you have a large/complex project. It has the following features: - It inherits `EventEmitter` - It has setter/getter methods which can be used to save and retrieve `settings` - It can load and expose your `app` to external world and manage maps between url and app function - It works with [Core](core.html) - the `plugin` system - It works with `view` and renders result by convention - Settings, plugins and apps are all namespaced by `env` A `site` object can be created by calling `genji.site()`: ```javascript var mySite = genji.site(); ``` ## Getter/Setter You can use `mySite` to set and get settings. ```javascript mySite.set('title', 'My Great Website'); // 'My Great Website' var title = mySite.get('title'); // set a batch of settings mySite.set({ host: '127.0.0.1', port: 8888 }); // get a batch of settings var settings = mySite.get(['title', 'host', 'port']); // {title: 'My Great Website', host: '127.0.0.1', port: 8888} ``` ## Use middleware You don't have to initialize [middleware manager](#core.html) by yourself when you use site. You only need to call `use` method of the site instance. ```javascript // use built-in middlewares mySite.use('conditional-get'); mySite.use('logger', conf); // use custom middleware mySite.use(function(core, conf) { // do something }, conf); ``` ## Load app Using app with site is as simple as middleware. But instead of `use` you need to call `load` with app instance. ```javascript var blog = new BlogApp(); mySite.load(blog); // site instance will be setted to app instance's `delegate` property // blog.delegate === mySite ``` If you have a lots of apps which have similar initializing options. Then you can set the default app options and let site initialize them for you. ```javascript var options = {x: 1, y: 2}; mySite.set('appOptions', options); mySite.load(BlogApp); mySite.load(MyOtherApp); ``` The default options could be overridden and inherited. ```javascript var someOptions = {y: 3, z: 2}; // the actual intializing option is {x: 1, y: 3, z: 2} mySite.load(SomeApp, someOptions); // load three apps at once mySite.load([SomeApp1, SomeApp2, SomeApp3], someOptions); ``` ## Routing All methods in the `app.publicMethods` property will be mapped to url by default follows the [convention](app#naming-and-url-mapping). For example, the `blog.createPost` will be mapped to url that matches `^/blog/create/post` by default. Of course, if the default convention/mapping does not meet your needs, you can use the `map` function to map individual url to app method and override the default options. ```javascript mySite.map({ // handle `POST` requests for url '/blog/create/post' blogCreatePost: {method: 'post'} // handle both `GET` and `POST` requests for url '/blog/read/post/:id' blogReadPost: {url: '^/blog/read/post/[0-9]{16}'}, // add hooks blogUpdatePost: {method: 'put', hooks: [preFn1, null, postFn1]} }); ``` If you have predefined routing definition object, you can load it at the same time when loading app. ```javascript var routes = { // it's an app default settings if the property key of the route is one of the app's name (in lower case) blog: {hooks: [fn1, null, fn2], method: 'get', urlRoot: '^/blog/'}, blogReadPost: {url: '^/blog/read/post/[0-9]{16}'}, // a comprehensive route definition blogCreatePost: { url: '/create/post', method: 'post', hooks: [fn3, fn4, null, fn5], view: 'json' // see [Output result](#output-result) } }; mySite.load(AnotherApp, someOptions, routes); ``` The `routes.blog` object holds default settings for all `publicMethods` of `blog` instance. It means if some setting is not specified in route, it will use the default one provided by `routes.blog`. And hooks will be combined. So the final routes of above example normalized by genji would be: ```javascript var routes = { blogReadPost: { url: '^/blog/read/post/[0-9]{16}', method: 'get', hooks: [fn1, null, fn2], view: 'html' // site default value, see [Output result](#output-result) }, // a comprehensive route definition blogCreatePost: { url: '^/blog/create/post', method: 'post', hooks: [fn1, fn3, fn4, null, fn5, fn2], view: 'json' // see [Output result](#output-result) } }; ``` ## Output result We already knew how to map a url to an app's method. Let's see how we can output the result. - Output the result as html string (default): ```javascript blogReadPost: {url: '^/blog/read/post/[0-9]{16}', view: 'html'} ``` - Output the result as json string: ```javascript blogReadPost: {url: '^/blog/read/post/[0-9]{16}', view: 'json'} ``` - Handle result by customized function: ```javascript blogReadPost: {url: '^/blog/read/post/[0-9]{16}', view: function(err, result) { if (err) { this.error(err); return; } this.sendJSON(result); }} ``` When you use genji's `view` system, site can render view template automatically for you. ```javascript var hogan = require('hogan.js'); mySite.use('view', {engine: hogan, rootViewPath: __dirname}); mySite.map({ // render template file at "rootViewPath + /blog/views/read_post.html" blogReadPost: {url: '^/blog/read/post/[0-9]{16}', view: '/blog/views/read_post.html'}, // the default behavior is try to find a template file at "rootViewPath + /blog/update_post.html" if you use the view system blogUpdatePost: {method: 'put'} }); ``` Of course, it's possible to do some tweaks and render manually. ```javascript blogUpdatePost: {method: 'put', view: function(err, result) { result.someValue = 1; // auto template file discovery, render and send this.render(result); // or indicates template view name manually this.render('blog/update_post.html', result); var self = this; // or render and send manually this.render('/path/to/blog/views/update_post.html', result, function (err, html) { self.sendHTML(html); }); }} ``` ## Environment By using `env` you can have different settings, middlewares and apps for different environments. The default environment named `default`. ```javascript // switch to environment "dev" mySite.env('dev'); // the following title and middleware will be used if your 'process.env.NODE_ENV' === 'dev' mySite.set('title', '[DEV] My Great Website'); mySite.use('dev-verbose', 'all'); // the "DevApp" is also only avaliable for "dev" environment mySite.load(DevApp); // switch back to the 'default' environment mySite.env(); // or mySite.env('default') ``` The `dev` environment inherits `default`. It means all settings, middlewares and apps setted before you switched to `dev` are also setted/used/loaded. So when you switched to new environment, `set/use/load` overrides the differences. ## Start your site Start the server is easy ```javascript mySite.start(); ```