class DataEntry

Simple class which allows for the non-destructive and prioritized separation of data. The final DataEntry.data is made up of deeply unique components (DataEntry.components) and is rebuilt every time a component changes. This allows for any component to be non-destructively swapped or modified at will.

new DataEntry(
initialData: Record<string, Partial<RenderData>> = {}
): DataEntry

No description.

readonly data: RenderData

No description.

No description.

static DEFAULT_PRIORITY: number

No description.

getComponentData(name: "frontmatter"): Partial<RenderData>

Get the data of a given component.

setComponent(
name: "frontmatter",
data: Partial<RenderData>,
priority?: number
): Partial<RenderData>
setComponent(
name: "global",
data: Partial<RenderData>,
priority?: number
): Partial<RenderData>
setComponent(
name: string,
data: Partial<RenderData>,
priority?: number
): Partial<RenderData>
setComponent(
name: "base",
data: RenderData,
priority?: number
): Partial<RenderData>

Set the data of a component to a deep clone of the given data. This can be used both as an initial data set and a full replace.

Returns The full rebuilt render data (DataEntry.data).

amendComponent(
name: string,
additionalData: {
render: {
draft: boolean,
engine: string,
layout: string,
source: string,
targetURL: string
},

page: {
content: string,
url: string,
staticData: {
render: {
draft: boolean,
engine: string,
layout: string,
source: string,
targetURL: string
},

page: unknown,
$override: unknown,
$propagate: ,
$children: ,
$layouts:
}
}
},

mergeDeep: boolean = false
): Partial<RenderData>

Add a deep clone of the given data to a component. If mergeDeep is set, the data will be merged deeply, otherwise it will be merged shallowly. In both cases, the given data will override any existing conflicting properties. If no component under the given name exists, one is created.

Returns The full rebuilt render data (DataEntry.data).

class DataHandler

No description.

Serve paths mapped to their render data. May not contain all possible serve paths, but those specified in the initial page data are guaranteed to be contained.

No description.

No description.

Page data as supplied by the user without any modifications made.

addGlobal(
propertyName: string,
value: any,
mergeDeep: boolean = false
): void

See also SimpleViewRouter.addGlobalData

getViewDataEntry(pagePath: string): DataEntry

Get the initial render data for the given serve path, i.e. the data of the base file as well as any registered global data but excluding data of potential layouts. Global data is not cloned beforehand.

setViewDataEntry(
pagePath: string,
data: PageDataEntry
): DataEntry

No description.

getLayoutDataEntry(
pagePath: string,
layoutName: string
): DataEntry

No description.

static mergeDeep<T extends any[] | Record<any, any>>(
target: T,
...sources: Array<any[] | Record<any, any>>
): T

Deeply merge multiple object literals or arrays. Behaves like a deep version of ObjectConstructor.assign, i.e. the target object will be modified in place and the priority of given objects follow their parameter order. Arrays will be combined and not deeply merged.

Returns The modified initial target.

See also mergeDeepWithOverride for a version which respects the $override directive.

Remarks

This approach works by filling/merging an empty object with any source properties it does not already have, starting with the last specified source and ending with the first.

Originally adapted from https://stackoverflow.com/a/34749873

static mergeDeepWithOverride<T extends OverridableObject>(
target: T,
...sources: OverridableObject[]
): T

Extension of mergeDeep in which $override properties within given objects will be respected. Any properties within one such property will not be deeply merged with objects of lower priority and will instead be written into the target as-is.

Returns The modified initial target.

static isObjectLiteral(item: any): item

No description.

static resolvePageData(
data: PageDataEntry,
pagePath: string = '/',
propagatedData: object = {},
layoutData: Record<string, PageDataEntry> = {}
): PageDataEntry

Recursively resolves directives of a page data entry. Modifies the data in-place.

static resolveOverride(target: OverridableObject): void

Resolve the $override directive within any object in-place.

class EngineHandler

new EngineHandler(
engineRootPath: string,
markdownOptions?: Options
): EngineHandler

No description.

addFilter(name: string, callback: EngineFilterCallback): void

No description.

registerEngine(
extensions: string[],
engineSetupFn: EngineSetupFn
): void

See also SimpleViewRouter.addEngine

addExtensionAlias(
sourceExtension: string,
aliasExtensions: string[]
): void

See also SimpleViewRouter.addFileExtensionAlias

getEngineExtensionFromFilePath(
filePath: string
): string | undefined

Find the first eligible engine extension from the given file path in a reverse-order loop, i.e. eligible engines registered at a later point in time take priority.

Remarks

This is done in favor of merely getting the file's extension manually to allow for arbitrary extensions such as .myextension.html.

compile(
engineExt: string,
source: string,
filePath: string | undefined
): Promise<RenderCallback>

Get the render callback for the given engine and serve path as returned from the compile callback registered under the given engine.

Parameters

  • engineExt: The extension identifying the used engine as registered via registerEngine.
  • source: The content that shall be rendered.
  • filePath: The absolute path of the file containing the given source, if any.
static checkRequiredLowercase(
extension: string,
scope: string
): void

No description.

static getExtensionWithoutLeadingDot(
extension: string
): string

No description.

class MarkdownEngine

new MarkdownEngine(markdownOptions: Options = {}): MarkdownEngine

Parameters

  • markdownOptions: Options for Markdown-It. No default options will be applied.
md: MarkdownIt

No description.

compile(content: string): () => string

Callback called once on each page each time it needs to be compiled, i.e. each time its source has changed. Returns a (potentially async) callback which is called each time a page's content is requested to be rendered.

This means that the function itself may define a compilation step of the content. The inner function can then use the compilaton result to render the content repeatedly.

See also EngineHandler.registerEngine

static Init(markdownOptions?: Options): MarkdownEngine

No description.

class NunjucksEngine

new NunjucksEngine(rootPath: string): NunjucksEngine

No description.

env: Environment

No description.

addFilter(name: string, callback: EngineFilterCallback): void

Callback used for registering custom filters, given the specific template engine supports it. This callback will be exposed to the generic addFilter method of the public API.

compile(src: string, path?: string): any

Callback called once on each page each time it needs to be compiled, i.e. each time its source has changed. Returns a (potentially async) callback which is called each time a page's content is requested to be rendered.

This means that the function itself may define a compilation step of the content. The inner function can then use the compilaton result to render the content repeatedly.

See also EngineHandler.registerEngine

static Init(_args: SetupData): NunjucksEngine

No description.

class RenderController

new RenderController(
pageData: PageDataEntry,
engineRootPath: string = ...,
markdownOptions?: Options
): RenderController

No description.

getViewURL(pagePath: string): string

Get the final URL of the given page path. The file must have been compiled first for this method to yield a meaningful result.

Get all data entries registered thus far. These may be manipulated at will.

See also DataEntry

getLayoutData(
pagePath: string,
layoutName: string
): RenderData

Inherit doc

SimpleViewRouter.getReadonlyLayoutData

addGlobalData(
name: string,
data: any,
mergeDeep: boolean = false
): void

Inherit doc

SimpleViewRouter.addGlobalData

getEligibleEngineExtension(
filePath: string
): string | undefined

Get the file extension of an engine eligible for handling the given file path. Eligible engines registered at a later point in time take priority.

addFilter<Params extends [name, callback]>(
...args: Params
): void

No description.

addEngine(
extensions: string | string[],
engineSetupFn: EngineSetupFn
): void

See also SimpleViewRouter.addEngine

addFileExtensionAlias(
sourceExtension: string,
aliasExtensions: string[]
): void

No description.

getLayoutNames(pagePath: string): string[]

Get the names of all layouts configured in the data of the given page path, i.e. all layouts which may be used in rendering the page.

hasCompiledView(pagePath: string): boolean

Test if a view under the given page path has already been compiled.

hasCompiledLayout(
pagePath: string,
layoutName: string
): boolean

