@midwayjs/view 3.0.0-beta.8 → 3.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,11 +1,227 @@
1
1
  # midway-view
2
2
 
3
- [![Package Quality](http://npm.packagequality.com/shield/@midwayjs/view.svg)](http://packagequality.com/#?package=@midwayjs/view)
4
- [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/midwayjs/midway/pulls)
3
+ Base view component for midway.
5
4
 
6
- this is a sub package for midway.
5
+ ## Install
6
+
7
+ @midwayjs/view don't have build-in view engine, So you should choose a template engine like ejs, and install `@midwayjs/view-ejs`.
8
+ View component will be auto install and enable by import `view-ejs`.
9
+
10
+ ```bash
11
+ $ npm i @midwayjs/view-ejs --save
12
+ ```
13
+
14
+ ## Usage
15
+
16
+ First, import component in `src/configuration.ts`.
17
+
18
+ ```typescript
19
+ import { Configuration } from '@midwayjs/decorator';
20
+ import * as view from '@midwayjs/view-ejs';
21
+ import { join } from 'path'
22
+
23
+ @Configuration({
24
+ imports: [
25
+ // ...
26
+ view
27
+ ],
28
+ importConfigs: [
29
+ join(__dirname, 'config')
30
+ ]
31
+ })
32
+ export class ContainerLifeCycle {
33
+ }
34
+ ```
35
+
36
+ Configure the mapping, the file with `.ejs` extension will be rendered by ejs.
37
+
38
+ ```typescript
39
+ // src/config/config.default.ts
40
+ export const view = {
41
+ defaultViewEngine: 'ejs',
42
+ mapping: {
43
+ '.ejs': 'ejs',
44
+ },
45
+ };
46
+
47
+ // ejs config
48
+ export const ejs = {};
49
+ ```
50
+
51
+ In controller, you can call `ctx.render`.
52
+
53
+ ```typescript
54
+ import { Inject, Provide } from '@midwayjs/decorator';
55
+ import { Context } from '@midwayjs/koa';
56
+
57
+ @Controller('/')
58
+ export class HomeController {
59
+
60
+ @Inject()
61
+ ctx: Context;
62
+
63
+ @Get('/')
64
+ async render(){
65
+ await this.ctx.render('hello.ejs', {
66
+ data: 'world',
67
+ });
68
+ }
69
+ }
70
+ ```
71
+
72
+ ## Use multiple view engine
73
+
74
+ @midwayjs/view support multiple view engine, so you can use more than one template engine in one application.
75
+
76
+ If you want add another template engine like nunjucks, then you can add @midwayjs/view-nunjucks component.
77
+
78
+ Configure the plugin and mapping
79
+
80
+ ```typescript
81
+ // src/config/config.default.ts
82
+ export const view = {
83
+ mapping: {
84
+ '.ejs': 'ejs',
85
+ '.nj': 'nunjucks',
86
+ },
87
+ };
88
+ ```
89
+ You can simply render the file with .nj extension.
90
+
91
+ ```typescript
92
+ await this.ctx.render('user.nj');
93
+ ```
94
+
95
+ ## Write a view engine
96
+
97
+ Create a view engine class first, and implement render and renderString, if the template engine don't support, just throw an error.
98
+
99
+ ```typescript
100
+ // lib/view.ts
101
+ import { Provide } from '@midwayjs/decorator';
102
+
103
+ @Provide()
104
+ export class MyView {
105
+
106
+ @Config('xxxx')
107
+ viewConfig;
108
+
109
+ async render(fullpath, locals) {
110
+ return myengine.render(fullpath, locals);
111
+ }
112
+
113
+ async renderString() { throw new Error('not implement'); }
114
+ };
115
+ ```
116
+
117
+ These methods receive three arguments, `renderString` will pass tpl as the first argument instead of name in `render`.
118
+
119
+ `render(name, locals, viewOptions)`
120
+
121
+ - name: the file path that can resolve from root (`/view` by default)
122
+ - locals: data used by template
123
+ - 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.
124
+ When you implement view engine, you will receive this options from `render`, the options contain:
125
+ - root: it will resolve the name to full path, but seperating root and name in viewOptions.
126
+ - name: the original name when call render
127
+ - locals: the original locals when call render
128
+
129
+ `renderString(tpl, locals, viewOptions)`
130
+
131
+ - tpl: the template string instead of the file, using in `renderString`
132
+ - locals: same as `render`
133
+ - viewOptions: same as `render`
134
+
135
+ ### Register
136
+
137
+ After define a view engine, you can register it.
138
+
139
+ ```typescript
140
+ // src/configuration.ts
141
+ import { Configuration, Inject, Provide } from '@midwayjs/decorator';
142
+ import * as koa from '@midwayjs/koa';
143
+ import * as view from '@midwayjs/view';
144
+ import { MyView } from './lib/my';
145
+
146
+ @Configuration({
147
+ imports: [koa, view],
148
+ importConfigs: [join(__dirname, 'config')]
149
+ })
150
+ export class AutoConfiguration {
151
+
152
+ @Inject()
153
+ viewManager: view.ViewManager;
154
+
155
+ async onReady(){
156
+ this.viewManager.use('ejs', MyView);
157
+ }
158
+ }
159
+
160
+ ```
161
+
162
+ You can define a view engine name, normally it's a template name.
163
+
164
+ ## Configuration
165
+
166
+ ### Root
167
+
168
+ Root is `${appDir}/view` by default, but you can define multiple directory.
169
+
170
+ ```typescript
171
+ export default appInfo => {
172
+ const appDir = appInfo.appDir;
173
+ return {
174
+ view: {
175
+ rootDir: {
176
+ default: `${appDir}/view`,
177
+ anotherDir: `${appDir}/view2`
178
+ }
179
+ }
180
+ }
181
+ }
182
+ ```
183
+
184
+ ### defaultExtension
185
+
186
+ When render a file, you should specify a extension that let @midway/view know which engine you want to use. However you can define `defaultExtension` without write the extension.
187
+
188
+ ```typescript
189
+ // src/config/config.default.ts
190
+ export const view = {
191
+ defaultExtension: '.html',
192
+ };
193
+
194
+ // controller
195
+ import { Inject, Provide } from '@midwayjs/decorator';
196
+ import { Context } from '@midwayjs/koa';
197
+
198
+ @Controller('/')
199
+ export class HomeController {
200
+
201
+ @Inject()
202
+ ctx: Context;
203
+
204
+ @Get('/')
205
+ async render(){
206
+ // render user.html
207
+ await this.ctx.render('user');
208
+ }
209
+ }
210
+ ```
211
+
212
+ ### viewEngine and defaultViewEngine
213
+
214
+ If you are using `renderString`, you should specify viewEngine in view config, see example above.
215
+
216
+ However, you can define `defaultViewEngine` without set each time.
217
+
218
+ ```js
219
+ // config/config.default.js
220
+ export const view = {
221
+ defaultViewEngine: 'ejs',
222
+ };
223
+ ```
7
224
 
8
- Document: [https://midwayjs.org](https://midwayjs.org)
9
225
 
10
226
  ## License
11
227
 
@@ -1,3 +1,22 @@
1
- declare const _default: (appInfo: any) => any;
1
+ declare const _default: (appInfo: any) => {
2
+ /**
3
+ * view default config
4
+ * @member Config#view
5
+ * @property {String} [rootDir=${appDir}/view] - give a path to find the file, object.values() got array and find for view file
6
+ * @property {Boolean} [cache=true] - whether cache the file's path
7
+ * @property {String} [defaultExtension] - defaultExtension can be added automatically when there is no extension when call `ctx.render`
8
+ * @property {String} [defaultViewEngine] - set the default view engine if you don't want specify the viewEngine every request.
9
+ * @property {Object} mapping - map the file extension to view engine, such as `{ '.ejs': 'ejs' }`
10
+ */
11
+ view: {
12
+ cache: boolean;
13
+ defaultExtension: string;
14
+ defaultViewEngine: string;
15
+ mapping: {};
16
+ rootDir: {
17
+ default: string;
18
+ };
19
+ };
20
+ };
2
21
  export default _default;
3
22
  //# sourceMappingURL=config.default.d.ts.map
@@ -1,13 +1,24 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const path_1 = require("path");
4
- const extend = require("extend2");
5
- exports.default = appInfo => {
6
- const originConfig = require('egg-view/config/config.default')(appInfo);
7
- return extend(true, originConfig, {
8
- view: {
9
- root: (0, path_1.join)(appInfo.appDir, 'view'),
4
+ exports.default = appInfo => ({
5
+ /**
6
+ * view default config
7
+ * @member Config#view
8
+ * @property {String} [rootDir=${appDir}/view] - give a path to find the file, object.values() got array and find for view file
9
+ * @property {Boolean} [cache=true] - whether cache the file's path
10
+ * @property {String} [defaultExtension] - defaultExtension can be added automatically when there is no extension when call `ctx.render`
11
+ * @property {String} [defaultViewEngine] - set the default view engine if you don't want specify the viewEngine every request.
12
+ * @property {Object} mapping - map the file extension to view engine, such as `{ '.ejs': 'ejs' }`
13
+ */
14
+ view: {
15
+ cache: true,
16
+ defaultExtension: '.html',
17
+ defaultViewEngine: '',
18
+ mapping: {},
19
+ rootDir: {
20
+ default: (0, path_1.join)(appInfo.appDir, 'view'),
10
21
  },
11
- });
12
- };
22
+ },
23
+ });
13
24
  //# sourceMappingURL=config.default.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.default.js","sourceRoot":"","sources":["../../src/config/config.default.ts"],"names":[],"mappings":";;AAAA,+BAA4B;AAE5B,kBAAe,OAAO,CAAC,EAAE,CAAC,CAAC;IACzB;;;;;;;;OAQG;IACH,IAAI,EAAE;QACJ,KAAK,EAAE,IAAI;QACX,gBAAgB,EAAE,OAAO;QACzB,iBAAiB,EAAE,EAAE;QACrB,OAAO,EAAE,EAAE;QACX,OAAO,EAAE;YACP,OAAO,EAAE,IAAA,WAAI,EAAC,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC;SACtC;KACF;CACF,CAAC,CAAC","sourcesContent":["import { join } from 'path';\n\nexport default appInfo => ({\n /**\n * view default config\n * @member Config#view\n * @property {String} [rootDir=${appDir}/view] - give a path to find the file, object.values() got array and find for view file\n * @property {Boolean} [cache=true] - whether cache the file's path\n * @property {String} [defaultExtension] - defaultExtension can be added automatically when there is no extension when call `ctx.render`\n * @property {String} [defaultViewEngine] - set the default view engine if you don't want specify the viewEngine every request.\n * @property {Object} mapping - map the file extension to view engine, such as `{ '.ejs': 'ejs' }`\n */\n view: {\n cache: true,\n defaultExtension: '.html',\n defaultViewEngine: '',\n mapping: {},\n rootDir: {\n default: join(appInfo.appDir, 'view'),\n },\n },\n});\n"]}
@@ -1,3 +1,4 @@
1
- declare const _default: any;
2
- export default _default;
1
+ export declare const view: {
2
+ cache: boolean;
3
+ };
3
4
  //# sourceMappingURL=config.local.d.ts.map
@@ -1,4 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.default = require('egg-view/config/config.local');
3
+ exports.view = void 0;
4
+ exports.view = {
5
+ cache: false,
6
+ };
4
7
  //# sourceMappingURL=config.local.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.local.js","sourceRoot":"","sources":["../../src/config/config.local.ts"],"names":[],"mappings":";;;AAAa,QAAA,IAAI,GAAG;IAClB,KAAK,EAAE,KAAK;CACb,CAAC","sourcesContent":["export const view = {\n cache: false,\n};\n"]}
@@ -1,5 +1,6 @@
1
+ import { MidwayApplicationManager } from '@midwayjs/core';
1
2
  export declare class ViewConfiguration {
2
- app: any;
3
+ applicationManager: MidwayApplicationManager;
3
4
  onReady(container: any): Promise<void>;
4
5
  }
5
6
  //# sourceMappingURL=configuration.d.ts.map
@@ -11,28 +11,58 @@ var __metadata = (this && this.__metadata) || function (k, v) {
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.ViewConfiguration = void 0;
13
13
  const decorator_1 = require("@midwayjs/decorator");
14
- const mw_util_1 = require("@midwayjs/mw-util");
15
14
  const DefaultConfig = require("./config/config.default");
16
15
  const LocalConfig = require("./config/config.local");
17
16
  const viewManager_1 = require("./viewManager");
17
+ const core_1 = require("@midwayjs/core");
18
+ const contextView_1 = require("./contextView");
18
19
  let ViewConfiguration = class ViewConfiguration {
19
20
  async onReady(container) {
20
- if (!this.app.config) {
21
- this.app.config = this.app.getConfig();
22
- }
23
- (0, mw_util_1.completeAssign)(this.app.context, require('egg-view/app/extend/context'));
24
- this.app.view = await container.getAsync(viewManager_1.ViewManager);
25
- if (!this.app.toAsyncFunction) {
26
- this.app.toAsyncFunction = method => {
27
- return method;
28
- };
29
- }
21
+ this.applicationManager
22
+ .getApplications(['koa', 'egg', 'faas'])
23
+ .forEach((app) => {
24
+ Object.defineProperties(app.context, {
25
+ /**
26
+ * Render a file, then set to body, the parameter is same as {@link @ContextView#render}
27
+ * @return {Promise} result
28
+ */
29
+ render: {
30
+ value: async function (...args) {
31
+ const contextView = await this.requestContext.getAsync(contextView_1.ContextView);
32
+ return contextView.render(...args).then(body => {
33
+ this.body = body;
34
+ });
35
+ },
36
+ },
37
+ /**
38
+ * Render a file, same as {@link @ContextView#render}
39
+ * @return {Promise} result
40
+ */
41
+ renderView: {
42
+ value: async function (...args) {
43
+ const contextView = await this.requestContext.getAsync(contextView_1.ContextView);
44
+ return contextView.render(...args);
45
+ },
46
+ },
47
+ /**
48
+ * Render template string, same as {@link @ContextView#renderString}
49
+ * @return {Promise} result
50
+ */
51
+ renderString: {
52
+ value: async function (...args) {
53
+ const contextView = await this.requestContext.getAsync(contextView_1.ContextView);
54
+ return contextView.renderString(...args);
55
+ },
56
+ },
57
+ });
58
+ });
59
+ await container.getAsync(viewManager_1.ViewManager);
30
60
  }
31
61
  };
32
62
  __decorate([
33
- (0, decorator_1.App)(),
34
- __metadata("design:type", Object)
35
- ], ViewConfiguration.prototype, "app", void 0);
63
+ (0, decorator_1.Inject)(),
64
+ __metadata("design:type", core_1.MidwayApplicationManager)
65
+ ], ViewConfiguration.prototype, "applicationManager", void 0);
36
66
  ViewConfiguration = __decorate([
37
67
  (0, decorator_1.Configuration)({
38
68
  namespace: 'view',
@@ -0,0 +1 @@
1
+ {"version":3,"file":"configuration.js","sourceRoot":"","sources":["../src/configuration.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,mDAA4D;AAC5D,yDAAyD;AACzD,qDAAqD;AACrD,+CAA4C;AAC5C,yCAA0D;AAC1D,+CAA4C;AAW5C,IAAa,iBAAiB,GAA9B,MAAa,iBAAiB;IAI5B,KAAK,CAAC,OAAO,CAAC,SAAS;QACrB,IAAI,CAAC,kBAAkB;aACpB,eAAe,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;aACvC,OAAO,CAAC,CAAC,GAAQ,EAAE,EAAE;YACpB,MAAM,CAAC,gBAAgB,CAAC,GAAG,CAAC,OAAO,EAAE;gBACnC;;;mBAGG;gBACH,MAAM,EAAE;oBACN,KAAK,EAAE,KAAK,WAAW,GAAG,IAAI;wBAC5B,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,QAAQ,CACpD,yBAAW,CACZ,CAAC;wBACF,OAAO,WAAW,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;4BAC7C,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;wBACnB,CAAC,CAAC,CAAC;oBACL,CAAC;iBACF;gBAED;;;mBAGG;gBACH,UAAU,EAAE;oBACV,KAAK,EAAE,KAAK,WAAW,GAAG,IAAI;wBAC5B,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,QAAQ,CACpD,yBAAW,CACZ,CAAC;wBACF,OAAO,WAAW,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;oBACrC,CAAC;iBACF;gBAED;;;mBAGG;gBACH,YAAY,EAAE;oBACZ,KAAK,EAAE,KAAK,WAAW,GAAG,IAAI;wBAC5B,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,QAAQ,CACpD,yBAAW,CACZ,CAAC;wBACF,OAAO,WAAW,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC,CAAC;oBAC3C,CAAC;iBACF;aACF,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEL,MAAM,SAAS,CAAC,QAAQ,CAAC,yBAAW,CAAC,CAAC;IACxC,CAAC;CACF,CAAA;AApDC;IADC,IAAA,kBAAM,GAAE;8BACW,+BAAwB;6DAAC;AAFlC,iBAAiB;IAT7B,IAAA,yBAAa,EAAC;QACb,SAAS,EAAE,MAAM;QACjB,aAAa,EAAE;YACb;gBACE,OAAO,EAAE,aAAa;gBACtB,KAAK,EAAE,WAAW;aACnB;SACF;KACF,CAAC;GACW,iBAAiB,CAsD7B;AAtDY,8CAAiB","sourcesContent":["import { Inject, Configuration } from '@midwayjs/decorator';\nimport * as DefaultConfig from './config/config.default';\nimport * as LocalConfig from './config/config.local';\nimport { ViewManager } from './viewManager';\nimport { MidwayApplicationManager } from '@midwayjs/core';\nimport { ContextView } from './contextView';\n\n@Configuration({\n namespace: 'view',\n importConfigs: [\n {\n default: DefaultConfig,\n local: LocalConfig,\n },\n ],\n})\nexport class ViewConfiguration {\n @Inject()\n applicationManager: MidwayApplicationManager;\n\n async onReady(container) {\n this.applicationManager\n .getApplications(['koa', 'egg', 'faas'])\n .forEach((app: any) => {\n Object.defineProperties(app.context, {\n /**\n * Render a file, then set to body, the parameter is same as {@link @ContextView#render}\n * @return {Promise} result\n */\n render: {\n value: async function (...args) {\n const contextView = await this.requestContext.getAsync(\n ContextView\n );\n return contextView.render(...args).then(body => {\n this.body = body;\n });\n },\n },\n\n /**\n * Render a file, same as {@link @ContextView#render}\n * @return {Promise} result\n */\n renderView: {\n value: async function (...args) {\n const contextView = await this.requestContext.getAsync(\n ContextView\n );\n return contextView.render(...args);\n },\n },\n\n /**\n * Render template string, same as {@link @ContextView#renderString}\n * @return {Promise} result\n */\n renderString: {\n value: async function (...args) {\n const contextView = await this.requestContext.getAsync(\n ContextView\n );\n return contextView.renderString(...args);\n },\n },\n });\n });\n\n await container.getAsync(ViewManager);\n }\n}\n"]}
@@ -0,0 +1,18 @@
1
+ import { ViewManager } from './viewManager';
2
+ import { IViewEngine, RenderOptions } from './interface';
3
+ /**
4
+ * View instance for each request.
5
+ *
6
+ * It will find the view engine, and render it.
7
+ * The view engine should be registered in {@link ViewManager}.
8
+ */
9
+ export declare class ContextView implements IViewEngine {
10
+ viewManager: ViewManager;
11
+ viewConfig: any;
12
+ ctx: any;
13
+ render(name: string, locals?: Record<string, any>, options?: RenderOptions): Promise<string>;
14
+ renderString(tpl: string, locals?: Record<string, any>, options?: RenderOptions): Promise<string>;
15
+ private getViewEngine;
16
+ private setLocals;
17
+ }
18
+ //# sourceMappingURL=contextView.d.ts.map
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.ContextView = void 0;
13
+ const viewManager_1 = require("./viewManager");
14
+ const decorator_1 = require("@midwayjs/decorator");
15
+ const assert = require("assert");
16
+ const path_1 = require("path");
17
+ /**
18
+ * View instance for each request.
19
+ *
20
+ * It will find the view engine, and render it.
21
+ * The view engine should be registered in {@link ViewManager}.
22
+ */
23
+ let ContextView = class ContextView {
24
+ async render(name, locals, options) {
25
+ // retrieve fullpath matching name from `config.root`
26
+ const filename = await this.viewManager.resolve(name);
27
+ options = options !== null && options !== void 0 ? options : {};
28
+ options.name = name;
29
+ options.root = filename.replace((0, path_1.normalize)(name), '').replace(/[/\\]$/, '');
30
+ options.locals = locals;
31
+ // get the name of view engine,
32
+ // if viewEngine is specified in options, don't match extension
33
+ let viewEngineName = options.viewEngine;
34
+ if (!viewEngineName) {
35
+ const ext = (0, path_1.extname)(filename);
36
+ viewEngineName = this.viewManager.extMap.get(ext);
37
+ }
38
+ // use the default view engine that is configured if no matching above
39
+ if (!viewEngineName) {
40
+ viewEngineName = this.viewConfig.defaultViewEngine;
41
+ }
42
+ assert(viewEngineName, `Can't find viewEngine for ${filename}`);
43
+ // get view engine and render
44
+ const view = await this.getViewEngine(viewEngineName);
45
+ return await view.render(filename, this.setLocals(locals), options);
46
+ }
47
+ async renderString(tpl, locals, options) {
48
+ var _a;
49
+ options = options !== null && options !== void 0 ? options : {};
50
+ const viewEngineName = (_a = options.viewEngine) !== null && _a !== void 0 ? _a : this.viewConfig.defaultViewEngine;
51
+ assert(viewEngineName, "Can't find viewEngine");
52
+ // get view engine and render
53
+ const view = await this.getViewEngine(viewEngineName);
54
+ return await view.renderString(tpl, this.setLocals(locals), options);
55
+ }
56
+ async getViewEngine(name) {
57
+ // get view engine
58
+ const ViewEngine = this.viewManager.get(name);
59
+ assert(ViewEngine, `Can't find ViewEngine "${name}"`);
60
+ // use view engine to render
61
+ const engine = await this.ctx.requestContext.getAsync(ViewEngine);
62
+ // wrap render and renderString to support both async function and generator function
63
+ if (engine.render) {
64
+ engine.render = decorator_1.Utils.toAsyncFunction(engine.render);
65
+ }
66
+ if (engine.renderString) {
67
+ engine.renderString = decorator_1.Utils.toAsyncFunction(engine.renderString);
68
+ }
69
+ return engine;
70
+ }
71
+ setLocals(locals) {
72
+ return Object.assign({
73
+ ctx: this.ctx,
74
+ request: this.ctx.request,
75
+ }, this.ctx.locals, locals);
76
+ }
77
+ };
78
+ __decorate([
79
+ (0, decorator_1.Inject)(),
80
+ __metadata("design:type", viewManager_1.ViewManager)
81
+ ], ContextView.prototype, "viewManager", void 0);
82
+ __decorate([
83
+ (0, decorator_1.Config)('view'),
84
+ __metadata("design:type", Object)
85
+ ], ContextView.prototype, "viewConfig", void 0);
86
+ __decorate([
87
+ (0, decorator_1.Inject)(),
88
+ __metadata("design:type", Object)
89
+ ], ContextView.prototype, "ctx", void 0);
90
+ ContextView = __decorate([
91
+ (0, decorator_1.Provide)()
92
+ ], ContextView);
93
+ exports.ContextView = ContextView;
94
+ //# sourceMappingURL=contextView.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contextView.js","sourceRoot":"","sources":["../src/contextView.ts"],"names":[],"mappings":"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","sourcesContent":["import { ViewManager } from './viewManager';\nimport { Provide, Inject, Config, Utils } from '@midwayjs/decorator';\nimport * as assert from 'assert';\nimport { normalize, extname } from 'path';\nimport { IViewEngine, RenderOptions } from './interface';\n\n/**\n * View instance for each request.\n *\n * It will find the view engine, and render it.\n * The view engine should be registered in {@link ViewManager}.\n */\n@Provide()\nexport class ContextView implements IViewEngine {\n @Inject()\n viewManager: ViewManager;\n\n @Config('view')\n viewConfig;\n\n @Inject()\n ctx;\n\n async render(\n name: string,\n locals?: Record<string, any>,\n options?: RenderOptions\n ): Promise<string> {\n // retrieve fullpath matching name from `config.root`\n const filename = await this.viewManager.resolve(name);\n options = options ?? {};\n options.name = name;\n options.root = filename.replace(normalize(name), '').replace(/[/\\\\]$/, '');\n options.locals = locals;\n\n // get the name of view engine,\n // if viewEngine is specified in options, don't match extension\n let viewEngineName = options.viewEngine;\n if (!viewEngineName) {\n const ext = extname(filename);\n viewEngineName = this.viewManager.extMap.get(ext);\n }\n // use the default view engine that is configured if no matching above\n if (!viewEngineName) {\n viewEngineName = this.viewConfig.defaultViewEngine;\n }\n assert(viewEngineName, `Can't find viewEngine for ${filename}`);\n\n // get view engine and render\n const view = await this.getViewEngine(viewEngineName);\n return await view.render(filename, this.setLocals(locals), options);\n }\n\n async renderString(\n tpl: string,\n locals?: Record<string, any>,\n options?: RenderOptions\n ): Promise<string> {\n options = options ?? {};\n const viewEngineName =\n options.viewEngine ?? this.viewConfig.defaultViewEngine;\n assert(viewEngineName, \"Can't find viewEngine\");\n\n // get view engine and render\n const view = await this.getViewEngine(viewEngineName);\n return await view.renderString(tpl, this.setLocals(locals), options);\n }\n\n private async getViewEngine(name) {\n // get view engine\n const ViewEngine = this.viewManager.get(name);\n assert(ViewEngine, `Can't find ViewEngine \"${name}\"`);\n\n // use view engine to render\n const engine = await this.ctx.requestContext.getAsync(ViewEngine);\n // wrap render and renderString to support both async function and generator function\n if (engine.render) {\n engine.render = Utils.toAsyncFunction(engine.render);\n }\n if (engine.renderString) {\n engine.renderString = Utils.toAsyncFunction(engine.renderString);\n }\n return engine;\n }\n\n private setLocals(locals) {\n return Object.assign(\n {\n ctx: this.ctx,\n request: this.ctx.request,\n },\n this.ctx.locals,\n locals\n );\n }\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
1
  export { ViewConfiguration as Configuration } from './configuration';
2
+ export * from './interface';
3
+ export * from './contextView';
2
4
  export * from './viewManager';
3
5
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -13,5 +13,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
13
13
  exports.Configuration = void 0;
14
14
  var configuration_1 = require("./configuration");
15
15
  Object.defineProperty(exports, "Configuration", { enumerable: true, get: function () { return configuration_1.ViewConfiguration; } });
16
+ __exportStar(require("./interface"), exports);
17
+ __exportStar(require("./contextView"), exports);
16
18
  __exportStar(require("./viewManager"), exports);
17
19
  //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,iDAAqE;AAA5D,8GAAA,iBAAiB,OAAiB;AAC3C,8CAA4B;AAC5B,gDAA8B;AAC9B,gDAA8B","sourcesContent":["export { ViewConfiguration as Configuration } from './configuration';\nexport * from './interface';\nexport * from './contextView';\nexport * from './viewManager';\n"]}
@@ -0,0 +1,25 @@
1
+ export interface RenderOptions {
2
+ name?: string;
3
+ root?: string;
4
+ locals?: Record<string, any>;
5
+ viewEngine?: string;
6
+ }
7
+ export interface IViewEngine {
8
+ /**
9
+ * Render a file by view engine, then set to body
10
+ * @param {String} name - the file path based on root
11
+ * @param {Object} [locals] - data used by template
12
+ * @param {Object} [options] - view options, you can use `options.viewEngine` to specify view engine
13
+ * @return {Promise<String>} result - return a promise with a render result
14
+ */
15
+ render(name: string, locals?: Record<string, any>, options?: RenderOptions): Promise<string>;
16
+ /**
17
+ * Render a template string by view engine
18
+ * @param {String} tpl - template string
19
+ * @param {Object} [locals] - data used by template
20
+ * @param {Object} [options] - view options, you can use `options.viewEngine` to specify view engine
21
+ * @return {Promise<String>} result - return a promise with a render result
22
+ */
23
+ renderString(tpl: string, locals?: Record<string, any>, options?: RenderOptions): Promise<string>;
24
+ }
25
+ //# sourceMappingURL=interface.d.ts.map
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interface.js","sourceRoot":"","sources":["../src/interface.ts"],"names":[],"mappings":"","sourcesContent":["export interface RenderOptions {\n name?: string;\n root?: string;\n locals?: Record<string, any>;\n viewEngine?: string;\n}\n\nexport interface IViewEngine {\n /**\n * Render a file by view engine, then set to body\n * @param {String} name - the file path based on root\n * @param {Object} [locals] - data used by template\n * @param {Object} [options] - view options, you can use `options.viewEngine` to specify view engine\n * @return {Promise<String>} result - return a promise with a render result\n */\n render(name: string, locals?: Record<string, any>, options?: RenderOptions): Promise<string>;\n\n /**\n * Render a template string by view engine\n * @param {String} tpl - template string\n * @param {Object} [locals] - data used by template\n * @param {Object} [options] - view options, you can use `options.viewEngine` to specify view engine\n * @return {Promise<String>} result - return a promise with a render result\n */\n renderString(\n tpl: string,\n locals?: Record<string, any>,\n options?: RenderOptions\n ): Promise<string>;\n}\n"]}
@@ -1,9 +1,11 @@
1
- export declare class ViewManager {
1
+ import { IViewEngine } from './interface';
2
+ export declare class ViewManager extends Map {
2
3
  app: any;
3
- innerManager: any;
4
- get extMap(): any;
5
- get config(): any;
6
- init(): Promise<void>;
4
+ viewConfig: any;
5
+ config: any;
6
+ extMap: Map<any, any>;
7
+ fileMap: Map<any, any>;
8
+ init(): void;
7
9
  /**
8
10
  * This method can register view engine.
9
11
  *
@@ -18,15 +20,14 @@ export declare class ViewManager {
18
20
  * @param {String} name - the name of view engine
19
21
  * @param {Object} viewEngine - the class of view engine
20
22
  */
21
- use(name: string, viewEngine: any): void;
23
+ use(name: string, viewEngine: new (...args: any[]) => IViewEngine): void;
22
24
  /**
23
25
  * Resolve the path based on the given name,
24
- * if the name is `user.html` and root is `app/view` (by default),
25
- * it will return `app/view/user.html`
26
+ * if the name is `user.html` and root is `view` (by default),
27
+ * it will return `view/user.html`
26
28
  * @param {String} name - the given path name, it's relative to config.root
27
29
  * @return {String} filename - the full path
28
30
  */
29
31
  resolve(name: string): Promise<string>;
30
- get(key: any): any;
31
32
  }
32
33
  //# sourceMappingURL=viewManager.d.ts.map