expressjs/expressMIT9a34acfReport / request removal

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 conditionConstructor actionObservable result
name already has an extensionKeeps the extension returned by extnameUses the original name as fileName
name has no extension and defaultEngine existsPrefixes defaultEngine with . when necessary and appends itProduces an extended fileName
Neither an extension nor defaultEngine existsThrows an errorConstruction 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:

Known render hand-off — What call is proven immediately before template output returns?

Evidence

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.

ConfigurationShown useEffect established by the excerpts
view engineSet to tmpl before rendering emailEnables an extensionless view name to select tmpl
viewsSet to the fixtures directoryProvides the configured view location used by the render test
viewSet to GithubViewReplaces 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

  • View derives an extension from defaultEngine only 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 root and delegates final path resolution to lookup; the lookup algorithm is not included in the supplied excerpt.
  • The proven application render boundary is tryRender calling view.render(options, callback) and converting thrown errors into the callback.
  • view engine, views, and view are 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

Want this for your repos?

Try Angada AI Wiki