Test if a layout under the given page path with the given name has already been compiled.

compileView(
pagePath: string,
filePath?: string
): Promise<void>

Compile the page at the given page path, optionally using the content of a given file, and cache the resulting render callback.

Important: This method does not automatically associate a file to the given URL. When the aim is to compile a single view, you probably want to use SimpleViewRouter.buildSingleView instead.

compileLayout(
pagePath: string,
layoutName: string,
filePath?: string
): Promise<void>

Compile the layout at the given page path under the given layout name, optionally using the content of a given file, and cache the resulting render callback.

Important: This method does not automatically associate a file to the given URL. When the aim is to compile a single layout, you probably want to use SimpleViewRouter.buildSingleLayout instead.

renderView(pagePath: string): Promise<string>

Render the page at the given page path. Loops through all required layouts and returns the final rendered content. Both the initial page and all required layouts must have been compiled beforehand (see compileView and compileLayout).

renderSingle(
dataEntry: DataEntry,
renderData: RenderData
): Promise<string | undefined>

Fetch the potential render callback from the cache by the given data entry and call it with the given render data. Returns undefined if nothing was in the cache, in which case the page has not yet been compiled (see compileView and compileLayout).

This method is rather low-level. You probably want to use renderView instead.

class StaticViewRouter extends SimpleViewRouter

Simple wrapper for Polka with a few filesystem-oriented helper functions.

hono: Hono<BlankEnv, BlankSchema, "/">

No description.

logger: Logger

No description.

No description.

watchHandler: WatchHandler

No description.

devMode: boolean

No description.

port: number

No description.

staticPaths: Map<string, string>

Statically served directories, mapped from filesystem path to serve root.

notFoundAliases: Map<string, string>

404 Not Found aliases, mapped from root prefix to the target view's page path.

layoutPathStore: PathStore

No description.

viewPathStore: PathStore

No description.

Total count of all views built through the central build instrastructure, namely buildSingleView (and thus also build).

outDir: string

No description.

No description.

static WATCH_DELAY: 100

No description.

static DEFAULT_PORT: 8000

No description.

static IN_DEV_ENV: boolean

No description.

static DEFAULT_IGNORED_PATTERNS: readonly [
"**/.git/**/*",
"**/.yarn/**/*",
"**/node_modules/**/*",
"**/.git*",
"**/.pnp.*",
"**/.nvmrc",
"**/.npmrc",
"**/.pnpmrc",
"**/.yarnrc.yml",
"**/package.json",
"**/package-lock.json",
"**/yarn.lock",
"**/bun.lock",
"**/pnpm-lock.yaml",
"**/pnpm-workspace.yaml"
]

No description.

start(): Promise<void>

Run all registered modification callbacks, precompile and setup the registered pages, and start a web server on the configured port.

listen(): Promise<AddressInfo>

Start a web server at the configured port.

buildSingleLayout(
pagePath: string,
layoutName: string,
sourceViewFile: string | | undefined = ...
): Promise<any>

Build a specific layout of the given name under the namespace of the given page path. This method is called automatically by buildSingleView for all layouts specified in the view's data.

If there is no prior data for the specified page path, a data entry is registered with the default values (see getReadonlyLayoutData and DataEntry).

(The page path is the URL as configured through the file system and page data, ignoring any potential target URL remap.)

Parameters

  • pagePath: The page path the layout will be registered under.
  • layoutName: The name of the layout.
  • sourceViewFile: A view file this layout belongs to. Only used for logging, can be disregarded.
buildSingleView(
pagePath: string,
sourceFile: string | | undefined = ...
): Promise<any>

Build a view under the given page path using either the content of the given source file, or a registered source file if left unspecified. If there is no registered source file or it is explicitly set to a nullish value, the content must exist in the registered data. Any layouts specified in the data are resolved automatically (by calling buildSingleLayout).

If there is no prior data for the specified page path, a data entry is registered with the default values (see getReadonlyViewData and DataEntry).

(The page path is the URL as configured through the file system and page data, ignoring any potential target URL remap.)

buildStaticPath(
serveRoot: string,
sourcePath: string
): Promise<any>

Build the given directory or file under the given serve root.

This is a build function, meaning it will watch the given static files in dev mode and, if using the StaticViewRouter, copy them into the output directory. Additionally, it will respect the previously configured ignored paths. If the goal is merely to serve the directory under the built-in webserver, use SimpleViewRouter.serveStatic instead.

Register a plugin, which is nothing more than a callback invoked with the current Router instance as its only argument. Plugins are called immediately before the compile process.

Register a data preprocessor, i.e. a callback that is called on each data entry before compiling and rendering the registered pages. The given data may be modified freely.

The passed data is already processed: All directives have been resolved and each specified page has its data registered in the data handler.

addEngine(
extension: string | string[],
engineSetupFn: EngineSetupFn
): StaticViewRouter

Register an engine with the given extension/identifier and the given engine setup callback. Extensions can be specified with and without a leading dot, and must be specified in lowercase.

After registration, an extension can be used as a possible value in a data entry's "engine" field without a leading dot, and will also be used to derive the engine from the file extension of a path. Using an array, multiple extensions can be registered for the same callback.

The given setup callback will be called once with some setup data (see EngineSetupFn). It must return an object or class instance with at least the compile method (of type CompileCallback), which will be called each time the content needs to be compiled (i.e. every time the content has changed). The compile callback must itself return a render method (of type RenderCallback), which receives the data and will be called every time the content must be rendered.

Example

Register an engine for all files ending with ".cat.json" which renders the given JSON files with the content of the property "cat". The extension will be called cat.json internally.

addEngine('.cat.json', () => {
  return {
    compile: (sourceContent: string, filePath?: string) => {
      // Parse the JSON in the compile step
      // TODO: Throw a meaningful error message when parsing fails.
      const data = JSON.parse(sourceContent);
      return () => {
        if (typeof sourceContent.cat === 'string') {
          return sourceContent.cat;
        } else {
          // TODO: Error handling...
        }
      };
    }
  }
});
addFileExtensionAlias(
sourceExtension: string,
aliasExtensions: string[]
): void

Alias one or multiple file extensions to any existing actions of another extension. In other words, files of the extensions aliases will be rendered as if they had the given source extension. Both the source and alias extensions can be specified with or without a leading dot. Extensions are stored and compared exclusively in lowercase. As such, they must always be specified in lowercase in order to avoid confusion.

Aliasing an extension will only have an effect if the source extension has a registered engine handler (see addEngine). Registering aliases will override any existing aliases. In addition, engine handlers will always have priority over extension aliases.

Example

The following will cause files ending with njk.bak to be rendered as Nunjucks files using the same engine:

addFileExtensionAlias('njk', ['njk.bak']);
addGlobalData(
name: string,
data: any,
mergeDeep: boolean = false
): StaticViewRouter

Add global data in any form which is made available to every rendered content. The data will be passed into the RenderCallback of the used render engine (see CompileCallback).

If mergeDeep is set to true, the data will be merged using the usual merge strategy. Otherwise, any existing data under the specified name will be replaced with the given data.

addSymlink(
target: string,
destination: string
): StaticViewRouter

Add a relative symlink towards the given target at the given destination (link target -> dest). If a link already exists at the destination and is broken, i.e. points to an invalid target, it will automatically be rebuilt. Unlike normal symlink behavior, both target and destination will be resolved relative to the current working directory.

This utility can be used to group directories or files under a common directory to ease their addressability. One use case can be grouping layouts and snippets for use within a template engine so that they can be accessed using a common subdirectory.

Parameters

  • target: A path to a file or directory the symlink shall point to.
  • destination: The path denoting the destination of the symlink.
addIgnores(...sourcePathPrefixes: string[]): StaticViewRouter

