In-depth source
First, look express template default configuration.
- view: template engine module, corresponding to require ( './ view'), binding res.render (name) a better understanding of these. The following modules will look view.
- views: template path, the default directory under views.
// default configuration
this.set('view', View);
this.set('views', resolve('views'));
Tencent IVWEB front-end team recruit front-end engineers, more than 2 years of work experience, undergraduate education, interested persons can private letter, leave a message, or mail contact 2377488447 @ qq.com, JD refer here
From examples
From the official scaffold code generated template configuration is as follows:
- views: template files in the directory views;
- view engine: template rendering engine with jade this template;
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
Assuming the following code calls, internal logic is how to achieve?
res.render('index');
res.render(view)
Complete render
method code as follows:
/**
* Render `view` with the given `options` and optional callback `fn`.
* When a callback function is given a response will _not_ be made
* automatically, otherwise a response of _200_ and _text/html_ is given.
*
* Options:
*
* - `cache` boolean hinting to the engine it should cache
* - `filename` filename of the view being rendered
*
* @public
*/
res.render = function render(view, options, callback) {
var app = this.req.app;
var done = callback;
var opts = options || {};
var req = this.req;
var self = this;
// support callback function as second arg
if (typeof options === 'function') {
done = options;
opts = {};
}
// merge res.locals
opts._locals = self.locals;
// default callback to respond
done = done || function (err, str) {
if (err) return req.next(err);
self.send(str);
};
// render
app.render(view, opts, done);
};
The core code one, called app.render (view) this method.
res.render = function (name, options, callback) {
var app = this.req.app;
app.render(view, opts, done);
};
app.render(view)
Complete source code is as follows:
/**
* Render the given view `name` name with `options`
* and a callback accepting an error and the
* rendered template string.
*
* Example:
*
* app.render('email', { name: 'Tobi' }, function(err, html){
* // ...
* })
*
* @param {String} name
* @param {String|Function} options or fn
* @param {Function} callback
* @public
*/
app.render = function render(name, options, callback) {
var cache = this.cache;
var done = callback;
var engines = this.engines;
var opts = options;
var renderOptions = {};
var view;
// support callback function as second arg
if (typeof options === 'function') {
done = options;
opts = {};
}
// merge app.locals
merge(renderOptions, this.locals);
// merge options._locals
if (opts._locals) {
merge(renderOptions, opts._locals);
}
// merge options
merge(renderOptions, opts);
// set .cache unless explicitly provided
if (renderOptions.cache == null) {
renderOptions.cache = this.enabled('view cache');
}
// primed cache
if (renderOptions.cache) {
view = cache[name];
}
// view
if (!view) {
var View = this.get('view');
view = new View(name, {
defaultEngine: this.get('view engine'),
root: this.get('views'),
engines: engines
});
if (!view.path) {
var dirs = Array.isArray(view.root) && view.root.length > 1
? 'directories "' + view.root.slice(0, -1).join('", "') + '" or "' + view.root[view.root.length - 1] + '"'
: 'directory "' + view.root + '"'
var err = new Error('Failed to lookup view "' + name + '" in views ' + dirs);
err.view = view;
return done(err);
}
// prime the cache
if (renderOptions.cache) {
cache[name] = view;
}
}
// render
tryRender(view, renderOptions, done);
};
The beginning of the source code there cache
, engines
two properties, they app.int()
stage initialized.
this.cache = {};
this.engines = {};
View source module
Look at the source code View module:
/**
* Initialize a new `View` with the given `name`.
*
* Options:
*
* - `defaultEngine` the default template engine name
* - `engines` template engine require() cache
* - `root` root path for view lookup
*
* @param {string} name
* @param {object} options
* @public
*/
function View(name, options) {
var opts = options || {};
this.defaultEngine = opts.defaultEngine;
this.ext = extname(name);
this.name = name;
this.root = opts.root;
if (!this.ext && !this.defaultEngine) {
throw new Error('No default engine was specified and no extension was provided.');
}
var fileName = name;
if (!this.ext) {
// get extension from default engine name
this.ext = this.defaultEngine[0] !== '.'
? '.' + this.defaultEngine
: this.defaultEngine;
fileName += this.ext;
}
if (!opts.engines[this.ext]) {
// load engine
opts.engines[this.ext] = require(this.ext.substr(1)).__express;
}
// store loaded engine
this.engine = opts.engines[this.ext];
// lookup path
this.path = this.lookup(fileName);
}
The core concept: the template engine
They are not familiar template engine, and on the introduction express template engine can refer to the official documentation .
The following is mainly about the use of content under allocation, selection and so on.
Optional template engine
Including but not limited to template engine
- jade
- ejs
- dust.js
- dot
- mustache
- handlerbar
- nunjunks
Configuration instructions
Look at the code.
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
There are two configuration on template engine:
views
: Where is the template file in default under the project root directory. for example:app.set('views', './views')
view engine
: What template engine, for example:app.set('view engine', 'jade')
You can see, the default is jade
to do template. If you do not want to jade
how to do it? The following will provide some idea of the selected template engine.
Selection Criteria
We need to consider two things: the actual business needs, personal preferences.
First, consider the business requirements, the following properties need to support.
- Support templates inherit (extend)
- Extended support templates (block)
- Support templates combination (include)
- Support precompiled
jade
Compared, the , nunjunks
requirements are met. More accustomed to personal nunjunks
style, then finalized. So, how to use it?
Support nunjucks
First, install dependencies
npm install --save nunjucks
Then, add the following configuration
var nunjucks = require('nunjucks');
nunjucks.configure('views', {
autoescape: true,
express: app
});
app.set('view engine', 'html');
Lookviews/layout.html
<!DOCTYPE html>
<html>
<head>
<title>
{% block title %}
layout title
{% endblock %}
</title>
</head>
<body>
<h1>
{% block appTitle %}
layout app title
{% endblock %}
</h1>
<p>正文</p>
</body>
</html>
Lookviews/index.html
{% extends "layout.html" %}
{% block title %}首页{% endblock %}
{% block appTitle %}首页{% endblock %}
Develop template engine
By app.engine(engineExt, engineFunc)
registering the template engine. among them
- engineExt: Template file extension. For example
jade
. - engineFunc: template engine core logic definition, a function with three parameters (see below)
// filepath: 模板文件的路径
// options:渲染模板所用的参数
// callback:渲染完成回调
app.engine(engineExt, function(filepath, options, callback){
// 参数一:渲染过程的错误,如成功,则为null
// 参数二:渲染出来的字符串
return callback(null, 'Hello World');
});
For example, the following example, the template engine + registered modify the configuration together, so they can have fun using the suffix tmpl
of the template engine.
app.engine('tmpl', function(filepath, options, callback){
// 参数一:渲染过程的错误,如成功,则为null
// 参数二:渲染出来的字符串
return callback(null, 'Hello World');
});
app.set('views', './views');
app.set('view engine', 'tmpl');
res.render(view [, locals] [, callback])
Parameter Description:
- view: the path of the template.
- locals: object type. Pass in local variables when rendering templates.
- callback: callback function. If the statement, then, when rendering is complete is called, two parameters, namely the error (if an error occurs, then), the rendered string. In this case, response will not be completed automatically. When an error occurs, the inside will automatically call next (err)
view Parameters:
- It may be a relative path (relative to the
views
set of directory), or an absolute path; - If there is no declaration file suffix, places
view engine
setting prevail; - If you declare a file extension, then Express will be based on the file extension, by require () to load the corresponding template engine to render the complete work (rendering to finish by __express method template engine).
locals Parameters:
locals.cache start template cache. In a production environment, the template cache is enabled by default. In the development environment, you can locals.cache set to true to enable template caching by.
example:
// send the rendered view to the client
res.render('index');
// if a callback is specified, the rendered HTML string has to be sent explicitly
res.render('index', function(err, html) {
res.send(html);
});
// pass a local variable to the view
res.render('user', { name: 'Tobi' }, function(err, html) {
// ...
});
About view cache
. The local variable cache enables view caching Set it to true, to cache the view during development; view caching is enabled in production by default.
When the render (view, opt, callback) This method is invoked, the value Express based view of conduct as follows
- Determine the path of the template
- According scalable template determines which rendering engine adopted
- Load rendering engine
Repeated calls to render () method, if cache === false
then the above steps every time to re-do it again; if cache === true
, then the above steps are skipped;
Key Source:
if (renderOptions.cache) {
view = cache[name];
}
In addition, in view.render(options, callback)
years, options
it will be passed as a parameter this.engine(this.path, options, callback)
. That is, the rendering engine (for example jade
) will read options.cache
this configuration. According to options.cache
the value of internal rendering engine may also be buffered operation. (Such is true, jade
after reading the template will be cached, if false, each time re-read from the file system)
View.prototype.render = function render(options, callback) {
debug('render "%s"', this.path);
this.engine(this.path, options, callback);
};
Note: cache
affect the configuration of the rendering engine is uncertain, so the actual need to use a rendering engine, the need to ensure adequate understanding of the rendering engine.
With jade, for example, in the development stage, NODE_ENV !== 'production'
, cahce default is false. So every time a template is read from the file system, and then rendering. Therefore, in the development stage, you can dynamically modify the template content to see the effect.
When NODE_ENV === 'production'
, cache default is true, this case will be the template cache to improve performance.
Hybrid engines use a variety of templates
According to the analysis of the source code, very simple to achieve. Just bring the file extension, Express will load the appropriate template engine according to the extension. such as:
index.jade
: Load Enginejade
index.ejs
: Load Engineejss
// 混合使用多种模板引擎
var express = require('express');
var app = express();
app.get('/index.jade', function (req, res, next) {
res.render('index.jade', {title: 'jade'});
});
app.get('/index.ejs', function (req, res, next) {
res.render('index.ejs', {title: 'ejs'});
});
app.listen(3000);
The same template engine, different file extensions
For example, a template engines jade
, but for some reason, need extensions.tpl
// 同样的模板引擎,不同的扩展名
var express = require('express');
var app = express();
// 模板采用 tpl 扩展名
app.set('view engine', 'tpl');
// 对于以 tpl 扩展名结尾的模板,采用 jade 引擎
app.engine('tpl', require('jade').__express);
app.get('/index', function (req, res, next) {
res.render('index', {title: 'tpl'});
});
app.listen(3000);
Related Links
Using template engines with Express
http://expressjs.com/en/guide/using-template-engines.html
res.render method described
http://expressjs.com/en/4x/api.html#res.render
Tencent IVWEB front-end team recruit front-end engineers, more than 2 years of work experience, undergraduate education, interested persons can private letter, leave a message, or mail contact 2377488447 @ qq.com, JD refer here