# @eggjs/view

> Base view plugin for egg

Latest version **4.1.0** (published 2026-10-07) · MIT license · 0 weekly downloads

## Install

```sh
npm install @eggjs/view
pnpm add @eggjs/view
yarn add @eggjs/view
bun add @eggjs/view
```

## Health

**Score 70/100 (B)** — status: active.

Positive: has types; esm support; no vulnerabilities; has provenance; recently updated; high maintenance score.

Warnings: low downloads.

## Facts

| | |
|---|---|
| Version | 4.1.0 |
| Published | 2026-10-07 |
| First published | 2025-02-03 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM |
| Node | >=22.18.0 |
| Dependencies | 2 |
| Unpacked size | 27.7 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Provenance | attested (GitHub Actions) |
| Author | popomore |
| Maintainers | gxkl, eggjs-admin, fengmk2, atian25, hyj1991, killagu, coolme200, akitasummer, elrrrrrrr, niania |
| Keywords | egg, egg-plugin, egg-view, eggPlugin, view |

## Links

- npm: https://www.npmjs.com/package/@eggjs/view
- Repository: https://github.com/eggjs/egg
- Homepage: https://github.com/eggjs/egg/tree/next/plugins/view
- Issues: https://github.com/eggjs/egg/issues
- npm.io page: https://npm.io/package/@eggjs/view

## Dependencies (2)