Add a path prefix (file or directory) to be exempt from the build process, resulting in the ignored paths not being built or served (applies to both views and static files). Specified paths may contain globs and are resolved using the current working directory. Given directories will be excluded completely - There's no need for a trailing **. Added patterns cannot be removed again.

See SimpleViewRouter.DEFAULT_IGNORED_PATTERNS for all default ignored patterns.

Remarks

Default ignored patterns cannot be removed. You can, however, alter SimpleViewRouter.DEFAULT_IGNORED_PATTERNS before instantiating the class.

addViewWatchAlias(
watchedPaths: string | string[],
servePaths: string | string[]
): StaticViewRouter

Alias one or multiple given local paths to the watch actions of the view files adressed using the given serve paths. In other words, recompile all of the corresponding view files when any of the given local files changes.

This has only an effect when devMode is enabled.

Globs must be expanded manually using fs.glob or fileUtil.glob before being passed.

add404View(
viewPagePath: string,
rootPrefix: string = '/'
): StaticViewRouter

Add the page path of a view to use as the default 404 page for a specific root prefix (default = '/'). The page path is the URL as configured through the file system and page data, ignoring any potential target URL remap.

Example

The following configuration will use the view as configured through /blog/posts/1 for all /blog/* pages throwing a 404 error (and /blog). The view /404 is used in all other 404 cases.

add404View('/404')
add404View('/blog/posts/1', '/blog')
addFilter(
name: string,
filterCallback: EngineFilterCallback
): StaticViewRouter

Add a filter function to all eligible template engines. Filters are used by several engines such as Liquid or Nunjucks and provide a shortcut for modifying a value using special syntax.

Whether a template engine supports filters depends on its nature and its implementation. External template engines must implement this method individually. For this, see TemplateEngine.addFilter and EngineFilterCallback.

addMarkdownPlugin(
plugin: PluginWithParams,
...params: any[]
): this
addMarkdownPlugin<T>(
plugin: PluginWithOptions<T>,
options?: T
): this
addMarkdownPlugin(plugin: PluginSimple): this

Add a plugin for the built-in Markdown engine. This is a simple pass-thru for the use(...args) method of the underlying markdown-it instance.

getRenderedView(pagePath: string): Promise<string>

Render and return the content of the given page path with the following condition:

If dev mode is set, this method will inject the script needed for hot reload into the HTML, given the file contains a HTML scaffold. See also HOT_RELOAD_SCRIPT.

If dev mode is not set, this method is equal to RenderController.renderView.

getReadonlyViewData(pagePath: string): RenderData

Get the final combined render data for a view of the given page path (i.e. the URL as given in the page data without any potential redirects). If the path does not have any associated data, an empty object for the page path will be registered and returned.

Remarks

Important: The data is considered read-only since it is volatile and can change any time (specifically it changes whenever a data component changes). Use addDataPreprocessor for a way to modify data.

getReadonlyLayoutData(
pagePath: string,
layoutName: string
): RenderData

Get the final combined render data for a layout of the given page path (i.e. the URL without any potential redirects) and layout name. Both the page path and the layout name are required because layouts may have different data for each individual page path. If the path does not have any associated data, an empty object will be registered and returned.

Remarks

Important: The data is considered read-only since it is volatile and can change any time (specifically it changes whenever a data component changes).

Get the engine registered for the given extension, if any. This is most useful for grabbing built-in engines which are not exposed otherwise in order to configure them freely. It can also be used to compile and render custom content using the given engine. Engine extensions can be specified with and without the leading dot.

When the goal is to add a plugin for the built-in Markdown-It, addMarkdownPlugin should be preferred.

The configuration of engines provided by plugins should preferrably be done through the plugin configuration itself (if an option is not exposed, contribute to the plugin ;).

useStatic(
sourcePath: string,
serveRoot: string = '/'
): StaticViewRouter

Serve the given local static directory at the given root. A relative directory will be resolved using the current working directory.

Returns The current instance to allow for chaining.

useLayout(
sourcePath: string,
rootPrefix: string = '/'
): StaticViewRouter

Search used layouts within this directory with the given root prefixed. A relative directory will be resolved using the current working directory.

Returns The current instance to allow for chaining.

useView(
viewPath: string,
serveRoot: string = '/'
): StaticViewRouter

Setup routes based on the given local viewPath relative to the given serveRoot. The viewPath will be resolved using the current working directory. Files starting with index will be served under their respective parent paths directly, otherwise the file is put into its own directory containing an index.html.

If viewPath is a file, it will be served directly at the given root (or /).

If viewPath is a directory, it is recursively traversed and all supported files will be served according to the directory structure. As per convention, files starting with index will represent the path of the folder itself.

Parameters

  • viewPath: Path to the file or folder to serve in the local filesystem.
  • serveRoot: The prefix at which to serve the file in the webserver.

Returns The current instance to allow for chaining.

serveStatic(
sourcePath: string,
serveRoot: string = '/',
options: {
index: string,
ignoredPaths: Set<string>,
ignoreHidden: boolean,
ignoreTrailingSlash: boolean,
range: {
boundary: string,
maxRanges: number
}
} = {}
): void

Serve a path under the built-in webserver at the given serve root or '/' if left unspecified. This utility uses serveStatic.

This merely sets up the directory to be served. If you want to setup the files to be watched (and compiled if using the StaticViewRouter), use buildStaticPath instead.

watchPathDev(
watchedPaths: string | string[],
callback: WatchCallback | WatchCallback[]
): void

If devMode is set, recursively watch one or multiple paths for file changes, calling the given callback(s) with the full path of the changed file.

Parameters

  • watchedPaths: A file or directory path to recursively watch for changes.
  • callback: Called when a change has been detected.
_sendFileChangeToDevServer(changedFileURL: string): void

Send a file change event to the frontend if the given path is eligible.

renderMarkdown(content: string): string

Render the given content as markdown using the built-in Markdown engine.

Is used for the "md" filter.

No description.

build(): Promise<void>

Compile all configured files into the configured static output directory.

getServableViewContent(
pagePath: string
): Promise<{
content: ReadableStream<Uint8Array<ArrayBufferLike>>,
length: number
}
>

Get the final content and its length of a given page path. The content can either be a Web Stream (ReadableStream) or a string, for consumption by the webserver.

Remarks

Important: This method returns requested content from whatever source is plausible (i.e. cache, file system or ad-hoc render, depending on used configuration and router) and shall only be used for serving it via the web server. Use RenderController.renderView to actually render a view.

setupStaticFile(
sourceFile: string,
targetFile: string
): Promise<void>

No description.

static ensureNewlineLF(source: string): string

Return the given source content with LF line endings (\n), i.e. replace all CRLF line endings (\r\n) with LF.

static readFrontmatter(source: string): FrontmatterData

Read a potential frontmatter from the given source content. This method is very forgiving and will try to strip away falsely specified frontmatter.

Returns The frontmatter data, if any, and the trimmed source string without the frontmatter.

Throws

YAMLException Thrown when the frontmatter's YAML contains errors.

static parseYAML(source: string): unknown

No description.

static readPageDataYAML(
filePath: string
): Promise<PageDataEntry>

No description.

static addPathsToMap(
sourcePaths: string | string[],
rootPrefixes: string | string[],
storage: Map<string, string>
): void

No description.

class DynamicViewRouter extends SimpleViewRouter

Simple wrapper for Polka with a few filesystem-oriented helper functions.

No description.

readonly _tmpDir: string

The temporary directory in which all files will be cached when caching is enabled.

cacheTTL: number

See DynamicRouterOptions.cacheTTL. This property may be modified on the fly.

No description.

No description.

hono: Hono<BlankEnv, BlankSchema, "/">

No description.

logger: Logger

No description.

No description.

watchHandler: WatchHandler

No description.

devMode: boolean

No description.

port: number

No description.

staticPaths: Map<string, string>

Statically served directories, mapped from filesystem path to serve root.

notFoundAliases: Map<string, string>

404 Not Found aliases, mapped from root prefix to the target view's page path.

layoutPathStore: PathStore

No description.

viewPathStore: PathStore

No description.

Total count of all views built through the central build instrastructure, namely buildSingleView (and thus also build).

static WATCH_DELAY: 100

No description.

static DEFAULT_PORT: 8000

No description.

static IN_DEV_ENV: boolean

No description.

static DEFAULT_IGNORED_PATTERNS: readonly [
"**/.git/**/*",
"**/.yarn/**/*",
"**/node_modules/**/*",
"**/.git*",
"**/.pnp.*",
"**/.nvmrc",
"**/.npmrc",
"**/.pnpmrc",
"**/.yarnrc.yml",
"**/package.json",
"**/package-lock.json",
"**/yarn.lock",
"**/bun.lock",
"**/pnpm-lock.yaml",
"**/pnpm-workspace.yaml"
]

