expressjs/express
View
Active contributors: dougwilson, wesleytodd, ulisesgascon
Purpose
lib/view.js is the smallest meaningful file in lib/: it implements filesystem template lookup and dispatches to a registered template engine. app.render (in lib/application.js) constructs a View and calls view.render(options, callback).
Directory layout
lib/
└── view.js # this file (205 lines)Key abstractions
| Symbol | Type | What it does |
|---|---|---|
View(name, options) |
constructor | Resolves the file extension (defaulting to defaultEngine), loads the engine module if not already cached, and looks up the file path on disk. Throws if no extension and no defaultEngine, or if the engine module does not export __express. |
View.prototype.lookup(name) |
method | Iterates over this.root (string or array of root directories) and returns the first existing file path. |
View.prototype.resolve(dir, file) |
method | For a single root, tries <dir>/<file> then <dir>/<basename>/index<ext>. Both must be regular files (not directories). |
View.prototype.render(options, callback) |
method | Calls this.engine(this.path, options, ...) and normalises sync callbacks to async with process.nextTick. |
tryStat(path) |
private | fs.statSync wrapped in try/catch, returns undefined on error. Used by resolve to avoid throwing when probing paths. |
How it works
graph TD
AppRender[app.render] --> NewView[new View name, opts]
NewView --> Ext{has extension?}
Ext -- yes --> EngineLoad{engines ext loaded?}
Ext -- no --> NeedDefault{defaultEngine?}
NeedDefault -- no --> ThrowErr[throw No default engine]
NeedDefault -- yes --> AddExt[ext = defaultEngine; fileName += ext]
AddExt --> EngineLoad
EngineLoad -- no --> Require[require ext slice 1]
Require --> CheckExpress[require mod __express must be a function]
CheckExpress --> Cache[engines ext = fn]
EngineLoad -- yes --> UseCached[use existing engine]
Cache --> Lookup[view.lookup fileName]
UseCached --> Lookup
Lookup --> Resolve[for each root: resolve dir, file]
Resolve --> SetPath[this.path = first match]
SetPath --> Done[ready to render]view.render itself just ensures the callback is asynchronous, even if the engine calls back synchronously:
View.prototype.render = function render(options, callback) {
var sync = true;
this.engine(this.path, options, function onRender() {
if (!sync) return callback.apply(this, arguments);
var args = new Array(arguments.length);
for (var i = 0; i < arguments.length; i++) args[i] = arguments[i];
var cntx = this;
return process.nextTick(function () {
return callback.apply(cntx, args);
});
});
sync = false;
};This guards against the Zalgo problem (sometimes-async callbacks).
Engine convention
Express expects engines to expose either:
require('engine').__express—(path, options, callback) => callback(err, html)- Or be wrapped via
app.engine(ext, fn)to map an extension to any compatible function.
Most popular template engines either expose __express themselves or are wrapped by @ladjs/consolidate. app.engine('html', require('ejs').renderFile) is the documented escape hatch.
File resolution
View.prototype.resolve(dir, file) checks for the file in two patterns, in order:
<dir>/<file>— direct match.<dir>/<basename(file, ext)>/index<ext>— index-style match for templates organised in folders.
fs.statSync is used (synchronous I/O). This is acceptable because views are typically resolved once per file and then cached on app.cache when the view cache setting is enabled (which is the default in production).
Integration points
- Imports:
debug,node:path,node:fs. - Constructed by:
app.renderinlib/application.js. - Caches: nothing on its own; the cache lives on
app.cacheviaapp.render.
Entry points for modification
- Change template lookup precedence → edit
View.prototype.resolve. - Add support for an alternative engine signature → edit the engine load logic in the constructor (the
__expressrequirement is currently hard-coded for engines auto-loaded by file extension). - Make stat asynchronous → would require API changes; the
view.lookupis currently synchronous and called from insideapp.renderbefore invoking the engine.
Key source files
| File | Purpose |
|---|---|
lib/view.js |
The View constructor and lookup logic |
lib/application.js |
app.engine, app.render, the view cache setting |
lib/response.js |
res.render (a thin wrapper around app.render) |
Related pages
- Application —
app.renderandapp.engine. - Response —
res.render. - Features / Templating — usage-level guide.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.