mancha 0.18.2 → 0.18.4

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 (78) hide show
  1. package/.github/workflows/ci.yml +3 -0
  2. package/README.md +19 -477
  3. package/biome.json +46 -0
  4. package/dist/browser.d.ts +39 -33
  5. package/dist/browser.js +13 -1
  6. package/dist/browser.js.map +1 -1
  7. package/dist/cli.js +37 -6
  8. package/dist/cli.js.map +1 -1
  9. package/dist/css_gen_basic.d.ts +1 -1
  10. package/dist/css_gen_basic.js.map +1 -1
  11. package/dist/dome.d.ts +3 -3
  12. package/dist/dome.js +26 -16
  13. package/dist/dome.js.map +1 -1
  14. package/dist/expressions/ast.test.js +5 -5
  15. package/dist/expressions/ast.test.js.map +1 -1
  16. package/dist/expressions/ast_factory.d.ts +1 -1
  17. package/dist/expressions/ast_factory.test.js.map +1 -1
  18. package/dist/expressions/constants.test.js +1 -1
  19. package/dist/expressions/constants.test.js.map +1 -1
  20. package/dist/expressions/eval.d.ts +2 -2
  21. package/dist/expressions/eval.js +19 -9
  22. package/dist/expressions/eval.js.map +1 -1
  23. package/dist/expressions/eval.test.js +23 -0
  24. package/dist/expressions/eval.test.js.map +1 -1
  25. package/dist/expressions/parser.d.ts +2 -2
  26. package/dist/expressions/parser.js +13 -9
  27. package/dist/expressions/parser.js.map +1 -1
  28. package/dist/expressions/parser.test.js +2 -1
  29. package/dist/expressions/parser.test.js.map +1 -1
  30. package/dist/expressions/tokenizer.js +17 -17
  31. package/dist/expressions/tokenizer.js.map +1 -1
  32. package/dist/expressions/tokenizer.test.js +1 -1
  33. package/dist/expressions/tokenizer.test.js.map +1 -1
  34. package/dist/index.d.ts +2 -2
  35. package/dist/index.js +1 -1
  36. package/dist/index.js.map +1 -1
  37. package/dist/interfaces-Dizh9utI.d.ts +220 -0
  38. package/dist/interfaces.d.ts +1 -1
  39. package/dist/mancha.d.ts +5 -2
  40. package/dist/mancha.js +57 -1
  41. package/dist/mancha.js.map +1 -1
  42. package/dist/plugins.js +39 -24
  43. package/dist/plugins.js.map +1 -1
  44. package/dist/query.d.ts +1 -1
  45. package/dist/query.js +1 -1
  46. package/dist/query.js.map +1 -1
  47. package/dist/renderer-B3R6_o-2.js +30 -0
  48. package/dist/renderer.d.ts +3 -3
  49. package/dist/renderer.js +4 -3
  50. package/dist/renderer.js.map +1 -1
  51. package/dist/safe_browser.d.ts +15 -13
  52. package/dist/safe_browser.js +1 -1
  53. package/dist/store.d.ts +2 -2
  54. package/dist/store.js +6 -2
  55. package/dist/store.js.map +1 -1
  56. package/dist/test_utils.d.ts +8 -7
  57. package/dist/test_utils.js +8 -3
  58. package/dist/test_utils.js.map +1 -1
  59. package/dist/type_checker.js +37 -30
  60. package/dist/type_checker.js.map +1 -1
  61. package/dist/worker.d.ts +5 -5
  62. package/dist/worker.js +5 -5
  63. package/dist/worker.js.map +1 -1
  64. package/docs/components.md +199 -0
  65. package/docs/quickstart.md +18 -701
  66. package/docs/reactivity.md +135 -0
  67. package/docs/ssr.md +78 -0
  68. package/docs/syntax.md +123 -0
  69. package/docs/testing.md +66 -0
  70. package/docs/typescript.md +167 -0
  71. package/gulpfile.ts +25 -22
  72. package/package.json +9 -7
  73. package/scripts/generate-css-docs.ts +6 -9
  74. package/tsconfig.json +3 -10
  75. package/tsdown.config.ts +32 -0
  76. package/.prettierrc +0 -3
  77. package/webpack.config.esmodule.ts +0 -26
  78. package/webpack.config.ts +0 -21
@@ -33,6 +33,9 @@ jobs:
33
33
  - name: Install dependencies