No description.

build(): Promise<void>

Run all registered modification callbacks and precompile all of the registered pages, then set them up for the webserver.

getServableViewContent(
servePath: string
): Promise<{
content: string,
length: number
} |
{
content: ReadableStream<Uint8Array<ArrayBufferLike>>,
length: number
}
>

Get the final content and its length of a given page path. The content can either be a Web Stream (ReadableStream) or a string, for consumption by the webserver.

Remarks

Important: This method returns requested content from whatever source is plausible (i.e. cache, file system or ad-hoc render, depending on used configuration and router) and shall only be used for serving it via the web server. Use RenderController.renderView to actually render a view.

_serveView(servePath: string): void

Serve a file from the given URL. The corresponding file must have been compiled already. You probably want to use useView instead.

Internal

Get a collection of all ignored paths, i.e. the union of user ignored paths and default ignored paths. All paths are absolute and fully resolved. In order to improve performance, this method will keep track of changed patterns and only update ignored paths when they have changed.

start(): Promise<void>

Run all registered modification callbacks, precompile and setup the registered pages, and start a web server on the configured port.

listen(): Promise<AddressInfo>

Start a web server at the configured port.

buildSingleLayout(
pagePath: string,
layoutName: string,
sourceViewFile: string | | undefined = ...
): Promise<any>

Build a specific layout of the given name under the namespace of the given page path. This method is called automatically by buildSingleView for all layouts specified in the view's data.

If there is no prior data for the specified page path, a data entry is registered with the default values (see getReadonlyLayoutData and DataEntry).

(The page path is the URL as configured through the file system and page data, ignoring any potential target URL remap.)

Parameters

  • pagePath: The page path the layout will be registered under.
  • layoutName: The name of the layout.
  • sourceViewFile: A view file this layout belongs to. Only used for logging, can be disregarded.
buildSingleView(
pagePath: string,
sourceFile: string | | undefined = ...
): Promise<any>

Build a view under the given page path using either the content of the given source file, or a registered source file if left unspecified. If there is no registered source file or it is explicitly set to a nullish value, the content must exist in the registered data. Any layouts specified in the data are resolved automatically (by calling buildSingleLayout).

If there is no prior data for the specified page path, a data entry is registered with the default values (see getReadonlyViewData and DataEntry).

(The page path is the URL as configured through the file system and page data, ignoring any potential target URL remap.)

buildStaticPath(
serveRoot: string,
sourcePath: string
): Promise<any>

Build the given directory or file under the given serve root.

This is a build function, meaning it will watch the given static files in dev mode and, if using the StaticViewRouter, copy them into the output directory. Additionally, it will respect the previously configured ignored paths. If the goal is merely to serve the directory under the built-in webserver, use SimpleViewRouter.serveStatic instead.

Register a plugin, which is nothing more than a callback invoked with the current Router instance as its only argument. Plugins are called immediately before the compile process.

Register a data preprocessor, i.e. a callback that is called on each data entry before compiling and rendering the registered pages. The given data may be modified freely.

The passed data is already processed: All directives have been resolved and each specified page has its data registered in the data handler.

addEngine(
extension: string | string[],
engineSetupFn: EngineSetupFn
): DynamicViewRouter

Register an engine with the given extension/identifier and the given engine setup callback. Extensions can be specified with and without a leading dot, and must be specified in lowercase.

After registration, an extension can be used as a possible value in a data entry's "engine" field without a leading dot, and will also be used to derive the engine from the file extension of a path. Using an array, multiple extensions can be registered for the same callback.

The given setup callback will be called once with some setup data (see EngineSetupFn). It must return an object or class instance with at least the compile method (of type CompileCallback), which will be called each time the content needs to be compiled (i.e. every time the content has changed). The compile callback must itself return a render method (of type RenderCallback), which receives the data and will be called every time the content must be rendered.

Example

Register an engine for all files ending with ".cat.json" which renders the given JSON files with the content of the property "cat". The extension will be called cat.json internally.

addEngine('.cat.json', () => {
  return {
    compile: (sourceContent: string, filePath?: string) => {
      // Parse the JSON in the compile step
      // TODO: Throw a meaningful error message when parsing fails.
      const data = JSON.parse(sourceContent);
      return () => {
        if (typeof sourceContent.cat === 'string') {
          return sourceContent.cat;
        } else {
          // TODO: Error handling...
        }
      };
    }
  }
});
addFileExtensionAlias(
sourceExtension: string,
aliasExtensions: string[]
): void

Alias one or multiple file extensions to any existing actions of another extension. In other words, files of the extensions aliases will be rendered as if they had the given source extension. Both the source and alias extensions can be specified with or without a leading dot. Extensions are stored and compared exclusively in lowercase. As such, they must always be specified in lowercase in order to avoid confusion.

Aliasing an extension will only have an effect if the source extension has a registered engine handler (see addEngine). Registering aliases will override any existing aliases. In addition, engine handlers will always have priority over extension aliases.

Example

The following will cause files ending with njk.bak to be rendered as Nunjucks files using the same engine:

addFileExtensionAlias('njk', ['njk.bak']);
addGlobalData(
name: string,
data: any,
mergeDeep: boolean = false
): DynamicViewRouter

Add global data in any form which is made available to every rendered content. The data will be passed into the RenderCallback of the used render engine (see CompileCallback).

If mergeDeep is set to true, the data will be merged using the usual merge strategy. Otherwise, any existing data under the specified name will be replaced with the given data.

addSymlink(
target: string,
destination: string
): DynamicViewRouter

Add a relative symlink towards the given target at the given destination (link target -> dest). If a link already exists at the destination and is broken, i.e. points to an invalid target, it will automatically be rebuilt. Unlike normal symlink behavior, both target and destination will be resolved relative to the current working directory.

This utility can be used to group directories or files under a common directory to ease their addressability. One use case can be grouping layouts and snippets for use within a template engine so that they can be accessed using a common subdirectory.

Parameters

  • target: A path to a file or directory the symlink shall point to.
  • destination: The path denoting the destination of the symlink.
addIgnores(
...sourcePathPrefixes: string[]
): DynamicViewRouter

Add a path prefix (file or directory) to be exempt from the build process, resulting in the ignored paths not being built or served (applies to both views and static files). Specified paths may contain globs and are resolved using the current working directory. Given directories will be excluded completely - There's no need for a trailing **. Added patterns cannot be removed again.

See SimpleViewRouter.DEFAULT_IGNORED_PATTERNS for all default ignored patterns.

Remarks

Default ignored patterns cannot be removed. You can, however, alter SimpleViewRouter.DEFAULT_IGNORED_PATTERNS before instantiating the class.

addViewWatchAlias(
watchedPaths: string | string[],
servePaths: string | string[]
): DynamicViewRouter

Alias one or multiple given local paths to the watch actions of the view files adressed using the given serve paths. In other words, recompile all of the corresponding view files when any of the given local files changes.

This has only an effect when devMode is enabled.

Globs must be expanded manually using fs.glob or fileUtil.glob before being passed.

