@zenweb/template 3.0.0
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 +94 -0
- package/dist/engine/handlebars.d.ts +14 -0
- package/dist/engine/handlebars.js +35 -0
- package/dist/engine/nunjucks.d.ts +36 -0
- package/dist/engine/nunjucks.js +34 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +51 -0
- package/dist/render.d.ts +11 -0
- package/dist/render.js +49 -0
- package/dist/types.d.ts +50 -0
- package/dist/types.js +2 -0
- package/dist/utils.d.ts +3 -0
- package/dist/utils.js +13 -0
- package/package.json +43 -0
package/README.md
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# zenweb-template
|
|
2
|
+
|
|
3
|
+
zenweb template render module
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @zenweb/template
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
### nunjucks
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install nunjucks
|
|
15
|
+
npm install @types/nunjucks --save-dev
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### handlebars
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install handlebars
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Config
|
|
25
|
+
|
|
26
|
+
src/index.ts
|
|
27
|
+
```ts
|
|
28
|
+
import { create } from 'zenweb';
|
|
29
|
+
import modTemplate from '@zenweb/template';
|
|
30
|
+
import nunjucks from '@zenweb/template/engine/nunjucks';
|
|
31
|
+
import handlebars from '@zenweb/template/handlebars';
|
|
32
|
+
|
|
33
|
+
const app = create();
|
|
34
|
+
|
|
35
|
+
app.setup(modTemplate({
|
|
36
|
+
matchPath: [/\.html$/i],
|
|
37
|
+
engine: nunjucks({
|
|
38
|
+
filter: require('./template/filter'),
|
|
39
|
+
global: require('./template/global'),
|
|
40
|
+
}),
|
|
41
|
+
}));
|
|
42
|
+
|
|
43
|
+
// Multiple Engines
|
|
44
|
+
app.setup(modTemplate({
|
|
45
|
+
type: 'xml',
|
|
46
|
+
matchPath: [/\.xml$/i],
|
|
47
|
+
templateAffix: '.xml',
|
|
48
|
+
engineName: 'xml',
|
|
49
|
+
engine: handlebars(),
|
|
50
|
+
}));
|
|
51
|
+
|
|
52
|
+
app.start();
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Use
|
|
56
|
+
|
|
57
|
+
src/controller/demo.ts
|
|
58
|
+
```ts
|
|
59
|
+
import { Context, mapping } from "zenweb";
|
|
60
|
+
|
|
61
|
+
export class DemoController {
|
|
62
|
+
@mapping({ path: ['/', '/index.html'] })
|
|
63
|
+
index(ctx: Context) {
|
|
64
|
+
ctx.template('index.html');
|
|
65
|
+
return { name: 'Hello' };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
@mapping({ path: '/test.html' })
|
|
69
|
+
test() {
|
|
70
|
+
return { name: 'Test' };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
@mapping()
|
|
74
|
+
xml(ctx: Context) {
|
|
75
|
+
ctx.template({ engine: 'xml' })
|
|
76
|
+
return { name: 'Test' };
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
template/index.html
|
|
82
|
+
```html
|
|
83
|
+
<h1>Hello {{name}}</h1>
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
template/test.html
|
|
87
|
+
```html
|
|
88
|
+
<h1>Hello {{name}}</h1>
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
template/xml.xml
|
|
92
|
+
```xml
|
|
93
|
+
<root>{{name}}</root>
|
|
94
|
+
```
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { TemplateEngine } from '../types';
|
|
2
|
+
export interface HandlebarsOption extends CompileOptions {
|
|
3
|
+
/**
|
|
4
|
+
* 模版文件夹
|
|
5
|
+
* @default './template'
|
|
6
|
+
*/
|
|
7
|
+
path?: string | string[];
|
|
8
|
+
/**
|
|
9
|
+
* 缓存已编译模版
|
|
10
|
+
* @default true
|
|
11
|
+
*/
|
|
12
|
+
cache?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export default function (option?: HandlebarsOption): TemplateEngine;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const path = require("path");
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
const util_1 = require("util");
|
|
6
|
+
const handlebars_1 = require("handlebars");
|
|
7
|
+
const utils_1 = require("../utils");
|
|
8
|
+
const fs_exists = (0, util_1.promisify)(fs.exists);
|
|
9
|
+
const fs_readFile = (0, util_1.promisify)(fs.readFile);
|
|
10
|
+
function default_1(option) {
|
|
11
|
+
const opt = Object.assign({
|
|
12
|
+
path: './template',
|
|
13
|
+
cache: true,
|
|
14
|
+
}, option);
|
|
15
|
+
(0, utils_1.debug)('option: %o', opt);
|
|
16
|
+
const paths = (Array.isArray(opt.path) ? opt.path : [opt.path]).map(p => (0, utils_1.cwdPath)(p));
|
|
17
|
+
async function loadTemplate(template) {
|
|
18
|
+
for (const p of paths) {
|
|
19
|
+
const filename = path.join(p, template);
|
|
20
|
+
if (await fs_exists(filename)) {
|
|
21
|
+
return await fs_readFile(filename, 'utf-8');
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
throw new Error(`Template file not found: ${template}`);
|
|
25
|
+
}
|
|
26
|
+
const cache = {};
|
|
27
|
+
return async function handlebars(template, data) {
|
|
28
|
+
if (opt.cache && !cache[template]) {
|
|
29
|
+
const content = await loadTemplate(template);
|
|
30
|
+
cache[template] = (0, handlebars_1.compile)(content, opt);
|
|
31
|
+
}
|
|
32
|
+
return cache[template](data);
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
exports.default = default_1;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Environment, ConfigureOptions, Extension } from 'nunjucks';
|
|
2
|
+
import { TemplateEngine } from '../types';
|
|
3
|
+
export interface NunjucksOption {
|
|
4
|
+
/**
|
|
5
|
+
* 模版文件夹
|
|
6
|
+
* @default './template'
|
|
7
|
+
*/
|
|
8
|
+
path?: string | string[];
|
|
9
|
+
/**
|
|
10
|
+
* 配置过滤器
|
|
11
|
+
*/
|
|
12
|
+
filter?: {
|
|
13
|
+
[name: string]: (...args: any[]) => any;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* 配置自定义扩展
|
|
17
|
+
*/
|
|
18
|
+
extension?: {
|
|
19
|
+
[name: string]: Extension;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* 配置全局变量
|
|
23
|
+
*/
|
|
24
|
+
global?: {
|
|
25
|
+
[name: string]: any;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* 设置 nunjucks 配置
|
|
29
|
+
*/
|
|
30
|
+
nunjucksConfig?: ConfigureOptions;
|
|
31
|
+
/**
|
|
32
|
+
* 设置 nunjucks 环境变量
|
|
33
|
+
*/
|
|
34
|
+
configureEnvironment?: (env: Environment) => any;
|
|
35
|
+
}
|
|
36
|
+
export default function (option?: NunjucksOption): TemplateEngine;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const nunjucks_1 = require("nunjucks");
|
|
4
|
+
const utils_1 = require("../utils");
|
|
5
|
+
function default_1(option) {
|
|
6
|
+
const opt = Object.assign({
|
|
7
|
+
path: './template',
|
|
8
|
+
}, option);
|
|
9
|
+
(0, utils_1.debug)('option: %o', opt);
|
|
10
|
+
const paths = (Array.isArray(opt.path) ? opt.path : [opt.path]).map(p => (0, utils_1.cwdPath)(p));
|
|
11
|
+
const env = (0, nunjucks_1.configure)(paths, opt.nunjucksConfig);
|
|
12
|
+
if (opt.filter) {
|
|
13
|
+
Object.entries(opt.filter).forEach(([name, func]) => env.addFilter(name, func));
|
|
14
|
+
}
|
|
15
|
+
if (opt.extension) {
|
|
16
|
+
Object.entries(opt.extension).forEach(([name, ext]) => env.addExtension(name, ext));
|
|
17
|
+
}
|
|
18
|
+
if (opt.global) {
|
|
19
|
+
Object.entries(opt.global).forEach(([name, value]) => env.addGlobal(name, value));
|
|
20
|
+
}
|
|
21
|
+
if (typeof opt.configureEnvironment === 'function') {
|
|
22
|
+
opt.configureEnvironment(env);
|
|
23
|
+
}
|
|
24
|
+
return function nunjucks(name, data) {
|
|
25
|
+
return new Promise((resolve, reject) => {
|
|
26
|
+
env.render(name, data, (err, res) => {
|
|
27
|
+
if (err)
|
|
28
|
+
return reject(err);
|
|
29
|
+
resolve(res);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
exports.default = default_1;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { SetupFunction } from '@zenweb/core';
|
|
2
|
+
import { RenderManager } from '@zenweb/result';
|
|
3
|
+
import { TemplateSetupOption, TemplateOption } from './types';
|
|
4
|
+
import { TEMPLATE_OPTION } from './render';
|
|
5
|
+
export * from './types';
|
|
6
|
+
export { RenderManager };
|
|
7
|
+
export default function setup(option: TemplateSetupOption): SetupFunction;
|
|
8
|
+
declare module '@zenweb/core' {
|
|
9
|
+
interface Context {
|
|
10
|
+
[TEMPLATE_OPTION]?: TemplateOption;
|
|
11
|
+
/**
|
|
12
|
+
* 启用并设置模版渲染
|
|
13
|
+
* - 不传参数: 启用
|
|
14
|
+
* - false: 关闭模版渲染
|
|
15
|
+
* - string: 设置模版文件名
|
|
16
|
+
* - TemplateOption: 详细设置
|
|
17
|
+
*/
|
|
18
|
+
template(template_or_option?: false | string | TemplateOption): void;
|
|
19
|
+
}
|
|
20
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.RenderManager = void 0;
|
|
18
|
+
const result_1 = require("@zenweb/result");
|
|
19
|
+
Object.defineProperty(exports, "RenderManager", { enumerable: true, get: function () { return result_1.RenderManager; } });
|
|
20
|
+
const render_1 = require("./render");
|
|
21
|
+
__exportStar(require("./types"), exports);
|
|
22
|
+
function contextTemplate(template_or_option) {
|
|
23
|
+
if (template_or_option === false) {
|
|
24
|
+
delete this[render_1.TEMPLATE_OPTION];
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (!this[render_1.TEMPLATE_OPTION]) {
|
|
28
|
+
this[render_1.TEMPLATE_OPTION] = {};
|
|
29
|
+
}
|
|
30
|
+
if (typeof template_or_option === 'string') {
|
|
31
|
+
Object.assign(this[render_1.TEMPLATE_OPTION], { template: template_or_option });
|
|
32
|
+
}
|
|
33
|
+
else if (typeof template_or_option === 'object') {
|
|
34
|
+
Object.assign(this[render_1.TEMPLATE_OPTION], template_or_option);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function setup(option) {
|
|
38
|
+
return async function template(setup) {
|
|
39
|
+
if (!option.engineName) {
|
|
40
|
+
option.engineName = option.engine.name;
|
|
41
|
+
}
|
|
42
|
+
setup.debug('option: %o', option);
|
|
43
|
+
setup.assertModuleExists('result', '@zenweb/result');
|
|
44
|
+
const renderManager = await setup.core.injector.getInstance(result_1.RenderManager);
|
|
45
|
+
renderManager.add(new render_1.TemplateRender(option));
|
|
46
|
+
if (!('template' in setup.app.context)) {
|
|
47
|
+
setup.defineContextProperty('template', { value: contextTemplate });
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
exports.default = setup;
|
package/dist/render.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Context } from '@zenweb/core';
|
|
2
|
+
import { ResultRender } from '@zenweb/result';
|
|
3
|
+
import { TemplateSetupOption } from './types';
|
|
4
|
+
export declare const TEMPLATE_OPTION: unique symbol;
|
|
5
|
+
export declare class TemplateRender implements ResultRender {
|
|
6
|
+
private _option;
|
|
7
|
+
type: string;
|
|
8
|
+
constructor(_option: TemplateSetupOption);
|
|
9
|
+
match(ctx: Context): boolean;
|
|
10
|
+
render(ctx: Context, data?: unknown): any;
|
|
11
|
+
}
|
package/dist/render.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TemplateRender = exports.TEMPLATE_OPTION = void 0;
|
|
4
|
+
const utils_1 = require("./utils");
|
|
5
|
+
exports.TEMPLATE_OPTION = Symbol('template@option');
|
|
6
|
+
class TemplateRender {
|
|
7
|
+
constructor(_option) {
|
|
8
|
+
this._option = _option;
|
|
9
|
+
this.type = this._option.type || 'html';
|
|
10
|
+
}
|
|
11
|
+
match(ctx) {
|
|
12
|
+
const opt = ctx[exports.TEMPLATE_OPTION];
|
|
13
|
+
if (opt && opt.engine === this._option.engineName) {
|
|
14
|
+
(0, utils_1.debug)('matchEngine: %o', this._option.engineName);
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
// 匹配路径规则
|
|
18
|
+
if (this._option.matchPath) {
|
|
19
|
+
for (const reg of this._option.matchPath) {
|
|
20
|
+
if (reg.test(ctx.path)) {
|
|
21
|
+
(0, utils_1.debug)('matchPath: %o', reg);
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
// 匹配 Accept 头类型
|
|
27
|
+
if (this._option.matchAccept) {
|
|
28
|
+
const _type = ctx.accepts(this._option.matchAccept);
|
|
29
|
+
if (_type) {
|
|
30
|
+
(0, utils_1.debug)('matchAccept: %o', _type);
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
render(ctx, data) {
|
|
37
|
+
console.log(this);
|
|
38
|
+
const opt = ctx[exports.TEMPLATE_OPTION];
|
|
39
|
+
let template = opt === null || opt === void 0 ? void 0 : opt.template;
|
|
40
|
+
if (!template) {
|
|
41
|
+
template = ctx.path.slice(1);
|
|
42
|
+
if (this._option.templateAffix) {
|
|
43
|
+
template += this._option.templateAffix;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return this._option.engine(template, data);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
exports.TemplateRender = TemplateRender;
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 渲染引擎的渲染方法
|
|
3
|
+
* - 方法名作为默认的引擎名称
|
|
4
|
+
*/
|
|
5
|
+
export type TemplateEngine = (template: string, data?: any) => any;
|
|
6
|
+
export interface TemplateSetupOption {
|
|
7
|
+
/**
|
|
8
|
+
* 输出类型
|
|
9
|
+
* @default 'html'
|
|
10
|
+
*/
|
|
11
|
+
type?: string;
|
|
12
|
+
/**
|
|
13
|
+
* 匹配路径结尾例如 `/.html$/i`
|
|
14
|
+
*/
|
|
15
|
+
matchPath?: RegExp[];
|
|
16
|
+
/**
|
|
17
|
+
* 匹配 Accept Type 头信息
|
|
18
|
+
*/
|
|
19
|
+
matchAccept?: string[];
|
|
20
|
+
/**
|
|
21
|
+
* 模版名后缀
|
|
22
|
+
* - 例如 '.html'
|
|
23
|
+
* - 在不指定 `TemplateOption.template` 时有效
|
|
24
|
+
*/
|
|
25
|
+
templateAffix?: string;
|
|
26
|
+
/**
|
|
27
|
+
* 失败使用模版
|
|
28
|
+
*/
|
|
29
|
+
failTemplate?: string;
|
|
30
|
+
/**
|
|
31
|
+
* 渲染引擎
|
|
32
|
+
*/
|
|
33
|
+
engine: TemplateEngine;
|
|
34
|
+
/**
|
|
35
|
+
* 设置渲染引擎名称
|
|
36
|
+
* - 引擎名称默认取 `engine.name` 可以设置此项改名,可用于多模块切换
|
|
37
|
+
*/
|
|
38
|
+
engineName?: string;
|
|
39
|
+
}
|
|
40
|
+
export interface TemplateOption {
|
|
41
|
+
/**
|
|
42
|
+
* 指定模版名,不指定取 `ctx.path`
|
|
43
|
+
*/
|
|
44
|
+
template?: string;
|
|
45
|
+
/**
|
|
46
|
+
* 使用的渲染引擎
|
|
47
|
+
* - 对应的是 `TemplateSetupOption.engineName`
|
|
48
|
+
*/
|
|
49
|
+
engine?: string;
|
|
50
|
+
}
|
package/dist/types.js
ADDED
package/dist/utils.d.ts
ADDED
package/dist/utils.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.cwdPath = exports.debug = void 0;
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const debug_1 = require("debug");
|
|
6
|
+
exports.debug = (0, debug_1.default)('zenweb:template');
|
|
7
|
+
function cwdPath(p) {
|
|
8
|
+
if (p.startsWith('./')) {
|
|
9
|
+
return path.join(process.cwd(), p.slice(2));
|
|
10
|
+
}
|
|
11
|
+
return p;
|
|
12
|
+
}
|
|
13
|
+
exports.cwdPath = cwdPath;
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@zenweb/template",
|
|
3
|
+
"version": "3.0.0",
|
|
4
|
+
"description": "zenweb template render module",
|
|
5
|
+
"exports": {
|
|
6
|
+
".": "./dist/index.js",
|
|
7
|
+
"./engine": "./dist/engine"
|
|
8
|
+
},
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "rimraf dist && tsc",
|
|
12
|
+
"prepublishOnly": "npm run build",
|
|
13
|
+
"dev": "cd example && cross-env DEBUG=* ts-node app"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"author": {
|
|
19
|
+
"name": "YeFei",
|
|
20
|
+
"email": "316606233@qq.com"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"zenweb",
|
|
24
|
+
"koa",
|
|
25
|
+
"template",
|
|
26
|
+
"nunjucks"
|
|
27
|
+
],
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"homepage": "https://zenweb.node.ltd",
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@types/nunjucks": "^3.2.1",
|
|
32
|
+
"cross-env": "^7.0.3",
|
|
33
|
+
"handlebars": "^4.7.7",
|
|
34
|
+
"nunjucks": "^3.2.3",
|
|
35
|
+
"rimraf": "^4.4.1",
|
|
36
|
+
"ts-node": "^10.9.1",
|
|
37
|
+
"typescript": "^5.0.2",
|
|
38
|
+
"zenweb": "^3.18.0"
|
|
39
|
+
},
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"debug": "^4.3.4"
|
|
42
|
+
}
|
|
43
|
+
}
|