34
34
  run: npm ci
35
35
 
36
+ - name: Run lint/format check
37
+ run: npm run lint
38
+
36
39
  - name: Install Playwright browsers
37
40
  run: npx playwright install
38
41
 
package/README.md CHANGED
@@ -1,7 +1,6 @@
1
1
  # mancha
2
2
 
3
- `mancha` is a simple HTML templating and reactivity library for simple people. It works on the
4
- browser or the server. It can be used as a command-line tool, or imported as a Javascript module.
3
+ `mancha` is a simple HTML templating and reactivity library for simple people. It works on the browser or the server. It can be used as a command-line tool, or imported as a Javascript module.
5
4
 
6
5
  Here's a small sample of the things that you can do with `mancha`:
7
6
 
@@ -35,496 +34,39 @@ Here's a small sample of the things that you can do with `mancha`:
35
34
 
36
35
  ## Why another front-end Javascript library?
37
36
 
38
- There are plenty of other front-end Javascript libraries, many of them of great quality, including:
39
-
40
- - [Google's Svelte](https://svelte.dev)
41
- - [Meta's React](https://react.dev)
42
- - [Vue.js](https://vuejs.org) and [petite-vue](https://github.com/vuejs/petite-vue)
43
- - [Alpine.js](https://alpinejs.dev)
37
+ `mancha` is great for:
44
38
 
45
- None of them have all the key features that make `mancha` unique:
39
+ - **prototyping**, just plop a script tag in your HTML and off you go
40
+ - **testing**, individual components can be rendered and tested outside the browser
41
+ - **progressive enhancement**, from simple templating and basic reactivity to a full-blown app
46
42
 
47
43
  | Feature | mancha | Svelte | React.js | Vue.js | petite-vue | Alpine.js |
48
44
  | --------------------- | ------ | ------ | -------- | ------ | ---------- | --------- |
49
45
  | Simple to learn | ✔️ | ❌ | ❌ | ❌ | ✔️ | ✔️ |
50
- | < 17kb compressed | ✔️ | ✔️ | ❌ | ❌ | ✔️ | ❌ |
46
+ | < 16kb compressed | ✔️ | ✔️ | ❌ | ❌ | ✔️ | ❌ |
51
47
  | Custom web components | ✔️ | ✔️ | ✔️ | ✔️ | ❌ | ❌ |
52
48
  | Client-side rendering | ✔️ | ❌ | ❌ | ✔️ | ✔️ | ✔️ |
53
49
  | Server-side rendering | ✔️ | ✔️ | ✔️ | ✔️ | ❌ | ❌ |
54
50
 
55
- `mancha` is great for:
56
-
57
- - **prototyping**, just plop a script tag in your HTML and off you go
58
- - **testing**, individual components can be rendered and tested outside the browser
59
- - **progressive enhancement**, from simple templating and basic reactivity to a full-blown app
60
-
61
- A core benefit of using `mancha` is that it allows you to compartmentalize the complexity of
62
- front-end development. Whether you decide to break up your app into reusable partial sections via
63
- `<include>` or create custom web components, you can write HTML as if your mother was watching.
64
-
65
- `mancha` implements its own reactivity engine, so the bundled browser module contains no external
66
- dependencies with the exception of [`jexpr`][jexpr] for safe expression evaluation (see the
67
- [dependencies section](#dependencies)).
68
-
69
- ## Preprocessing
70
-
71
- As part of the rendering lifecycle, `mancha` first preprocesses the HTML. The two main stages of
72
- preprocessing consist of:
73
-
74
- - Resolution of `<include>` tags
75
-
76
- ```html
77
- <!-- ./button.tpl.html -->
78
- <button>Click Me</button>
79
-
80
- <!-- ./index.html -->
81
- <div>
82
- <include src="button.tpl.html"></include>
83
- </div>
84
-
85
- <!-- Result after rendering `index.html`. -->
86
- <div>
87
- <button>Click Me</button>
88
- </div>
89
- ```
90
-
91
- - Registration and resolution of all custom web components
92
-
93
- ```html
94
- <!-- Use <template is="my-component-name"> to register a component. -->
95
- <template is="my-red-button">
96
- <button style="background-color: red;">
97
- <slot></slot>
98
- </button>
99
- </template>
100
-
101
- <!-- Any node traversed after registration can use the component. -->
102
- <my-red-button :on:click="console.log('clicked')">
103
- <!-- The contents within will replace the `<slot></slot>` tag. -->
104
- Click Me
105
- </my-red-button>
106
- ```
107
-
108
- ## Rendering
109
-
110
- Once the HTML has been preprocessed, it is rendered by traversing every node in the DOM and applying
111
- a series of plugins. Each plugin is only applied if specific conditions are met such as the HTML
112
- element tag or attributes match a specific criteria. Here's the list of attributes handled:
113
-
114
- - `:data` provides scoped variables to all subnodes, evaluated using `jexpr`
115
- ```html
116
- <div :data="{ name: 'Stranger' }"></div>
117
- ```
118
- - `:for` clones the node and repeats it
119
- ```html
120
- <div :for="item in ['a', 'b', 'c']">{{ item }}</div>
121
- ```
122
- - `:text` sets the `textContent` value of a node
123
- ```html
124
- <div :data="{foo: 'bar'}" :text="foo"></div>
125
- ```
126
- - `:html` sets the `innerHTML` value of a node
127
- ```html
128
- <div :html="<span>Hello World</span>"></div>
129
- ```
130
- - `:show` toggles `$elem.style.display` to `none`
131
- ```html
132
- <div :data="{foo: false}" :show="foo"></div>
133
- ```
134
- - `:if` conditionally renders the element (removes it from the DOM when false). **Note**: `:else` is not currently supported.
135
- ```html
136
- <div :data="{visible: true}" :if="visible">Content</div>
137
- ```
138
- - `:class` appends rendered text to existing class attribute
139
- ```html
140
- <span :class="error ? 'red' : 'blue'" class="text-xl">...</span>
141
- ```
142
- - `:bind` binds (two-way) a variable to the `value` or `checked` property of the element
143
- ```html
144
- <div :data="{ name: 'Stranger' }">
145
- <input type="text" :bind="name" />
146
- </div>
147
- ```
148
- - `:on:{event}` adds an event listener for `event` to the node
149
- ```html
150
- <button :on:click="console.log('clicked')"></button>
151
- ```
152
- - `:on:{event}.prevent` calls `event.preventDefault()` in the event handler
153
- ```html
154
- <a href="#" :on:click.prevent="console.log('clicked')"></a>
155
- ```
156
- - `:attr:{name}` sets the corresponding attribute for `name` in the node
157
- ```html
158
- <a :attr:href="buildUrl()"></a>
159
- ```
160
- - `:prop:{name}` sets the corresponding property for (camel-case converted) `name` in the node
161
- ```html
162
- <video :prop:src="buildSrc()"></video>
163
- ```
164
- - `:render` links an element to a JavaScript ES module for initialization
165
- ```html
166
- <canvas :render="./chart-init.js"></canvas>
167
- ```
168
- The module's default export is called with the element and renderer:
169
- ```js
170
- // chart-init.js
171
- export default function (elem, renderer) {
172
- new Chart(elem, { type: "bar" });
173
- }
174
- ```
175
- - `{{ value }}` replaces `value` in text nodes
176
- ```html
177
- <button :data="{label: 'Click Me'}">{{ label }}</button>
178
- ```
179
- - `:types` **(experimental)** declares TypeScript types for static type checking
180
- ```html
181
- <div :types='{"user": "@import:./types/user.ts:User"}'>
182
- <span>{{ user.name.toUpperCase() }}</span>
183
- </div>
184
- ```
185
- The value of `:types` is parsed with `jexpr` during static analysis. It must evaluate to a plain
186
- object whose values are strings containing TypeScript snippets. When you need quotes inside a type,
187
- either escape them in a double-quoted attribute (e.g.
188
- `<div :types="{\"status\": \"'active' | 'inactive'\"}">`) or, preferably, move the definition into a
189
- TypeScript module and reference it via `@import`.
190
- See the [Type Checking section in the quickstart guide](./docs/quickstart.md#type-checking-experimental) for more details.
191
-
192
- ## Evaluation
193
-
194
- To avoid violation of Content Security Policy (CSP) that forbids the use of `eval()`, `Mancha`
195
- evaluates all expressions using a safe expression parser. This means that only simple expressions are
196
- allowed, but it supports many modern JavaScript features, including optional chaining, the spread
197
- operator, and arrow functions. For example:
198
-
199
- ```html
200
- <!-- Valid expression: string concatenation -->
201
- <body :data="{ pos: 1 }">
202
- <p :text="'you are number ' + pos + ' in the queue'"></p>
203
- </body>
204
-
205
- <!-- Valid expression: optional chaining -->
206
- <body :data="{ user: null }">
207
- <p :text="user?.name ?? 'Anonymous'"></p>
208
- </body>
209
-
210
- <!-- Valid expression: spread operator -->
211
- <body :data="{ list: [1, 2], extra: 3 }">
212
- <div :for="item in [...list, extra]">{{ item }}</div>
213
- </body>
214
-
215
- <!-- Valid expression: arrow functions (e.g. in map) -->
216
- <body :data="{ items: [1, 2, 3] }">
217
- <div :for="n in items.map((x) => x * 2)">{{ n }}</div>
218
- </body>
219
-
220
- <!-- Valid expression: boolean logic -->
221
- <body :data="{ pos: 1, finished: false }">
222
- <p :show="pos >= 1 && !finished">you are number {{ pos }} in the queue</p>
223
- </body>
224
-
225
- <!-- Valid expression: ternary operators -->
226
- <body :data="{ pos: 1 }">
227
- <p :text="pos % 2 == 0 ? 'even' : 'odd'"></p>
228
- </body>
229
-
230
- <!-- Valid expression: function calling -->
231
- <body :data="{ pos : 1 }">
232
- <p :text="buildQueueMessage()"></p>
233
- <script>
234
- const { $ } = Mancha;
235
- $.buildQueueMessage = function () {
236
- return "you are number " + this.pos + " in the queue";
237
- };
238
- // Alternatively, anonymous functions without `this`:
239
- // $.buildQueueMessage = () => 'you are number ' + $.pos + ' in the queue';
240
- </script>
241
- </body>
242
-
243
- <!-- Valid expression: simple assignment -->
244
- <body :data="{ pos: 1 }">
245
- <p :text="'you are number ' + pos + ' in the queue'"></p>
246
- <button :on:click="pos = pos + 1">Click to get there faster</button>
247
- </body>
248
-
249
- <!-- Invalid expression: multiple statements -->
250
- <button :on:click="console.log('yes'); answer = 'no'"></button>
251
-
252
- <!-- Invalid expression: function definition (top-level) -->
253
- <body :data="{ foo: function() { return 'yes'; } }">
254
- <p :text="foo()"></p>
255
- </body>
256
- ```
257
-
258
- ## Variable Scoping
259
-
260
- Contents of the `:data` attribute are only available to subnodes in the HTML tree. This is better
261
- illustrated with an example:
262
-
263
- ```html
264
- <body :data="{ name: 'stranger', key: '1234' }">
265
- <!-- Hello, stranger -->
266
- <h1>Hello, {{ name }}</h1>
267
-
268
- <!-- Initially "undefined", but reactive to later changes -->
269
- <span>{{ message }}</span>
270
-
271
- <!-- How are you, danger? The secret message is "secret" and the key is "1234" -->
272
- <p :data="{ name: 'danger', message: 'secret' }">
273
- How are you, {{ name }}? The secret message is "{{ message }}" and the key is "{{ key }}"
274
- </p>
275
- </body>
276
- ```
277
-
278
- By default, the target root element is the `body` tag. So, any variables defined in the body's
279
- `:data` attribute are available to the main renderer.
280
-
281
- In the example above, the `<span>` references `message` which is not defined in the body's `:data`.
282
- This auto-initializes `message` to `undefined` and attaches an observer, so setting `$.message`
283
- later will update the `<span>` content. The `<p>` tag has its own local `message` variable which
284
- shadows any parent value. Since the variables are not accessible via the global object, you'll need
285
- to retrieve the renderer from the element's properties:
286
-
287
- ```js
288
- // Explicitly render the body, so we can await it and then modify variables.
289
- const { $ } = Mancha;
290
- await $.mount(document.body);
291
-
292
- // This modifies the `name` variable in all the renderer contexts.
293
- $.name = "world";
294
-
295
- // This updates the `<span>` content to "bandit" because `message` was
296
- // auto-initialized when the template referenced it. However, the `<p>` tag
297
- // still shows "secret" because it has its own local `message` variable.
298
- $.message = "bandit";
299
-
300
- // We extract the subrenderer from the element's properties. Only elements
301
- // with `:data` attribute have a `renderer` property.
302
- const subrenderer = document.querySelector("p").renderer;
303
-
304
- // This modifies the `message` variable only in the `<p>` tag.
305
- subrenderer.$.message = "banana";
306
- ```
307
-
308
- When accessing variables, `mancha` searches the current renderer first, then the parent, the
309
- parent's parent, and so forth until the root renderer is reached. If the requested variable is not
310
- found in the current renderer or any of the ancestor renderers, then `undefined` is returned:
311
-
312
- ```html
313
- <body :data="{ name: 'stranger' }">
314
- <!-- Hello, stranger! -->
315
- <p :data="{}">Hello, {{ name }}!</p>
316
- </body>
317
- ```
318
-
319
- ### Reactive Undefined Variables
51
+ ## Documentation
320
52
 
321
- When a variable is referenced in a template expression but not yet defined, `mancha` automatically
322
- initializes it to `undefined` and attaches an observer. This means you can set the variable later
323
- using the same renderer (or a subrenderer) and the template will reactively update:
53
+ - **[Quick Start](./docs/quickstart.md)**: Get up and running in minutes.
54
+ - **[Syntax](./docs/syntax.md)**: Reference for attributes and expressions.
55
+ - **[Reactivity](./docs/reactivity.md)**: How variables, scoping, and URL binding work.
56
+ - **[Components](./docs/components.md)**: Creating reusable components and includes.
57
+ - **[CSS](./docs/css.md)**: Built-in CSS utilities.
58
+ - **[Server-Side Rendering](./docs/ssr.md)**: Using Mancha on the server (Node, Workers).
59
+ - **[TypeScript](./docs/typescript.md)**: Type safety and checking.
60
+ - **[Testing](./docs/testing.md)**: Testing your UI.
324
61
 
325
- ```html
326
- <body>
327
- <!-- Initially shows "undefined", but updates reactively when `message` is set -->
328
- <p>{{ message }}</p>
329
- </body>
330
- <script type="module">
331
- const { $ } = Mancha;
332
- await $.mount(document.body);
333
-
334
- // The template initially renders with `message` as undefined.
335
- // Setting it now will trigger a reactive update.
336
- $.message = "Hello, World!";
337
- </script>
338
- ```
339
-
340
- This behavior is particularly useful with the `:render` attribute, where a JavaScript module can
341
- set variables that are already referenced in the template:
342
-
343
- ```html
344
- <div :render="./init.js">
345
- <!-- These variables are set by the :render callback -->
346
- <span>{{ title }}</span>
347
- <ul :for="item in items">
348
- <li>{{ item }}</li>
349
- </ul>
350
- </div>
351
- ```
352
-
353
- ```js
354
- // init.js
355
- export default async function (elem, renderer) {
356
- await renderer.set("title", "My List");
357
- await renderer.set("items", ["a", "b", "c"]);
358
- }
359
- ```
360
-
361
- The auto-initialization only happens when variables are accessed during an effect (such as template
362
- rendering). Accessing a variable outside of an effect context will return `undefined` without
363
- creating an observer.
364
-
365
- When setting a variable, there are 3 possible cases:
366
-
367
- 1. The variable has already been defined in the current renderer. Then it gets updated in the
368
- current renderer.
369
- 1. The variable is undefined in the current renderer but has already been defined in an ancestor
370
- renderer. Then it gets updated in the corresponding ancestor renderer.
371
- 1. The variable is not defined in the current renderer or any ancestor renderers. Then it is set in
372
- the current renderer.
373
-
374
- NOTE: This does not apply to variables defined via `:data` attribute, which always set a new
375
- variable for the newly created renderer.
376
-
377
- Renderers also have a `$parent`, `$rootRenderer` and `$rootNode` attributes. The `$parent` attribute
378
- references the immediate ancestor renderer if any, or it's `null` otherwise. The `$rootRenderer`
379
- attribute references the root renderer where `mancha` was mounted, which could be a self-reference.
380
- Finally, the `$rootNode` attribute references the HTML node where `mancha` was mounted.
381
-
382
- While evaluating expressions, there will also be an `$elem` attribute which references the current
383
- element being rendered or, in the case of events, the element dispatching the event as well as the
384
- corresponding `$event` attribute.
385
-
386
- ### URL Query Parameter Binding
387
-
388
- `mancha` provides a convenient way to establish a two-way binding between the state of your application and the URL query parameters. This is useful for preserving state across page reloads and for sharing links that restore the application to a specific state.
389
-
390
- This feature is enabled automatically. When a renderer is mounted to a DOM element, any variable in its store prefixed with `$$` will be automatically synchronized with the URL query parameters.
391
-
392
- - **Store to URL**: When you set a variable like `$.$$page = 2` (where `$` is the renderer's reactive proxy), the URL will be updated to `/?page=2`. If you set the value to a falsy value (e.g., `null`, `undefined`, `false`, `0`, or `''`), the parameter will be removed from the URL.
393
-
394
- - **URL to Store**: When the page loads or the user navigates using the browser's back/forward buttons, the store is automatically updated from the current URL's query parameters. For example, if the URL is `/?search=mancha`, the store variable `$$search` will be set to `"mancha"`.
395
-
396
- This allows you to react to URL changes declaratively within your components:
397
-
398
- ```html
399
- <body :data="{ $$search: '' }">
400
- <input type="text" :bind="$$search" placeholder="Search..." />
401
- <div :show="$$search">Searching for: {{ $$search }}</div>
402
- </body>
403
- <script type="module">
404
- import { Mancha } from "//unpkg.com/mancha";
405
- await Mancha.mount(document.body);
406
- </script>
407
- ```
408
-
409
- ## Styling
410
-
411
- Some basic styling rules are built into the library and can be optionally used. The styling
412
- component was designed to be used in the browser, and it's enabled by adding a `css` attribute
413
- to the `<script>` tag that loads `mancha`. The supported rulesets are:
414
-
415
- - `basic`: inspired by [these rules](https://www.swyx.io/css-100-bytes), the full CSS can be found
416
- [here](./src/css_gen_basic.ts).
417
- - `utils`: utility classes inspired by [tailwindcss](https://tailwindcss.com), the resulting CSS is
418
- a drop-in replacement for a subset of the classes provided by `tailwindcss` with the main
419
- exception of the color palette which is borrowed from
420
- [material design](https://www.materialpalette.com/colors).
421
-
422
- ## Usage
423
-
424
- ### Client Side Rendering (CSR)
62
+ ## AI Agents
425
63
 
426
- To use `mancha` on the client (browser), use the `mancha` bundled file available via `unpkg`.
427
-
428
- ```html
429
- <body :data="{ name: 'John' }">
430
- <span>Hello, {{ name }}!</span>
431
- </body>
432
-
433
- <script src="//unpkg.com/mancha" target="body" css="basic+utils" init></script>
434
- ```
435
-
436
- Script tag attributes:
437
-
438
- - `init`: whether to automatically render upon script load
439
- - `target`: document elements separated by `+` to render e.g. "body" or "head+body" (defaults to
440
- "body")
441
- - `css`: inject predefined CSS rulesets into the `<head>` element, see the
442
- [styling section](#styling) for more details.
443
-
444
- For a more complete example, see [examples/browser](./examples/browser).
445
-
446
- ### Compile Time Server Side Rendering (SSR)
447
-
448
- To use `mancha` on the server at compile time, you can use the `npx mancha` command. For example,
449
- if this is your project structure:
450
-
451
- ```
452
- src/
453
- ├─ components/
454
- | ├─ main.tpl.html
455
- | ├─ footer.tpl.html
456
- ├─ index.html
457
- ├─ vars.json
458
- ```
459
-
460
- You can run the following command to compile the site into a `public` folder:
64
+ If you are an AI agent building with `mancha`, you can dump all the documentation in a single concatenated output by running:
461
65
 
462
66
  ```bash
463
- npx mancha --input="./src/index.html" --vars="$(cat vars.json)" --output="./public"
67
+ npx mancha docs
464
68
  ```
465
69
 
466
- For a more complete example, see [examples/compiled](./examples/compiled).
467
-
468
- ### On Demand Server Side Rendering (SSR)
469
-
470
- You can also use `mancha` as part of your server's request handling. Assuming a similar folder
471
- structure as described in the previous section, the following `express` node server would render
472
- the HTML code on demand for each incoming request:
473
-
474
- ```js
475
- import express from "express";
476
- import { Renderer } from "mancha";
477
- import vars from "./vars.json";
478
-
479
- const app = express();
480
-
481
- app.get("/", async (req, res) => {
482
- const name = req.query.name || "Stranger";
483
- // Instantiate a new renderer.
484
- const renderer = new Renderer({ name, ...vars });
485
- // Preprocess input HTML from a local file path.
486
- const fragment = await renderer.preprocessLocal("src/index.html");
487
- // Render and serialize output HTML.
488
- const html = renderer.serializeHTML(await renderer.renderNode(fragment));
489
- // Send it to the client.
490
- res.set("Content-Type", "text/html");
491
- res.send(html);
492
- });
493
-
494
- app.listen(process.env.PORT || 8080);
495
- ```
496
-
497
- For a more complete example, see [examples/express](./examples/express).
498
-
499
- ### Web Worker Runtime Server Side Rendering (SSR)
500
-
501
- For servers hosted as worker runtimes, such as `Cloudflare Workers`, you will need to import a
502
- stripped down version of `mancha` that does not have the ability to read local files.
503
-
504
- ```js
505
- import { Renderer } from "mancha/dist/worker";
506
- import htmlIndex from "./index.html";
507
- import vars from "./vars.json";
508
-
509
- self.addEventListener("fetch", async (event) => {
510
- // Instantiate a new renderer.
511
- const renderer = new Renderer({ ...vars });
512
- // Preprocess input HTML from a string.
513
- const fragment = await renderer.preprocessString(htmlIndex);
514
- // Render and serialize output HTML.
515
- const html = renderer.serializeHTML(await renderer.renderNode(fragment));
516
- // Send it to the client.
517
- event.respondWith(new Response(content, { headers: { "Content-Type": "text/html" } }));
518
- });
519
- ```
520
-
521
- To meet the size requirements of popular worker runtimes, the worker version of `mancha` uses
522
- `htmlparser2` instead of `jsdom` for the underlying HTML and DOM manipulation. This keeps the
523
- footprint of `mancha` and its dependencies under 100kb.
524
-
525
- For a more complete example, see [examples/wrangler](./examples/wrangler).
526
-
527
70
  ## Dependencies
528
71
 
529
- The browser bundle contains no external dependencies. The unbundled version
530
- can use `htmlparser2`, which is compatible with web workers, or `jsdom`.
72
+ The browser bundle contains no external dependencies. The unbundled version can use `htmlparser2`, which is compatible with web workers, or `jsdom`.
package/biome.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "$schema": "https://biomejs.dev/schemas/2.3.10/schema.json",
3
+ "vcs": {
4
+ "enabled": true,
5
+ "clientKind": "git",
6
+ "useIgnoreFile": true
7
+ },
8
+ "files": {
9
+ "ignoreUnknown": true,
10
+ "includes": ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx", "**/*.json"]
11
+ },
12
+ "formatter": {
13
+ "enabled": true,
14
+ "formatWithErrors": false,
15
+ "indentStyle": "tab",
16
+ "indentWidth": 2,
17
+ "lineEnding": "lf",
18
+ "lineWidth": 100,
19
+ "attributePosition": "auto"
20
+ },
21
+ "linter": {
22
+ "enabled": true,
23
+ "rules": {
24
+ "recommended": true,
25
+ "complexity": {
26
+ "noUselessTypeConstraint": "error"
27
+ },
28
+ "style": {
29
+ "noNonNullAssertion": "error",
30
+ "useConst": "error",
31
+ "useImportType": "error"
32
+ },
33
+ "suspicious": {
34
+ "noExplicitAny": "error",
35
+ "useIterableCallbackReturn": "error"
36
+ }
37
+ }
38
+ },
39
+ "javascript": {
40
+ "formatter": {
41
+ "quoteStyle": "double",
42
+ "trailingCommas": "all",
43
+ "semicolons": "always"
44
+ }
45
+ }
46
+ }
package/dist/browser.d.ts CHANGED
@@ -1,48 +1,52 @@
1
- import { IRenderer } from "./renderer.js";
2
- import type { StoreState } from "./store.js";
3
- import type { ParserParams, RenderParams } from "./interfaces.js";
4
- export { IRenderer } from "./renderer.js";
5
- export type { ParserParams, RenderParams, RendererPlugin } from "./interfaces.js";
6
- export { default as basicCssRules } from "./css_gen_basic.js";
7
- export { default as utilsCssRules } from "./css_gen_utils.js";
8
- export declare class Renderer<T extends StoreState = StoreState> extends IRenderer<T> {
9
- readonly impl = "browser";
10
- protected readonly dirpath: string;
11
- parseHTML(content: string, params?: ParserParams): Document | DocumentFragment;
12
- serializeHTML(root: Node | DocumentFragment): string;
13
- preprocessLocal(fpath: string, params?: RenderParams & ParserParams): Promise<Document | DocumentFragment>;
14
- createElement(tag: string, owner?: Document | null): Element;
15
- createComment(content: string, owner?: Document | null): Node;
16
- textContent(node: Node, content: string): void;
1
+ import { a as StoreState, i as IRenderer, n as RenderParams, r as RendererPlugin, t as ParserParams } from "./interfaces-Dizh9utI.js";
2
+ import { SafeStyleSheet } from "safevalues";
3
+
4
+ //#region src/css_gen_basic.d.ts
5
+ declare function rules(): SafeStyleSheet;
6
+ //#endregion
7
+ //#region src/css_gen_utils.d.ts
8
+
9
+ declare function rules$1(): string;
10
+ //#endregion
11
+ //#region src/browser.d.ts
12
+ declare class Renderer<T extends StoreState = StoreState> extends IRenderer<T> {
13
+ readonly impl = "browser";
14
+ protected readonly dirpath: string;
15
+ parseHTML(content: string, params?: ParserParams): Document | DocumentFragment;
16
+ serializeHTML(root: Node | DocumentFragment): string;
17
+ preprocessLocal(fpath: string, params?: RenderParams & ParserParams): Promise<Document | DocumentFragment>;
18
+ createElement(tag: string, owner?: Document | null): Element;
19
+ createComment(content: string, owner?: Document | null): Node;
20
+ textContent(node: Node, content: string): void;
17
21
  }
18
- export declare const Mancha: Renderer<StoreState>;
22
+ declare const Mancha: Renderer<StoreState>;
19
23
  /** Options for CSS injection. */
20
- export type CssName = "basic" | "utils";
24
+ type CssName = "basic" | "utils";
21
25
  /**
22
26
  * Injects CSS rules into the document head.
23
27
  * @param names - Array of CSS names to inject ("basic", "utils").
24
28
  */
25
- export declare function injectCss(names: CssName[]): void;
29
+ declare function injectCss(names: CssName[]): void;
26
30
  /**
27
31
  * Injects the basic CSS rules into the document head.
28
32
  */
29
- export declare function injectBasicCss(): void;
33
+ declare function injectBasicCss(): void;
30
34
  /**
31
35
  * Injects the utils CSS rules into the document head.
32
36
  */
33
- export declare function injectUtilsCss(): void;
37
+ declare function injectUtilsCss(): void;
34
38
  /** Options for initializing Mancha. */
35
- export interface InitManchaOptions {
36
- /** CSS styles to inject before mounting. */
37
- css?: CssName[];
38
- /** Target selector(s) to mount the renderer to. */
39
- target?: string | string[];
40
- /** Enable debug mode. */
41
- debug?: boolean;
42
- /** Cache policy for fetch requests. */
43
- cache?: RequestCache;
44
- /** Initial state to set before mounting. */
45
- state?: Record<string, unknown>;
39
+ interface InitManchaOptions {
40
+ /** CSS styles to inject before mounting. */
41
+ css?: CssName[];
42
+ /** Target selector(s) to mount the renderer to. */
43
+ target?: string | string[];
44
+ /** Enable debug mode. */
45
+ debug?: boolean;
46
+ /** Cache policy for fetch requests. */
47
+ cache?: RequestCache;
48
+ /** Initial state to set before mounting. */
49
+ state?: Record<string, unknown>;
46
50
  }
47
51
  /**
48
52
  * Initializes Mancha with the provided options.
@@ -51,4 +55,6 @@ export interface InitManchaOptions {
51
55
  * @param options - Initialization options.
52
56
  * @returns A promise that resolves to the Renderer instance.
53
57
  */
54
- export declare function initMancha<T extends StoreState = StoreState>(options?: InitManchaOptions): Promise<Renderer<T>>;
58
+ declare function initMancha<T extends StoreState = StoreState>(options?: InitManchaOptions): Promise<Renderer<T>>;
59
+ //#endregion
60
+ export { CssName, IRenderer, InitManchaOptions, Mancha, type ParserParams, type RenderParams, Renderer, type RendererPlugin, rules as basicCssRules, initMancha, injectBasicCss, injectCss, injectUtilsCss, rules$1 as utilsCssRules };