add404View(
viewPagePath: string,
rootPrefix: string = '/'
): DynamicViewRouter

Add the page path of a view to use as the default 404 page for a specific root prefix (default = '/'). The page path is the URL as configured through the file system and page data, ignoring any potential target URL remap.

Example

The following configuration will use the view as configured through /blog/posts/1 for all /blog/* pages throwing a 404 error (and /blog). The view /404 is used in all other 404 cases.

add404View('/404')
add404View('/blog/posts/1', '/blog')
addFilter(
name: string,
filterCallback: EngineFilterCallback
): DynamicViewRouter

Add a filter function to all eligible template engines. Filters are used by several engines such as Liquid or Nunjucks and provide a shortcut for modifying a value using special syntax.

Whether a template engine supports filters depends on its nature and its implementation. External template engines must implement this method individually. For this, see TemplateEngine.addFilter and EngineFilterCallback.

addMarkdownPlugin(
plugin: PluginWithParams,
...params: any[]
): this
addMarkdownPlugin<T>(
plugin: PluginWithOptions<T>,
options?: T
): this
addMarkdownPlugin(plugin: PluginSimple): this

Add a plugin for the built-in Markdown engine. This is a simple pass-thru for the use(...args) method of the underlying markdown-it instance.

getRenderedView(pagePath: string): Promise<string>

Render and return the content of the given page path with the following condition:

If dev mode is set, this method will inject the script needed for hot reload into the HTML, given the file contains a HTML scaffold. See also HOT_RELOAD_SCRIPT.

If dev mode is not set, this method is equal to RenderController.renderView.

getReadonlyViewData(pagePath: string): RenderData

Get the final combined render data for a view of the given page path (i.e. the URL as given in the page data without any potential redirects). If the path does not have any associated data, an empty object for the page path will be registered and returned.

Remarks

Important: The data is considered read-only since it is volatile and can change any time (specifically it changes whenever a data component changes). Use addDataPreprocessor for a way to modify data.

getReadonlyLayoutData(
pagePath: string,
layoutName: string
): RenderData

Get the final combined render data for a layout of the given page path (i.e. the URL without any potential redirects) and layout name. Both the page path and the layout name are required because layouts may have different data for each individual page path. If the path does not have any associated data, an empty object will be registered and returned.

Remarks

Important: The data is considered read-only since it is volatile and can change any time (specifically it changes whenever a data component changes).

Get the engine registered for the given extension, if any. This is most useful for grabbing built-in engines which are not exposed otherwise in order to configure them freely. It can also be used to compile and render custom content using the given engine. Engine extensions can be specified with and without the leading dot.

When the goal is to add a plugin for the built-in Markdown-It, addMarkdownPlugin should be preferred.

The configuration of engines provided by plugins should preferrably be done through the plugin configuration itself (if an option is not exposed, contribute to the plugin ;).

useStatic(
sourcePath: string,
serveRoot: string = '/'
): DynamicViewRouter

Serve the given local static directory at the given root. A relative directory will be resolved using the current working directory.

Returns The current instance to allow for chaining.

useLayout(
sourcePath: string,
rootPrefix: string = '/'
): DynamicViewRouter

Search used layouts within this directory with the given root prefixed. A relative directory will be resolved using the current working directory.

Returns The current instance to allow for chaining.

useView(
viewPath: string,
serveRoot: string = '/'
): DynamicViewRouter

Setup routes based on the given local viewPath relative to the given serveRoot. The viewPath will be resolved using the current working directory. Files starting with index will be served under their respective parent paths directly, otherwise the file is put into its own directory containing an index.html.

If viewPath is a file, it will be served directly at the given root (or /).

If viewPath is a directory, it is recursively traversed and all supported files will be served according to the directory structure. As per convention, files starting with index will represent the path of the folder itself.

Parameters

  • viewPath: Path to the file or folder to serve in the local filesystem.
  • serveRoot: The prefix at which to serve the file in the webserver.

Returns The current instance to allow for chaining.

serveStatic(
sourcePath: string,
serveRoot: string = '/',
options: {
index: string,
ignoredPaths: Set<string>,
ignoreHidden: boolean,
ignoreTrailingSlash: boolean,
range: {
boundary: string,
maxRanges: number
}
} = {}
): void

Serve a path under the built-in webserver at the given serve root or '/' if left unspecified. This utility uses serveStatic.

This merely sets up the directory to be served. If you want to setup the files to be watched (and compiled if using the StaticViewRouter), use buildStaticPath instead.

watchPathDev(
watchedPaths: string | string[],
callback: WatchCallback | WatchCallback[]
): void

If devMode is set, recursively watch one or multiple paths for file changes, calling the given callback(s) with the full path of the changed file.

Parameters

  • watchedPaths: A file or directory path to recursively watch for changes.
  • callback: Called when a change has been detected.
_sendFileChangeToDevServer(changedFileURL: string): void

Send a file change event to the frontend if the given path is eligible.

renderMarkdown(content: string): string

Render the given content as markdown using the built-in Markdown engine.

Is used for the "md" filter.

No description.

static ensureNewlineLF(source: string): string

Return the given source content with LF line endings (\n), i.e. replace all CRLF line endings (\r\n) with LF.

static readFrontmatter(source: string): FrontmatterData

Read a potential frontmatter from the given source content. This method is very forgiving and will try to strip away falsely specified frontmatter.

Returns The frontmatter data, if any, and the trimmed source string without the frontmatter.

Throws

YAMLException Thrown when the frontmatter's YAML contains errors.

static parseYAML(source: string): unknown

No description.

static readPageDataYAML(
filePath: string
): Promise<PageDataEntry>

No description.

static addPathsToMap(
sourcePaths: string | string[],
rootPrefixes: string | string[],
storage: Map<string, string>
): void

No description.

class SimpleViewRouter

Simple wrapper for Polka with a few filesystem-oriented helper functions.

No description.

hono: Hono<BlankEnv, BlankSchema, "/">

No description.

logger: Logger

No description.

No description.

watchHandler: WatchHandler

No description.

devMode: boolean

No description.

port: number

No description.

staticPaths: Map<string, string>

Statically served directories, mapped from filesystem path to serve root.

notFoundAliases: Map<string, string>

404 Not Found aliases, mapped from root prefix to the target view's page path.

layoutPathStore: PathStore

No description.

viewPathStore: PathStore

No description.

Total count of all views built through the central build instrastructure, namely buildSingleView (and thus also build).

static WATCH_DELAY: 100

No description.

static DEFAULT_PORT: 8000

No description.

static IN_DEV_ENV: boolean

No description.

static DEFAULT_IGNORED_PATTERNS: readonly [
"**/.git/**/*",
"**/.yarn/**/*",
"**/node_modules/**/*",
"**/.git*",
"**/.pnp.*",
"**/.nvmrc",
"**/.npmrc",
"**/.pnpmrc",
"**/.yarnrc.yml",
"**/package.json",
"**/package-lock.json",
"**/yarn.lock",
"**/bun.lock",
"**/pnpm-lock.yaml",
"**/pnpm-workspace.yaml"
]

No description.

start(): Promise<void>

Run all registered modification callbacks, precompile and setup the registered pages, and start a web server on the configured port.

build(): Promise<void>

Run all registered modification callbacks and precompile all of the registered pages, then set them up for the webserver.

listen(): Promise<AddressInfo>

Start a web server at the configured port.

buildSingleLayout(
pagePath: string,
layoutName: string,
sourceViewFile: string | | undefined = ...
): Promise<any>

Build a specific layout of the given name under the namespace of the given page path. This method is called automatically by buildSingleView for all layouts specified in the view's data.

If there is no prior data for the specified page path, a data entry is registered with the default values (see getReadonlyLayoutData and DataEntry).

(The page path is the URL as configured through the file system and page data, ignoring any potential target URL remap.)

