miki-template 2.2.2 → 2.3.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/.github/workflows/docs.yml +3 -1
- package/.github/workflows/release.yml +1 -0
- package/benchmarks/ejs-results.json +6 -6
- package/benchmarks/ejs.js +5 -3
- package/benchmarks/handlebars-results.json +6 -6
- package/benchmarks/handlebars.js +5 -8
- package/benchmarks/miki-results.json +6 -6
- package/benchmarks/miki.js +6 -3
- package/benchmarks/pug-results.json +6 -6
- package/benchmarks/pug.js +5 -3
- package/docs/api/async-render.md +88 -3
- package/docs/api/cache.md +90 -3
- package/docs/api/compile.md +131 -3
- package/docs/api/context-processors.md +80 -3
- package/docs/api/filters.md +223 -3
- package/docs/api/finder.md +97 -3
- package/docs/api/helpers.md +56 -3
- package/docs/api/i18n.md +160 -3
- package/docs/api/index.md +82 -28
- package/docs/api/libraries.md +210 -3
- package/docs/api/render-partial.md +84 -3
- package/docs/api/render.md +95 -3
- package/docs/api/security.md +148 -3
- package/docs/api/setup-express.md +78 -2
- package/docs/api/tags.md +138 -4
- package/docs/filter.md +0 -0
- package/docs/guide/advanced-usage.md +403 -6
- package/docs/guide/async-rendering.md +312 -4
- package/docs/guide/context-processors.md +261 -4
- package/docs/guide/custom-filters.md +315 -4
- package/docs/guide/custom-tags.md +275 -4
- package/docs/guide/filters.md +675 -3
- package/docs/guide/getting-started.md +109 -7
- package/docs/guide/installation.md +99 -4
- package/docs/guide/partial-templates.md +371 -4
- package/docs/guide/quick-start.md +228 -6
- package/docs/guide/security.md +348 -3
- package/docs/guide/tags.md +789 -6
- package/docs/guide/template-discovery.md +174 -4
- package/docs/guide/template-inheritance.md +277 -4
- package/docs/index.md +24 -42
- package/docs/integrations/elysia.md +4 -2
- package/docs/integrations/express.md +219 -219
- package/docs/integrations/fastify.md +4 -2
- package/docs/integrations/hono.md +4 -2
- package/docs/integrations/index.md +68 -68
- package/docs/integrations/koa.md +4 -2
- package/docs/integrations/nestjs.md +4 -2
- package/docs/integrations/tsed.md +4 -2
- package/docs/performance.md +45 -8
- package/ex.mjs +1 -1
- package/mkdocs.yml +0 -22
- package/overrides/main.html +1 -1
- package/package.json +1 -1
- package/requirements-docs.txt +2 -1
- package/src/codegen.js +905 -0
- package/src/context.js +42 -30
- package/src/filters.js +16 -0
- package/src/index.js +66 -61
- package/src/tags/control.js +15 -12
- package/src/utils.js +60 -0
- package/tests/filters.test.js +9 -0
- package/.github/workflows/npm-publish-github-packages.yml +0 -36
- package/docs/javascripts/extra.js +0 -174
- package/docs/stylesheets/extra.css +0 -819
- package/overrides/partials/footer.html +0 -9
|
@@ -1,257 +1,514 @@
|
|
|
1
|
-
# Context Processors
|
|
1
|
+
# Context Processors
|
|
2
|
+
|
|
3
|
+
|
|
2
4
|
|
|
3
5
|
Context processors are functions that automatically inject variables into every template render. This follows Django's context processor pattern — ideal for injecting global settings, user data, or feature flags.
|
|
4
6
|
|
|
7
|
+
|
|
8
|
+
|
|
5
9
|
## Table of Contents
|
|
6
10
|
|
|
11
|
+
|
|
12
|
+
|
|
7
13
|
- [How Context Processors Work](#how-context-processors-work)
|
|
14
|
+
|
|
8
15
|
- [Register a Context Processor](#register-a-context-processor)
|
|
16
|
+
|
|
9
17
|
- [Context Processor Signature](#context-processor-signature)
|
|
18
|
+
|
|
10
19
|
- [Overriding Behavior](#overriding-behavior)
|
|
20
|
+
|
|
11
21
|
- [Real-World Examples](#real-world-examples)
|
|
22
|
+
|
|
12
23
|
- [Clearing Processors](#clearing-processors)
|
|
13
24
|
|
|
25
|
+
|
|
26
|
+
|
|
14
27
|
---
|
|
15
28
|
|
|
29
|
+
|
|
30
|
+
|
|
16
31
|
## How Context Processors Work
|
|
17
32
|
|
|
33
|
+
|
|
34
|
+
|
|
18
35
|
Context processors run on **every render** (both `render()` and `compile().render()`). They return an object of key/value pairs that are merged into the rendering context **before** your template's local context is applied.
|
|
19
36
|
|
|
37
|
+
|
|
38
|
+
|
|
20
39
|
```mermaid
|
|
40
|
+
|
|
21
41
|
graph LR
|
|
42
|
+
|
|
22
43
|
A[Your Context] --> B[Apply Processors]
|
|
44
|
+
|
|
23
45
|
B --> C[Processor adds global vars]
|
|
46
|
+
|
|
24
47
|
C --> D[Your Context wins]
|
|
48
|
+
|
|
25
49
|
D --> E[Template renders]
|
|
50
|
+
|
|
26
51
|
```
|
|
27
52
|
|
|
53
|
+
|
|
54
|
+
|
|
28
55
|
**Key behavior:** Your explicit context values **always win** over processor values. This means you can override global defaults per-render without fighting the processor.
|
|
29
56
|
|
|
57
|
+
|
|
58
|
+
|
|
30
59
|
## Register a Context Processor
|
|
31
60
|
|
|
61
|
+
|
|
62
|
+
|
|
32
63
|
=== "CommonJS"
|
|
33
64
|
|
|
65
|
+
|
|
66
|
+
|
|
34
67
|
```javascript
|
|
68
|
+
|
|
35
69
|
const { registerContextProcessor } = require('miki-template');
|
|
36
70
|
|
|
71
|
+
|
|
72
|
+
|
|
37
73
|
registerContextProcessor((context) => {
|
|
74
|
+
|
|
38
75
|
return {
|
|
76
|
+
|
|
39
77
|
siteName: 'My App',
|
|
78
|
+
|
|
40
79
|
currentYear: new Date().getFullYear(),
|
|
80
|
+
|
|
41
81
|
debug: process.env.NODE_ENV !== 'production'
|
|
82
|
+
|
|
42
83
|
};
|
|
84
|
+
|
|
43
85
|
});
|
|
86
|
+
|
|
44
87
|
```
|
|
45
88
|
|
|
89
|
+
|
|
90
|
+
|
|
46
91
|
=== "ES Modules"
|
|
47
92
|
|
|
93
|
+
|
|
94
|
+
|
|
48
95
|
```javascript
|
|
96
|
+
|
|
49
97
|
import { registerContextProcessor } from 'miki-template';
|
|
50
98
|
|
|
99
|
+
|
|
100
|
+
|
|
51
101
|
registerContextProcessor((context) => {
|
|
102
|
+
|
|
52
103
|
return {
|
|
104
|
+
|
|
53
105
|
siteName: 'My App',
|
|
106
|
+
|
|
54
107
|
currentYear: new Date().getFullYear(),
|
|
108
|
+
|
|
55
109
|
debug: process.env.NODE_ENV !== 'production'
|
|
110
|
+
|
|
56
111
|
};
|
|
112
|
+
|
|
57
113
|
});
|
|
114
|
+
|
|
58
115
|
```
|
|
59
116
|
|
|
117
|
+
|
|
118
|
+
|
|
60
119
|
### Multiple Processors
|
|
61
120
|
|
|
121
|
+
|
|
122
|
+
|
|
62
123
|
You can register multiple processors. They run in order — later processors can overwrite earlier ones:
|
|
63
124
|
|
|
125
|
+
|
|
126
|
+
|
|
64
127
|
=== "CommonJS"
|
|
65
128
|
|
|
129
|
+
|
|
130
|
+
|
|
66
131
|
```javascript
|
|
132
|
+
|
|
67
133
|
const { registerContextProcessor } = require('miki-template');
|
|
68
134
|
|
|
135
|
+
|
|
136
|
+
|
|
69
137
|
registerContextProcessor(() => ({ siteName: 'My App' }));
|
|
138
|
+
|
|
70
139
|
registerContextProcessor(() => ({ version: '2.0.0' }));
|
|
140
|
+
|
|
71
141
|
registerContextProcessor(() => ({
|
|
142
|
+
|
|
72
143
|
footerText: '© 2024 My App. All rights reserved.'
|
|
144
|
+
|
|
73
145
|
}));
|
|
146
|
+
|
|
74
147
|
```
|
|
75
148
|
|
|
149
|
+
|
|
150
|
+
|
|
76
151
|
=== "ES Modules"
|
|
77
152
|
|
|
153
|
+
|
|
154
|
+
|
|
78
155
|
```javascript
|
|
156
|
+
|
|
79
157
|
import { registerContextProcessor } from 'miki-template';
|
|
80
158
|
|
|
159
|
+
|
|
160
|
+
|
|
81
161
|
registerContextProcessor(() => ({ siteName: 'My App' }));
|
|
162
|
+
|
|
82
163
|
registerContextProcessor(() => ({ version: '2.0.0' }));
|
|
164
|
+
|
|
83
165
|
registerContextProcessor(() => ({
|
|
166
|
+
|
|
84
167
|
footerText: '© 2024 My App. All rights reserved.'
|
|
168
|
+
|
|
85
169
|
}));
|
|
170
|
+
|
|
86
171
|
```
|
|
87
172
|
|
|
173
|
+
|
|
174
|
+
|
|
88
175
|
## Context Processor Signature
|
|
89
176
|
|
|
177
|
+
|
|
178
|
+
|
|
90
179
|
The processor function receives the rendering `context` as an argument and must return a plain object:
|
|
91
180
|
|
|
181
|
+
|
|
182
|
+
|
|
92
183
|
```javascript
|
|
184
|
+
|
|
93
185
|
registerContextProcessor((context) => {
|
|
186
|
+
|
|
94
187
|
// context is the full Context object — you can inspect contextObj
|
|
188
|
+
|
|
95
189
|
// but don't mutate it
|
|
190
|
+
|
|
96
191
|
return {
|
|
192
|
+
|
|
97
193
|
key: 'value'
|
|
194
|
+
|
|
98
195
|
};
|
|
196
|
+
|
|
99
197
|
});
|
|
198
|
+
|
|
100
199
|
```
|
|
101
200
|
|
|
201
|
+
|
|
202
|
+
|
|
102
203
|
**Important:** If a processor returns `null`, `undefined`, or nothing, it's treated as returning an empty object `{}`. Processors must **not** return a Promise — if you need async data, compute it before rendering and pass it as context.
|
|
103
204
|
|
|
205
|
+
|
|
206
|
+
|
|
104
207
|
## Overriding Behavior
|
|
105
208
|
|
|
209
|
+
|
|
210
|
+
|
|
106
211
|
Since your explicit context always wins, you can override global defaults per-render:
|
|
107
212
|
|
|
213
|
+
|
|
214
|
+
|
|
108
215
|
=== "CommonJS"
|
|
109
216
|
|
|
217
|
+
|
|
218
|
+
|
|
110
219
|
```javascript
|
|
220
|
+
|
|
111
221
|
const { render } = require('miki-template');
|
|
112
222
|
|
|
223
|
+
|
|
224
|
+
|
|
113
225
|
// processor sets debug: false
|
|
226
|
+
|
|
114
227
|
// but this render overrides it:
|
|
228
|
+
|
|
115
229
|
render(template, { debug: true });
|
|
230
|
+
|
|
116
231
|
```
|
|
117
232
|
|
|
233
|
+
|
|
234
|
+
|
|
118
235
|
=== "ES Modules"
|
|
119
236
|
|
|
237
|
+
|
|
238
|
+
|
|
120
239
|
```javascript
|
|
240
|
+
|
|
121
241
|
import { render } from 'miki-template';
|
|
122
242
|
|
|
243
|
+
|
|
244
|
+
|
|
123
245
|
render(template, { debug: true });
|
|
246
|
+
|
|
124
247
|
```
|
|
125
248
|
|
|
249
|
+
|
|
250
|
+
|
|
126
251
|
## Real-World Examples
|
|
127
252
|
|
|
253
|
+
|
|
254
|
+
|
|
128
255
|
### App-wide Settings
|
|
129
256
|
|
|
257
|
+
|
|
258
|
+
|
|
130
259
|
=== "CommonJS"
|
|
131
260
|
|
|
261
|
+
|
|
262
|
+
|
|
132
263
|
```javascript
|
|
264
|
+
|
|
133
265
|
const { registerContextProcessor } = require('miki-template');
|
|
134
266
|
|
|
267
|
+
|
|
268
|
+
|
|
135
269
|
registerContextProcessor(() => ({
|
|
270
|
+
|
|
136
271
|
appName: process.env.APP_NAME || 'MyApp',
|
|
272
|
+
|
|
137
273
|
appVersion: require('./package.json').version,
|
|
274
|
+
|
|
138
275
|
environment: process.env.NODE_ENV || 'development',
|
|
276
|
+
|
|
139
277
|
apiUrl: process.env.API_URL || 'http://localhost:3000/api',
|
|
278
|
+
|
|
140
279
|
assetsUrl: process.env.ASSETS_URL || '/assets'
|
|
280
|
+
|
|
141
281
|
}));
|
|
282
|
+
|
|
142
283
|
```
|
|
143
284
|
|
|
285
|
+
|
|
286
|
+
|
|
144
287
|
=== "ES Modules"
|
|
145
288
|
|
|
289
|
+
|
|
290
|
+
|
|
146
291
|
```javascript
|
|
292
|
+
|
|
147
293
|
import { registerContextProcessor } from 'miki-template';
|
|
294
|
+
|
|
148
295
|
import pkg from './package.json' with { type: 'json' };
|
|
149
296
|
|
|
297
|
+
|
|
298
|
+
|
|
150
299
|
registerContextProcessor(() => ({
|
|
300
|
+
|
|
151
301
|
appName: process.env.APP_NAME || 'MyApp',
|
|
302
|
+
|
|
152
303
|
appVersion: pkg.version,
|
|
304
|
+
|
|
153
305
|
environment: process.env.NODE_ENV || 'development',
|
|
306
|
+
|
|
154
307
|
apiUrl: process.env.API_URL || 'http://localhost:3000/api',
|
|
308
|
+
|
|
155
309
|
assetsUrl: process.env.ASSETS_URL || '/assets'
|
|
310
|
+
|
|
156
311
|
}));
|
|
312
|
+
|
|
157
313
|
```
|
|
158
314
|
|
|
315
|
+
|
|
316
|
+
|
|
159
317
|
### User Authentication
|
|
160
318
|
|
|
319
|
+
|
|
320
|
+
|
|
161
321
|
=== "CommonJS"
|
|
162
322
|
|
|
323
|
+
|
|
324
|
+
|
|
163
325
|
```javascript
|
|
326
|
+
|
|
164
327
|
const { registerContextProcessor } = require('miki-template');
|
|
165
328
|
|
|
329
|
+
|
|
330
|
+
|
|
166
331
|
registerContextProcessor((context) => {
|
|
332
|
+
|
|
167
333
|
const user = context.get('user');
|
|
334
|
+
|
|
168
335
|
if (!user) return {};
|
|
336
|
+
|
|
169
337
|
return {
|
|
338
|
+
|
|
170
339
|
user_name: user.name,
|
|
340
|
+
|
|
171
341
|
user_avatar: user.avatar || '/default-avatar.png',
|
|
342
|
+
|
|
172
343
|
user_is_admin: user.isAdmin || false
|
|
344
|
+
|
|
173
345
|
};
|
|
346
|
+
|
|
174
347
|
});
|
|
348
|
+
|
|
175
349
|
```
|
|
176
350
|
|
|
351
|
+
|
|
352
|
+
|
|
177
353
|
=== "ES Modules"
|
|
178
354
|
|
|
355
|
+
|
|
356
|
+
|
|
179
357
|
```javascript
|
|
358
|
+
|
|
180
359
|
import { registerContextProcessor } from 'miki-template';
|
|
181
360
|
|
|
361
|
+
|
|
362
|
+
|
|
182
363
|
registerContextProcessor((context) => {
|
|
364
|
+
|
|
183
365
|
const user = context.get('user');
|
|
366
|
+
|
|
184
367
|
if (!user) return {};
|
|
368
|
+
|
|
185
369
|
return {
|
|
370
|
+
|
|
186
371
|
user_name: user.name,
|
|
372
|
+
|
|
187
373
|
user_avatar: user.avatar || '/default-avatar.png',
|
|
374
|
+
|
|
188
375
|
user_is_admin: user.isAdmin || false
|
|
376
|
+
|
|
189
377
|
};
|
|
378
|
+
|
|
190
379
|
});
|
|
380
|
+
|
|
191
381
|
```
|
|
192
382
|
|
|
383
|
+
|
|
384
|
+
|
|
193
385
|
### Feature Flags
|
|
194
386
|
|
|
387
|
+
|
|
388
|
+
|
|
195
389
|
=== "CommonJS"
|
|
196
390
|
|
|
391
|
+
|
|
392
|
+
|
|
197
393
|
```javascript
|
|
394
|
+
|
|
198
395
|
const { registerContextProcessor } = require('miki-template');
|
|
199
396
|
|
|
397
|
+
|
|
398
|
+
|
|
200
399
|
registerContextProcessor(() => ({
|
|
400
|
+
|
|
201
401
|
flags: {
|
|
402
|
+
|
|
202
403
|
newDashboard: process.env.FEATURE_NEW_DASHBOARD === 'true',
|
|
404
|
+
|
|
203
405
|
betaFeature: process.env.FEATURE_BETA === 'true',
|
|
406
|
+
|
|
204
407
|
darkModeDefault: process.env.FEATURE_DARK_MODE === 'true'
|
|
408
|
+
|
|
205
409
|
}
|
|
410
|
+
|
|
206
411
|
}));
|
|
412
|
+
|
|
207
413
|
```
|
|
208
414
|
|
|
415
|
+
|
|
416
|
+
|
|
209
417
|
=== "ES Modules"
|
|
210
418
|
|
|
419
|
+
|
|
420
|
+
|
|
211
421
|
```javascript
|
|
422
|
+
|
|
212
423
|
import { registerContextProcessor } from 'miki-template';
|
|
213
424
|
|
|
425
|
+
|
|
426
|
+
|
|
214
427
|
registerContextProcessor(() => ({
|
|
428
|
+
|
|
215
429
|
flags: {
|
|
430
|
+
|
|
216
431
|
newDashboard: process.env.FEATURE_NEW_DASHBOARD === 'true',
|
|
432
|
+
|
|
217
433
|
betaFeature: process.env.FEATURE_BETA === 'true',
|
|
434
|
+
|
|
218
435
|
darkModeDefault: process.env.FEATURE_DARK_MODE === 'true'
|
|
436
|
+
|
|
219
437
|
}
|
|
438
|
+
|
|
220
439
|
}));
|
|
440
|
+
|
|
221
441
|
```
|
|
222
442
|
|
|
443
|
+
|
|
444
|
+
|
|
223
445
|
Template usage:
|
|
224
446
|
|
|
447
|
+
|
|
448
|
+
|
|
225
449
|
```html
|
|
450
|
+
|
|
226
451
|
{% if flags.newDashboard %}
|
|
452
|
+
|
|
227
453
|
<a href="/new-dashboard">New Dashboard</a>
|
|
454
|
+
|
|
228
455
|
{% else %}
|
|
456
|
+
|
|
229
457
|
<a href="/dashboard">Classic Dashboard</a>
|
|
458
|
+
|
|
230
459
|
{% endif %}
|
|
460
|
+
|
|
231
461
|
```
|
|
232
462
|
|
|
463
|
+
|
|
464
|
+
|
|
233
465
|
## Clearing Processors
|
|
234
466
|
|
|
467
|
+
|
|
468
|
+
|
|
235
469
|
Clear all registered processors (useful in tests or dynamic configuration):
|
|
236
470
|
|
|
471
|
+
|
|
472
|
+
|
|
237
473
|
=== "CommonJS"
|
|
238
474
|
|
|
475
|
+
|
|
476
|
+
|
|
239
477
|
```javascript
|
|
478
|
+
|
|
240
479
|
const { clearContextProcessors } = require('miki-template');
|
|
241
480
|
|
|
481
|
+
|
|
482
|
+
|
|
242
483
|
clearContextProcessors();
|
|
484
|
+
|
|
243
485
|
```
|
|
244
486
|
|
|
487
|
+
|
|
488
|
+
|
|
245
489
|
=== "ES Modules"
|
|
246
490
|
|
|
491
|
+
|
|
492
|
+
|
|
247
493
|
```javascript
|
|
494
|
+
|
|
248
495
|
import { clearContextProcessors } from 'miki-template';
|
|
249
496
|
|
|
497
|
+
|
|
498
|
+
|
|
250
499
|
clearContextProcessors();
|
|
500
|
+
|
|
251
501
|
```
|
|
252
502
|
|
|
503
|
+
|
|
504
|
+
|
|
253
505
|
## Next Steps
|
|
254
506
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
- [
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
- [Advanced Usage: Context Processors](./advanced-usage.md)
|
|
510
|
+
|
|
511
|
+
- [Async Rendering](./async-rendering.md)
|
|
512
|
+
|
|
513
|
+
- [API Reference: Context Processors](../api/context-processors.md)
|
|
514
|
+
|