Comparing version 5.1.0 to 5.2.0
146
API.md
# API Reference | ||
Most interaction with **vision** is done via the [server](https://github.com/hapijs/hapi/blob/master/API.md#server) | ||
and [reply](https://github.com/hapijs/hapi/blob/master/API.md#reply-interface) interfaces. When the | ||
**vision** plugin is registered, the base [Hapi APIs](https://github.com/hapijs/hapi/blob/master/API.md) | ||
and the `h` response [toolkit](https://github.com/hapijs/hapi/blob/master/API.md#response-toolkit) interfaces. When the | ||
**vision** plugin is registered, the base [hapi APIs](https://github.com/hapijs/hapi/blob/master/API.md) | ||
are augmented as follows: | ||
- [Server](#server) | ||
- [`server.views(options)`](#serverviewsoptions) | ||
- [`server.render(template, context, [options], [callback])`](#serverrendertemplate-context-options-callback) | ||
- [`server.views(options)`](#serverviewsoptions) | ||
- [`server.render(template, context, [options], [callback])`](#serverrendertemplate-context-options-callback) | ||
- [Requests](#requests) | ||
- [`request.render(template, context, [options], [callback])`](#requestrendertemplate-context-options-callback) | ||
- [The `view` handler](#the-view-handler) | ||
- [Reply interface](#reply-interface) | ||
- [`reply.view(template, [context, [options]])`](#replyviewtemplate-context-options) | ||
- [`request.render(template, context, [options], [callback])`](#requestrendertemplate-context-options-callback) | ||
- [The `view` handler](#the-view-handler) | ||
- [`h` response toolkit interface](#response-toolkit-interface) | ||
- [`h.view(template, [context], [options]])`](#hviewtemplate-context-options) | ||
- [View Manager](#view-manager) | ||
- [`manager.registerHelper(name, helper)`](#managerregisterhelpername-helper) | ||
- [`manager.render(template, context, options, callback)`](#managerrendertemplate-context-options-callback) | ||
- [`manager.registerHelper(name, helper)`](#managerregisterhelpername-helper) | ||
- [`manager.render(template, context, options, callback)`](#managerrendertemplate-context-options-callback) | ||
@@ -51,2 +51,5 @@ ## [Server](https://github.com/hapijs/hapi/blob/master/API.md#server) | ||
defaults for a specific engine. | ||
- `compileMode` - specify whether the engine `compile()` method is `'sync'` or `'async'`. | ||
Defaults to `'sync'`. | ||
- `defaultExtension` - defines the default filename extension to append to template names when | ||
@@ -56,3 +59,3 @@ multiple engines are configured and not explicit extension is provided for a given template. | ||
- `path` - the root file path, or array of file paths, used to resolve and load the templates identified when calling | ||
[`reply.view()`](https://github.com/hapijs/hapi/blob/master/API.md#replyviewtemplate-context-options). | ||
[`h.view()`](#hviewtemplate-context-options). | ||
Defaults to current working directory. | ||
@@ -67,3 +70,3 @@ - `partialsPath` - the root file path, or array of file paths, where partials are located. Partials are small segments | ||
`function(context)` and return a string. Sub-folders are not supported and are ignored. | ||
Defaults to no helpers support (empty path). Note that jade does not support loading helpers | ||
Defaults to no helpers support (empty path). Note that pug does not support loading helpers | ||
this way. | ||
@@ -86,6 +89,6 @@ - `relativeTo` - a base path used as prefix for `path` and `partialsPath`. No default. | ||
- `allowAbsolutePaths` - if set to `true`, allows absolute template paths passed to | ||
[`reply.view()`](https://github.com/hapijs/hapi/blob/master/API.md#replyviewtemplate-context-options). | ||
[`h.view()`](#hviewtemplate-context-options). | ||
Defaults to `false`. | ||
- `allowInsecureAccess` - if set to `true`, allows template paths passed to | ||
[`reply.view()`](https://github.com/hapijs/hapi/blob/master/API.md#replyviewtemplate-context-options) | ||
[`h.view()`](#hviewtemplate-context-options) | ||
to contain '../'. Defaults to `false`. | ||
@@ -97,17 +100,13 @@ - `compileOptions` - options object passed to the engine's compile function. Defaults to empty | ||
- `contentType` - the content type of the engine results. Defaults to `'text/html'`. | ||
- `compileMode` - specify whether the engine `compile()` method is `'sync'` or `'async'`. | ||
Defaults to `'sync'`. | ||
- `context` - a global context used with all templates. The global context option can be either | ||
an object or a function that takes the [`request`](https://github.com/hapijs/hapi/blob/master/API.md#request-properties) | ||
as its only argument and returns a context object. The | ||
[`request`](https://github.com/hapijs/hapi/blob/master/API.md#request-properties) object is only provided when using | ||
the [view handler](#the-view-handler) or [`reply.view()`](#replyviewtemplate-context-options). When using | ||
an object or a function that takes the [`request`](https://github.com/hapijs/hapi/blob/master/API.md#request) | ||
as its only argument and returns a context object. The [`request`](https://github.com/hapijs/hapi/blob/master/API.md#request) object is only provided when using | ||
the [view handler](#the-view-handler) or [`h.view()`](#hviewtemplate-context-options). When using | ||
[`server.render()`](#serverrendertemplate-context-options-callback) or | ||
[`request.render()`](#requestrendertemplate-context-options-callback), the | ||
[`request`](https://github.com/hapijs/hapi/blob/master/API.md#request-properties) argument will be `null`. When rendering | ||
[`request.render()`](#requestrendertemplate-context-options-callback), the [`request`](https://github.com/hapijs/hapi/blob/master/API.md#request) argument will be `null`. When rendering | ||
views, the global context will be merged with any context object specified on the handler or using | ||
[`reply.view()`](#replyviewtemplate-context-options). When multiple context objects are used, values from the global | ||
[`h.view()`](#hviewtemplate-context-options). When multiple context objects are used, values from the global | ||
context always have lowest precedence. | ||
When [`server.views()`](https://github.com/hapijs/hapi/blob/master/API.md#serverviewsoptions) is called within a | ||
When [`server.views()`](#serverviewsoptions) is called within a | ||
plugin, the views manager is only available to [plugins](https://github.com/hapijs/hapi/blob/master/API.md#plugins) | ||
@@ -126,3 +125,3 @@ methods. | ||
- `options` - optional object used to override the views manager configuration. | ||
- `callback` - the callback function with signature `function (err, rendered, config)` where: | ||
- callback - the callback function with signature function (err, rendered, config) where: | ||
- `err` - the rendering error if any. | ||
@@ -133,15 +132,14 @@ - `rendered` - the result view string. | ||
If no `callback` is provided, a `Promise` object is returned. The returned promise is resolved with only the | ||
rendered content an not the configuration object. | ||
rendered content and not the configuration object. | ||
```js | ||
const Hapi = require('hapi'); | ||
const server = new Hapi.Server(); | ||
server.connection({ port: 80 }); | ||
const server = Hapi.Server({ port: 3000 }); | ||
server.register(require('vision'), (err) => { | ||
const internals = {}; | ||
if (err) { | ||
throw err; | ||
} | ||
internals.provision = async () => { | ||
await server.register(require('vision')); | ||
server.views({ | ||
@@ -157,7 +155,6 @@ engines: { html: require('handlebars') }, | ||
server.render('hello', context, (err, rendered, config) => { | ||
return server.render('hello', context); | ||
}; | ||
console.log(rendered); | ||
}); | ||
}); | ||
internals.provision(); | ||
``` | ||
@@ -169,10 +166,10 @@ | ||
`request.render()` works the same way as [`server.render()`](#serverrendertemplate-context-options-callback) | ||
[`request.render()`](#requestrendertemplate-context-options-callback) works the same way as [`server.render()`](#serverrendertemplate-context-options-callback) | ||
but is for use inside of request handlers. [`server.render()`](#serverrendertemplate-context-options-callback) | ||
does not work inside request handlers when called via `request.server.render()` if the view manager was created | ||
by a plugin. This is because the `request.server` object does not have access to the plugin realm where the | ||
view manager was configured. `request.render()` gets its realm from the route that the request was bound to. | ||
view manager was configured. [`request.render()`](#requestrendertemplate-context-options-callback) gets its realm from the route that the request was bound to. | ||
Note that this will not work in `onRequest` extensions added by the plugin because the route isn't yet set at | ||
this point in the request lifecycle and the `request.render()` method will produce the same limited results | ||
this point in the request lifecycle and the [`request.render()`](#requestrendertemplate-context-options-callback) method will produce the same limited results | ||
[`server.render()`](#serverrendertemplate-context-options-callback) can. | ||
@@ -182,11 +179,10 @@ | ||
const Hapi = require('hapi'); | ||
const server = new Hapi.Server(); | ||
server.connection({ port: 80 }); | ||
const server = Hapi.Server({ port: 3000 }); | ||
server.register(require('vision'), (err) => { | ||
const internals = {}; | ||
if (err) { | ||
throw err; | ||
} | ||
internals.provision = async () => { | ||
await server.register(require('vision')); | ||
server.views({ | ||
@@ -200,14 +196,13 @@ engines: { html: require('handlebars') }, | ||
path: '/view', | ||
handler: function (request, reply) { | ||
handler: function (request, h) { | ||
request.render('test', { message: 'hello' }, (err, rendered, config) => { | ||
return reply(rendered); | ||
}); | ||
return request.render('test', { message: 'hello' }); | ||
} | ||
}); | ||
}); | ||
}; | ||
internals.provision(); | ||
``` | ||
### The `view` handler | ||
## The `view` [handler](https://github.com/hapijs/hapi/blob/master/API.md#serverdecoratetype-property-method-options) | ||
@@ -229,3 +224,3 @@ The `view` handler can be used with routes registered in the same realm as the view manager. The | ||
The rendering `context` contains the `params`, `payload`, `query`, and `pre` values from the | ||
[request](https://github.com/hapijs/hapi/blob/master/API.md#request-properties) by default (these | ||
[request](https://github.com/hapijs/hapi/blob/master/API.md#request) by default (these | ||
can be overriden by values explicitly set via the `options`). | ||
@@ -235,11 +230,10 @@ | ||
const Hapi = require('hapi'); | ||
const server = new Hapi.Server(); | ||
server.connection({ port: 80 }); | ||
const server = Hapi.Server({ port: 3000 }); | ||
server.register(require('vision'), (err) => { | ||
const internals = {}; | ||
if (err) { | ||
throw err; | ||
} | ||
internals.provision = async () => { | ||
await server.register(require('vision')); | ||
server.views({ | ||
@@ -263,10 +257,12 @@ engines: { html: require('handlebars') }, | ||
}); | ||
}); | ||
}; | ||
internals.provision(); | ||
``` | ||
## [Reply Interface](https://github.com/hapijs/hapi/blob/master/API.md#reply-interface) | ||
## [Response Toolkit Interface](https://github.com/hapijs/hapi/blob/master/API.md#response-toolkit) | ||
### `reply.view(template, [context, [options]])` | ||
### `h.view(template, [context, [options]])` | ||
Concludes the handler activity by returning control over to the router with a templatized view | ||
Uses the response [toolkit](https://github.com/hapijs/hapi/blob/master/API.md#response-toolkit) interface by means of returning control over to the router with a templatized view | ||
response where: | ||
@@ -285,15 +281,14 @@ | ||
The [response flow control rules](https://github.com/hapijs/hapi/blob/master/API.md#flow-control) apply. | ||
The same [lifecycle workflow](https://github.com/hapijs/hapi/blob/master/API.md#lifecycle-workflow) applies. | ||
```js | ||
const Hapi = require('hapi'); | ||
const server = new Hapi.Server(); | ||
server.connection({ port: 80 }); | ||
const server = Hapi.Server({ port: 3000 }); | ||
server.register(require('vision'), (err) => { | ||
const internals = {}; | ||
if (err) { | ||
throw err; | ||
} | ||
internals.provision = async () => { | ||
await server.register(require('vision')); | ||
server.views({ | ||
@@ -304,3 +299,3 @@ engines: { html: require('handlebars') }, | ||
const handler = function (request, reply) { | ||
const rootHandler = function (request, h) { | ||
@@ -312,7 +307,9 @@ const context = { | ||
return reply.view('hello', context); | ||
return h.view('hello', context); | ||
}; | ||
server.route({ method: 'GET', path: '/', handler: handler }); | ||
}); | ||
server.route({ method: 'GET', path: '/', handler: rootHandler }); | ||
}; | ||
internals.provision(); | ||
``` | ||
@@ -323,3 +320,2 @@ | ||
```html | ||
<!DOCTYPE html> | ||
<html> | ||
@@ -326,0 +322,0 @@ <head> |
@@ -12,53 +12,48 @@ 'use strict'; | ||
module.exports = class Pages { | ||
internals.Pages = function (dirPath) { | ||
constructor(dirPath) { | ||
this._dirPath = dirPath; | ||
this._cache = {}; | ||
this.loadPagesIntoCache(); | ||
}; | ||
this._dirPath = dirPath; | ||
this._cache = {}; | ||
this.loadPagesIntoCache(); | ||
} | ||
loadPagesIntoCache() { | ||
internals.Pages.prototype.loadPagesIntoCache = function () { | ||
const self = this; | ||
Fs.readdirSync(this._dirPath).forEach((file) => { | ||
const self = this; | ||
Fs.readdirSync(this._dirPath).forEach((file) => { | ||
if (file[0] !== '.') { | ||
self._cache[file] = self.loadPageFile(file); | ||
} | ||
}); | ||
} | ||
if (file[0] !== '.') { | ||
self._cache[file] = self.loadPageFile(file); | ||
} | ||
}); | ||
}; | ||
getAll() { | ||
return this._cache; | ||
} | ||
internals.Pages.prototype.getAll = function () { | ||
getPage(name) { | ||
return this._cache; | ||
}; | ||
return this._cache[name]; | ||
} | ||
savePage(name, contents) { | ||
internals.Pages.prototype.getPage = function (name) { | ||
const pageName = Path.normalize(name); | ||
Fs.writeFileSync(Path.join(this._dirPath, pageName), contents); | ||
this._cache[pageName] = { pageName, contents }; | ||
} | ||
return this._cache[name]; | ||
}; | ||
loadPageFile(file) { | ||
const contents = Fs.readFileSync(Path.join(this._dirPath, file)); | ||
internals.Pages.prototype.savePage = function (name, contents) { | ||
name = Path.normalize(name); | ||
Fs.writeFileSync(Path.join(this._dirPath, name), contents); | ||
this._cache[name] = { name, contents }; | ||
return { | ||
name: file, | ||
contents: contents.toString() | ||
}; | ||
} | ||
}; | ||
internals.Pages.prototype.loadPageFile = function (file) { | ||
const contents = Fs.readFileSync(Path.join(this._dirPath, file)); | ||
return { | ||
name: file, | ||
contents: contents.toString() | ||
}; | ||
}; | ||
exports = module.exports = new internals.Pages(Path.join(__dirname, '_pages')); |
@@ -6,2 +6,4 @@ 'use strict'; | ||
const Vision = require('../..'); | ||
const Path = require('path'); | ||
const Ejs = require('ejs'); | ||
@@ -11,10 +13,18 @@ | ||
const internals = {}; | ||
const internals = { | ||
templatePath: 'withLayout' | ||
}; | ||
const today = new Date(); | ||
internals.thisYear = today.getFullYear(); | ||
const rootHandler = function (request, reply) { | ||
reply.view('index', { | ||
title: 'examples/views/ejs/layout.js | Hapi ' + request.server.version, | ||
message: 'Index - Hello World!' | ||
const rootHandler = (request, h) => { | ||
const relativePath = Path.relative(`${__dirname}/../..`, `${__dirname}/templates/${internals.templatePath}`); | ||
return h.view('index', { | ||
title: `Running ${relativePath} | Hapi ${request.server.version}`, | ||
message: 'Hello Ejs Layout!', | ||
year: internals.thisYear | ||
}); | ||
@@ -24,29 +34,19 @@ }; | ||
internals.main = function () { | ||
internals.main = async () => { | ||
const server = new Hapi.Server(); | ||
server.connection({ port: 8000 }); | ||
server.register(Vision, (err) => { | ||
const server = Hapi.Server({ port: 3000 }); | ||
if (err) { | ||
throw err; | ||
} | ||
await server.register(Vision); | ||
server.views({ | ||
engines: { ejs: require('ejs') }, | ||
relativeTo: __dirname, | ||
path: 'templates/withLayout', | ||
layout: true | ||
}); | ||
server.views({ | ||
engines: { ejs: Ejs }, | ||
relativeTo: __dirname, | ||
path: `templates/${internals.templatePath}`, | ||
layout: true | ||
}); | ||
server.route({ method: 'GET', path: '/', handler: rootHandler }); | ||
server.start((err) => { | ||
server.route({ method: 'GET', path: '/', handler: rootHandler }); | ||
if (err) { | ||
throw err; | ||
} | ||
console.log('Server is running at ' + server.info.uri); | ||
}); | ||
}); | ||
await server.start(); | ||
console.log('Server is running at ' + server.info.uri); | ||
}; | ||
@@ -53,0 +53,0 @@ |
@@ -6,2 +6,4 @@ 'use strict'; | ||
const Vision = require('../..'); | ||
const Path = require('path'); | ||
const Handlebars = require('handlebars'); | ||
@@ -11,10 +13,20 @@ | ||
const internals = {}; | ||
const internals = { | ||
templatePath: 'withHelpers' | ||
}; | ||
const today = new Date(); | ||
internals.thisYear = today.getFullYear(); | ||
const handler = function (request, reply) { | ||
reply.view('index', { | ||
title: 'examples/views/handlebars/helpers.js | Hapi ' + request.server.version, | ||
message: 'Hello World!' | ||
const rootHandler = (request, h) => { | ||
const relativePath = Path.relative(`${__dirname}/../..`, `${__dirname}/templates/${internals.templatePath}`); | ||
return h.view('index', { | ||
title: `Running ${relativePath} | Hapi ${request.server.version}`, | ||
message: 'Hello Handlebars Helpers!', | ||
year: internals.thisYear, | ||
min: 0, | ||
max: 50 | ||
}); | ||
@@ -24,29 +36,20 @@ }; | ||
internals.main = function () { | ||
internals.main = async () => { | ||
const server = new Hapi.Server(); | ||
server.connection({ port: 8000 }); | ||
server.register(Vision, (err) => { | ||
const server = Hapi.Server({ port: 3000 }); | ||
if (err) { | ||
throw err; | ||
} | ||
await server.register(Vision); | ||
server.views({ | ||
engines: { html: require('handlebars') }, | ||
relativeTo: __dirname, | ||
path: 'templates/withHelpers', | ||
helpersPath: 'templates/withHelpers/helpers' | ||
}); | ||
server.views({ | ||
engines: { html: Handlebars }, | ||
relativeTo: __dirname, | ||
path: `templates/${internals.templatePath}`, | ||
helpersPath: `templates/${internals.templatePath}/helpers`, | ||
isCached: false | ||
}); | ||
server.route({ method: 'GET', path: '/', handler }); | ||
server.start((err) => { | ||
server.route({ method: 'GET', path: '/', handler: rootHandler }); | ||
if (err) { | ||
throw err; | ||
} | ||
console.log('Server is listening at ' + server.info.uri); | ||
}); | ||
}); | ||
await server.start(); | ||
console.log('Server is running at ' + server.info.uri); | ||
}; | ||
@@ -53,0 +56,0 @@ |
@@ -6,2 +6,4 @@ 'use strict'; | ||
const Vision = require('../..'); | ||
const Path = require('path'); | ||
const Handlebars = require('handlebars'); | ||
@@ -11,10 +13,18 @@ | ||
const internals = {}; | ||
const internals = { | ||
templatePath: 'withLayout' | ||
}; | ||
const today = new Date(); | ||
internals.thisYear = today.getFullYear(); | ||
const handler = function (request, reply) { | ||
reply.view('withLayout/index', { | ||
title: 'examples/views/handlebars/layout.js | Hapi ' + request.server.version, | ||
message: 'Hello World!\n' | ||
const rootHandler = (request, h) => { | ||
const relativePath = Path.relative(`${__dirname}/../..`, `${__dirname}/templates/${internals.templatePath}`); | ||
return h.view('index', { | ||
title: `Running ${relativePath} | Hapi ${request.server.version}`, | ||
message: 'Hello Handlebars Layout!', | ||
year: internals.thisYear | ||
}); | ||
@@ -24,28 +34,20 @@ }; | ||
internals.main = function () { | ||
internals.main = async () => { | ||
const server = new Hapi.Server(); | ||
server.connection({ port: 8000 }); | ||
server.register(Vision, (err) => { | ||
const server = Hapi.Server({ port: 3000 }); | ||
if (err) { | ||
throw err; | ||
} | ||
await server.register(Vision); | ||
server.views({ | ||
engines: { html: require('handlebars') }, | ||
path: __dirname + '/templates', | ||
layout: true | ||
}); | ||
server.views({ | ||
engines: { html: Handlebars }, | ||
relativeTo: __dirname, | ||
path: 'templates/withLayout', | ||
layout: true, | ||
layoutPath: 'templates/withLayout/layouts' | ||
}); | ||
server.route({ method: 'GET', path: '/', handler }); | ||
server.start((err) => { | ||
server.route({ method: 'GET', path: '/', handler: rootHandler }); | ||
if (err) { | ||
throw err; | ||
} | ||
console.log('Server is listening at ' + server.info.uri); | ||
}); | ||
}); | ||
await server.start(); | ||
console.log('Server is running at ' + server.info.uri); | ||
}; | ||
@@ -52,0 +54,0 @@ |
@@ -6,2 +6,4 @@ 'use strict'; | ||
const Vision = require('../..'); | ||
const Path = require('path'); | ||
const Handlebars = require('handlebars'); | ||
@@ -11,10 +13,18 @@ | ||
const internals = {}; | ||
const internals = { | ||
templatePath: 'withPartials' | ||
}; | ||
const today = new Date(); | ||
internals.thisYear = today.getFullYear(); | ||
const handler = function (request, reply) { | ||
reply.view('withPartials/index', { | ||
title: 'examples/views/handlebars/partials.js | Hapi ' + request.server.version, | ||
message: 'Hello World!\n' | ||
const rootHandler = (request, h) => { | ||
const relativePath = Path.relative(`${__dirname}/../..`, `${__dirname}/templates/${internals.templatePath}`); | ||
return h.view('index', { | ||
title: `Running ${relativePath} | Hapi ${request.server.version}`, | ||
message: 'Hello Handlebars Partials!', | ||
year: internals.thisYear | ||
}); | ||
@@ -24,28 +34,20 @@ }; | ||
internals.main = function () { | ||
internals.main = async () => { | ||
const server = new Hapi.Server(); | ||
server.connection({ port: 8000 }); | ||
server.register(Vision, (err) => { | ||
const server = Hapi.Server({ port: 3000 }); | ||
if (err) { | ||
throw err; | ||
} | ||
await server.register(Vision); | ||
server.views({ | ||
engines: { html: require('handlebars') }, | ||
path: __dirname + '/templates', | ||
partialsPath: __dirname + '/templates/withPartials' | ||
}); | ||
server.views({ | ||
engines: { html: Handlebars }, | ||
relativeTo: __dirname, | ||
path: 'templates/withPartials', | ||
partialsPath: 'templates/withPartials/partials', | ||
isCached: false | ||
}); | ||
server.route({ method: 'GET', path: '/', handler }); | ||
server.start((err) => { | ||
server.route({ method: 'GET', path: '/', handler: rootHandler }); | ||
if (err) { | ||
throw err; | ||
} | ||
console.log('Server is listening at ' + server.info.uri); | ||
}); | ||
}); | ||
await server.start(); | ||
console.log('Server is running at ' + server.info.uri); | ||
}; | ||
@@ -52,0 +54,0 @@ |
@@ -6,2 +6,4 @@ 'use strict'; | ||
const Vision = require('../..'); | ||
const Path = require('path'); | ||
const HapiReactViews = require('hapi-react-views'); | ||
@@ -15,18 +17,30 @@ require('babel-core/register')({ | ||
const internals = {}; | ||
const internals = { | ||
templatePath: '.' | ||
}; | ||
const today = new Date(); | ||
internals.thisYear = today.getFullYear(); | ||
const rootHandler = function (request, reply) { | ||
reply.view('index', { | ||
title: 'examples/views/jsx/index.js | Hapi ' + request.server.version, | ||
message: 'Index - Hello World!' | ||
const rootHandler = (request, h) => { | ||
const relativePath = Path.relative(`${__dirname}/../..`, `${__dirname}/templates/${internals.templatePath}`); | ||
return h.view('index', { | ||
title: `Running ${relativePath} | Hapi ${request.server.version}`, | ||
message: 'Hello Jsx!', | ||
year: internals.thisYear | ||
}); | ||
}; | ||
const aboutHandler = function (request, reply) { | ||
reply.view('about', { | ||
title: 'examples/views/jsx/index.js | Hapi ' + request.server.version, | ||
message: 'About - Hello World!' | ||
const aboutHandler = (request, h) => { | ||
const relativePath = Path.relative(`${__dirname}/../..`, `${__dirname}/templates/${internals.templatePath}`); | ||
return h.view('about', { | ||
title: `Running ${relativePath} | Hapi ${request.server.version}`, | ||
message: 'Jsx About Page', | ||
year: internals.thisYear | ||
}); | ||
@@ -36,31 +50,19 @@ }; | ||
internals.main = function () { | ||
internals.main = async () => { | ||
const server = new Hapi.Server(); | ||
server.connection({ port: 8000 }); | ||
server.register(Vision, (err) => { | ||
const server = Hapi.Server({ port: 3000 }); | ||
if (err) { | ||
throw err; | ||
} | ||
await server.register(Vision); | ||
server.views({ | ||
engines: { jsx: require('hapi-react-views') }, | ||
path: __dirname + '/templates', | ||
compileOptions: { | ||
pretty: true | ||
} | ||
}); | ||
server.views({ | ||
engines: { jsx: HapiReactViews }, | ||
relativeTo: __dirname, | ||
path: `templates/${internals.templatePath}` | ||
}); | ||
server.route({ method: 'GET', path: '/', handler: rootHandler }); | ||
server.route({ method: 'GET', path: '/about', handler: aboutHandler }); | ||
server.start((err) => { | ||
server.route({ method: 'GET', path: '/', handler: rootHandler }); | ||
server.route({ method: 'GET', path: '/about', handler: aboutHandler }); | ||
if (err) { | ||
throw err; | ||
} | ||
console.log('Server is listening at ' + server.info.uri); | ||
}); | ||
}); | ||
await server.start(); | ||
console.log('Server is running at ' + server.info.uri); | ||
}; | ||
@@ -67,0 +69,0 @@ |
@@ -1,19 +0,16 @@ | ||
var React = require('react'); | ||
var Head = require('./includes/head.jsx'); | ||
var Foot = require('./includes/foot.jsx'); | ||
const React = require('react'); | ||
var Component = React.createClass({ | ||
render: function() { | ||
return ( | ||
<html> | ||
<Head /> | ||
<body> | ||
{this.props.children} | ||
</body> | ||
<Foot /> | ||
</html> | ||
); | ||
} | ||
}); | ||
const Layout = require('./layout.jsx'); | ||
module.exports = Component; | ||
module.exports = class AboutPageComponent extends React.PureComponent { | ||
render() { | ||
return ( | ||
<Layout year={this.props.year}> | ||
<h1>{this.props.title}</h1> | ||
<p>{this.props.message}</p> | ||
</Layout> | ||
); | ||
} | ||
}; |
@@ -1,13 +0,14 @@ | ||
var React = require('react'); | ||
const React = require('react'); | ||
var Component = React.createClass({ | ||
render: function() { | ||
return ( | ||
<div id="footer"> | ||
<p>hapi.js 203</p> | ||
</div> | ||
); | ||
} | ||
}); | ||
module.exports = class FootComponent extends React.PureComponent { | ||
module.exports = Component; | ||
render() { | ||
return ( | ||
<footer> | ||
Footer component | ||
<p>@ hapi visionaries {this.props.year}</p> | ||
</footer> | ||
); | ||
} | ||
}; |
@@ -1,13 +0,17 @@ | ||
var React = require('react'); | ||
const React = require('react'); | ||
var Component = React.createClass({ | ||
render: function() { | ||
return ( | ||
<head> | ||
<script src='//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js' /> | ||
</head> | ||
); | ||
} | ||
}); | ||
module.exports = class HeadComponent extends React.PureComponent { | ||
module.exports = Component; | ||
render() { | ||
return ( | ||
<header> | ||
<h3>Head component</h3> | ||
<nav> | ||
<a href='/'>Index</a> | ||
<br /> | ||
<a href='/about'>About</a> | ||
</nav> | ||
</header> | ||
); | ||
} | ||
}; |
@@ -1,15 +0,15 @@ | ||
var React = require('react'); | ||
var Layout = require('./layout.jsx'); | ||
const React = require('react'); | ||
const Layout = require('./layout.jsx'); | ||
var Component = React.createClass({ | ||
render: function() { | ||
return ( | ||
<Layout> | ||
<h1>{this.props.title}</h1> | ||
<p>{this.props.message}</p> | ||
</Layout> | ||
); | ||
} | ||
}); | ||
module.exports = class IndexPage extends React.PureComponent { | ||
module.exports = Component; | ||
render() { | ||
return ( | ||
<Layout year={this.props.year}> | ||
<h1>{this.props.title}</h1> | ||
<p>{this.props.message}</p> | ||
</Layout> | ||
); | ||
} | ||
}; |
@@ -1,19 +0,21 @@ | ||
var React = require('react'); | ||
var Head = require('./includes/head.jsx'); | ||
var Foot = require('./includes/foot.jsx'); | ||
const React = require('react'); | ||
const T = require('prop-types'); | ||
var Component = React.createClass({ | ||
render: function() { | ||
return ( | ||
<html> | ||
<Head /> | ||
<body> | ||
{this.props.children} | ||
<Foot /> | ||
</body> | ||
</html> | ||
); | ||
} | ||
}); | ||
const Head = require('./includes/head.jsx'); | ||
const Foot = require('./includes/foot.jsx'); | ||
module.exports = Component; | ||
module.exports = class Layout extends React.PureComponent { | ||
render() { | ||
return ( | ||
<html> | ||
<Head /> | ||
<body> | ||
{this.props.children} | ||
</body> | ||
<Foot year={this.props.year}/> | ||
</html> | ||
); | ||
} | ||
}; |
@@ -5,4 +5,5 @@ 'use strict'; | ||
const Hapi = require('hapi'); | ||
const Vision = require('../..'); | ||
const Path = require('path'); | ||
const Marko = require('marko'); | ||
const Vision = require('../..'); | ||
@@ -12,54 +13,53 @@ | ||
const internals = {}; | ||
const internals = { | ||
templatePath: '.' | ||
}; | ||
const today = new Date(); | ||
internals.thisYear = today.getFullYear(); | ||
const handler = function (request, reply) { | ||
reply.view('index', { | ||
title: 'examples/views/marko/basic.js | Hapi ' + request.server.version, | ||
message: 'Hello World!' | ||
const rootHandler = (request, h) => { | ||
const relativePath = Path.relative(`${__dirname}/../..`, `${__dirname}/templates/${internals.templatePath}`); | ||
return h.view('index', { | ||
title: `Running ${relativePath} | Hapi ${request.server.version}`, | ||
message: 'Hello Marko!', | ||
year: internals.thisYear | ||
}); | ||
}; | ||
internals.main = async () => { | ||
internals.main = function () { | ||
const server = Hapi.Server({ port: 3000 }); | ||
const server = new Hapi.Server(); | ||
server.connection({ port: 8000 }); | ||
server.register(Vision, (err) => { | ||
await server.register(Vision); | ||
if (err) { | ||
throw err; | ||
} | ||
server.views({ | ||
engines: { | ||
marko: { | ||
compile: (src, options) => { | ||
server.views({ | ||
engines: { | ||
html: { | ||
compile: function (src, options) { | ||
const opts = { preserveWhitespace: true, writeToDisk: false }; | ||
const template = Marko.load(options.filename, src); | ||
const template = Marko.load(options.filename, opts); | ||
return function (context) { | ||
return (context) => { | ||
return template.renderSync(context); | ||
}; | ||
} | ||
return template.renderToString(context); | ||
}; | ||
} | ||
}, | ||
path: __dirname + '/templates' | ||
}); | ||
} | ||
}, | ||
relativeTo: __dirname, | ||
path: `templates/${internals.templatePath}` | ||
}); | ||
server.route({ method: 'GET', path: '/', handler }); | ||
server.start((err) => { | ||
server.route({ method: 'GET', path: '/', handler: rootHandler }); | ||
if (err) { | ||
throw err; | ||
} | ||
console.log('Server is listening at ' + server.info.uri); | ||
}); | ||
}); | ||
await server.start(); | ||
console.log('Server is running at ' + server.info.uri); | ||
}; | ||
internals.main(); |
@@ -6,59 +6,60 @@ 'use strict'; | ||
const Vision = require('../..'); | ||
const Path = require('path'); | ||
const Handlebars = require('handlebars'); | ||
const Pug = require('pug'); | ||
// Declare internals | ||
const internals = {}; | ||
const internals = { | ||
templatePath: '.' | ||
}; | ||
const today = new Date(); | ||
internals.thisYear = today.getFullYear(); | ||
const indexHandler = function (request, reply) { | ||
reply.view('index.html'); | ||
const indexHandler = (request, h) => { | ||
return h.view('index.html'); | ||
}; | ||
const oneHandler = function (request, reply) { | ||
const oneHandler = (request, h) => { | ||
reply.view('index.jade'); | ||
return h.view('index.pug'); | ||
}; | ||
const twoHandler = function (request, reply) { | ||
const twoHandler = (request, h) => { | ||
reply.view('handlebars.html'); | ||
return h.view('handlebars.html'); | ||
}; | ||
internals.main = function () { | ||
internals.main = async () => { | ||
const server = new Hapi.Server(); | ||
server.connection({ port: 8000 }); | ||
server.register(Vision, (err) => { | ||
const server = Hapi.Server({ port: 3000 }); | ||
if (err) { | ||
throw err; | ||
} | ||
await server.register(Vision); | ||
server.views({ | ||
engines: { | ||
'html': require('handlebars'), | ||
'jade': require('jade') | ||
}, | ||
path: __dirname + '/templates', | ||
context: { | ||
title: 'examples/views/mixed | Hapi ' + server.version, | ||
message: 'Hello World!' | ||
} | ||
}); | ||
const relativePath = Path.relative(`${__dirname}/../..`, `${__dirname}/templates/${internals.templatePath}`); | ||
server.route({ method: 'GET', path: '/', handler: indexHandler }); | ||
server.route({ method: 'GET', path: '/one', handler: oneHandler }); | ||
server.route({ method: 'GET', path: '/two', handler: twoHandler }); | ||
server.start((err) => { | ||
server.views({ | ||
engines: { | ||
'html': Handlebars, | ||
'pug': Pug | ||
}, | ||
relativeTo: __dirname, | ||
path: `templates/${internals.templatePath}`, | ||
context: { | ||
title: `Running ${relativePath} | Hapi ${server.version}`, | ||
message: 'Hello Mixed Engines!', | ||
year: internals.thisYear | ||
} | ||
}); | ||
if (err) { | ||
throw err; | ||
} | ||
server.route({ method: 'GET', path: '/', handler: indexHandler }); | ||
server.route({ method: 'GET', path: '/one', handler: oneHandler }); | ||
server.route({ method: 'GET', path: '/two', handler: twoHandler }); | ||
console.log('Server is listening at ' + server.info.uri); | ||
}); | ||
}); | ||
await server.start(); | ||
console.log('Server is running at ' + server.info.uri); | ||
}; | ||
@@ -65,0 +66,0 @@ |
@@ -5,4 +5,5 @@ 'use strict'; | ||
const Hapi = require('hapi'); | ||
const Vision = require('../..'); | ||
const Path = require('path'); | ||
const Mustache = require('mustache'); | ||
const Vision = require('../..'); | ||
@@ -12,10 +13,18 @@ | ||
const internals = {}; | ||
const internals = { | ||
templatePath: 'withLayout' | ||
}; | ||
const today = new Date(); | ||
internals.thisYear = today.getFullYear(); | ||
const rootHandler = function (request, reply) { | ||
reply.view('index', { | ||
title: 'examples/views/mustache/layout.js | Hapi ' + request.server.version, | ||
message: 'Index - Hello World!' | ||
const rootHandler = (request, h) => { | ||
const relativePath = Path.relative(`${__dirname}/../..`, `${__dirname}/templates/${internals.templatePath}`); | ||
return h.view('index', { | ||
title: `Running ${relativePath} | Hapi ${request.server.version}`, | ||
message: 'Hello Mustache Layout!', | ||
year: internals.thisYear | ||
}); | ||
@@ -25,41 +34,31 @@ }; | ||
internals.main = function () { | ||
internals.main = async () => { | ||
const server = new Hapi.Server(); | ||
server.connection({ port: 8000 }); | ||
server.register(Vision, (err) => { | ||
const server = Hapi.Server({ port: 3000 }); | ||
if (err) { | ||
throw err; | ||
} | ||
await server.register(Vision); | ||
server.views({ | ||
engines: { | ||
html: { | ||
compile: function (template) { | ||
server.views({ | ||
engines: { | ||
html: { | ||
compile: function (template) { | ||
Mustache.parse(template); | ||
Mustache.parse(template); | ||
return function (context) { | ||
return function (context) { | ||
return Mustache.render(template, context); | ||
}; | ||
} | ||
return Mustache.render(template, context); | ||
}; | ||
} | ||
}, | ||
relativeTo: __dirname, | ||
path: 'templates/withLayout', | ||
layout: true | ||
}); | ||
} | ||
}, | ||
relativeTo: __dirname, | ||
path: `templates/${internals.templatePath}`, | ||
layout: true | ||
}); | ||
server.route({ method: 'GET', path: '/', handler: rootHandler }); | ||
server.start((err) => { | ||
server.route({ method: 'GET', path: '/', handler: rootHandler }); | ||
if (err) { | ||
throw err; | ||
} | ||
console.log('Server is listening at ' + server.info.uri); | ||
}); | ||
}); | ||
await server.start(); | ||
console.log('Server is running at ' + server.info.uri); | ||
}; | ||
@@ -66,0 +65,0 @@ |
@@ -5,4 +5,5 @@ 'use strict'; | ||
const Hapi = require('hapi'); | ||
const Vision = require('../..'); | ||
const Path = require('path'); | ||
const Mustache = require('mustache'); | ||
const Vision = require('../..'); | ||
@@ -12,10 +13,18 @@ | ||
const internals = {}; | ||
const internals = { | ||
templatePath: 'withPartials' | ||
}; | ||
const today = new Date(); | ||
internals.thisYear = today.getFullYear(); | ||
const rootHandler = function (request, reply) { | ||
reply.view('index', { | ||
title: 'examples/views/mustache/partials.js | Hapi ' + request.server.version, | ||
message: 'Index - Hello World!' | ||
const rootHandler = (request, h) => { | ||
const relativePath = Path.relative(`${__dirname}/../..`, `${__dirname}/templates/${internals.templatePath}`); | ||
return h.view('index', { | ||
title: `Running ${relativePath} | Hapi ${request.server.version}`, | ||
message: 'Hello Mustache Partials!', | ||
year: internals.thisYear | ||
}); | ||
@@ -25,48 +34,38 @@ }; | ||
internals.main = function () { | ||
internals.main = async () => { | ||
const server = new Hapi.Server(); | ||
server.connection({ port: 8000 }); | ||
server.register(Vision, (err) => { | ||
const server = Hapi.Server({ port: 3000 }); | ||
if (err) { | ||
throw err; | ||
} | ||
await server.register(Vision); | ||
const partials = {}; | ||
const partials = {}; | ||
server.views({ | ||
engines: { | ||
html: { | ||
compile: function (template) { | ||
server.views({ | ||
engines: { | ||
html: { | ||
compile: function (template) { | ||
Mustache.parse(template); | ||
Mustache.parse(template); | ||
return function (context) { | ||
return function (context) { | ||
return Mustache.render(template, context, partials); | ||
}; | ||
}, | ||
return Mustache.render(template, context, partials); | ||
}; | ||
}, | ||
registerPartial: function (name, src) { | ||
registerPartial: function (name, src) { | ||
partials[name] = src; | ||
} | ||
partials[name] = src; | ||
} | ||
}, | ||
relativeTo: __dirname, | ||
path: 'templates/withPartials', | ||
partialsPath: 'templates/withPartials/partials' | ||
}); | ||
} | ||
}, | ||
relativeTo: __dirname, | ||
path: `templates/${internals.templatePath}`, | ||
partialsPath: `templates/${internals.templatePath}/partials` | ||
}); | ||
server.route({ method: 'GET', path: '/', handler: rootHandler }); | ||
server.start((err) => { | ||
server.route({ method: 'GET', path: '/', handler: rootHandler }); | ||
if (err) { | ||
throw err; | ||
} | ||
console.log('Server is listening at ' + server.info.uri); | ||
}); | ||
}); | ||
await server.start(); | ||
console.log('Server is running at ' + server.info.uri); | ||
}; | ||
@@ -73,0 +72,0 @@ |
@@ -5,5 +5,5 @@ 'use strict'; | ||
const Hapi = require('hapi'); | ||
const Vision = require('../..'); | ||
const Path = require('path'); | ||
const Nunjucks = require('nunjucks'); | ||
const Path = require('path'); | ||
const Vision = require('../..'); | ||
@@ -13,10 +13,18 @@ | ||
const internals = {}; | ||
const internals = { | ||
templatePath: '.' | ||
}; | ||
const today = new Date(); | ||
internals.thisYear = today.getFullYear(); | ||
const rootHandler = function (request, reply) { | ||
reply.view('index', { | ||
title: 'examples/views/nunjucks/index.js | Hapi ' + request.server.version, | ||
message: 'Index - Hello World!' | ||
const rootHandler = (request, h) => { | ||
const relativePath = Path.relative(`${__dirname}/../..`, `${__dirname}/templates/${internals.templatePath}`); | ||
return h.view('index', { | ||
title: `Running ${relativePath} | Hapi ${request.server.version}`, | ||
message: 'Hello Nunjucks!', | ||
year: internals.thisYear | ||
}); | ||
@@ -26,45 +34,35 @@ }; | ||
internals.main = function () { | ||
internals.main = async () => { | ||
const server = new Hapi.Server(); | ||
server.connection({ port: 8000 }); | ||
server.register(Vision, (err) => { | ||
const server = Hapi.Server({ port: 3000 }); | ||
if (err) { | ||
throw err; | ||
} | ||
await server.register(Vision); | ||
server.views({ | ||
engines: { | ||
html: { | ||
compile: function (src, options) { | ||
server.views({ | ||
engines: { | ||
html: { | ||
compile: (src, options) => { | ||
const template = Nunjucks.compile(src, options.environment); | ||
const template = Nunjucks.compile(src, options.environment); | ||
return function (context) { | ||
return (context) => { | ||
return template.render(context); | ||
}; | ||
}, | ||
return template.render(context); | ||
}; | ||
}, | ||
prepare: function (options, next) { | ||
prepare: (options, next) => { | ||
options.compileOptions.environment = Nunjucks.configure(options.path, { watch: false }); | ||
return next(); | ||
} | ||
options.compileOptions.environment = Nunjucks.configure(options.path, { watch: false }); | ||
return next(); | ||
} | ||
}, | ||
path: Path.join(__dirname, 'templates') | ||
}); | ||
} | ||
}, | ||
path: `${__dirname}/templates` | ||
}); | ||
server.route({ method: 'GET', path: '/', handler: rootHandler }); | ||
server.start((err) => { | ||
server.route({ method: 'GET', path: '/', handler: rootHandler }); | ||
if (err) { | ||
throw err; | ||
} | ||
console.log('Server is listening at ' + server.info.uri); | ||
}); | ||
}); | ||
await server.start(); | ||
console.log('Server is running at ' + server.info.uri); | ||
}; | ||
@@ -71,0 +69,0 @@ |
'use strict'; | ||
// Load modules | ||
@@ -7,2 +6,4 @@ | ||
const Vision = require('../..'); | ||
const Path = require('path'); | ||
const Pug = require('pug'); | ||
@@ -12,51 +13,37 @@ | ||
const internals = {}; | ||
const internals = { | ||
templatePath: '.' | ||
}; | ||
const today = new Date(); | ||
internals.thisYear = today.getFullYear(); | ||
const rootHandler = function (request, reply) { | ||
reply.view('index', { | ||
title: 'examples/views/pug/index.js | Hapi ' + request.server.version, | ||
message: 'Index - Hello World!' | ||
}); | ||
}; | ||
const rootHandler = (request, h) => { | ||
const aboutHandler = function (request, reply) { | ||
const relativePath = Path.relative(`${__dirname}/../..`, `${__dirname}/templates/${internals.templatePath}`); | ||
reply.view('about', { | ||
title: 'examples/views/pug/index.js | Hapi ' + request.server.version, | ||
message: 'About - Hello World!' | ||
return h.view('index', { | ||
title: `Running ${relativePath} | Hapi ${request.server.version}`, | ||
message: 'Hello Pug!', | ||
year: internals.thisYear | ||
}); | ||
}; | ||
internals.main = async () => { | ||
internals.main = function () { | ||
const server = Hapi.Server({ port: 3000 }); | ||
const server = new Hapi.Server(); | ||
server.connection({ port: 8000 }); | ||
server.register(Vision, (err) => { | ||
await server.register(Vision); | ||
if (err) { | ||
throw err; | ||
} | ||
server.views({ | ||
engines: { pug: Pug }, | ||
relativeTo: __dirname, | ||
path: `templates/${internals.templatePath}` | ||
}); | ||
server.views({ | ||
engines: { pug: require('pug') }, | ||
path: __dirname + '/templates', | ||
compileOptions: { | ||
pretty: true | ||
} | ||
}); | ||
server.route({ method: 'GET', path: '/', handler: rootHandler }); | ||
server.route({ method: 'GET', path: '/', handler: rootHandler }); | ||
server.route({ method: 'GET', path: '/about', handler: aboutHandler }); | ||
server.start((err) => { | ||
if (err) { | ||
throw err; | ||
} | ||
console.log('Server is listening at ' + server.info.uri); | ||
}); | ||
}); | ||
await server.start(); | ||
console.log('Server is running at ' + server.info.uri); | ||
}; | ||
@@ -63,0 +50,0 @@ |
@@ -257,2 +257,6 @@ 'use strict'; | ||
try { | ||
if (!engine.config.isCached) { | ||
delete require.cache[require.resolve(file)]; // bust require's cache | ||
} | ||
const helper = require(file); | ||
@@ -379,2 +383,7 @@ if (typeof helper === 'function') { | ||
if (!engine.config.isCached) { | ||
this._loadPartials(engine); | ||
this._loadHelpers(engine); | ||
} | ||
this._compile(templatePath, engine, compiled.settings, (err, compiledTemplate) => { | ||
@@ -542,3 +551,3 @@ | ||
settings.compileOptions.filename = template; // Pass the template to Jade via this copy of compileOptions | ||
settings.compileOptions.filename = template; // Pass the template to Pug via this copy of compileOptions | ||
@@ -545,0 +554,0 @@ // Read file |
{ | ||
"name": "vision", | ||
"description": "Templates rendering plugin support for hapi.js", | ||
"version": "5.1.0", | ||
"version": "5.2.0", | ||
"repository": "git://github.com/hapijs/vision", | ||
@@ -16,2 +16,8 @@ "main": "lib/index.js", | ||
}, | ||
"scripts": { | ||
"test": "lab -a code -t 100 -L", | ||
"test-cov-html": "lab -a code -r html -o coverage.html", | ||
"coveralls": "lab -r lcov | coveralls", | ||
"lint": "lab -L -d" | ||
}, | ||
"dependencies": { | ||
@@ -27,3 +33,3 @@ "boom": "7.x.x", | ||
"devDependencies": { | ||
"babel-core": "6.x.x", | ||
"babel-core": "^6.26.0", | ||
"babel-plugin-transform-react-jsx": "6.x.x", | ||
@@ -35,17 +41,12 @@ "code": "5.x.x", | ||
"hapi": "17.x.x", | ||
"hapi-react-views": "6.x.x", | ||
"hapi-react-views": "10.x.x", | ||
"lab": "15.x.x", | ||
"marko": "3.x.x", | ||
"mustache": "2.x.x", | ||
"marko": "4.x.x", | ||
"mustache": ">=2.2.1", | ||
"nunjucks": "2.x.0", | ||
"pug": ">=2.0.0-beta6", | ||
"react": "0.14.x", | ||
"react-dom": "0.14.x" | ||
"react": "^16.1.0", | ||
"react-dom": "^16.0.0" | ||
}, | ||
"scripts": { | ||
"test": "lab -a code -t 100 -L", | ||
"test-cov-html": "lab -a code -r html -o coverage.html", | ||
"coveralls": "lab -r lcov | coveralls" | ||
}, | ||
"license": "BSD-3-Clause" | ||
} |
313
README.md
@@ -10,37 +10,73 @@ # vision | ||
**vision** decorates the [server](https://github.com/hapijs/hapi/blob/master/API.md#server), | ||
[request](https://github.com/hapijs/hapi/blob/master/API.md#request-object), and | ||
[reply](https://github.com/hapijs/hapi/blob/master/API.md#reply-interface) interfaces with additional | ||
methods for managing view engines that can be used to render templated responses. **vision** also | ||
provides a built-in [handler](https://github.com/hapijs/hapi/blob/master/API.md#serverhandlername-method) | ||
implementation for creating templated responses. | ||
[request](https://github.com/hapijs/hapi/blob/master/API.md#request), and | ||
`h` response [toolkit](https://github.com/hapijs/hapi/blob/master/API.md#response-toolkit) interfaces with additional | ||
methods for managing view engines that can be used to render templated responses. | ||
**You will need to install `vision` using something like `npm install --save vision` before you can register it.** | ||
**vision** also provides a built-in [handler](https://github.com/hapijs/hapi/blob/master/API.md#-serverdecoratetype-property-method-options) implementation for creating templated responses. | ||
## Usage | ||
> See also the [API Reference](./API.md) | ||
```js | ||
const server = new Hapi.Server(); | ||
server.connection({ port: 8080 }); | ||
const Hapi = require('hapi'); | ||
const Vision = require('vision'); | ||
server.register(require('vision'), (err) => { | ||
const server = Hapi.Server({ port: 3000 }); | ||
if (err) { | ||
console.log("Failed to load vision."); | ||
} | ||
}); | ||
const provision = async () => { | ||
await server.register(Vision); | ||
await server.start(); | ||
console.log('Server running at:', server.info.uri); | ||
}; | ||
provision(); | ||
``` | ||
**NOTE:** Vision is included with and loaded by default in Hapi < 9.0. | ||
- [Examples](#examples) | ||
- [EJS](#ejs) | ||
- [Handlebars](#handlebars) | ||
- [Jade](#jade) | ||
- [Mustache](#mustache) | ||
- [Nunjucks](#nunjucks) | ||
### Note: | ||
- Vision `5.x.x` requires hapi `17.x.x`. For use with hapi `16.x.x`, use vision `4.x.x`. | ||
- Vision is included with and loaded by default in Hapi < `9.0`. | ||
See [API.md](./API.md) for detailed usage information. | ||
## Examples | ||
The examples in the `examples` folder can be run with `node`. | ||
``` | ||
git clone https://github.com/hapijs/vision.git && cd vision | ||
npm install | ||
node examples/handlebars | ||
``` | ||
:point_up: That command will run the handlebars basic template. | ||
There are three more examples in there: for helpers, layout, and partials. | ||
Use this hierarchy to know which commands to run, e.g. | ||
``` | ||
node examples/mustache | ||
node examples/mustache/partials | ||
node examples/jsx | ||
``` | ||
``` | ||
- cms // A bare-bones Content Management System with a WYSIWYG editor | ||
- ejs | ||
- layout | ||
- handlebars | ||
- helpers | ||
- layout | ||
- partials | ||
- jsx // React server-side rendering | ||
- marko | ||
- mixed // Using multiple render engines (handlebars and pug) | ||
- mustache | ||
- layout | ||
- partials | ||
- nunjucks | ||
- pug | ||
``` | ||
**vision** is compatible with most major templating engines out of the box. Engines that don't follow | ||
the normal API pattern can still be used by mapping their API to the **vision** API. Working code for | ||
the following examples can be found in the [examples directory](./examples). | ||
the normal API pattern can still be used by mapping their API to the [**vision** API](./API.md). Some of the examples below use the `compile` and `prepare` methods which are part of the API. | ||
@@ -50,97 +86,154 @@ ### EJS | ||
```js | ||
const server = new Hapi.Server(); | ||
server.connection({ port: 8000 }); | ||
const Hapi = require('hapi'); | ||
const Vision = require('vision'); | ||
const Ejs = require('ejs'); | ||
const rootHandler = function (request, reply) { | ||
const server = Hapi.Server({ port: 3000 }); | ||
reply.view('index', { | ||
title: 'examples/views/ejs/index.js | Hapi ' + request.server.version, | ||
message: 'Index - Hello World!' | ||
const rootHandler = (request, h) => { | ||
return h.view('index', { | ||
title: 'examples/ejs/templates/basic | Hapi ' + request.server.version, | ||
message: 'Hello Ejs!' | ||
}); | ||
}; | ||
server.register(require('vision'), (err) => { | ||
const provision = async () => { | ||
if (err) { | ||
throw err; | ||
} | ||
await server.register(Vision); | ||
server.views({ | ||
engines: { ejs: require('ejs') }, | ||
engines: { ejs: Ejs }, | ||
relativeTo: __dirname, | ||
path: 'templates' | ||
path: 'examples/ejs/templates/basic' | ||
}); | ||
server.route({ method: 'GET', path: '/', handler: rootHandler }); | ||
}); | ||
await server.start(); | ||
console.log('Server running at:', server.info.uri); | ||
}; | ||
provision(); | ||
``` | ||
### Handlebars | ||
```js | ||
const server = new Hapi.Server(); | ||
server.connection({ port: 8000 }); | ||
const Hapi = require('hapi'); | ||
const Vision = require('vision'); | ||
const Handlebars = require('handlebars'); | ||
const handler = function (request, reply) { | ||
const server = Hapi.Server({ port: 3000 }); | ||
reply.view('basic/index', { | ||
title: 'examples/views/handlebars/basic.js | Hapi ' + request.server.version, | ||
message: 'Hello World!' | ||
const rootHandler = (request, h) => { | ||
return h.view('index', { | ||
title: 'examples/handlebars/templates/basic | Hapi ' + request.server.version, | ||
message: 'Hello Handlebars!' | ||
}); | ||
}; | ||
server.register(require('vision'), (err) => { | ||
const provision = async () => { | ||
if (err) { | ||
throw err; | ||
} | ||
await server.register(Vision); | ||
server.views({ | ||
engines: { html: require('handlebars') }, | ||
path: __dirname + '/templates' | ||
engines: { html: Handlebars }, | ||
relativeTo: __dirname, | ||
path: 'examples/handlebars/templates/basic' | ||
}); | ||
server.route({ method: 'GET', path: '/', handler: handler }); | ||
}); | ||
server.route({ method: 'GET', path: '/', handler: rootHandler }); | ||
await server.start(); | ||
console.log('Server running at:', server.info.uri); | ||
}; | ||
provision(); | ||
``` | ||
### Jade | ||
### Pug | ||
```js | ||
const server = new Hapi.Server(); | ||
server.connection({ port: 8000 }); | ||
const Hapi = require('hapi'); | ||
const Vision = require('vision'); | ||
const Pug = require('pug'); | ||
const rootHandler = function (request, reply) { | ||
const server = Hapi.Server({ port: 3000 }); | ||
reply.view('index', { | ||
title: 'examples/views/jade/index.js | Hapi ' + request.server.version, | ||
message: 'Index - Hello World!' | ||
const rootHandler = (request, h) => { | ||
return h.view('index', { | ||
title: 'examples/pug/templates | Hapi ' + request.server.version, | ||
message: 'Hello Pug!' | ||
}); | ||
}; | ||
const aboutHandler = function (request, reply) { | ||
const provision = async () => { | ||
reply.view('about', { | ||
title: 'examples/views/jade/index.js | Hapi ' + request.server.version, | ||
message: 'About - Hello World!' | ||
await server.register(Vision); | ||
server.views({ | ||
engines: { pug: Pug }, | ||
relativeTo: __dirname, | ||
path: 'examples/pug/templates' | ||
}); | ||
server.route({ method: 'GET', path: '/', handler: rootHandler }); | ||
await server.start(); | ||
console.log('Server running at:', server.info.uri); | ||
}; | ||
server.register(require('vision'), (err) => { | ||
provision(); | ||
``` | ||
if (err) { | ||
throw err; | ||
} | ||
### Marko | ||
```js | ||
const Hapi = require('hapi'); | ||
const Vision = require('vision'); | ||
const Marko = require('marko'); | ||
const server = Hapi.Server({ port: 3000 }); | ||
const rootHandler = (request, h) => { | ||
return h.view('index', { | ||
title: 'examples/marko/templates | Hapi ' + request.server.version, | ||
message: 'Hello Marko!' | ||
}); | ||
}; | ||
const provision = async () => { | ||
await server.register(Vision); | ||
server.views({ | ||
engines: { jade: require('jade') }, | ||
path: __dirname + '/templates', | ||
compileOptions: { | ||
pretty: true | ||
} | ||
engines: { | ||
marko: { | ||
compile: (src, options) => { | ||
const opts = { preserveWhitespace: true, writeToDisk: false }; | ||
const template = Marko.load(options.filename, opts); | ||
return (context) => { | ||
return template.renderToString(context); | ||
}; | ||
} | ||
} | ||
}, | ||
relativeTo: __dirname, | ||
path: 'examples/marko/templates' | ||
}); | ||
server.route({ method: 'GET', path: '/', handler: rootHandler }); | ||
server.route({ method: 'GET', path: '/about', handler: aboutHandler }); | ||
}); | ||
await server.start(); | ||
console.log('Server running at:', server.info.uri); | ||
}; | ||
provision(); | ||
``` | ||
@@ -151,18 +244,19 @@ | ||
```js | ||
const server = new Hapi.Server(); | ||
server.connection({ port: 8000 }); | ||
const Hapi = require('hapi'); | ||
const Vision = require('vision'); | ||
const Mustache = require('mustache'); | ||
const rootHandler = function (request, reply) { | ||
const server = Hapi.Server({ port: 3000 }); | ||
reply.view('index', { | ||
title: 'examples/views/mustache/index.js | Hapi ' + request.server.version, | ||
message: 'Index - Hello World!' | ||
const rootHandler = (request, h) => { | ||
return h.view('index', { | ||
title: 'examples/mustache/templates/basic | Hapi ' + request.server.version, | ||
message: 'Hello Mustache!' | ||
}); | ||
}; | ||
server.register(require('vision'), (err) => { | ||
const provision = async () => { | ||
if (err) { | ||
throw err; | ||
} | ||
await server.register(Vision); | ||
@@ -172,7 +266,7 @@ server.views({ | ||
html: { | ||
compile: function (template) { | ||
compile: (template) => { | ||
Mustache.parse(template); | ||
return function (context) { | ||
return (context) => { | ||
@@ -185,7 +279,12 @@ return Mustache.render(template, context); | ||
relativeTo: __dirname, | ||
path: 'templates' | ||
path: 'examples/mustache/templates/basic' | ||
}); | ||
server.route({ method: 'GET', path: '/', handler: rootHandler }); | ||
}); | ||
await server.start(); | ||
console.log('Server running at:', server.info.uri); | ||
}; | ||
provision(); | ||
``` | ||
@@ -196,18 +295,19 @@ | ||
```js | ||
const server = new Hapi.Server(); | ||
server.connection({ port: 8000 }); | ||
const Hapi = require('hapi'); | ||
const Vision = require('vision'); | ||
const Nunjucks = require('nunjucks'); | ||
const rootHandler = function (request, reply) { | ||
const server = Hapi.Server({ port: 3000 }); | ||
reply.view('index', { | ||
title: 'examples/views/nunjucks/index.js | Hapi ' + request.server.version, | ||
message: 'Index - Hello World!' | ||
const rootHandler = (request, h) => { | ||
return h.view('index', { | ||
title: 'examples/nunjucks/templates | Hapi ' + request.server.version, | ||
message: 'Hello Nunjucks!' | ||
}); | ||
}; | ||
server.register(require('vision'), (err) => { | ||
const provision = async () => { | ||
if (err) { | ||
throw err; | ||
} | ||
await server.register(Vision); | ||
@@ -217,7 +317,7 @@ server.views({ | ||
html: { | ||
compile: function (src, options) { | ||
compile: (src, options) => { | ||
var template = Nunjucks.compile(src, options.environment); | ||
const template = Nunjucks.compile(src, options.environment); | ||
return function (context) { | ||
return (context) => { | ||
@@ -228,5 +328,6 @@ return template.render(context); | ||
prepare: function (options, next) { | ||
prepare: (options, next) => { | ||
options.compileOptions.environment = Nunjucks.configure(options.path, { watch : false }); | ||
return next(); | ||
@@ -236,7 +337,13 @@ } | ||
}, | ||
path: Path.join(__dirname, 'templates') | ||
relativeTo: __dirname, | ||
path: 'examples/nunjucks/templates' | ||
}); | ||
server.route({ method: 'GET', path: '/', handler: rootHandler }); | ||
}); | ||
await server.start(); | ||
console.log('Server running at:', server.info.uri); | ||
}; | ||
provision(); | ||
``` |
@@ -75,3 +75,3 @@ 'use strict'; | ||
const pre = function (request, reply) { | ||
const pre = function (request, h) { | ||
@@ -227,5 +227,5 @@ return 'PreHello'; | ||
method: 'GET', | ||
handler: function (request, reply) { | ||
handler: function (request, h) { | ||
return reply.view('test', { message: 'steve' }); | ||
return h.view('test', { message: 'steve' }); | ||
} | ||
@@ -457,10 +457,10 @@ }); | ||
server.route({ path: '/view', method: 'GET', handler: (request, reply) => reply.view('test', { message: options.message }) }); | ||
server.ext('onRequest', (request, reply) => { | ||
server.route({ path: '/view', method: 'GET', handler: (request, h) => h.view('test', { message: options.message }) }); | ||
server.ext('onRequest', (request, h) => { | ||
if (request.path === '/ext') { | ||
return reply.view('test', { message: 'grabbed' }).takeover(); | ||
return h.view('test', { message: 'grabbed' }).takeover(); | ||
} | ||
return reply.continue; | ||
return h.continue; | ||
}); | ||
@@ -493,3 +493,3 @@ } | ||
server.route({ path: '/view', method: 'GET', handler: (request, reply) => reply.view('test', { message: 'steve' }) }); | ||
server.route({ path: '/view', method: 'GET', handler: (request, h) => h.view('test', { message: 'steve' }) }); | ||
} | ||
@@ -516,3 +516,3 @@ }; | ||
method: 'GET', | ||
handler: (request, reply) => reply.view('test', { message: options.message }) | ||
handler: (request, h) => h.view('test', { message: options.message }) | ||
}); | ||
@@ -519,0 +519,0 @@ } |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
169514
109
3147
341
0
6