micra.js 2.2.1 → 2.3.1

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/CHANGELOG.md CHANGED
@@ -4,6 +4,124 @@ All notable changes to Micra.js will be documented in this file. Format follows
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), versioning follows
5
5
  [SemVer](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [2.3.1] — 2026-05-30
8
+
9
+ ### Performance
10
+
11
+ - **Batch scheduler now uses `queueMicrotask` instead of
12
+ `Promise.resolve().then(...)`.** Each render batch enqueues a single
13
+ microtask instead of allocating a Promise plus a reaction job, and the
14
+ flush callback is hoisted out of the hot path so it isn't re-created on
15
+ every `schedule()` call. Behaviour is identical — same microtask timing,
16
+ same write-collapsing. No public-API change.
17
+
18
+ ### Internal — dead-code removal
19
+
20
+ - Removed the `src/dom/query.ts` module (`queryAll` / `queryOwn` /
21
+ `queryOwnAll` / `filterOwn`). It had no importers since the 2.2.0
22
+ single-pass scan replaced per-render `querySelectorAll` calls with one
23
+ `TreeWalker` traversal — esbuild already tree-shook it out of the
24
+ bundle, so this is a source-only cleanup.
25
+ - Removed two dead bookkeeping writes: `node.__micraEach` and
26
+ `node.__micraKey` were assigned during list rendering but never read
27
+ (keys live in the keyed-diff `Map`; the no-key path doesn't tag rows).
28
+ Dropped the matching fields from `MicraElement`.
29
+ - Dropped the unused `instance` parameter from `applyDirectives` — it was
30
+ never referenced in the body.
31
+
32
+ ### Docs
33
+
34
+ - New [Rails + Micra recipe](https://github.com/denisfl/micra.js/blob/master/docs/recipes/rails.md)
35
+ (`docs/recipes/rails.md` + a site page): manual importmap integration,
36
+ the `micra-rails` gem with its caveats, a Tasks board demonstrating SSR
37
+ props / CSRF-attached `this.fetch` / cross-component bus, and the Turbo
38
+ Drive / Streams / Frames mount-and-cleanup story.
39
+ - README gains a **TypeScript** section spelling out what's checked
40
+ end-to-end (state, methods, event payloads) versus what isn't (the
41
+ expression strings inside `data-*` attributes).
42
+ - Landing page gains **Speed** (cross-library benchmark cards) and **AI
43
+ sandboxes** (copy-the-LLM-prompt) sections.
44
+
45
+ ### Bundle
46
+
47
+ - **5.5 KB gzip** (5582 bytes) — a few bytes lighter than 2.3.0 after the
48
+ dead-code removal.
49
+
50
+ ## [2.3.0] — 2026-05-30
51
+
52
+ ### TypeScript — type-safe event bus
53
+
54
+ - **New augmentable `MicraEvents` interface.** Declare your app's events
55
+ once and `Micra.emit` / `Micra.on` / `this.emit` / `this.on` enforce
56
+ payload types and arity at the call site:
57
+
58
+ ```ts
59
+ declare module 'micra.js' {
60
+ interface MicraEvents {
61
+ 'cart:updated': { count: number }
62
+ 'modal:close': void
63
+ }
64
+ }
65
+
66
+ Micra.emit('cart:updated', { count: 3 }) // ✓
67
+ Micra.emit('cart:updated', { count: '3' }) // ✗ type error
68
+ Micra.emit('modal:close') // ✓ void → no args
69
+ ```
70
+
71
+ - Events that are NOT declared in `MicraEvents` keep the previous
72
+ behaviour — payload typed as `unknown`, optional argument. Untyped
73
+ code keeps compiling unchanged.
74
+ - New exported types: `MicraEvents`, `EventPayload<K>`, `EmitArgs<K>`.
75
+ - Bundle stays at **5.4 KB gzip** — types only, no runtime change.
76
+
77
+ ### Breaking — types only
78
+
79
+ - The legacy `on<T>(event, handler)` generic now infers `T` as the
80
+ event *key*, not the handler payload. Code that explicitly passed a
81
+ payload type via the generic (`Micra.on<User>('user:updated', h)`)
82
+ still compiles, but `h`'s parameter falls back to `unknown` unless
83
+ the event is declared in `MicraEvents`. Migration: register the
84
+ event via `declare module 'micra.js'` and drop the explicit generic.
85
+ No runtime impact.
86
+
87
+ ### Performance — non-keyed `data-each` now reuses DOM nodes
88
+
89
+ - **Non-keyed `<template data-each>` no longer re-renders the whole list
90
+ on every update.** The new path keeps the first `min(prev, next)` row
91
+ nodes in place — only the length delta is touched (tail removed when
92
+ the list shrinks, new rows cloned when it grows). Each retained row
93
+ gets a fresh `itemState` and a re-applied directive pass through its
94
+ cached `__micraScan`, so content updates correctly without the
95
+ remove/re-clone overhead.
96
+ - Row identity is now stable across renders for the no-key path: event
97
+ listeners bound via `data-on` / `@event` / `data-model` survive
98
+ re-renders without re-binding, and DOM-level state (focus, scroll,
99
+ CSS transitions) is preserved on retained rows.
100
+ - Items that didn't change (same reference + same index) skip
101
+ `applyDirectives` entirely when only the `data-each` source array is
102
+ the trigger for this render cycle — same `canSkipUnchanged`
103
+ optimisation the keyed path already had.
104
+ - Bundle: **5.5 KB gzip** (raised guard from 5.4 → 5.5 to give the
105
+ shared row-creation helper room; net code is slightly smaller after
106
+ factoring `createRowNode` out of both keyed and non-keyed paths).
107
+
108
+ ### Breaking — non-keyed multi-root rows now wrap in `<micra-each-item>`
109
+
110
+ - Templates whose `data-each` content has more than one top-level node
111
+ now render each row inside a `<micra-each-item style="display:contents">`
112
+ wrapper, mirroring the keyed path's existing behaviour. The wrapper is
113
+ visually inert (CSS `display:contents` opts out of the box model) but
114
+ it does add one node to the parse tree.
115
+ - Impact:
116
+ - **CSS:** child selectors that targeted `parent > .row` will now
117
+ match `parent > micra-each-item` instead. Use descendant selectors
118
+ (`parent .row`) or update the rules.
119
+ - **Invalid HTML contexts:** templates whose rows are `<tr>` / `<td>` /
120
+ `<li>` inside `<tbody>` / `<tr>` / `<ul>` cannot legally have a
121
+ wrapper between the parent and the row. Hoist the wrapper into the
122
+ template (so the row is single-rooted) or use a `data-key`.
123
+ - Single-root templates are unchanged — by far the common case.
124
+
7
125
  ## [2.2.1] — 2026-05-28
8
126
 
9
127
  ### Performance — batched first list render
package/README.md CHANGED
@@ -71,6 +71,48 @@ npm install micra.js
71
71
  import * as Micra from "micra.js";
72
72
  ```
73
73
 
74
+ ### TypeScript
75
+
76
+ The npm package ships its own `dist/index.d.ts` — no `@types/micra.js` package
77
+ needed. Inside every method body and lifecycle hook, both `this.state.X` and
78
+ `this.someMethod()` are fully checked at the call site (both `state` and the
79
+ method set are inferred from the literal you pass to `Micra.define`).
80
+
81
+ ```ts
82
+ import * as Micra from "micra.js";
83
+
84
+ Micra.define("counter", {
85
+ state: { count: 0 },
86
+ inc() {
87
+ this.state.count++; // ✓ number
88
+ this.dec(); // ✓ inferred sibling method
89
+ // this.foo(); // ✗ Property 'foo' does not exist
90
+ },
91
+ dec() { this.state.count--; },
92
+ });
93
+
94
+ // Type-safe event bus via declaration merging
95
+ declare module "micra.js" {
96
+ interface MicraEvents {
97
+ "cart:updated": { count: number };
98
+ "modal:close": void;
99
+ }
100
+ }
101
+
102
+ Micra.emit("cart:updated", { count: 3 }); // ✓
103
+ Micra.emit("cart:updated", { count: "3" }); // ✗ type error
104
+ Micra.emit("modal:close"); // ✓ void → no args
105
+ ```
106
+
107
+ **What's checked:** imports, state shape, method names, event-bus payloads,
108
+ lifecycle hooks, refs, `Micra.mount()` return type.
109
+
110
+ **What's not:** the expression strings inside `data-text="…"` / `@click="…"`
111
+ attributes — those are plain HTML to the IDE and validated only at mount
112
+ time. Same trade-off as Alpine.js `x-*` and petite-vue `v-*`; the
113
+ alternatives are JSX or a single-file-component compiler, neither of which
114
+ Micra ships.
115
+
74
116
  ## Basic usage
75
117
 
76
118
  A counter mounted automatically from `data-component`:
@@ -182,6 +224,8 @@ this.on(event, handler)
182
224
  - Recipes:
183
225
  - [Todo app](./docs/recipes/todo-app.md)
184
226
  - [Server-sent events (SSE)](./docs/recipes/sse.md)
227
+ - [htmx bridge](./docs/recipes/htmx.md)
228
+ - [Rails + Micra](./docs/recipes/rails.md)
185
229
 
186
230
  ## Code generation with LLMs
187
231
 
@@ -10,23 +10,25 @@
10
10
  * Component instances subscribe via `instance.on()` which auto-registers
11
11
  * the unsub token in `instance.__micraSubs` for cleanup on destroy().
12
12
  */
13
- import type { EventHandler, UnsubFn } from '../types';
13
+ import type { EmitArgs, EventPayload, UnsubFn } from '../types';
14
14
  /**
15
15
  * Subscribe to a named event. Returns an unsubscribe function.
16
+ * Payload is typed via the `MicraEvents` interface (augmentable).
16
17
  *
17
18
  * @example
18
19
  * const unsub = on('user:login', (user) => console.log(user))
19
20
  * unsub() // stop listening
20
21
  */
21
- export declare function on<T = unknown>(event: string, handler: EventHandler<T>): UnsubFn;
22
+ export declare function on<K extends string>(event: K, handler: (payload: EventPayload<K>) => void): UnsubFn;
22
23
  /**
23
24
  * Unsubscribe a specific handler from an event.
24
25
  */
25
- export declare function off(event: string, handler: EventHandler): void;
26
+ export declare function off<K extends string>(event: K, handler: (payload: EventPayload<K>) => void): void;
26
27
  /**
27
28
  * Publish an event to all subscribers. Errors are caught per-handler.
29
+ * Payload is typed via the `MicraEvents` interface (augmentable).
28
30
  *
29
31
  * @example
30
32
  * emit('user:updated', { id: 1, name: 'Alice' })
31
33
  */
32
- export declare function emit(event: string, payload?: unknown): void;
34
+ export declare function emit<K extends string>(event: K, ...args: EmitArgs<K>): void;
@@ -23,6 +23,10 @@ export declare function createReactiveState<S extends StateRecord>(obj: S, sched
23
23
  * Return a debounce function that defers `render` to the next microtask.
24
24
  * Multiple calls within the same tick collapse to a single render.
25
25
  *
26
+ * Uses `queueMicrotask` so each batch enqueues a single microtask instead of
27
+ * allocating a Promise + reaction job. `flush` is hoisted out of the hot path
28
+ * so it isn't re-created on every schedule() call.
29
+ *
26
30
  * @example
27
31
  * const schedule = createScheduler(render)
28
32
  * schedule() // defers render
@@ -11,7 +11,7 @@
11
11
  *
12
12
  * Important: this module does NOT handle data-each — see dom/each.ts.
13
13
  */
14
- import type { InternalInstance, ScanIndex, StateRecord } from '../types';
14
+ import type { ScanIndex, StateRecord } from '../types';
15
15
  import { warn } from '../utils/expr';
16
16
  /**
17
17
  * Apply all non-each directives to a component subtree.
@@ -23,7 +23,7 @@ import { warn } from '../utils/expr';
23
23
  * @param state - Expression state (may include item/index for each rows)
24
24
  * @param rawState - Raw (non-proxy) state for model sync
25
25
  */
26
- export declare function applyDirectives<S extends StateRecord>(scan: ScanIndex, state: StateRecord, rawState: StateRecord, _instance: InternalInstance<S>): void;
26
+ export declare function applyDirectives(scan: ScanIndex, state: StateRecord, rawState: StateRecord): void;
27
27
  /**
28
28
  * Validate directive usage and emit dev warnings.
29
29
  * Called once after the initial render of a component, with the already-built
@@ -4,7 +4,8 @@
4
4
  * Responsibilities:
5
5
  * - Process `<template data-each="items" data-key="id">` elements
6
6
  * - Keyed diff: reuse/reorder DOM nodes by key — O(n) with a Map
7
- * - Non-keyed fallback: full replace (no key → warn in dev, full re-render)
7
+ * - Non-keyed fallback: length-based positional reuse min(old, new) rows
8
+ * are kept as-is, the tail is removed or new rows are appended
8
9
  * - Apply directives to each row with a scoped itemState
9
10
  *
10
11
  * LLM NOTE: renderList() is called on every render cycle AFTER applyDirectives().
@@ -12,7 +13,9 @@
12
13
  * Each row node gets its own ScanIndex cached on `node.__micraScan` so
13
14
  * re-renders of that row don't re-walk the DOM.
14
15
  * Keyed mode (data-key present) mutates the DOM in-place — nodes are
15
- * created once and reused. Non-keyed mode removes all nodes and re-clones.
16
+ * created once and reused. Non-keyed mode also reuses existing nodes
17
+ * positionally: only the length delta is touched, the rest gets a fresh
18
+ * itemState and re-applies directives.
16
19
  */
17
20
  import type { InternalInstance, StateRecord } from '../types';
18
21
  /**
@@ -5,12 +5,13 @@
5
5
  * traversal that classifies every directive attribute in a single visit.
6
6
  *
7
7
  * Boundaries:
8
- * - REJECT (skip subtree) on nested [data-component] — same semantics as
9
- * the old `filterOwn` helper, but applied during the walk so we don't
10
- * even *visit* those nodes.
8
+ * - REJECT (skip subtree) on nested [data-component] — a parent component
9
+ * never processes directives owned by a nested child. Applied during the
10
+ * walk so we don't even *visit* those nodes.
11
11
  * - <template> contents are not visited (browser TreeWalker default).
12
12
  * `<template data-each>` itself IS visited and classified into scan.each;
13
- * its children are processed by each.ts on every render via scanFragment.
13
+ * its children are processed by each.ts on every render fresh rows
14
+ * are wrapped in a per-row element and scanned via scanComponent.
14
15
  *
15
16
  * Hot-path notes:
16
17
  * - We read `el.attributes` once and switch by suffix. No allocations per
@@ -27,8 +28,3 @@ import type { ScanIndex } from "../types";
27
28
  * are free.
28
29
  */
29
30
  export declare function scanComponent(root: Element): ScanIndex;
30
- /**
31
- * Scan a DocumentFragment (no-key each clone). Not cached — these fragments
32
- * are temporary and re-cloned every render.
33
- */
34
- export declare function scanFragment(frag: DocumentFragment): ScanIndex;
package/dist/index.d.ts CHANGED
@@ -21,7 +21,7 @@
21
21
  *
22
22
  * @module Micra
23
23
  */
24
- export type { StateRecord, UnsubFn, EventHandler, FetchOptions, ComponentMethods, ComponentBuiltins, ComponentInstance, ComponentDefinition, } from './types';
24
+ export type { StateRecord, UnsubFn, EventHandler, EventPayload, EmitArgs, MicraEvents, FetchOptions, ComponentMethods, ComponentBuiltins, ComponentInstance, ComponentDefinition, } from './types';
25
25
  export { FetchError } from './utils/fetch';
26
26
  export { define, defineComponent, instances, registry, debug } from './core/registry';
27
27
  export { mount } from './core/mount';
package/dist/micra.cjs.js CHANGED
@@ -1,4 +1,4 @@
1
- /* Micra.js v2.2.1 — https://github.com/micra-js/micra — MIT */
1
+ /* Micra.js v2.3.1 — https://github.com/micra-js/micra — MIT */
2
2
  "use strict";
3
3
  var __defProp = Object.defineProperty;
4
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -227,8 +227,9 @@ function off(event, handler) {
227
227
  set.delete(handler);
228
228
  if (set.size === 0) _bus.delete(event);
229
229
  }
230
- function emit(event, payload) {
230
+ function emit(event, ...args) {
231
231
  var _a;
232
+ const payload = args[0];
232
233
  (_a = _bus.get(event)) == null ? void 0 : _a.forEach((h) => {
233
234
  try {
234
235
  h(payload);
@@ -252,13 +253,14 @@ function createReactiveState(obj, schedule, onKey) {
252
253
  }
253
254
  function createScheduler(render) {
254
255
  let pending = false;
256
+ const flush = () => {
257
+ pending = false;
258
+ render();
259
+ };
255
260
  return function schedule() {
256
261
  if (pending) return;
257
262
  pending = true;
258
- Promise.resolve().then(() => {
259
- pending = false;
260
- render();
261
- });
263
+ queueMicrotask(flush);
262
264
  };
263
265
  }
264
266
 
@@ -324,7 +326,7 @@ function applyModel(el, key, rawState) {
324
326
  const desired = stateVal == null ? "" : String(stateVal);
325
327
  if (html.value !== desired) html.value = desired;
326
328
  }
327
- function applyDirectives(scan, state, rawState, _instance) {
329
+ function applyDirectives(scan, state, rawState) {
328
330
  for (const b of scan.if) applyIf(b, state);
329
331
  for (const b of scan.text) applyText(b.el, b.expr, state);
330
332
  for (const b of scan.html) applyHtml(b.el, b.expr, state);
@@ -535,20 +537,6 @@ function scanComponent(root) {
535
537
  }
536
538
  return scan;
537
539
  }
538
- function scanFragment(frag) {
539
- const scan = emptyScan();
540
- const walker = document.createTreeWalker(
541
- frag,
542
- NodeFilter.SHOW_ELEMENT,
543
- NESTED_COMPONENT_FILTER
544
- );
545
- let node = walker.nextNode();
546
- while (node) {
547
- classify(node, scan);
548
- node = walker.nextNode();
549
- }
550
- return scan;
551
- }
552
540
 
553
541
  // src/dom/each.ts
554
542
  function renderList(templates, state, rawState, instance, triggerKey) {
@@ -579,10 +567,28 @@ function renderList(templates, state, rawState, instance, triggerKey) {
579
567
  if (keyAttr) {
580
568
  renderKeyed(tmpl, items, keyAttr, marker, keyMap, state, rawState, instance, canSkipUnchanged);
581
569
  } else {
582
- renderNoKey(tmpl, items, marker, state, rawState, instance);
570
+ renderNoKey(tmpl, items, marker, state, rawState, instance, canSkipUnchanged);
583
571
  }
584
572
  }
585
573
  }
574
+ function createRowNode(tmpl, state, instance) {
575
+ const frag = tmpl.content.cloneNode(true);
576
+ let node;
577
+ if (frag.childNodes.length === 1) {
578
+ node = frag.firstElementChild;
579
+ } else {
580
+ node = document.createElement("micra-each-item");
581
+ node.style.display = "contents";
582
+ node.append(frag);
583
+ }
584
+ const rowScan = scanComponent(node);
585
+ node.__micraScan = rowScan;
586
+ node._itemState = Object.create(state);
587
+ bindDataOn(rowScan.on, instance);
588
+ bindAtEvents(rowScan.atEvents, instance);
589
+ bindModels(rowScan.model, instance);
590
+ return node;
591
+ }
586
592
  function renderKeyed(tmpl, items, keyAttr, marker, keyMap, state, rawState, instance, canSkipUnchanged) {
587
593
  var _a;
588
594
  const nextKeys = /* @__PURE__ */ new Set();
@@ -602,22 +608,8 @@ function renderKeyed(tmpl, items, keyAttr, marker, keyMap, state, rawState, inst
602
608
  nextKeys.add(key);
603
609
  let node = keyMap.get(key);
604
610
  if (!node) {
605
- const frag = tmpl.content.cloneNode(true);
606
- if (frag.childNodes.length === 1) {
607
- node = frag.firstElementChild;
608
- } else {
609
- node = document.createElement("micra-each-item");
610
- node.style.display = "contents";
611
- node.append(frag);
612
- }
613
- node.__micraKey = key;
611
+ node = createRowNode(tmpl, state, instance);
614
612
  keyMap.set(key, node);
615
- const rowScan2 = scanComponent(node);
616
- node.__micraScan = rowScan2;
617
- bindDataOn(rowScan2.on, instance);
618
- bindAtEvents(rowScan2.atEvents, instance);
619
- bindModels(rowScan2.model, instance);
620
- node._itemState = Object.create(state);
621
613
  } else if (canSkipUnchanged && node.__micraItem === item && node.__micraIndex === index) {
622
614
  nextNodes.push(node);
623
615
  continue;
@@ -629,7 +621,7 @@ function renderKeyed(tmpl, items, keyAttr, marker, keyMap, state, rawState, inst
629
621
  itemState.index = index;
630
622
  itemState.$index = index;
631
623
  const rowScan = (_a = node.__micraScan) != null ? _a : node.__micraScan = scanComponent(node);
632
- applyDirectives(rowScan, itemState, rawState, instance);
624
+ applyDirectives(rowScan, itemState, rawState);
633
625
  nextNodes.push(node);
634
626
  }
635
627
  for (const [key, node] of keyMap) {
@@ -695,29 +687,50 @@ function reorderKeyed(nextNodes, prevList, marker) {
695
687
  anchor = node;
696
688
  }
697
689
  }
698
- function renderNoKey(tmpl, items, marker, state, rawState, instance) {
699
- tmpl.__micraList.forEach((n) => n.remove());
700
- tmpl.__micraList = [];
701
- const frag = document.createDocumentFragment();
702
- for (const [index, item] of items.entries()) {
703
- const clone = tmpl.content.cloneNode(true);
704
- const itemState = Object.assign(
705
- Object.create(state),
706
- { item, index, $index: index }
707
- );
708
- const fragScan = scanFragment(clone);
709
- applyDirectives(fragScan, itemState, rawState, instance);
710
- bindDataOn(fragScan.on, instance);
711
- bindAtEvents(fragScan.atEvents, instance);
712
- bindModels(fragScan.model, instance);
713
- const nodes = Array.from(clone.childNodes);
714
- nodes.forEach((n) => {
715
- n.__micraEach = true;
716
- frag.append(n);
717
- });
718
- tmpl.__micraList.push(...nodes);
719
- }
720
- marker.after(frag);
690
+ function renderNoKey(tmpl, items, marker, state, rawState, instance, canSkipUnchanged) {
691
+ const prevList = tmpl.__micraList;
692
+ const prevLen = prevList.length;
693
+ const nextLen = items.length;
694
+ const reuseLen = nextLen < prevLen ? nextLen : prevLen;
695
+ const nextList = new Array(nextLen);
696
+ for (let i = 0; i < reuseLen; i++) {
697
+ const node = prevList[i];
698
+ const item = items[i];
699
+ if (canSkipUnchanged && node.__micraItem === item && node.__micraIndex === i) {
700
+ nextList[i] = node;
701
+ continue;
702
+ }
703
+ node.__micraItem = item;
704
+ node.__micraIndex = i;
705
+ const itemState = node._itemState;
706
+ itemState.item = item;
707
+ itemState.index = i;
708
+ itemState.$index = i;
709
+ applyDirectives(node.__micraScan, itemState, rawState);
710
+ nextList[i] = node;
711
+ }
712
+ for (let i = nextLen; i < prevLen; i++) {
713
+ prevList[i].remove();
714
+ }
715
+ if (nextLen > prevLen) {
716
+ const frag = document.createDocumentFragment();
717
+ for (let i = prevLen; i < nextLen; i++) {
718
+ const node = createRowNode(tmpl, state, instance);
719
+ const item = items[i];
720
+ const itemState = node._itemState;
721
+ itemState.item = item;
722
+ itemState.index = i;
723
+ itemState.$index = i;
724
+ node.__micraItem = item;
725
+ node.__micraIndex = i;
726
+ applyDirectives(node.__micraScan, itemState, rawState);
727
+ nextList[i] = node;
728
+ frag.append(node);
729
+ }
730
+ const anchor = prevLen > 0 ? nextList[prevLen - 1] : marker;
731
+ anchor.after(frag);
732
+ }
733
+ tmpl.__micraList = nextList;
721
734
  }
722
735
 
723
736
  // src/dom/refs.ts
@@ -809,7 +822,7 @@ function mount(selector, definition) {
809
822
  try {
810
823
  const mRoot2 = root;
811
824
  const scan = (_a2 = mRoot2.__micraScan) != null ? _a2 : mRoot2.__micraScan = scanComponent(root);
812
- applyDirectives(scan, exprState, rawState, instance);
825
+ applyDirectives(scan, exprState, rawState);
813
826
  renderList(scan.each, exprState, rawState, instance, triggerKey);
814
827
  bindDataOn(scan.on, instance);
815
828
  bindAtEvents(scan.atEvents, instance);