Parameters

  • pagePath: The page path the layout will be registered under.
  • layoutName: The name of the layout.
  • sourceViewFile: A view file this layout belongs to. Only used for logging, can be disregarded.
buildSingleView(
pagePath: string,
sourceFile: string | | undefined = ...
): Promise<any>

Build a view under the given page path using either the content of the given source file, or a registered source file if left unspecified. If there is no registered source file or it is explicitly set to a nullish value, the content must exist in the registered data. Any layouts specified in the data are resolved automatically (by calling buildSingleLayout).

If there is no prior data for the specified page path, a data entry is registered with the default values (see getReadonlyViewData and DataEntry).

(The page path is the URL as configured through the file system and page data, ignoring any potential target URL remap.)

buildStaticPath(
serveRoot: string,
sourcePath: string
): Promise<any>

Build the given directory or file under the given serve root.

This is a build function, meaning it will watch the given static files in dev mode and, if using the StaticViewRouter, copy them into the output directory. Additionally, it will respect the previously configured ignored paths. If the goal is merely to serve the directory under the built-in webserver, use SimpleViewRouter.serveStatic instead.

Register a plugin, which is nothing more than a callback invoked with the current Router instance as its only argument. Plugins are called immediately before the compile process.

Register a data preprocessor, i.e. a callback that is called on each data entry before compiling and rendering the registered pages. The given data may be modified freely.

The passed data is already processed: All directives have been resolved and each specified page has its data registered in the data handler.

addEngine(
extension: string | string[],
engineSetupFn: EngineSetupFn
): SimpleViewRouter

Register an engine with the given extension/identifier and the given engine setup callback. Extensions can be specified with and without a leading dot, and must be specified in lowercase.

After registration, an extension can be used as a possible value in a data entry's "engine" field without a leading dot, and will also be used to derive the engine from the file extension of a path. Using an array, multiple extensions can be registered for the same callback.

The given setup callback will be called once with some setup data (see EngineSetupFn). It must return an object or class instance with at least the compile method (of type CompileCallback), which will be called each time the content needs to be compiled (i.e. every time the content has changed). The compile callback must itself return a render method (of type RenderCallback), which receives the data and will be called every time the content must be rendered.

Example

Register an engine for all files ending with ".cat.json" which renders the given JSON files with the content of the property "cat". The extension will be called cat.json internally.

addEngine('.cat.json', () => {
  return {
    compile: (sourceContent: string, filePath?: string) => {
      // Parse the JSON in the compile step
      // TODO: Throw a meaningful error message when parsing fails.
      const data = JSON.parse(sourceContent);
      return () => {
        if (typeof sourceContent.cat === 'string') {
          return sourceContent.cat;
        } else {
          // TODO: Error handling...
        }
      };
    }
  }
});
addFileExtensionAlias(
sourceExtension: string,
aliasExtensions: string[]
): void

Alias one or multiple file extensions to any existing actions of another extension. In other words, files of the extensions aliases will be rendered as if they had the given source extension. Both the source and alias extensions can be specified with or without a leading dot. Extensions are stored and compared exclusively in lowercase. As such, they must always be specified in lowercase in order to avoid confusion.

Aliasing an extension will only have an effect if the source extension has a registered engine handler (see addEngine). Registering aliases will override any existing aliases. In addition, engine handlers will always have priority over extension aliases.

Example

The following will cause files ending with njk.bak to be rendered as Nunjucks files using the same engine:

addFileExtensionAlias('njk', ['njk.bak']);
addGlobalData(
name: string,
data: any,
mergeDeep: boolean = false
): SimpleViewRouter

Add global data in any form which is made available to every rendered content. The data will be passed into the RenderCallback of the used render engine (see CompileCallback).

If mergeDeep is set to true, the data will be merged using the usual merge strategy. Otherwise, any existing data under the specified name will be replaced with the given data.

addIgnores(...sourcePathPrefixes: string[]): SimpleViewRouter

Add a path prefix (file or directory) to be exempt from the build process, resulting in the ignored paths not being built or served (applies to both views and static files). Specified paths may contain globs and are resolved using the current working directory. Given directories will be excluded completely - There's no need for a trailing **. Added patterns cannot be removed again.

See SimpleViewRouter.DEFAULT_IGNORED_PATTERNS for all default ignored patterns.

Remarks

Default ignored patterns cannot be removed. You can, however, alter SimpleViewRouter.DEFAULT_IGNORED_PATTERNS before instantiating the class.

addViewWatchAlias(
watchedPaths: string | string[],
servePaths: string | string[]
): SimpleViewRouter

Alias one or multiple given local paths to the watch actions of the view files adressed using the given serve paths. In other words, recompile all of the corresponding view files when any of the given local files changes.

This has only an effect when devMode is enabled.

Globs must be expanded manually using fs.glob or fileUtil.glob before being passed.

add404View(
viewPagePath: string,
rootPrefix: string = '/'
): SimpleViewRouter

Add the page path of a view to use as the default 404 page for a specific root prefix (default = '/'). The page path is the URL as configured through the file system and page data, ignoring any potential target URL remap.

Example

