UNPKG

4.29 kBJavaScriptView Raw
1const
2 fs = require('fs'),
3 path = require('path'),
4 extend = require('extend'),
5 objectHash = require('object-hash'),
6 sgUtil = require('./util');
7
8class TemplateEngine {
9 constructor({conf}) {
10 this.conf = conf;
11 this.baseDir = conf.get('baseDir');
12 this.logLevel = conf.get('logLevel', 0);
13 this.engines = new Map();
14 this.cache = new Map();
15
16 this.setDefaultEngine();
17 this.setCustomEngine();
18
19 this.render = this.render.bind(this);
20 }
21
22 async wrap(source, data = {}, templatePath, instance) {
23
24 const wrapperTemplatePath = this.getWrapperTemplatePath(instance);
25
26 if (!fs.existsSync(wrapperTemplatePath)) {
27 return source;
28 }
29
30 const
31 baseDir = this.conf.get('rootPath'),
32 global = this.conf.get('app.globals');
33
34 global.packageName = this.conf.get('package.name');
35 global.packageVersion = this.conf.get('version', this.conf.get('package.version'));
36
37 const
38 options = extend({}, data, {
39 global,
40 source,
41 templatePath,
42 baseDir,
43 cache: false,
44 pretty: true
45 });
46
47 return this.engines.get('pug').render(wrapperTemplatePath, {}, options);
48 }
49
50 getWrapperTemplatePath(instance) {
51 const filename = `../app/templates/wrapper/${instance}Template.pug`;
52 return this.conf.get(`app.wrapperTemplates.${instance}`, path.join(__dirname, filename));
53 }
54
55 setDefaultEngine() {
56 const
57 engine = require('./templateEngines/pug'),
58 options = {
59 basedir: this.baseDir,
60 pretty: true,
61 cache: false,
62 plugins: [require('./pugGlobLoaderPlugin')]
63 };
64 this.setEngine(new engine(options));
65 }
66
67 setCustomEngine() {
68
69 const {conf} = this;
70
71 if (conf.has('customTemplateEngine')) {
72
73 if (conf.has('customTemplateEngine.name')) {
74 const
75 engine = require('./templateEngines/' + conf.get('customTemplateEngine.name')),
76 options = conf.get('customTemplateEngine.options', {}),
77 root = path.resolve(this.baseDir),
78 ext = conf.get('templateExt');
79
80 this.setEngine(new engine(options, root, ext));
81 }
82 else {
83 this.setEngine(conf.get('customTemplateEngine'));
84 }
85 }
86 }
87
88 setEngine(engine) {
89 this.engines.set(engine.ext, engine);
90 }
91
92 async render(file, global = {}, wrap = true) {
93 const {filename, componentName, instance, timestamp, saveHtml, saveLocals, renderHook, extension} = file;
94 const data = extend({}, file.data);
95 const hash = file.hash ? file.hash : objectHash.MD5({componentName, data, global});
96
97 if (this.cache.has(hash) && this.cache.get(hash).timestamp === timestamp) {
98 if (this.logLevel > 0) {
99 sgUtil.log(`Component: \u001b[1m${componentName}\u001b[22m use cached (${hash}).`);
100 }
101 return this.cache.get(hash);
102 }
103
104 let
105 {locals, schema} = data,
106 html = '',
107 source = '';
108
109 if (!fs.existsSync(filename)) {
110 sgUtil.log(`Component: \u001b[1m${componentName}\u001b[22m template file missing.`, 'warn');
111 return {html, source, data, locals};
112 }
113
114 delete data.locals;
115
116 const engine = this.engines.get(extension)
117
118 source = await engine.render(filename, locals, extend({}, {atomatic: data}, global));
119
120 if (typeof source !== 'string' && source.error) {
121
122 if (typeof saveLocals === 'function') {
123 saveLocals({locals, schema});
124 }
125
126 if (typeof saveHtml === 'function') {
127 saveHtml({html: source.error, source});
128 }
129
130 return source.error;
131 }
132
133 if (typeof renderHook === 'function') {
134 ({source, locals} = renderHook(file, source));
135 }
136
137 if (wrap) {
138 html = await this.wrap(source, data, filename, instance);
139 }
140
141 if (typeof saveHtml === 'function') {
142 saveHtml({html, source});
143 }
144
145 if (typeof saveLocals === 'function') {
146 saveLocals({locals, schema});
147 }
148
149 sgUtil.log(`Component: \u001b[1m${componentName}\u001b[22m rendered (${hash}).`, 'info');
150 this.cache.set(hash, {html, source, data, locals, timestamp: timestamp});
151
152 return this.cache.get(hash);
153 }
154
155 kill() {
156 [...this.engines.values()]
157 .filter(engine => typeof engine.kill === 'function')
158 .map((engine) => engine.kill())
159 }
160}
161
162module.exports = TemplateEngine;