Rendering Views
Rendering views turns a logical view name into a filesystem path, selects a template engine, and hands rendering to that engine. The central object is View, whose constructor records the request, loads an engine when needed, and stores the result of a lookup.
The render boundary invokes a view’s render method through tryRender, converting synchronous exceptions into the callback error path. The supplied excerpts do not include the implementations of res.render, app.render, or View.lookup, so this page distinguishes the proven call path from those omitted steps.
Sources: lib/view.js:52-95, lib/application.js:625-631, test/app.render.js:123-135
Core concepts
View instance
A view instance carries the requested name, selected engine, root option, and resolved path. View is imported by the application module and is the constructor shown in the source excerpts.
Sources: lib/view.js:52-95, lib/application.js:18
View name and extension
The view name is first inspected with extname; when it has no extension, defaultEngine supplies one and that extension is appended to the filename.
Sources: lib/view.js:55-73
Template engine
A template engine is the function stored in opts.engines for the selected extension; if it is absent, the constructor loads a module and reads its __express export.
Sources: lib/view.js:75-91
View root and resolved path
The constructor stores opts.root and assigns this.path from this.lookup(fileName), but the supplied excerpt does not show how lookup searches or combines paths.
Sources: lib/view.js:57-58, lib/view.js:93-95
How a view selects its engine and candidate file
The constructor has three observable decisions: preserve an existing extension, derive one from the default engine, or fail when neither is available. The following table summarizes those branches.
| Input condition | Constructor action | Observable result |
|---|---|---|
name already has an extension | Keeps the extension returned by extname | Uses the original name as fileName |
name has no extension and defaultEngine exists | Prefixes defaultEngine with . when necessary and appends it | Produces an extended fileName |
Neither an extension nor defaultEngine exists | Throws an error | Construction stops |
These branches are established directly by the constructor’s extension checks and filename assignment.
The engine registry is extension-based: the constructor checks opts.engines[this.ext], loads the module named by the extension without its leading dot, reads __express, validates that it is a function, caches it back into opts.engines, and stores it as this.engine. The actual filesystem lookup follows that selection through this.lookup(fileName), while tryStat shows that a filesystem-stat helper exists and returns undefined when fs.statSync fails.
This workflow shows only calls visible in the supplied constructor excerpt; the internal search performed by lookup is not shown.
Diagram omitted: missing
Sources: lib/view.js:55-73, lib/view.js:75-91, lib/view.js:93-95, lib/view.js:197-205, lib/view.js:52-95
How rendering hands off to the template engine
The proven application-side hand-off is small: tryRender calls view.render(options, callback) inside a try block, then calls callback(err) if that invocation throws. This means the callback is the error boundary around the view’s rendering method, but the supplied source does not show the implementation of that method or the engine’s eventual invocation.
The tests establish the externally exercised entry points and their configuration, but they do not expose the missing implementation calls between them. The visible call segment is therefore:
Evidence
- render-helperlib/application.js:625
- view-instancelib/application.js:625
- render-callbacklib/application.js:625
Sources: lib/application.js:625-631, test/app.render.js:123-135
How settings change lookup and rendering
The view engine setting supplies the default engine used when a view name has no extension, as demonstrated by tests that configure tmpl, render email, and expect the resulting HTML. The views setting supplies the configured view location in those same tests. The constructor receives these effects through defaultEngine and root, then resolves fileName through lookup.
| Configuration | Shown use | Effect established by the excerpts |
|---|---|---|
view engine | Set to tmpl before rendering email | Enables an extensionless view name to select tmpl |
views | Set to the fixtures directory | Provides the configured view location used by the render test |
view | Set to GithubView | Replaces the view constructor used by the example |
The test demonstrates view engine and views, while the custom-constructor example demonstrates view.
The custom constructor makes the root relationship explicit: its options.root is described as the app’s app.set('views') value, while its path is built from that value and the requested name. This example also registers md with app.engine and selects the engine from options.engines[extname(name)], showing that a custom constructor can use the same extension-to-engine boundary while choosing a different path strategy.
Sources: test/app.render.js:123-135, test/app.render.js:127-130, lib/view.js:55-58, lib/view.js:93-95, examples/view-constructor/index.js:26-30, examples/view-constructor/github-view.js:23-30, examples/view-constructor/index.js:11-24
How it connects
View configuration belongs with App Configuration & Settings, which documents the settings APIs that provide view engine, views, and custom view behavior.
The request-side entry point belongs with App Routing & Request Dispatch, because the supplied render test invokes res.render from an application middleware handler.
View-specific example wiring belongs with Examples: Views & Templating.
Sources: examples/view-constructor/index.js:26-30, test/res.render.js:139-145
Key takeaways
Viewderives an extension fromdefaultEngineonly when the name has none; otherwise construction fails without either value.- The selected extension indexes opts.engines, and a missing engine is loaded through
require(mod).__express. - The constructor stores
rootand delegates final path resolution tolookup; the lookup algorithm is not included in the supplied excerpt. - The proven application render boundary is
tryRendercallingview.render(options, callback)and converting thrown errors into the callback. view engine,views, andvieware demonstrated as separate configuration points.
Sources: lib/view.js:60-73, lib/view.js:75-91, lib/view.js:57-58, lib/view.js:93-95, lib/application.js:625-631, test/app.render.js:123-135, examples/view-constructor/index.js:26-30