The following configuration will use the view as configured through /blog/posts/1 for all /blog/* pages throwing a 404 error (and /blog). The view /404 is used in all other 404 cases.

add404View('/404')
add404View('/blog/posts/1', '/blog')
addFilter(
name: string,
filterCallback: EngineFilterCallback
): SimpleViewRouter

Add a filter function to all eligible template engines. Filters are used by several engines such as Liquid or Nunjucks and provide a shortcut for modifying a value using special syntax.

Whether a template engine supports filters depends on its nature and its implementation. External template engines must implement this method individually. For this, see TemplateEngine.addFilter and EngineFilterCallback.

addMarkdownPlugin(
plugin: PluginWithParams,
...params: any[]
): this
addMarkdownPlugin<T>(
plugin: PluginWithOptions<T>,
options?: T
): this
addMarkdownPlugin(plugin: PluginSimple): this

Add a plugin for the built-in Markdown engine. This is a simple pass-thru for the use(...args) method of the underlying markdown-it instance.

getRenderedView(pagePath: string): Promise<string>

Render and return the content of the given page path with the following condition:

If dev mode is set, this method will inject the script needed for hot reload into the HTML, given the file contains a HTML scaffold. See also HOT_RELOAD_SCRIPT.

If dev mode is not set, this method is equal to RenderController.renderView.

abstract getServableViewContent(
pagePath: string
): ContentData | Promise<ContentData>

Get the final content and its length of a given page path. The content can either be a Web Stream (ReadableStream) or a string, for consumption by the webserver.

Remarks

Important: This method returns requested content from whatever source is plausible (i.e. cache, file system or ad-hoc render, depending on used configuration and router) and shall only be used for serving it via the web server. Use RenderController.renderView to actually render a view.

getReadonlyViewData(pagePath: string): RenderData

Get the final combined render data for a view of the given page path (i.e. the URL as given in the page data without any potential redirects). If the path does not have any associated data, an empty object for the page path will be registered and returned.

Remarks

Important: The data is considered read-only since it is volatile and can change any time (specifically it changes whenever a data component changes). Use addDataPreprocessor for a way to modify data.

getReadonlyLayoutData(
pagePath: string,
layoutName: string
): RenderData

Get the final combined render data for a layout of the given page path (i.e. the URL without any potential redirects) and layout name. Both the page path and the layout name are required because layouts may have different data for each individual page path. If the path does not have any associated data, an empty object will be registered and returned.

Remarks

Important: The data is considered read-only since it is volatile and can change any time (specifically it changes whenever a data component changes).

Get the engine registered for the given extension, if any. This is most useful for grabbing built-in engines which are not exposed otherwise in order to configure them freely. It can also be used to compile and render custom content using the given engine. Engine extensions can be specified with and without the leading dot.

When the goal is to add a plugin for the built-in Markdown-It, addMarkdownPlugin should be preferred.

The configuration of engines provided by plugins should preferrably be done through the plugin configuration itself (if an option is not exposed, contribute to the plugin ;).

useStatic(
sourcePath: string,
serveRoot: string = '/'
): SimpleViewRouter

Serve the given local static directory at the given root. A relative directory will be resolved using the current working directory.

Returns The current instance to allow for chaining.

useLayout(
sourcePath: string,
rootPrefix: string = '/'
): SimpleViewRouter

Search used layouts within this directory with the given root prefixed. A relative directory will be resolved using the current working directory.

Returns The current instance to allow for chaining.

useView(
viewPath: string,
serveRoot: string = '/'
): SimpleViewRouter

Setup routes based on the given local viewPath relative to the given serveRoot. The viewPath will be resolved using the current working directory. Files starting with index will be served under their respective parent paths directly, otherwise the file is put into its own directory containing an index.html.

If viewPath is a file, it will be served directly at the given root (or /).

If viewPath is a directory, it is recursively traversed and all supported files will be served according to the directory structure. As per convention, files starting with index will represent the path of the folder itself.

Parameters

  • viewPath: Path to the file or folder to serve in the local filesystem.
  • serveRoot: The prefix at which to serve the file in the webserver.

Returns The current instance to allow for chaining.

serveStatic(
sourcePath: string,
serveRoot: string = '/',
options: {
index: string,
ignoredPaths: Set<string>,
ignoreHidden: boolean,
ignoreTrailingSlash: boolean,
range: {
boundary: string,
maxRanges: number
}
} = {}
): void

Serve a path under the built-in webserver at the given serve root or '/' if left unspecified. This utility uses serveStatic.

This merely sets up the directory to be served. If you want to setup the files to be watched (and compiled if using the StaticViewRouter), use buildStaticPath instead.

watchPathDev(
watchedPaths: string | string[],
callback: WatchCallback | WatchCallback[]
): void

If devMode is set, recursively watch one or multiple paths for file changes, calling the given callback(s) with the full path of the changed file.

Parameters

  • watchedPaths: A file or directory path to recursively watch for changes.
  • callback: Called when a change has been detected.
_sendFileChangeToDevServer(changedFileURL: string): void

Send a file change event to the frontend if the given path is eligible.

renderMarkdown(content: string): string

Render the given content as markdown using the built-in Markdown engine.

Is used for the "md" filter.

No description.

static ensureNewlineLF(source: string): string

Return the given source content with LF line endings (\n), i.e. replace all CRLF line endings (\r\n) with LF.

static readFrontmatter(source: string): FrontmatterData

Read a potential frontmatter from the given source content. This method is very forgiving and will try to strip away falsely specified frontmatter.

Returns The frontmatter data, if any, and the trimmed source string without the frontmatter.

Throws

YAMLException Thrown when the frontmatter's YAML contains errors.

static parseYAML(source: string): unknown

No description.

static readPageDataYAML(
filePath: string
): Promise<PageDataEntry>

No description.

static addPathsToMap(
sourcePaths: string | string[],
rootPrefixes: string | string[],
storage: Map<string, string>
): void

No description.

interface Component<Data>

priority: number

No description.

No description.

interface DataComponents

No description.

No description.

interface RenderDataRender

draft?: boolean

If set to true, mark a page or layout as a draft, resulting in the affected page or pages not being rendered. This may be useful for development purposes.

Remarks

The affected pages will be compiled, but not be processed and rendered further.

Default

false
engine?: string

Comma seperated list of file extensions that will be used to determine the renderers for the data entry's content (either source if specified or, more likely, the associated file). The content will be rendered in the same order as specified. The special value * will be expanded to the file extension of the associated file. Note that since the asterisk has special meaning in YAML, the engine value must be enclosed in quotation marks when using it.

When rendering inline content, the asterisk has no special meaning and will be ignored.

Internally, all content is pre-compiled using the first engine specified. This means that if render performance is relevant, consider specifying the slowest engine first (usually some kind of template engine). An example could be njk,md which will be faster than md,njk because the second case will have to compile the Nunjucks template each time a render request is made. At the same time, the Markdown engine does not need a compile step.

Default value

The file extension of the associated file, or html (content pass-thru) if unknown.

Example: With an associated file

Given the file index.md exists in a view directory, the following top-level entry renders the file first with Nunjucks (file extension njk) and then with Markdown. Here, the engine field is equivalent to njk,md.

engine: "njk,*"

Example: With inline content

Render the specified content with Nunjucks (file extension njk) and then with Markdown.

name: My template
content: "<div>*{{ name }}*</div>"
engine: njk,md
layout?: string

The layout used for the current page entry, if any. These can either be a path to a layout file, which will be looked up in the configured layout directories, or an arbitrary layout name, which must be defined in $layouts.

$layouts may always be used to annotate layouts with additional data, for example to create a layout cascade using the same layout property.

source?: string

Content of the page entry in question which will be rendered according to the specified engine. If unspecified, it will be automatically filled with the content of the associated file. This allows it to cascade to the specified layouts.

If specified, it will be prioritized over the file content of any associated file. If no associated file exists, engine must be set.

May not be set in the frontmatter.

targetURL?: string

Specifies an URL the file shall be served/placed at, overriding the default target URL. Will be written into RenderDataPage.url (i.e. into the page.url property of the resulting data) as a well-formed URL.

A well-formed URL always starts and never ends with a slash. The only exception is the root /.

interface RenderDataPage

content: string

The final rendered page content. Will be set automatically by the render process into the current data, which is then recursively passed on to any potential layouts. Cannot be overridden using data.

url: string

The resulting URL of the current file when served.

This URL is well-formed, i.e. it always starts and never ends with a slash. The only exception is the root /.

Example

The file `./views/foo/bar/baz.njk` relative to the current working
directory, where `./views/` is a registered view directory, will yield the
"url" value `/foo/bar/baz`. The actual served path would account to
`/foo/bar/baz/index.html`.

The full page data object after resolving its directives and other potential processing steps. Can be used to query the page data hierarchy regardless of current template, for example to build navigation breadcrumbs.

Does not include frontmatter.

interface RenderData

Specifies several optional data properties to configure the internal render pipeline.

Specifies several data properties regarding the state of the current path. This is a direct result of the compilation process and thus cannot be overridden by user data.

interface PageDataEntry extends Partial<RenderData>

All properties starting with $ are directives. Directives serve some special purpose in the pre-processing of the data. They will be fed into the template but may have been altered before.

Specifies several optional data properties to configure the internal render pipeline.

Specifies several data properties regarding the state of the current path. This is a direct result of the compilation process and thus cannot be overridden by user data.

Defines data which shall explicitly not be merged with and thus override any existing data under the same property names. This applies to any data including data propagated using $propagate.

This directive may be used within any other directives.

Example: Override a propagated value

The top level data entry (URL /) will contain the data property "myCoolList" with the value [ "foo", "bar" ]. In the data entry below (/lor) its value is [ "baz" ] since the list item "bar", as propagated from the top-level $propagate has explicitly been overriden.

myCoolList:
  - foo
$propagate:
  myCoolList:
    - bar
$children:
  lor:
    $override:
      myCoolList:
        - baz
$propagate?: Record<string, any>

Defines data which will propagate into all deeper levels of the data hierarchy. Data within $propagate directives will be deeply merged with any propagating data of higher levels and will then continue to propagate in that form.

The $override directive may be used to stop the propagation of data, either by overriding the whole $propagate directive or by overriding only certain properties within it.

Defines data of pages one hierarchy below the current one. The key must always be the file slug (which is equivalent to the URL slug) of the view which will receive the data.

The data entries do not have to correspond to an existing file in the filesystem. If no corresponding file can be found, the page will be rendered with an empty string for its content. This can be utilized when working with layouts (see render.RenderDataRender.layout and $layouts).

No other directive (starting with $) may be specified inside this one at any depth. This is not validated and may lead to unexpected behavior.

Example

Assuming the following view file hierarchy:

view/
|- index.html
|- blog.html
|- games.html

... Which will result in the following URLs:

  • / -> view/index.html
  • /blog -> view/blog.html
  • /games -> view/games.html

The page data may thus look like the following (assuming the pages use a data property title):

title: My cool Website
$children:
  blog:
    title: My cool blog
  games:
    title: Some cool games

Defines data which will be applied to the specified layouts. The data is applied to layouts of the current hierarchy level and all below, and will be merged with layout data defined in lower hierarchy levels. As such, it behaves just like $propagate but as a means for supplying layouts with data.

Most commonly, this is used for specifying a layout hierarchy using the layout data property.

All specified keys will be handled as layouts, even if there is no corresponding layout file. This results in the ability to specify alias layouts which in turn point to another layout.

Example

In this example, two pages will be created, The main page / and a blog page /blog. The main page uses the coolMain layout, which sets the isCool data property to true and is aliased to the main.njk layout. Since the data cascade prioritizes layout data, the initial isCool value of false is overriden by the coolMain layout. The blog uses the blog.njk layout which in turn is embedded within the main.njk layout.

Here, it is assumed that all specified layouts with a file extension also exist in the file system in one of the configured layout directories.

title: Main page
isCool: false
layout: coolMain
$layouts:
  coolMain:
    layout: main.njk
    isCool: true
$children:
  blog:
    $layouts:
      blog.njk:
        layout: main.njk
    layout: blog.njk
    title: My blog

interface SetupData

interface TemplateEngine

Callback used for registering custom filters, given the specific template engine supports it. This callback will be exposed to the generic addFilter method of the public API.

Callback called once on each page each time it needs to be compiled, i.e. each time its source has changed. Returns a (potentially async) callback which is called each time a page's content is requested to be rendered.

This means that the function itself may define a compilation step of the content. The inner function can then use the compilaton result to render the content repeatedly.

See also EngineHandler.registerEngine

interface StaticRouterOptions implements ViewRouterOptions

devMode?: boolean

Whether to explicitly enable or disable dev mode. In dev mode, registered files will be watched for changes, causing a recompilation or router restart depending on the changed file. Additionally, dev mode enables a hot reload on the client side.

Default value

Enabled if NodeJS is in a development environment (process.env.NODE_ENV == 'development')

port?: number

The port to use for the web server.

Default value

8000

The initial page data which will be processed and used for the render data of all possible serve paths (URLs).

Default value

{}
engineRootPath?: string

Path to a directory determining the root of the used template engines, i.e. the directory relative to which resources such as templates and snippets will be addressed from within a template.

This value will be stored in the SimpleViewRouter.engineRootPath class property and should be used when setting up a custom engine which requires such a parameter.

Default value

The current working directory
silent?: boolean

When set to true, suppress all informational log messages.

Default value

false
hono?: boolean | HonoOptions

Several options controlling the behavior of Hono (the used webserver).

Default value

{
   *   useEtag: true
   * }
markdownIt?: Options

Options passed on to Markdown-It.

Default value

{
   *   html: true
   * }

See also The Markdown-It repository for further info and all available options.

outDir: string

Output directory for the static files. If not absolute, it will be resolved relative to the current working directory.

interface DynamicRouterOptions implements ViewRouterOptions

cacheTTL?: number

How long the compiled content shall be cached, in seconds. Setting it to 0 disables the cache, causing the content to be re-rendered on every request. Enabling the cache is useful only when the templates do not contain dynamic content, or when any dynamic content does not have to be available immediately. Additionally, caching is most effective when the compilation process takes a while. The cache utilizes temporary files and not in-memory caching.

The cache may be flushed early when manually invoking a file change in production, when changing a watched file in dev mode, or when restarting the project.

Does not set the HTTP "Cache-Control" response header. Instead, it is recommended to enable etag support (see ViewRouterOptions.hono).

Remarks

The cache works by writing compiled content into a temporary directory (DynamicViewRouter._tmpDir), keyed using a sha1 hash of the corresponding URL. The file is then streamed to the webserver. This means that there is little to no memory overhead to this cache.

The temporary directory is not deleted upon closing the server. This is relevant to Windows users, where the tmp directory is usually never cleared.

Default value

0
devMode?: boolean

Whether to explicitly enable or disable dev mode. In dev mode, registered files will be watched for changes, causing a recompilation or router restart depending on the changed file. Additionally, dev mode enables a hot reload on the client side.

Default value

Enabled if NodeJS is in a development environment (process.env.NODE_ENV == 'development')

port?: number

The port to use for the web server.

Default value

8000

The initial page data which will be processed and used for the render data of all possible serve paths (URLs).

Default value

{}
engineRootPath?: string

Path to a directory determining the root of the used template engines, i.e. the directory relative to which resources such as templates and snippets will be addressed from within a template.

This value will be stored in the SimpleViewRouter.engineRootPath class property and should be used when setting up a custom engine which requires such a parameter.

Default value

The current working directory
silent?: boolean

When set to true, suppress all informational log messages.

Default value

false
hono?: boolean | HonoOptions

Several options controlling the behavior of Hono (the used webserver).

Default value

{
   *   useEtag: true
   * }
markdownIt?: Options

Options passed on to Markdown-It.

Default value

{
   *   html: true
   * }

See also The Markdown-It repository for further info and all available options.

interface ViewRouterOptions

devMode?: boolean

Whether to explicitly enable or disable dev mode. In dev mode, registered files will be watched for changes, causing a recompilation or router restart depending on the changed file. Additionally, dev mode enables a hot reload on the client side.

Default value

Enabled if NodeJS is in a development environment (process.env.NODE_ENV == 'development')

port?: number

The port to use for the web server.

Default value

8000

The initial page data which will be processed and used for the render data of all possible serve paths (URLs).

Default value

{}
engineRootPath?: string

Path to a directory determining the root of the used template engines, i.e. the directory relative to which resources such as templates and snippets will be addressed from within a template.

This value will be stored in the SimpleViewRouter.engineRootPath class property and should be used when setting up a custom engine which requires such a parameter.

Default value

The current working directory
silent?: boolean

When set to true, suppress all informational log messages.

Default value

false
hono?: boolean | HonoOptions

Several options controlling the behavior of Hono (the used webserver).

Default value

{
   *   useEtag: true
   * }
markdownIt?: Options

Options passed on to Markdown-It.

Default value

{
   *   html: true
   * }

See also The Markdown-It repository for further info and all available options.

group <Miscellaneous>

type DeepPartial<T>: T extends object
? {
[P in keyof T]: DeepPartial<T[P]>?
}
: T

Deeply mark an object as Partial. From https://stackoverflow.com/a/61132308

type RenderCallback: (data: RenderData) => Promise<string> | string

Callback called each time a page needs to be rendered.

See also

type CompileCallback: (source: string, filePath?: string) => Promise<> | RenderCallback

See also TemplateEngine.compile

type EngineFilterCallback: (inputValue: any, ...args: any[]) => any

Callback of a filter function for use in any supporting template engine. In case the template engine uses a different callback format, you should use an intermediate callback in order to cast it into this one.

type AddFilterCallback: (name: string, callback: EngineFilterCallback) => void

See also TemplateEngine.addFilter

type EngineSetupFn: (setupData: SetupData) => TemplateEngine

Is called exactly once upon registration with all relevant initialization data. Returns an engine object or class.

type PluginCallback<T extends SimpleViewRouter>: (router: T) => void

Callback called when the build or serve process is started and before any compilation is invoked.

See also SimpleViewRouter.addPlugin

type DataPreprocessorCallback: (data: RenderData) => Promise<void> | void

Callback called on each data entry.

See also SimpleViewRouter.addDataPreprocessor