miki-template 2.0.1 → 2.2.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.
Files changed (71) hide show
  1. package/.github/workflows/ci.yml +13 -37
  2. package/.github/workflows/docs.yml +105 -0
  3. package/.github/workflows/npm-publish-github-packages.yml +36 -0
  4. package/README.md +69 -14
  5. package/assets/logo.png +0 -0
  6. package/benchmarks/ejs-results.json +4 -4
  7. package/benchmarks/handlebars-results.json +6 -6
  8. package/benchmarks/miki-results.json +4 -4
  9. package/benchmarks/pug-results.json +4 -4
  10. package/benchmarks/stress.mjs +1 -1
  11. package/docs/api/async-render.md +85 -0
  12. package/docs/api/cache.md +87 -0
  13. package/docs/api/compile.md +128 -0
  14. package/docs/api/context-processors.md +77 -0
  15. package/docs/api/filters.md +217 -0
  16. package/docs/api/finder.md +94 -0
  17. package/docs/api/helpers.md +53 -0
  18. package/docs/api/i18n.md +157 -0
  19. package/docs/api/index.md +54 -0
  20. package/docs/api/libraries.md +207 -0
  21. package/docs/api/render-partial.md +81 -0
  22. package/docs/api/render.md +92 -0
  23. package/docs/api/security.md +145 -0
  24. package/docs/api/setup-express.md +76 -0
  25. package/docs/api/tags.md +134 -0
  26. package/docs/assets/banner.png +0 -0
  27. package/docs/assets/logo.png +0 -0
  28. package/docs/guide/advanced-usage.md +397 -0
  29. package/docs/guide/async-rendering.md +308 -0
  30. package/docs/guide/context-processors.md +257 -0
  31. package/docs/guide/custom-filters.md +311 -0
  32. package/docs/guide/custom-tags.md +271 -0
  33. package/docs/guide/filters.md +642 -0
  34. package/docs/guide/getting-started.md +102 -0
  35. package/docs/guide/installation.md +95 -0
  36. package/docs/guide/partial-templates.md +367 -0
  37. package/docs/guide/quick-start.md +222 -0
  38. package/docs/guide/security.md +345 -0
  39. package/docs/guide/tags.md +783 -0
  40. package/docs/guide/template-discovery.md +170 -0
  41. package/docs/guide/template-inheritance.md +273 -0
  42. package/docs/guide/what-is-miki-template.md +28 -0
  43. package/docs/guide/why-miki-template.md +75 -0
  44. package/docs/index.md +104 -0
  45. package/docs/integrations/elysia.md +78 -0
  46. package/docs/integrations/express.md +219 -0
  47. package/docs/integrations/fastify.md +77 -0
  48. package/docs/integrations/hono.md +78 -0
  49. package/docs/integrations/index.md +68 -0
  50. package/docs/integrations/koa.md +88 -0
  51. package/docs/integrations/nestjs.md +78 -0
  52. package/docs/integrations/tsed.md +81 -0
  53. package/docs/javascripts/extra.js +174 -0
  54. package/docs/performance.md +37 -0
  55. package/docs/stylesheets/extra.css +819 -0
  56. package/mkdocs.yml +217 -0
  57. package/overrides/main.html +26 -0
  58. package/overrides/partials/footer.html +9 -0
  59. package/package.json +4 -2
  60. package/requirements-docs.txt +1 -0
  61. package/docs/README.md +0 -18
  62. package/docs/advanced_usage.md +0 -71
  63. package/docs/api.md +0 -122
  64. package/docs/filters.md +0 -708
  65. package/docs/installation.md +0 -106
  66. package/docs/integrations.md +0 -214
  67. package/docs/overview.md +0 -79
  68. package/docs/partialdef.md +0 -70
  69. package/docs/security.md +0 -27
  70. package/docs/tags.md +0 -673
  71. package/docs/usage.md +0 -646