- [utility](https://npm.io/package/utility.md) ^2.5.0
- [is-type-of](https://npm.io/package/is-type-of.md) ^2.2.0

## Recent versions

- 4.1.0 (latest) — 2026-10-07
- 4.0.2-rc.1 (rc) — 2026-10-06
- 4.0.2-beta.27 (beta) — 2026-09-20
- 4.0.2 — 2026-10-06
- 4.0.2-rc.0 — 2026-09-23
- 4.0.2-beta.26 — 2026-08-07
- 4.0.2-beta.25 — 2026-07-13
- 4.0.2-beta.24 — 2026-07-12
- 4.0.2-beta.23 — 2026-07-11
- 4.0.2-beta.22 — 2026-07-11
- 4.0.2-beta.20 — 2026-07-09
- 4.0.2-beta.19 — 2026-06-29
- 4.0.2-beta.17 — 2026-06-28
- 4.0.2-beta.16 — 2026-06-26
- 4.0.2-beta.15 — 2026-06-26
- … 38 more at https://npm.io/package/@eggjs/view/versions

## README

# @eggjs/view

[![NPM version](https://img.shields.io/npm/v/@eggjs/view.svg?style=flat-square)](https://npmjs.org/package/@eggjs/view)
[![NPM download](https://img.shields.io/npm/dm/@eggjs/view.svg?style=flat-square)](https://npmjs.org/package/@eggjs/view)
[![Node.js Version](https://img.shields.io/node/v/@eggjs/view.svg?style=flat)](https://nodejs.org/en/download/)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://makeapullrequest.com)
![CodeRabbit Pull Request Reviews](https://img.shields.io/coderabbit/prs/github/eggjs/view)

Base view plugin for egg

**it's a plugin that has been built-in for egg.**

## Install

```bash
npm i @eggjs/view
```

## Usage

```js
// {app_root}/config/plugin.ts
export default {
  view: {
    enable: true,
    package: '@eggjs/view',
  },
};
```

## Use a template engine

[@eggjs/view] don't have build-in view engine, So you should choose a template engine like [ejs], and install [egg-view-ejs] plugin.

You can choose a template engine first, link [ejs], so we use [egg-view-ejs] plugin.

`egg-view` is in [eggjs], so you just need configure [egg-view-ejs].

```js
// config/plugin.ts
export default {
  ejs: {
    enable: true,
    package: 'egg-view-ejs',
  },
};
```

Configure the mapping, the file with `.ejs` extension will be rendered by ejs.

```js
// config/config.default.ts
export default {
  view: {
    mapping: {
      '.ejs': 'ejs',
    },
  },
};
```

In controller, you can call `ctx.render`.

```js
export default (app: Application) => {
  return class UserController extends app.Controller {
    async list() {
      const { ctx } = this;
      await ctx.render('user.ejs');
    }
  };
}
```

If you call `ctx.renderString`, you should specify viewEngine in viewOptions.

```js
export default (app: Application) => {
  return class UserController extends app.Controller {
    async list() {
      const { ctx } = this;
      ctx.body = await ctx.renderString(
        '<%= user %>',
        { user: 'popomore' },
        {
          viewEngine: 'ejs',
        }
      );
    }
  };
}
```

## Use multiple view engine

[egg-view] support multiple view engine, so you can use more than one template engine in one application.

If you want add another template engine like [nunjucks], then you can add [egg-view-nunjucks] plugin.

Configure the plugin and mapping

```js
// config/plugin.ts
export default {
  ejs: {
    enable: true,
    package: 'egg-view-ejs',
  },
  nunjucks: {
    enable: true,
    package: 'egg-view-nunjucks',
  },
};
```

```js
// config/config.default.ts
export default {
  view: {
    mapping: {
      '.ejs': 'ejs',
      '.nj': 'nunjucks',
    },
  },
};
```

You can simply render the file with `.nj` extension.

```js
await ctx.render('user.nj');
```

## How to write a view plugin

You can use [@eggjs/view]'s API to register a plugin.

### View engine

Create a view engine class first, and implement `render` and `renderString`, if the template engine don't support, just throw an error.
The view engine is context level, so it receive ctx in `constructor`.

```js
// lib/view.ts
export default class MyView {
  constructor(ctx) {
    // do some initialize
    // get the plugin config from `ctx.app.config`
  }

  async render(fullpath: string, locals: Record<string, any>) {
    return myengine.render(fullpath, locals);
  }

  async renderString() {
    throw new Error('not implement');
  }
}
```

`render` and `renderString` support generator function, async function, or normal function return a promise.

If the template engine only support callback, you can wrap it by Promise.

```js
class MyView {
  render(fullpath, locals) {
    return new Promise((resolve, reject) => {
      myengine.render(fullpath, locals, (err, result) => {
        if (err) {
          reject(err);
        } else {
          resolve(result);
        }
      });
    });
  }
}
```

These methods receive three arguments, `renderString` will pass tpl as the first argument instead of name in `render`.

`render(name, locals, viewOptions)`

- name: the file path that can resolve from root (`app/view` by default)
- locals: data used by template
- viewOptions: the view options for each render, it can override the view default config in `config/config.default.js`. Plugin should implement it if it has config.
  When you implement view engine, you will receive this options from `render`, the options contain:
  - root: egg-view will resolve the name to full path, but seperating root and name in viewOptions.
  - name: the original name when call render
  - locals: the original locals when call render

`renderString(tpl, locals, viewOptions)`

- tpl: the template string instead of the file, using in `renderString`
- locals: same as `render`
- viewOptions: same as `render`

### Register

After define a view engine, you can register it.

```js
// app.ts
import type { Application } from 'egg';
import MyView from './lib/view';

export default (app: Application) => {
  app.view.use('myName', MyView);
}
```

You can define a view engine name, normally it's a template name.

### Configure

Define plugin name and depend on [@eggjs/view]

```json
{
  "eggPlugin": {
    "name": "myName",
    "dependencies": ["view"]
  }
}
```

Set default config in `config/config.default.ts`, the name is equals to plugin name.

```js
export default {
  myName: {},
};
```

See some examples

- [egg-view-ejs]
- [egg-view-nunjucks]

## Configuration

### Root

Root is `${baseDir}/app/view` by default, but you can define multiple directory, seperated by `,`.
[@eggjs/view] will find a file from all root directories.

```js
export default (appInfo: EggAppInfo) => {
  const baseDir = appInfo.baseDir;
  return {
    view: {
      root: `${baseDir}/app/view,${baseDir}/app/view2`,
    },
  };
}
```

### defaultExtension

When render a file, you should specify a extension that let [@eggjs/view] know whitch engine you want to use.
However you can define `defaultExtension` without write the extension.

```js
// config/config.default.ts
export default {
  view: {
    defaultExtension: '.html',
  },
};

// controller
export default (app: Application) => {
  return class UserController extends app.Controller {
    async list() {
      const { ctx } = this;
      // render user.html
      await ctx.render('user');
    }
  }
}
```

### viewEngine and defaultViewEngine

If you are using `renderString`, you should specify viewEngine in view config, see example above.

However, you can define `defaultViewEngine` without set each time.

```js
// config/config.default.ts
export default {
  view: {
    defaultViewEngine: 'ejs',
  },
};
```

see [config/config.default.ts](https://github.com/eggjs/egg/blob/next/plugins/view/src/config/config.default.ts) for more detail.

## Questions & Suggestions

Please open an issue [here](https://github.com/eggjs/egg/issues).

## License

[MIT](LICENSE)

## Contributors

[![Contributors](https://contrib.rocks/image?repo=eggjs/egg)](https://github.com/eggjs/egg/graphs/contributors)

Made with [contributors-img](https://contrib.rocks).

[eggjs]: https://eggjs.org
[ejs]: https://github.com/mde/ejs
[egg-view-ejs]: https://github.com/eggjs/egg-view-ejs
[@eggjs/view]: https://github.com/eggjs/egg/tree/next/plugins/view
[nunjucks]: http://mozilla.github.io/nunjucks
[egg-view-nunjucks]: https://github.com/eggjs/egg-view-nunjucks

---
_Source: https://npm.io/package/@eggjs/view · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
