Express: Template Engine in-depth study

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 rendermethod 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, enginestwo 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:

  1. views: Where is the template file in default under the project root directory. for example:app.set('views', './views')
  2. view engine: What template engine, for example:app.set('view engine', 'jade')

You can see, the default is jadeto do template. If you do not want to jadehow 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

jadeCompared, the , nunjunksrequirements are met. More accustomed to personal nunjunksstyle, 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 tmplof 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 viewsset of directory), or an absolute path;
  • If there is no declaration file suffix, places view enginesetting 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

  1. Determine the path of the template
  2. According scalable template determines which rendering engine adopted
  3. Load rendering engine

Repeated calls to render () method, if cache === falsethen 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, optionsit will be passed as a parameter this.engine(this.path, options, callback). That is, the rendering engine (for example jade) will read options.cachethis configuration. According to options.cachethe value of internal rendering engine may also be buffered operation. (Such is true, jadeafter 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: cacheaffect 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:

  1. index.jade: Load Enginejade
  2. 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

Guess you like

Origin www.cnblogs.com/chyingp/p/express-render-engine.html