@@ -0,0 +1,170 @@
1
+ # Smart Template Discovery
2
+
3
+ miki-template includes a Django-inspired template finder that searches your project structure intelligently. You no longer need to manually configure every views directory or worry about `Failed to lookup view` errors when templates live in nested app folders.
4
+
5
+ ## Table of Contents
6
+
7
+ - [How It Works](#how-it-works)
8
+ - [Supported Layouts](#supported-layouts)
9
+ - [Express Integration](#express-integration)
10
+ - [Custom Template Directory Names](#custom-template-directory-names)
11
+ - [Manual Lookup](#manual-lookup)
12
+ - [ESM Import](#esm-import)
13
+ - [Next Steps](#next-steps)
14
+
15
+ ---
16
+
17
+ ## How It Works
18
+
19
+ When you call `res.render('name')` or `render('name', ctx, { views })`, miki-template:
20
+
21
+ 1. Resolves the view name against the configured views directories.
22
+ 2. Searches recursively through subdirectories for matching files.
23
+ 3. Recognizes app-style `templates/` directories automatically.
24
+ 4. Supports custom directory names via `setAppTemplateDirNames()`.
25
+
26
+ The search order is:
27
+
28
+ 1. **Direct resolution** — if you pass `nested/path`, it resolves relative to each views root.
29
+ 2. **Recursive search** — if you pass a bare name like `home`, the engine walks subdirectories searching for `home.html` or `home.miki`.
30
+ 3. **App-style directories** — directories named `templates` (or whatever you configure) are treated as additional view roots at any depth.
31
+
32
+ ## Supported Layouts
33
+
34
+ ```text
35
+ project/
36
+ ├── views/
37
+ │ └── home.html
38
+ ├── app/
39
+ │ └── templates/
40
+ │ └── dashboard.html
41
+ ├── packages/
42
+ │ └── admin/
43
+ │ └── templates/
44
+ │ └── settings.html
45
+ ```
46
+
47
+ All of these are discoverable without extra configuration.
48
+
49
+ ## Express Integration
50
+
51
+ When you use `setupExpress()`, the engine automatically expands your views roots to include all directories that contain template files:
52
+
53
+ === "CommonJS"
54
+
55
+ ```javascript
56
+ const express = require('express');
57
+ const miki = require('miki-template');
58
+
59
+ const app = express();
60
+ miki.setupExpress(app, { extension: 'html', views: './views' });
61
+
62
+ // Templates placed deeply in your project are found automatically:
63
+ app.get('/', (req, res) => res.render('home'));
64
+ app.get('/admin', (req, res) => res.render('settings'));
65
+ ```
66
+
67
+ === "ES Modules"
68
+
69
+ ```javascript
70
+ import express from 'express';
71
+ import miki from 'miki-template';
72
+
73
+ const app = express();
74
+ miki.setupExpress(app, { extension: 'html', views: './views' });
75
+
76
+ app.get('/', (req, res) => res.render('home'));
77
+ app.get('/admin', (req, res) => res.render('settings'));
78
+ ```
79
+
80
+ You can also pass multiple roots:
81
+
82
+ ```javascript
83
+ miki.setupExpress(app, {
84
+ extension: 'html',
85
+ views: ['./views', './app/templates', './packages/*/templates']
86
+ });
87
+ ```
88
+
89
+ ## Custom Template Directory Names
90
+
91
+ If your project uses a different convention than `templates`, configure it globally:
92
+
93
+ === "CommonJS"
94
+
95
+ ```javascript
96
+ const { setAppTemplateDirNames } = require('miki-template');
97
+
98
+ setAppTemplateDirNames(['templates', 'views', 'pages']);
99
+ ```
100
+
101
+ === "ES Modules"
102
+
103
+ ```javascript
104
+ import { setAppTemplateDirNames } from 'miki-template';
105
+
106
+ setAppTemplateDirNames(['templates', 'views', 'pages']);
107
+ ```
108
+
109
+ This affects both Express integration and manual `render()` / `findTemplateInViews()` calls.
110
+
111
+ ## Manual Lookup
112
+
113
+ You can use the finder directly:
114
+
115
+ === "CommonJS"
116
+
117
+ ```javascript
118
+ const { findTemplateInViews } = require('miki-template');
119
+
120
+ const found = findTemplateInViews('home', [
121
+ './views',
122
+ './app/templates'
123
+ ]);
124
+
125
+ console.log(found);
126
+ // Output: /absolute/path/to/home.html
127
+ ```
128
+
129
+ === "ES Modules"
130
+
131
+ ```javascript
132
+ import { findTemplateInViews } from 'miki-template';
133
+
134
+ const found = findTemplateInViews('home', [
135
+ './views',
136
+ './app/templates'
137
+ ]);
138
+
139
+ console.log(found);
140
+ // Output: /absolute/path/to/home.html
141
+ ```
142
+
143
+ ### Finder Behavior
144
+
145
+ - Searches recursively through subdirectories for bare template names.
146
+ - Tries `.html` and `.miki` extensions when no extension is provided.
147
+ - Also searches app-style `templates/` directories nested inside the views root.
148
+ - Returns the first match found, or `null` if not found.
149
+
150
+ ### ESM Import
151
+
152
+ === "ES Modules"
153
+
154
+ ```javascript
155
+ import { findTemplateInViews, setAppTemplateDirNames } from 'miki-template';
156
+
157
+ // Set custom directory names
158
+ setAppTemplateDirNames(['templates', 'app_templates']);
159
+
160
+ // Find a template
161
+ const path = findTemplateInViews('detail', ['./views', './packages']);
162
+ console.log(path);
163
+ // → /absolute/path/to/packages/product/templates/detail.html
164
+ ```
165
+
166
+ ## Next Steps
167
+
168
+ - [Partial Templates](./partial-templates)
169
+ - [Template Inheritance](./template-inheritance)
170
+ - [Integrations: Express](../integrations/express)
@@ -0,0 +1,273 @@
1
+ # Template Inheritance
2
+
3
+ miki-template supports Django-style template inheritance via `{% extends %}` and `{% block %}`. This lets you build layout hierarchies where child templates override parent blocks.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Basic Inheritance](#basic-inheritance)
8
+ - [block.super](#blocksuper)
9
+ - [Multi-Level Inheritance](#multi-level-inheritance)
10
+ - [Rendering a Single Block](#rendering-a-single-block)
11
+ - [block Default Behavior](#block-default-behavior)
12
+ - [Path Traversal Protection](#path-traversal-protection)
13
+ - [Smart Template Discovery for Inheritance](#smart-template-discovery-for-inheritance)
14
+
15
+ ---
16
+
17
+ ## Basic Inheritance
18
+
19
+ ### base.html
20
+
21
+ ```html
22
+ <!DOCTYPE html>
23
+ <html>
24
+ <head>
25
+ <title>{% block title %}Default Title{% endblock %}</title>
26
+ </head>
27
+ <body>
28
+ <header>{% block header %}Default Header{% endblock %}</header>
29
+ <main>{% block content %}Default Content{% endblock %}</main>
30
+ <footer>{% block footer %}Default Footer{% endblock %}</footer>
31
+ </body>
32
+ </html>
33
+ ```
34
+
35
+ ### child.html
36
+
37
+ ```html
38
+ {% extends "base.html" %}
39
+
40
+ {% block title %}My Page{% endblock %}
41
+
42
+ {% block content %}
43
+ <h1>Hello, {{ user.name }}!</h1>
44
+ {% for item in items %}
45
+ <p>{{ item }}</p>
46
+ {% endfor %}
47
+ {% endblock %}
48
+ ```
49
+
50
+ **Key behaviors:**
51
+
52
+ - The child template's text outside `{% block %}` tags is **ignored** — only the blocks are used to override the parent.
53
+ - Any blocks not overridden in the child use the parent's default content.
54
+ - The parent is located using the `views` option (or Express's `views` directory).
55
+
56
+ ## block.super
57
+
58
+ Inside a block, `{{ block.super }}` renders the parent template's version of that block. This is useful for augmentation rather than replacement.
59
+
60
+ === "Example"
61
+
62
+ ```html
63
+ {% extends "base.html" %}
64
+
65
+ {% block content %}
66
+ <h1>My Content</h1>
67
+ {{ block.super }}
68
+ {% endblock %}
69
+ ```
70
+
71
+ If `base.html`'s content block is `<p>Original</p>`, the output is:
72
+
73
+ ```html
74
+ <h1>My Content</h1>
75
+ <p>Original</p>
76
+ ```
77
+
78
+ **Real-world sidebar that adds to the parent:**
79
+
80
+ ```html
81
+ <!-- base.html -->
82
+ {% block sidebar %}
83
+ <ul class="nav">
84
+ <li><a href="/">Home</a></li>
85
+ </ul>
86
+ {% endblock %}
87
+
88
+ <!-- admin.html -->
89
+ {% extends "base.html" %}
90
+ {% block sidebar %}
91
+ {{ block.super }}
92
+ <li><a href="/admin">Admin Panel</a></li>
93
+ {% endblock %}
94
+ ```
95
+
96
+ ## Multi-Level Inheritance
97
+
98
+ Inheritance chains can be arbitrarily deep:
99
+
100
+ ```text
101
+ base.html
102
+ └── child.html
103
+ └── grandchild.html
104
+ ```
105
+
106
+ Each level can override blocks from its parent, and `{{ block.super }}` traverses the chain correctly.
107
+
108
+ ### Three-level example
109
+
110
+ **base.html:**
111
+
112
+ ```html
113
+ <html>
114
+ <body>
115
+ {% block content %}Base content{% endblock %}
116
+ </body>
117
+ </html>
118
+ ```
119
+
120
+ **child.html:**
121
+
122
+ ```html
123
+ {% extends "base.html" %}
124
+
125
+ {% block content %}
126
+ <h2>Child content</h2>
127
+ {{ block.super }}
128
+ {% endblock %}
129
+ ```
130
+
131
+ **grandchild.html:**
132
+
133
+ ```html
134
+ {% extends "child.html" %}
135
+
136
+ {% block content %}
137
+ <h1>Grandchild content</h1>
138
+ {{ block.super }}
139
+ {% endblock %}
140
+ ```
141
+
142
+ Rendering `grandchild.html` produces:
143
+
144
+ ```html
145
+ <html>
146
+ <body>
147
+ <h1>Grandchild content</h1>
148
+ <h2>Child content</h2>
149
+ Base content
150
+ </body>
151
+ </html>
152
+ ```
153
+
154
+ ## Rendering a Single Block
155
+
156
+ Compile a template and render only one block — useful for AJAX or HTMX responses where you only need a portion of the page:
157
+
158
+ === "CommonJS"
159
+
160
+ ```javascript
161
+ const { compile } = require('miki-template');
162
+
163
+ const compiled = compile(childTemplateStr, { views: './templates' });
164
+ const partialHtml = compiled.renderBlock('content', context);
165
+ ```
166
+
167
+ === "ES Modules"
168
+
169
+ ```javascript
170
+ import { compile } from 'miki-template';
171
+
172
+ const compiled = compile(childTemplateStr, { views: './templates' });
173
+ const partialHtml = compiled.renderBlock('content', context);
174
+ ```
175
+
176
+ ### renderBlock behavior
177
+
178
+ - If the block is not found, throws `Block 'blockName' not found in template`.
179
+ - If the block has no overrides, renders the default body.
180
+ - If the block has overrides, renders the child-most block first, then traverses up for `{{ block.super }}`.
181
+
182
+ **Real-world HTMX use case:**
183
+
184
+ ```html
185
+ <!-- layout.html -->
186
+ {% block main %}
187
+ <div id="main-content">
188
+ <!-- default content -->
189
+ </div>
190
+ {% endblock %}
191
+ ```
192
+
193
+ ```javascript
194
+ // Return only the main block for an AJAX update
195
+ app.get('/ajax/content', (req, res) => {
196
+ const compiled = miki.compile(template, { views: './views' });
197
+ res.send(compiled.renderBlock('main', { user: req.user }));
198
+ });
199
+ ```
200
+
201
+ ## block Default Behavior
202
+
203
+ If a child template does not override a block, the parent's default content is rendered:
204
+
205
+ ```html
206
+ <!-- base.html -->
207
+ <html>
208
+ <body>
209
+ {% block sidebar %}Default sidebar{% endblock %}
210
+ </body>
211
+ </html>
212
+ ```
213
+
214
+ ```html
215
+ <!-- child.html -->
216
+ {% extends "base.html" %}
217
+
218
+ {% block content %}Main content{% endblock %}
219
+ <!-- sidebar block is not overridden, so "Default sidebar" is used -->
220
+ ```
221
+
222
+ ## Dynamic extends
223
+
224
+ You can use expressions in `extends` for device-specific or conditional layouts:
225
+
226
+ ```html
227
+ {% extends device_type|default:"base.html" %}
228
+ ```
229
+
230
+ ```html
231
+ {% extends user.theme|default:"default.html" %}
232
+ ```
233
+
234
+ ## Path Traversal Protection
235
+
236
+ `{% extends %}` and `{% include %}` paths are validated to prevent directory traversal attacks:
237
+
238
+ ```html
239
+ {% extends "../../etc/passwd" %} {# REJECTED #}
240
+ {% include "../../secrets" %} {# REJECTED #}
241
+ ```
242
+
243
+ The engine checks that resolved paths stay within the allowed views directories. An `Error` with message starting `path traversal` is thrown if a path escapes the views root.
244
+
245
+ ## Smart Template Discovery for Inheritance
246
+
247
+ When using `setupExpress()`, the engine automatically searches for parent templates in:
248
+
249
+ - The configured `views` directory
250
+ - Nested `templates/` directories inside the views root
251
+ - Subdirectories of the views root
252
+ - App-style `app/templates/...`, `packages/*/templates/...`, etc.
253
+
254
+ This means you can organize templates like:
255
+
256
+ ```text
257
+ project/
258
+ ├── views/
259
+ │ ├── base.html
260
+ │ └── home.html
261
+ ├── app/
262
+ │ └── templates/
263
+ │ └── admin/
264
+ │ └── dashboard.html
265
+ ```
266
+
267
+ And `{% extends "base.html" %}` will be found regardless of where the child template lives.
268
+
269
+ ## Next Steps
270
+
271
+ - [Partial Templates](./partial-templates)
272
+ - [Tags: extends and block](./tags#inheritance-tags)
273
+ - [Template Discovery](./template-discovery)
@@ -0,0 +1,28 @@
1
+ # What is miki-template?
2
+
3
+ miki-template is a **Django-style template engine for Node.js and Express**. It brings Django's beloved template language — variables, filters, tags, inheritance, and partials — to the Node.js ecosystem with first-class Express integration and modern JavaScript support.
4
+
5
+ ## Philosophy
6
+
7
+ miki-template is designed for developers who love Django's template syntax but want the speed and flexibility of Node.js. It prioritizes:
8
+
9
+ - **Developer experience**: Familiar Django syntax, excellent error messages, and sensible defaults.
10
+ - **Performance**: Compiled AST rendering that scales to large, real-world templates.
11
+ - **Modern Node.js**: Full ESM and CommonJS support, async rendering, and compatibility with current Express/Koa/Fastify/Hono/Elysia versions.
12
+ - **Security**: Auto-escaping, safe strings, and Django-style security primitives built in.
13
+
14
+ ## Key Concepts
15
+
16
+ - **Templates** are text files using `{{ variables }}`, `{% tags %}`, and `| filters`.
17
+ - **Partials** let you define reusable components with `{% partialdef %}` and render them by name.
18
+ - **Template inheritance** uses `{% extends %}` and `{% block %}` to build layout hierarchies.
19
+ - **Smart discovery** finds templates across `views/`, `app/templates/`, and nested folders automatically.
20
+
21
+ ## Who is it for?
22
+
23
+ miki-template is a great fit if you:
24
+
25
+ - Prefer Django-style templates over JSX or pure string concatenation.
26
+ - Need **partial rendering** for HTMX or AJAX-heavy apps.
27
+ - Want a template engine that **scales** without rewriting templates as your app grows.
28
+ - Value **security** and want XSS protection by default.
@@ -0,0 +1,75 @@
1
+ # Why miki-template?
2
+
3
+ There are plenty of template engines for Node.js. Here is why miki-template stands out.
4
+
5
+ ## Django Syntax You Already Know
6
+
7
+ If you have used Django, you already know miki-template. The syntax is intentionally aligned:
8
+
9
+ ```html
10
+ {% if user.is_admin %}
11
+ <p>Welcome, {{ user.name|title }}!</p>
12
+ {% elif user.is_staff %}
13
+ <p>Staff dashboard</p>
14
+ {% else %}
15
+ <p>Please log in.</p>
16
+ {% endif %}
17
+ ```
18
+
19
+ No new DSL to learn. No context switching between backend and frontend templating styles.
20
+
21
+ ## Built for HTMX and Partial Responses
22
+
23
+ Modern web apps increasingly use HTMX, Turbo, or custom AJAX. miki-template makes partial rendering trivial:
24
+
25
+ ```javascript
26
+ app.get('/card/:id', (req, res) =>
27
+ res.render(`home#card`, { title: 'Hello', body: '...' })
28
+ );
29
+ ```
30
+
31
+ No extra middleware. No manual view resolution. Just `view#partial`.
32
+
33
+ ## Smart Template Discovery
34
+
35
+ Forget `Failed to lookup view` errors. miki-template searches your project structure intelligently:
36
+
37
+ - `views/`
38
+ - `app/templates/`
39
+ - `packages/*/templates/`
40
+ - Any custom folder name you configure
41
+
42
+ This mirrors Django's `APP_DIRS` behavior and means templates can live where they make sense in your codebase.
43
+
44
+ ## Performance That Scales
45
+
46
+ miki-template's compiled AST approach is especially fast on realistic templates — the ones with loops, conditionals, filters, and partials that make up real pages.
47
+
48
+ | Template | miki-template | pug | handlebars | ejs |
49
+ |----------|--------------|-----|------------|-----|
50
+ | Small | ~115k rps | 1.7M rps | 417k rps | 182k rps |
51
+ | Medium | ~454k rps | 625k rps | 48k rps | 29k rps |
52
+ | Large | **~476k rps** | 3.1k rps | 661 rps | 290 rps |
53
+
54
+ On large templates, miki-template is **~150× faster** than pug, handlebars, and ejs.
55
+
56
+ ## Security by Default
57
+
58
+ - Auto-escaping enabled by default.
59
+ - SafeString wrapper for explicit bypass.
60
+ - CSRF and CSP tags included.
61
+ - No `eval()` or unsafe code execution.
62
+
63
+ ## First-Class Express Integration
64
+
65
+ One function wires everything:
66
+
67
+ ```javascript
68
+ miki.setupExpress(app, { extension: 'html', views: './views' });
69
+ ```
70
+
71
+ That is it. No `app.engine()` boilerplate. No manual `res.render` patching. Partial responses work out of the box.
72
+
73
+ ## Extensible and Future-Proof
74
+
75
+ Need a custom tag? A custom filter? The API is clean and well-documented. miki-template is built to grow with your app, not lock you into a fragile abstraction.
package/docs/index.md ADDED
@@ -0,0 +1,104 @@
1
+ <div class="md-hero">
2
+ <h1 class="md-hero__title">miki-template</h1>
3
+ <p class="md-hero__subtitle">Django-style template magic for Node.js — blazing fast partials, smart template discovery, and zero friction for HTMX.</p>
4
+ <div class="md-hero__buttons">
5
+ <a href="guide/quick-start" class="md-button md-button--primary">Get Started</a>
6
+ <a href="api/" class="md-button">API Reference</a>
7
+ <a href="https://github.com/alainmiki/miki-template" class="md-button" target="_blank" rel="noopener">
8
+ <span class="md-icon">&#128190;</span> GitHub
9
+ </a>
10
+ </div>
11
+ <div style="margin-top: 1.5rem; display: flex; gap: 1rem; justify-content: center; flex-wrap: wrap; position: relative; align-items: center;">
12
+ <img src="assets/banner.png" alt="miki-template banner" style="max-width: 100%; height: auto; border-radius: 0.5rem; box-shadow: 0 4px 12px var(--md-shadow-color); max-height: 200px;">
13
+ </div>
14
+ <div style="margin-top: 1rem; display: flex; gap: 1rem; justify-content: center; flex-wrap: wrap; position: relative; align-items: center;">
15
+ <a href="https://www.npmjs.com/package/miki-template" target="_blank" rel="noopener">
16
+ <img src="https://img.shields.io/npm/v/miki-template.svg" alt="npm version" style="height: 20px;">
17
+ </a>
18
+ <a href="https://www.npmjs.com/package/miki-template" target="_blank" rel="noopener">
19
+ <img src="https://img.shields.io/npm/dm/miki-template.svg" alt="npm downloads" style="height: 20px;">
20
+ </a>
21
+ <a href="https://github.com/alainmiki/miki-template" target="_blank" rel="noopener">
22
+ <img src="https://img.shields.io/github/actions/workflow/status/alainmiki/miki-template/ci.yml?branch=main" alt="CI status" style="height: 20px;">
23
+ </a>
24
+ </div>
25
+ </div>
26
+
27
+ <div class="md-typeset">
28
+
29
+ ## Why miki-template?
30
+
31
+ miki-template brings Django's beloved template language to Node.js and Express. Define reusable partials with `{% partialdef %}`, render any slice of a page with `render('home#card')`, and let the engine find templates across your whole project — `templates/`, `app/templates/`, or whatever structure you prefer.
32
+
33
+ - **Partial-powered templating**: `{% partialdef %}` blocks render by name anywhere — `res.render('home#card')`, `renderPartialFromSource(...)`, or `compiled.renderBlock('block')`. Built for HTMX-style partial responses.
34
+ - **Smart template discovery**: Stop hardcoding view paths. The engine searches `templates/`, nested app directories, and custom folder names automatically — just like Django.
35
+ - **One-line Express integration**: `miki.setupExpress(app, { extension: 'html', views: dir })` wires everything up. No boilerplate, no extra middleware.
36
+ - **Full Django syntax parity**: Variables, dotted lookups, filters (`|`), block tags (`{% %}`), template inheritance with `extends` and `block.super`.
37
+ - **Blazing fast**: Compiled AST rendering dominates on realistic pages — ~150× faster than pug, handlebars, and ejs on large templates.
38
+ - **ESM & CommonJS**: Works seamlessly with both `import` and `require` syntax.
39
+ - **Security by default**: Auto-escaping, `SafeString`, CSRF and CSP tags.
40
+
41
+ ## Quick example
42
+
43
+ === "CommonJS"
44
+
45
+ ```javascript
46
+ const express = require('express');
47
+ const miki = require('miki-template');
48
+
49
+ const app = express();
50
+ miki.setupExpress(app, { extension: 'html', views: './views' });
51
+
52
+ app.get('/', (req, res) => res.render('home', { user: req.user }));
53
+ app.get('/partials/:name', (req, res) =>
54
+ res.render(`home#${req.params.name}`, { user: req.user })
55
+ );
56
+
57
+ app.listen(3000);
58
+ ```
59
+
60
+ === "ES Modules"
61
+
62
+ ```javascript
63
+ import express from 'express';
64
+ import miki from 'miki-template';
65
+
66
+ const app = express();
67
+ miki.setupExpress(app, { extension: 'html', views: './views' });
68
+
69
+ app.get('/', (req, res) => res.render('home', { user: req.user }));
70
+ app.get('/partials/:name', (req, res) =>
71
+ res.render(`home#${req.params.name}`, { user: req.user })
72
+ );
73
+
74
+ app.listen(3000);
75
+ ```
76
+
77
+ ## Installation
78
+
79
+ ```bash
80
+ npm install miki-template
81
+ ```
82
+
83
+ See the [Installation guide](guide/installation) for pnpm, yarn, and Bun instructions.
84
+
85
+ ## Documentation
86
+
87
+ - [What is miki-template?](guide/what-is-miki-template)
88
+ - [Getting Started](guide/getting-started)
89
+ - [Quick Start](guide/quick-start)
90
+ - [Filters](guide/filters)
91
+ - [Tags](guide/tags)
92
+ - [Partial Templates](guide/partial-templates)
93
+ - [Template Inheritance](guide/template-inheritance)
94
+ - [Template Discovery](guide/template-discovery)
95
+ - [Security](guide/security)
96
+ - [Integrations](integrations/)
97
+ - [API Reference](api/)
98
+ - [Performance](performance)
99
+
100
+ ## License
101
+
102
+ MIT
103
+
104
+ </div>