mikuru 1.0.22 → 1.0.24
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 +17 -0
- package/README.md +11 -10
- package/dist/compiler/compatDiagnostics.d.ts +8 -0
- package/dist/compiler/compatDiagnostics.js +45 -0
- package/dist/compiler/compatDiagnostics.js.map +1 -0
- package/dist/compiler/compile.js +29 -16
- package/dist/compiler/compile.js.map +1 -1
- package/dist/compiler/compileHydration.js +31 -18
- package/dist/compiler/compileHydration.js.map +1 -1
- package/dist/compiler/compileSsr.js +27 -14
- package/dist/compiler/compileSsr.js.map +1 -1
- package/dist/compiler/generate.d.ts +17 -1
- package/dist/compiler/generate.js +160 -8
- package/dist/compiler/generate.js.map +1 -1
- package/dist/compiler/generateHydration.js +195 -38
- package/dist/compiler/generateHydration.js.map +1 -1
- package/dist/compiler/generateSsr.js +14 -4
- package/dist/compiler/generateSsr.js.map +1 -1
- package/dist/compiler/parseTemplate.js +18 -5
- package/dist/compiler/parseTemplate.js.map +1 -1
- package/dist/compiler/types.d.ts +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/router/index.js +27 -3
- package/dist/router/index.js.map +1 -1
- package/dist/runtime/asyncComponent.js +24 -4
- package/dist/runtime/asyncComponent.js.map +1 -1
- package/dist/runtime/devtools.d.ts +16 -0
- package/dist/runtime/devtools.js +21 -0
- package/dist/runtime/devtools.js.map +1 -1
- package/dist/runtime/index.d.ts +2 -2
- package/dist/runtime/index.js +1 -1
- package/dist/runtime/index.js.map +1 -1
- package/dist/server.js +16 -6
- package/dist/server.js.map +1 -1
- package/package.json +1 -1
- package/templates/basic/src/App.mikuru +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.0.24 - 2026-05-14
|
|
4
|
+
|
|
5
|
+
- Added Mikuru-native `m-*` directive syntax across DOM rendering, SSR, and hydration while keeping `v-*` as compatibility aliases.
|
|
6
|
+
- Added debug compiler warnings for `v-*` compatibility aliases, pointing users to the matching `m-*` directive spelling.
|
|
7
|
+
- Updated README, docs, examples, and templates to present `m-*` as the recommended directive syntax.
|
|
8
|
+
- Added shared Debug Inspector diagnostic payloads for compiler, runtime, router, SSR, and hydration warning/error events.
|
|
9
|
+
- Added support for `<template m-if>` / `<template m-else-if>` / `<template m-else>` fragment branches across DOM rendering, SSR, and hydration.
|
|
10
|
+
- Added support for keyed `<template m-for>` fragment rows across DOM rendering, SSR, and hydration.
|
|
11
|
+
- Expanded `<template m-for>` coverage for unkeyed fragments, nested fragment loops, and nested `m-if` / `m-else` branches.
|
|
12
|
+
- Added hydrated `m-for` reconciliation so element and `<template m-for>` lists can append, remove, replace, and recreate rows after SSR hydration.
|
|
13
|
+
|
|
14
|
+
## 1.0.23 - 2026-05-13
|
|
15
|
+
|
|
16
|
+
- Added structured hydration diagnostic payloads with warning kind, recovery action, inferred expected/actual values, and DOM path context.
|
|
17
|
+
- Added hydration warning filtering to the dogfood Debug Panel and rendered hydration diagnostics in the SSR/hydration example.
|
|
18
|
+
- Stabilized the dogfood Debug Panel clear-events flow when background component and async debug events arrive after clearing.
|
|
19
|
+
|
|
3
20
|
## 1.0.22 - 2026-05-13
|
|
4
21
|
|
|
5
22
|
- Generalized component slot hydration to pass default, named, dynamic, and scoped slots through `props.children` and `props.slots`.
|
package/README.md
CHANGED
|
@@ -132,23 +132,24 @@ declare const Greeting: MikuruComponent<GreetingProps>;
|
|
|
132
132
|
- `.mikuru` SFCs with `<template>`, `<script>`, and `<style>`
|
|
133
133
|
- Vite plugin support through `mikuru/vite`
|
|
134
134
|
- Template interpolation with `{{ value }}`
|
|
135
|
-
- DOM events with `@click`, `
|
|
135
|
+
- DOM events with `@click`, `m-on:click`, inline handlers, object-form option modifiers, `.prevent`, `.stop`, `.self`, `.once`, `.capture`, `.passive`, key, mouse button, system, and `.exact` modifiers
|
|
136
136
|
- Component events with `@select` and `.once`
|
|
137
|
-
- Attribute bindings with normalized `:class` and `:style`, boolean/form property sync, direct/object `
|
|
138
|
-
- `
|
|
139
|
-
- `
|
|
137
|
+
- Attribute bindings with normalized `:class` and `:style`, boolean/form property sync, direct/object `m-bind` modifiers like `.prop`, `.attr`, and `.camel`, plus dynamic arguments like `:[name]` and `@[event]`
|
|
138
|
+
- `m-if`, `m-else-if`, `m-else`, `m-show`, `m-for`, `m-html`, `m-text`, `m-pre`, and `m-cloak`
|
|
139
|
+
- `m-model` for common form controls, checkbox arrays, radio groups, multiple selects, modifiers, and named child component models
|
|
140
|
+
- `v-*` directive spellings remain available as compatibility aliases for existing components and Vue-oriented migrations
|
|
140
141
|
- Component props, events, DOM attribute fallthrough, `useAttrs`, template refs, `defineProps`, `defineEmits`, default slots, named/dynamic slots, and slot props with simple defaults
|
|
141
|
-
- CSS class transitions with built-in `<Transition name="fade">`, `
|
|
142
|
+
- CSS class transitions with built-in `<Transition name="fade">`, `m-if` chains, dynamic components, class overrides, `appear`, `mode="out-in"`, and `<TransitionGroup>` for keyed lists
|
|
142
143
|
- Built-in `<Teleport to="#target">` for rendering content outside the current DOM position
|
|
143
144
|
- Built-in `<AsyncBoundary :loading :fallback :delay :timeout>` for grouped async loading, delayed loading UI, boundary timeouts, and retryable async failures with aggregated fallback errors
|
|
144
145
|
- Built-in `<ErrorBoundary :fallback>` for local component mount, descendant event handler, lifecycle, and cleanup fallbacks, with `errorInfo`, `retry`, `reset`, and `:reset-key` recovery
|
|
145
146
|
- Runtime helpers including `ref`, `isRef`, `unref`, `toRef`, `toRefs`, `reactive`, `readonly`, lazy cached read-only and writable `computed`, `effect` with optional scheduling, `queueJob`/`flushJobs`, `watch`, `watchEffect` with cleanup callbacks, `nextTick`, lifecycle callbacks including KeepAlive activation hooks, `provide`, `inject`, and `defineAsyncComponent` with ErrorBoundary handoff and SSR loader resolution
|
|
146
147
|
- Routing through `mikuru/router` with route matching, history/hash/memory histories, guards, router context helpers, and `RouterView` / `RouterLink` across mount, SSR, and hydration
|
|
147
|
-
- SSR through `compileSsr()` and `mikuru/server`, covering escaped text, static and bound attributes, content directives, `
|
|
148
|
-
- Hydration through `compileHydration()` and `hydrateRoute()`, reusing existing SSR DOM while attaching events, syncing text/attributes, recovering structural mismatches with an opt-out remount fallback, hydrating component context/lifecycle hooks, `
|
|
148
|
+
- SSR through `compileSsr()` and `mikuru/server`, covering escaped text, static and bound attributes, content directives, `m-pre`, `m-cloak`, `m-if` chains, `m-for`, async child components, props, named/default slots, scoped slot props, component tree context, Teleport collection, string and async iterable stream rendering, and router route rendering with context propagation
|
|
149
|
+
- Hydration through `compileHydration()` and `hydrateRoute()`, reusing existing SSR DOM while attaching events, syncing text/attributes, recovering structural mismatches with an opt-out remount fallback, hydrating component context/lifecycle hooks, `m-show`, DOM and component `m-model`, `m-pre`, `m-cloak`, initial `m-if` / `m-for` DOM, Teleport target and disabled inline content, delegating child and route components to `hydrate()` when available, and optionally starting router history listening after route hydration
|
|
149
150
|
- Style injection and basic `<style scoped>` selector rewriting
|
|
150
151
|
- Compile errors with filenames, line/column information, code frames, and typo suggestions for built-in attributes, directives, and modifiers
|
|
151
|
-
- Debug diagnostics with optional generated `sourceURL`, unstable devtools metadata/events, and hydration warnings that include phase, component, and filename context
|
|
152
|
+
- Debug diagnostics with optional generated `sourceURL`, `v-*` compatibility warnings, unstable devtools metadata/events, and hydration warnings that include phase, component, and filename context
|
|
152
153
|
|
|
153
154
|
## Package Exports
|
|
154
155
|
|
|
@@ -199,8 +200,8 @@ npx mikuru --list-templates
|
|
|
199
200
|
<template>
|
|
200
201
|
<button @click="open = !open">Toggle</button>
|
|
201
202
|
<Transition name="fade">
|
|
202
|
-
<p
|
|
203
|
-
<p
|
|
203
|
+
<p m-if="open">Saved changes</p>
|
|
204
|
+
<p m-else>Waiting for edits</p>
|
|
204
205
|
</Transition>
|
|
205
206
|
</template>
|
|
206
207
|
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ElementNode } from "./types.js";
|
|
2
|
+
type CompatDirectiveDiagnosticOptions = {
|
|
3
|
+
debug?: boolean;
|
|
4
|
+
filename?: string;
|
|
5
|
+
phase: string;
|
|
6
|
+
};
|
|
7
|
+
export declare function emitCompatDirectiveDiagnostics(ast: ElementNode, options: CompatDirectiveDiagnosticOptions): void;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { emitDebugDiagnostic } from "../runtime/devtools.js";
|
|
2
|
+
export function emitCompatDirectiveDiagnostics(ast, options) {
|
|
3
|
+
if (options.debug !== true) {
|
|
4
|
+
return;
|
|
5
|
+
}
|
|
6
|
+
walkElement(ast, (node) => {
|
|
7
|
+
for (const attr of node.attrs) {
|
|
8
|
+
if (!isLegacyDirectiveAttr(attr)) {
|
|
9
|
+
continue;
|
|
10
|
+
}
|
|
11
|
+
const sourceName = attr.sourceName ?? attr.name;
|
|
12
|
+
const preferredName = preferredDirectiveName(sourceName);
|
|
13
|
+
emitDebugDiagnostic("compiler", "warning", `${sourceName} is supported as a compatibility alias. Prefer ${preferredName} in Mikuru components.`, {
|
|
14
|
+
phase: options.phase,
|
|
15
|
+
filename: options.filename,
|
|
16
|
+
directive: sourceName,
|
|
17
|
+
preferredDirective: preferredName,
|
|
18
|
+
tag: node.tag,
|
|
19
|
+
loc: attr.loc
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
function walkElement(node, visit) {
|
|
25
|
+
visit(node);
|
|
26
|
+
if (node.attrs.some((attr) => attr.name === "v-pre")) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
for (const child of node.children) {
|
|
30
|
+
if (isElementNode(child)) {
|
|
31
|
+
walkElement(child, visit);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function isElementNode(node) {
|
|
36
|
+
return node.type === "element";
|
|
37
|
+
}
|
|
38
|
+
function isLegacyDirectiveAttr(attr) {
|
|
39
|
+
const sourceName = attr.sourceName ?? attr.name;
|
|
40
|
+
return sourceName.startsWith("v-");
|
|
41
|
+
}
|
|
42
|
+
function preferredDirectiveName(name) {
|
|
43
|
+
return name.startsWith("v-") ? `m-${name.slice("v-".length)}` : name;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=compatDiagnostics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compatDiagnostics.js","sourceRoot":"","sources":["../../src/compiler/compatDiagnostics.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAQ7D,MAAM,UAAU,8BAA8B,CAAC,GAAgB,EAAE,OAAyC;IACxG,IAAI,OAAO,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;QAC3B,OAAO;IACT,CAAC;IAED,WAAW,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE;QACxB,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC9B,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,EAAE,CAAC;gBACjC,SAAS;YACX,CAAC;YAED,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,IAAI,CAAC;YAChD,MAAM,aAAa,GAAG,sBAAsB,CAAC,UAAU,CAAC,CAAC;YACzD,mBAAmB,CACjB,UAAU,EACV,SAAS,EACT,GAAG,UAAU,kDAAkD,aAAa,wBAAwB,EACpG;gBACE,KAAK,EAAE,OAAO,CAAC,KAAK;gBACpB,QAAQ,EAAE,OAAO,CAAC,QAAQ;gBAC1B,SAAS,EAAE,UAAU;gBACrB,kBAAkB,EAAE,aAAa;gBACjC,GAAG,EAAE,IAAI,CAAC,GAAG;gBACb,GAAG,EAAE,IAAI,CAAC,GAAG;aACd,CACF,CAAC;QACJ,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,WAAW,CAAC,IAAiB,EAAE,KAAkC;IACxE,KAAK,CAAC,IAAI,CAAC,CAAC;IAEZ,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,OAAO,CAAC,EAAE,CAAC;QACrD,OAAO;IACT,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClC,IAAI,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,WAAW,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,IAAkB;IACvC,OAAO,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC;AACjC,CAAC;AAED,SAAS,qBAAqB,CAAC,IAAuB;IACpD,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,IAAI,CAAC;IAChD,OAAO,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;AACrC,CAAC;AAED,SAAS,sBAAsB,CAAC,IAAY;IAC1C,OAAO,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACvE,CAAC"}
|
package/dist/compiler/compile.js
CHANGED
|
@@ -1,24 +1,37 @@
|
|
|
1
1
|
import { analyzeTemplate } from "./analyzeTemplate.js";
|
|
2
|
+
import { emitCompatDirectiveDiagnostics } from "./compatDiagnostics.js";
|
|
2
3
|
import { generate } from "./generate.js";
|
|
3
4
|
import { parseSfc } from "./parseSfc.js";
|
|
4
5
|
import { parseTemplate } from "./parseTemplate.js";
|
|
5
6
|
import { createSourceMap } from "./sourceMap.js";
|
|
7
|
+
import { emitDebugDiagnostic } from "../runtime/devtools.js";
|
|
6
8
|
export function compile(source, options = {}) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
code,
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
9
|
+
try {
|
|
10
|
+
const descriptor = parseSfc(source, options.filename);
|
|
11
|
+
const ast = parseTemplate(descriptor.template, {
|
|
12
|
+
filename: options.filename,
|
|
13
|
+
source,
|
|
14
|
+
offset: descriptor.templateOffset
|
|
15
|
+
});
|
|
16
|
+
emitCompatDirectiveDiagnostics(ast, { debug: options.debug === true, filename: options.filename, phase: "compile" });
|
|
17
|
+
const bindings = analyzeTemplate(ast, { source, filename: options.filename });
|
|
18
|
+
const code = generate(descriptor, ast, { debug: options.debug === true, batchedUpdates: options.batchedUpdates === true });
|
|
19
|
+
const map = createSourceMap(code, descriptor, ast);
|
|
20
|
+
return {
|
|
21
|
+
code,
|
|
22
|
+
map,
|
|
23
|
+
descriptor,
|
|
24
|
+
ast,
|
|
25
|
+
bindings
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
emitDebugDiagnostic("compiler", "error", error instanceof Error ? error.message : String(error), {
|
|
30
|
+
phase: "compile",
|
|
31
|
+
filename: options.filename,
|
|
32
|
+
error
|
|
33
|
+
});
|
|
34
|
+
throw error;
|
|
35
|
+
}
|
|
23
36
|
}
|
|
24
37
|
//# sourceMappingURL=compile.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compile.js","sourceRoot":"","sources":["../../src/compiler/compile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"compile.js","sourceRoot":"","sources":["../../src/compiler/compile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,8BAA8B,EAAE,MAAM,wBAAwB,CAAC;AACxE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAE7D,MAAM,UAAU,OAAO,CAAC,MAAc,EAAE,UAA0B,EAAE;IAClE,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;QACtD,MAAM,GAAG,GAAG,aAAa,CAAC,UAAU,CAAC,QAAQ,EAAE;YAC7C,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,MAAM;YACN,MAAM,EAAE,UAAU,CAAC,cAAc;SAClC,CAAC,CAAC;QACH,8BAA8B,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,KAAK,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;QACrH,MAAM,QAAQ,GAAG,eAAe,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC9E,MAAM,IAAI,GAAG,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,KAAK,IAAI,EAAE,cAAc,EAAE,OAAO,CAAC,cAAc,KAAK,IAAI,EAAE,CAAC,CAAC;QAC3H,MAAM,GAAG,GAAG,eAAe,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,CAAC,CAAC;QAEnD,OAAO;YACL,IAAI;YACJ,GAAG;YACH,UAAU;YACV,GAAG;YACH,QAAQ;SACT,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,mBAAmB,CAAC,UAAU,EAAE,OAAO,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;YAC/F,KAAK,EAAE,SAAS;YAChB,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,KAAK;SACN,CAAC,CAAC;QACH,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC"}
|
|
@@ -1,27 +1,40 @@
|
|
|
1
1
|
import { analyzeTemplate } from "./analyzeTemplate.js";
|
|
2
|
+
import { emitCompatDirectiveDiagnostics } from "./compatDiagnostics.js";
|
|
2
3
|
import { generate } from "./generate.js";
|
|
3
4
|
import { generateHydration } from "./generateHydration.js";
|
|
4
5
|
import { parseSfc } from "./parseSfc.js";
|
|
5
6
|
import { parseTemplate } from "./parseTemplate.js";
|
|
6
7
|
import { createSourceMap } from "./sourceMap.js";
|
|
8
|
+
import { emitDebugDiagnostic } from "../runtime/devtools.js";
|
|
7
9
|
export function compileHydration(source, options = {}) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
code,
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
10
|
+
try {
|
|
11
|
+
const descriptor = parseSfc(source, options.filename);
|
|
12
|
+
const ast = parseTemplate(descriptor.template, {
|
|
13
|
+
filename: options.filename,
|
|
14
|
+
source,
|
|
15
|
+
offset: descriptor.templateOffset
|
|
16
|
+
});
|
|
17
|
+
emitCompatDirectiveDiagnostics(ast, { debug: options.debug === true, filename: options.filename, phase: "compile-hydration" });
|
|
18
|
+
const bindings = analyzeTemplate(ast, { source, filename: options.filename });
|
|
19
|
+
const mountCode = generate(descriptor, ast, { debug: options.debug === true, batchedUpdates: options.batchedUpdates === true });
|
|
20
|
+
const hydrationCode = generateHydration(descriptor, ast, { includeImports: false });
|
|
21
|
+
const code = mountCode.replace("export default __mikuru_component;", `${hydrationCode}\nconst __mikuru_hydrationComponent = { ...__mikuru_component, hydrate };\nexport default __mikuru_hydrationComponent;`);
|
|
22
|
+
const map = createSourceMap(code, descriptor, ast);
|
|
23
|
+
return {
|
|
24
|
+
code,
|
|
25
|
+
map,
|
|
26
|
+
descriptor,
|
|
27
|
+
ast,
|
|
28
|
+
bindings
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
emitDebugDiagnostic("compiler", "error", error instanceof Error ? error.message : String(error), {
|
|
33
|
+
phase: "compile-hydration",
|
|
34
|
+
filename: options.filename,
|
|
35
|
+
error
|
|
36
|
+
});
|
|
37
|
+
throw error;
|
|
38
|
+
}
|
|
26
39
|
}
|
|
27
40
|
//# sourceMappingURL=compileHydration.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compileHydration.js","sourceRoot":"","sources":["../../src/compiler/compileHydration.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"compileHydration.js","sourceRoot":"","sources":["../../src/compiler/compileHydration.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,8BAA8B,EAAE,MAAM,wBAAwB,CAAC;AACxE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAE7D,MAAM,UAAU,gBAAgB,CAAC,MAAc,EAAE,UAA0B,EAAE;IAC3E,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;QACtD,MAAM,GAAG,GAAG,aAAa,CAAC,UAAU,CAAC,QAAQ,EAAE;YAC7C,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,MAAM;YACN,MAAM,EAAE,UAAU,CAAC,cAAc;SAClC,CAAC,CAAC;QACH,8BAA8B,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,KAAK,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC,CAAC;QAC/H,MAAM,QAAQ,GAAG,eAAe,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC9E,MAAM,SAAS,GAAG,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,KAAK,IAAI,EAAE,cAAc,EAAE,OAAO,CAAC,cAAc,KAAK,IAAI,EAAE,CAAC,CAAC;QAChI,MAAM,aAAa,GAAG,iBAAiB,CAAC,UAAU,EAAE,GAAG,EAAE,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC,CAAC;QACpF,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,oCAAoC,EAAE,GAAG,aAAa,wHAAwH,CAAC,CAAC;QAC/M,MAAM,GAAG,GAAG,eAAe,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,CAAC,CAAC;QAEnD,OAAO;YACL,IAAI;YACJ,GAAG;YACH,UAAU;YACV,GAAG;YACH,QAAQ;SACT,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,mBAAmB,CAAC,UAAU,EAAE,OAAO,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;YAC/F,KAAK,EAAE,mBAAmB;YAC1B,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,KAAK;SACN,CAAC,CAAC;QACH,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC"}
|
|
@@ -1,21 +1,34 @@
|
|
|
1
1
|
import { analyzeTemplate } from "./analyzeTemplate.js";
|
|
2
|
+
import { emitCompatDirectiveDiagnostics } from "./compatDiagnostics.js";
|
|
2
3
|
import { generateSsr } from "./generateSsr.js";
|
|
3
4
|
import { parseSfc } from "./parseSfc.js";
|
|
4
5
|
import { parseTemplate } from "./parseTemplate.js";
|
|
6
|
+
import { emitDebugDiagnostic } from "../runtime/devtools.js";
|
|
5
7
|
export function compileSsr(source, options = {}) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
code,
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
8
|
+
try {
|
|
9
|
+
const descriptor = parseSfc(source, options.filename);
|
|
10
|
+
const ast = parseTemplate(descriptor.template, {
|
|
11
|
+
filename: options.filename,
|
|
12
|
+
source,
|
|
13
|
+
offset: descriptor.templateOffset
|
|
14
|
+
});
|
|
15
|
+
emitCompatDirectiveDiagnostics(ast, { debug: options.debug === true, filename: options.filename, phase: "compile-ssr" });
|
|
16
|
+
const bindings = analyzeTemplate(ast, { source, filename: options.filename });
|
|
17
|
+
const code = generateSsr(descriptor, ast);
|
|
18
|
+
return {
|
|
19
|
+
code,
|
|
20
|
+
descriptor,
|
|
21
|
+
ast,
|
|
22
|
+
bindings
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
emitDebugDiagnostic("compiler", "error", error instanceof Error ? error.message : String(error), {
|
|
27
|
+
phase: "compile-ssr",
|
|
28
|
+
filename: options.filename,
|
|
29
|
+
error
|
|
30
|
+
});
|
|
31
|
+
throw error;
|
|
32
|
+
}
|
|
20
33
|
}
|
|
21
34
|
//# sourceMappingURL=compileSsr.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compileSsr.js","sourceRoot":"","sources":["../../src/compiler/compileSsr.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"compileSsr.js","sourceRoot":"","sources":["../../src/compiler/compileSsr.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,8BAA8B,EAAE,MAAM,wBAAwB,CAAC;AACxE,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAE7D,MAAM,UAAU,UAAU,CAAC,MAAc,EAAE,UAA0B,EAAE;IACrE,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;QACtD,MAAM,GAAG,GAAG,aAAa,CAAC,UAAU,CAAC,QAAQ,EAAE;YAC7C,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,MAAM;YACN,MAAM,EAAE,UAAU,CAAC,cAAc;SAClC,CAAC,CAAC;QACH,8BAA8B,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,KAAK,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,CAAC;QACzH,MAAM,QAAQ,GAAG,eAAe,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC9E,MAAM,IAAI,GAAG,WAAW,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;QAE1C,OAAO;YACL,IAAI;YACJ,UAAU;YACV,GAAG;YACH,QAAQ;SACT,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,mBAAmB,CAAC,UAAU,EAAE,OAAO,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;YAC/F,KAAK,EAAE,aAAa;YACpB,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,KAAK;SACN,CAAC,CAAC;QACH,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC"}
|
|
@@ -1,7 +1,23 @@
|
|
|
1
|
-
import type { ElementNode, SfcDescriptor } from "./types.js";
|
|
1
|
+
import type { ElementNode, SfcDescriptor, TemplateNode } from "./types.js";
|
|
2
|
+
export type GenerateContext = {
|
|
3
|
+
lines: string[];
|
|
4
|
+
index: number;
|
|
5
|
+
source?: string;
|
|
6
|
+
filename?: string;
|
|
7
|
+
scopeAttr?: string;
|
|
8
|
+
templateRefMode?: "single" | "array";
|
|
9
|
+
componentContextVar?: string;
|
|
10
|
+
debug?: boolean;
|
|
11
|
+
batchedUpdates?: boolean;
|
|
12
|
+
once?: boolean;
|
|
13
|
+
};
|
|
2
14
|
type GenerateOptions = {
|
|
3
15
|
debug?: boolean;
|
|
4
16
|
batchedUpdates?: boolean;
|
|
5
17
|
};
|
|
6
18
|
export declare function generate(descriptor: SfcDescriptor, root: ElementNode, options?: GenerateOptions): string;
|
|
19
|
+
export declare function generateNode(context: GenerateContext, node: TemplateNode, parentVar: string, cleanupVar: string, indent: number, beforeVar?: string): string;
|
|
20
|
+
export declare function generateChildren(context: GenerateContext, children: TemplateNode[], parentVar: string, cleanupVar: string, indent: number, beforeVar?: string): void;
|
|
21
|
+
export declare function withoutForAttrs(node: ElementNode): ElementNode;
|
|
22
|
+
export declare function createScopeAttr(descriptor: SfcDescriptor): string;
|
|
7
23
|
export {};
|
|
@@ -20,7 +20,7 @@ export function generate(descriptor, root, options = {}) {
|
|
|
20
20
|
runtimeBaseImports.push("queueJob");
|
|
21
21
|
}
|
|
22
22
|
if (context.debug) {
|
|
23
|
-
runtimeBaseImports.push("emitDebugEvent", "registerDebugComponent");
|
|
23
|
+
runtimeBaseImports.push("createDebugDiagnostic", "emitDebugEvent", "registerDebugComponent");
|
|
24
24
|
}
|
|
25
25
|
const runtimeImports = mergeRuntimeImports(runtimeBaseImports, script.runtimeImports);
|
|
26
26
|
emit(context, 0, `import { ${runtimeImports.join(", ")} } from "mikuru/runtime";`);
|
|
@@ -41,7 +41,7 @@ export function generate(descriptor, root, options = {}) {
|
|
|
41
41
|
emit(context, 1, "const __mikuru_errorInfo = (phase) => ({ ...__mikuru_componentInfo, phase });");
|
|
42
42
|
emit(context, 1, "const __mikuru_reportError = (error, errorHandler = __mikuru_context.errorHandler, phase = \"runtime\") => {");
|
|
43
43
|
if (context.debug) {
|
|
44
|
-
emit(context, 2, "emitDebugEvent(\"component:error\", { component: __mikuru_componentInfo, error, errorInfo: __mikuru_errorInfo(phase), componentId: __mikuru_debug.id });");
|
|
44
|
+
emit(context, 2, "emitDebugEvent(\"component:error\", { component: __mikuru_componentInfo, error, errorInfo: __mikuru_errorInfo(phase), componentId: __mikuru_debug.id, diagnostic: createDebugDiagnostic(\"runtime\", \"error\", error instanceof Error ? error.message : String(error), { ...__mikuru_errorInfo(phase), error }) });");
|
|
45
45
|
}
|
|
46
46
|
emit(context, 2, "if (typeof errorHandler === \"function\") { Promise.resolve().then(() => errorHandler(error, __mikuru_errorInfo(phase))); return; }");
|
|
47
47
|
emit(context, 2, "setTimeout(() => { throw error; });");
|
|
@@ -235,7 +235,7 @@ function emitDevtoolsRootUpdate(context, rootVar, indent) {
|
|
|
235
235
|
emit(context, indent, `__mikuru_debug.update({ root: ${rootVar} });`);
|
|
236
236
|
emit(context, indent, "emitDebugEvent(\"component:mount\", { component: __mikuru_componentInfo, componentId: __mikuru_debug.id, root: __mikuru_debug.metadata.root, props: __mikuru_debug.metadata.props, attrs: __mikuru_debug.metadata.attrs });");
|
|
237
237
|
}
|
|
238
|
-
function generateNode(context, node, parentVar, cleanupVar, indent, beforeVar) {
|
|
238
|
+
export function generateNode(context, node, parentVar, cleanupVar, indent, beforeVar) {
|
|
239
239
|
if (node.type === "text") {
|
|
240
240
|
return generateText(context, node, parentVar, cleanupVar, indent, beforeVar);
|
|
241
241
|
}
|
|
@@ -286,8 +286,28 @@ function generateNode(context, node, parentVar, cleanupVar, indent, beforeVar) {
|
|
|
286
286
|
if (node.tag === "slot") {
|
|
287
287
|
return generateSlot(context, node, parentVar, cleanupVar, indent, beforeVar);
|
|
288
288
|
}
|
|
289
|
+
if (node.tag === "template") {
|
|
290
|
+
return generateTemplateFragment(context, node, parentVar, cleanupVar, indent, beforeVar);
|
|
291
|
+
}
|
|
289
292
|
return generateElement(context, node, parentVar, cleanupVar, indent, beforeVar);
|
|
290
293
|
}
|
|
294
|
+
function generateTemplateFragment(context, node, parentVar, cleanupVar, indent, beforeVar) {
|
|
295
|
+
validatePlainTemplate(context, node);
|
|
296
|
+
const startVar = nextVar(context, "templateStart");
|
|
297
|
+
const endVar = nextVar(context, "templateEnd");
|
|
298
|
+
emit(context, indent, `const ${startVar} = document.createComment("template");`);
|
|
299
|
+
emit(context, indent, `const ${endVar} = document.createComment("/template");`);
|
|
300
|
+
appendNode(context, parentVar, startVar, indent, beforeVar);
|
|
301
|
+
appendNode(context, parentVar, endVar, indent, beforeVar);
|
|
302
|
+
generateChildren(context, node.children, parentVar, cleanupVar, indent, endVar);
|
|
303
|
+
return startVar;
|
|
304
|
+
}
|
|
305
|
+
function validatePlainTemplate(context, node) {
|
|
306
|
+
const slotAttr = node.attrs.find((attr) => isSlotDirectiveAttr(attr));
|
|
307
|
+
if (slotAttr) {
|
|
308
|
+
throwTemplateError("Slot templates must be direct children of a component", context, slotAttr.loc);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
291
311
|
function generateTransition(context, node, parentVar, cleanupVar, indent, beforeVar) {
|
|
292
312
|
validateTransitionAttributes(context, node);
|
|
293
313
|
const children = getTransitionChildren(context, node);
|
|
@@ -420,7 +440,7 @@ function generateErrorBoundary(context, node, parentVar, cleanupVar, indent, bef
|
|
|
420
440
|
emit(context, indent + 1, `if (!${fallbackVar} || typeof ${fallbackVar}.mount !== "function") { throw ${errorVar}; }`);
|
|
421
441
|
emit(context, indent + 1, `const ${normalizedErrorInfoVar} = ${errorInfoVar} && typeof ${errorInfoVar} === "object" ? ${errorInfoVar} : {};`);
|
|
422
442
|
if (context.debug) {
|
|
423
|
-
emit(context, indent + 1, `emitDebugEvent("component:error", { component: __mikuru_componentInfo, componentId: __mikuru_debug.id, error: ${errorVar}, errorInfo: { ...${normalizedErrorInfoVar}, boundary: __mikuru_componentInfo } });`);
|
|
443
|
+
emit(context, indent + 1, `emitDebugEvent("component:error", { component: __mikuru_componentInfo, componentId: __mikuru_debug.id, error: ${errorVar}, errorInfo: { ...${normalizedErrorInfoVar}, boundary: __mikuru_componentInfo }, diagnostic: createDebugDiagnostic("runtime", "error", ${errorVar} instanceof Error ? ${errorVar}.message : String(${errorVar}), { ...${normalizedErrorInfoVar}, boundary: __mikuru_componentInfo, error: ${errorVar} }) });`);
|
|
424
444
|
}
|
|
425
445
|
emit(context, indent + 1, `const ${fallbackFragmentVar} = document.createDocumentFragment();`);
|
|
426
446
|
emit(context, indent + 1, `const ${fallbackInstanceVar} = ${fallbackVar}.mount(${fallbackFragmentVar}, { error: ${errorVar}, errorInfo: { ...${normalizedErrorInfoVar}, boundary: __mikuru_componentInfo }, retry: ${renderVar}, reset: ${renderVar}, __mikuru_context });`);
|
|
@@ -546,7 +566,7 @@ function generateAsyncBoundary(context, node, parentVar, cleanupVar, indent, bef
|
|
|
546
566
|
emit(context, indent + 1, `if (!${fallbackVar} || typeof ${fallbackVar}.mount !== "function") { throw ${errorVar}; }`);
|
|
547
567
|
emit(context, indent + 1, `const ${normalizedErrorInfoVar} = ${errorInfoVar} && typeof ${errorInfoVar} === "object" ? ${errorInfoVar} : {};`);
|
|
548
568
|
if (context.debug) {
|
|
549
|
-
emit(context, indent + 1, `emitDebugEvent("async:rejected", { component: __mikuru_componentInfo, componentId: __mikuru_debug.id, error: ${errorVar}, errors: [...${errorsVar}], pending: ${pendingVar}, errorInfo: { ...${normalizedErrorInfoVar}, boundary: __mikuru_componentInfo } });`);
|
|
569
|
+
emit(context, indent + 1, `emitDebugEvent("async:rejected", { component: __mikuru_componentInfo, componentId: __mikuru_debug.id, error: ${errorVar}, errors: [...${errorsVar}], pending: ${pendingVar}, errorInfo: { ...${normalizedErrorInfoVar}, boundary: __mikuru_componentInfo }, diagnostic: createDebugDiagnostic("runtime", "error", ${errorVar} instanceof Error ? ${errorVar}.message : String(${errorVar}), { ...${normalizedErrorInfoVar}, boundary: __mikuru_componentInfo, error: ${errorVar} }) });`);
|
|
550
570
|
}
|
|
551
571
|
emit(context, indent + 1, `const ${fallbackFragmentVar} = document.createDocumentFragment();`);
|
|
552
572
|
emit(context, indent + 1, `const ${fallbackInstanceVar} = ${fallbackVar}.mount(${fallbackFragmentVar}, { error: ${errorVar}, errors: [...${errorsVar}], errorInfo: { ...${normalizedErrorInfoVar}, boundary: __mikuru_componentInfo }, pending: ${pendingVar}, retry: ${lastRetryVar}, reset: ${lastRetryVar}, __mikuru_context });`);
|
|
@@ -1545,7 +1565,7 @@ function emitObjectListeners(context, elementVar, attr, cleanupVar, indent) {
|
|
|
1545
1565
|
emit(context, indent + 1, `${listenersVar}.clear();`);
|
|
1546
1566
|
emit(context, indent, "});");
|
|
1547
1567
|
}
|
|
1548
|
-
function generateChildren(context, children, parentVar, cleanupVar, indent, beforeVar) {
|
|
1568
|
+
export function generateChildren(context, children, parentVar, cleanupVar, indent, beforeVar) {
|
|
1549
1569
|
let index = 0;
|
|
1550
1570
|
while (index < children.length) {
|
|
1551
1571
|
const child = children[index];
|
|
@@ -1656,6 +1676,9 @@ function generateFor(context, node, parentVar, cleanupVar, indent, expression, b
|
|
|
1656
1676
|
const { item: itemName, index: indexName, source: sourceExpression } = parseForExpression(expression, toExpressionContext(context, getStringAttrLocation(node, "v-for")));
|
|
1657
1677
|
const keyExpression = getKeyExpression(node);
|
|
1658
1678
|
if (keyExpression) {
|
|
1679
|
+
if (node.tag === "template") {
|
|
1680
|
+
return generateKeyedTemplateFor(context, node, parentVar, cleanupVar, indent, itemName, indexName, sourceExpression, keyExpression, beforeVar);
|
|
1681
|
+
}
|
|
1659
1682
|
return generateKeyedFor(context, node, parentVar, cleanupVar, indent, itemName, indexName, sourceExpression, keyExpression, beforeVar);
|
|
1660
1683
|
}
|
|
1661
1684
|
const startVar = nextVar(context, "forStart");
|
|
@@ -1696,6 +1719,110 @@ function generateFor(context, node, parentVar, cleanupVar, indent, expression, b
|
|
|
1696
1719
|
emit(context, indent, "});");
|
|
1697
1720
|
return startVar;
|
|
1698
1721
|
}
|
|
1722
|
+
function generateKeyedTemplateFor(context, node, parentVar, cleanupVar, indent, itemName, indexName, sourceExpression, keyExpression, beforeVar) {
|
|
1723
|
+
validatePlainTemplate(context, node);
|
|
1724
|
+
const startVar = nextVar(context, "forStart");
|
|
1725
|
+
const endVar = nextVar(context, "forEnd");
|
|
1726
|
+
const recordsVar = nextVar(context, "forRecords");
|
|
1727
|
+
const stopVar = nextVar(context, "stop");
|
|
1728
|
+
const compiledSource = compileTemplateExpression(sourceExpression, "v-for source", toExpressionContext(context, getStringAttrLocation(node, "v-for")));
|
|
1729
|
+
const compiledKey = compileTemplateExpression(keyExpression, "v-for key", toExpressionContext(context, getKeyAttrLocation(node)));
|
|
1730
|
+
const compiledMemo = getMemoExpression(context, node) ?? getOnceMemoExpression(context, node);
|
|
1731
|
+
emit(context, indent, `const ${recordsVar} = new Map();`);
|
|
1732
|
+
emit(context, indent, `const ${startVar} = document.createComment("for");`);
|
|
1733
|
+
emit(context, indent, `const ${endVar} = document.createComment("/for");`);
|
|
1734
|
+
appendNode(context, parentVar, startVar, indent, beforeVar);
|
|
1735
|
+
appendNode(context, parentVar, endVar, indent, beforeVar);
|
|
1736
|
+
emit(context, indent, `const ${stopVar} = effect(() => {`);
|
|
1737
|
+
const sourceVar = nextVar(context, "forSource");
|
|
1738
|
+
const nextRecordsVar = nextVar(context, "nextRecords");
|
|
1739
|
+
const indexVar = nextVar(context, "forIndex");
|
|
1740
|
+
const rawItemVar = nextVar(context, "forItem");
|
|
1741
|
+
const rawIndexVar = nextVar(context, "forIndexValue");
|
|
1742
|
+
const keyVar = nextVar(context, "forKey");
|
|
1743
|
+
const recordVar = nextVar(context, "forRecord");
|
|
1744
|
+
const recordCleanupVar = nextVar(context, "forRecordCleanup");
|
|
1745
|
+
const itemRefVar = nextVar(context, "forItemRef");
|
|
1746
|
+
const indexRefVar = nextVar(context, "forIndexRef");
|
|
1747
|
+
const recordStartVar = nextVar(context, "forRecordStart");
|
|
1748
|
+
const recordEndVar = nextVar(context, "forRecordEnd");
|
|
1749
|
+
const memoVar = compiledMemo ? nextVar(context, "forMemo") : undefined;
|
|
1750
|
+
const memoChangedVar = compiledMemo ? nextVar(context, "forMemoChanged") : undefined;
|
|
1751
|
+
emit(context, indent + 1, `const ${sourceVar} = unwrap(${compiledSource}) ?? [];`);
|
|
1752
|
+
emit(context, indent + 1, `const ${nextRecordsVar} = new Map();`);
|
|
1753
|
+
emit(context, indent + 1, `for (let ${indexVar} = 0; ${indexVar} < ${sourceVar}.length; ${indexVar} += 1) {`);
|
|
1754
|
+
emit(context, indent + 2, `const ${rawItemVar} = ${sourceVar}[${indexVar}];`);
|
|
1755
|
+
emit(context, indent + 2, `const ${rawIndexVar} = ${indexVar};`);
|
|
1756
|
+
emit(context, indent + 2, `const ${itemName} = ${rawItemVar};`);
|
|
1757
|
+
if (indexName) {
|
|
1758
|
+
emit(context, indent + 2, `const ${indexName} = ${rawIndexVar};`);
|
|
1759
|
+
}
|
|
1760
|
+
emit(context, indent + 2, `const ${keyVar} = unwrap(${compiledKey});`);
|
|
1761
|
+
if (compiledMemo && memoVar) {
|
|
1762
|
+
emit(context, indent + 2, `const ${memoVar} = ${compiledMemo};`);
|
|
1763
|
+
}
|
|
1764
|
+
emit(context, indent + 2, `let ${recordVar} = ${recordsVar}.get(${keyVar});`);
|
|
1765
|
+
emit(context, indent + 2, `if (!${recordVar}) {`);
|
|
1766
|
+
emit(context, indent + 3, `const ${recordCleanupVar} = [];`);
|
|
1767
|
+
emit(context, indent + 3, `const ${itemRefVar} = ref(${rawItemVar});`);
|
|
1768
|
+
if (indexName) {
|
|
1769
|
+
emit(context, indent + 3, `const ${indexRefVar} = ref(${rawIndexVar});`);
|
|
1770
|
+
}
|
|
1771
|
+
emit(context, indent + 3, `const ${recordStartVar} = document.createComment("for item");`);
|
|
1772
|
+
emit(context, indent + 3, `const ${recordEndVar} = document.createComment("/for item");`);
|
|
1773
|
+
emit(context, indent + 3, `${parentVar}.insertBefore(${recordStartVar}, ${endVar});`);
|
|
1774
|
+
emit(context, indent + 3, `${parentVar}.insertBefore(${recordEndVar}, ${endVar});`);
|
|
1775
|
+
emit(context, indent + 3, `{`);
|
|
1776
|
+
emit(context, indent + 4, `const ${itemName} = ${itemRefVar};`);
|
|
1777
|
+
if (indexName) {
|
|
1778
|
+
emit(context, indent + 4, `const ${indexName} = ${indexRefVar};`);
|
|
1779
|
+
}
|
|
1780
|
+
withTemplateRefMode(context, "array", () => {
|
|
1781
|
+
generateChildren(context, node.children, parentVar, recordCleanupVar, indent + 4, recordEndVar);
|
|
1782
|
+
});
|
|
1783
|
+
emit(context, indent + 4, `${recordVar} = { start: ${recordStartVar}, end: ${recordEndVar}, cleanups: ${recordCleanupVar}, item: ${itemRefVar}${indexName ? `, index: ${indexRefVar}` : ""}${compiledMemo && memoVar ? `, memo: ${memoVar}` : ""} };`);
|
|
1784
|
+
emit(context, indent + 3, `}`);
|
|
1785
|
+
emit(context, indent + 2, `} else {`);
|
|
1786
|
+
if (compiledMemo && memoVar && memoChangedVar) {
|
|
1787
|
+
emit(context, indent + 3, `const ${memoChangedVar} = !__mikuru_memoEqual(${recordVar}.memo, ${memoVar});`);
|
|
1788
|
+
emit(context, indent + 3, `if (${memoChangedVar}) {`);
|
|
1789
|
+
emit(context, indent + 4, `${recordVar}.memo = ${memoVar};`);
|
|
1790
|
+
emit(context, indent + 4, `${recordVar}.item.value = ${rawItemVar};`);
|
|
1791
|
+
if (indexName) {
|
|
1792
|
+
emit(context, indent + 4, `${recordVar}.index.value = ${rawIndexVar};`);
|
|
1793
|
+
}
|
|
1794
|
+
emit(context, indent + 3, "}");
|
|
1795
|
+
}
|
|
1796
|
+
else {
|
|
1797
|
+
emit(context, indent + 3, `${recordVar}.item.value = ${rawItemVar};`);
|
|
1798
|
+
if (indexName) {
|
|
1799
|
+
emit(context, indent + 3, `${recordVar}.index.value = ${rawIndexVar};`);
|
|
1800
|
+
}
|
|
1801
|
+
}
|
|
1802
|
+
emitMoveRangeBefore(context, indent + 3, `${recordVar}.start`, `${recordVar}.end`, parentVar, endVar);
|
|
1803
|
+
emit(context, indent + 2, `}`);
|
|
1804
|
+
emit(context, indent + 2, `${nextRecordsVar}.set(${keyVar}, ${recordVar});`);
|
|
1805
|
+
emit(context, indent + 1, `}`);
|
|
1806
|
+
emit(context, indent + 1, `for (const [${keyVar}, ${recordVar}] of ${recordsVar}) {`);
|
|
1807
|
+
emit(context, indent + 2, `if (!${nextRecordsVar}.has(${keyVar})) {`);
|
|
1808
|
+
emit(context, indent + 3, `__mikuru_runCleanup(${recordVar}.cleanups);`);
|
|
1809
|
+
emitRemoveRange(context, indent + 3, `${recordVar}.start`, `${recordVar}.end`);
|
|
1810
|
+
emit(context, indent + 2, `}`);
|
|
1811
|
+
emit(context, indent + 1, `}`);
|
|
1812
|
+
emit(context, indent + 1, `${recordsVar}.clear();`);
|
|
1813
|
+
emit(context, indent + 1, `for (const [${keyVar}, ${recordVar}] of ${nextRecordsVar}) {`);
|
|
1814
|
+
emit(context, indent + 2, `${recordsVar}.set(${keyVar}, ${recordVar});`);
|
|
1815
|
+
emit(context, indent + 1, `}`);
|
|
1816
|
+
emit(context, indent, "});");
|
|
1817
|
+
emit(context, indent, `${cleanupVar}.push(() => {`);
|
|
1818
|
+
emit(context, indent + 1, `${stopVar}();`);
|
|
1819
|
+
emit(context, indent + 1, `for (const ${recordVar} of ${recordsVar}.values()) {`);
|
|
1820
|
+
emit(context, indent + 2, `__mikuru_runCleanup(${recordVar}.cleanups);`);
|
|
1821
|
+
emit(context, indent + 1, `}`);
|
|
1822
|
+
emit(context, indent + 1, `${recordsVar}.clear();`);
|
|
1823
|
+
emit(context, indent, "});");
|
|
1824
|
+
return startVar;
|
|
1825
|
+
}
|
|
1699
1826
|
function generateKeyedFor(context, node, parentVar, cleanupVar, indent, itemName, indexName, sourceExpression, keyExpression, beforeVar, transitionVar) {
|
|
1700
1827
|
const startVar = nextVar(context, "forStart");
|
|
1701
1828
|
const endVar = nextVar(context, "forEnd");
|
|
@@ -1807,6 +1934,31 @@ function emitRemoveBetween(context, indent, startVar, endVar) {
|
|
|
1807
1934
|
emit(context, indent + 1, `${currentVar} = ${nextVarName};`);
|
|
1808
1935
|
emit(context, indent, "}");
|
|
1809
1936
|
}
|
|
1937
|
+
function emitRemoveRange(context, indent, startExpression, endExpression) {
|
|
1938
|
+
const currentVar = nextVar(context, "current");
|
|
1939
|
+
const nextVarName = nextVar(context, "next");
|
|
1940
|
+
emit(context, indent, `let ${currentVar} = ${startExpression};`);
|
|
1941
|
+
emit(context, indent, `while (${currentVar}) {`);
|
|
1942
|
+
emit(context, indent + 1, `const ${nextVarName} = ${currentVar}.nextSibling;`);
|
|
1943
|
+
emit(context, indent + 1, `__mikuru_removeNode(${currentVar});`);
|
|
1944
|
+
emit(context, indent + 1, `if (${currentVar} === ${endExpression}) { break; }`);
|
|
1945
|
+
emit(context, indent + 1, `${currentVar} = ${nextVarName};`);
|
|
1946
|
+
emit(context, indent, "}");
|
|
1947
|
+
}
|
|
1948
|
+
function emitMoveRangeBefore(context, indent, startExpression, endExpression, parentVar, beforeExpression) {
|
|
1949
|
+
const fragmentVar = nextVar(context, "fragment");
|
|
1950
|
+
const currentVar = nextVar(context, "current");
|
|
1951
|
+
const nextVarName = nextVar(context, "next");
|
|
1952
|
+
emit(context, indent, `const ${fragmentVar} = document.createDocumentFragment();`);
|
|
1953
|
+
emit(context, indent, `let ${currentVar} = ${startExpression};`);
|
|
1954
|
+
emit(context, indent, `while (${currentVar}) {`);
|
|
1955
|
+
emit(context, indent + 1, `const ${nextVarName} = ${currentVar}.nextSibling;`);
|
|
1956
|
+
emit(context, indent + 1, `${fragmentVar}.appendChild(${currentVar});`);
|
|
1957
|
+
emit(context, indent + 1, `if (${currentVar} === ${endExpression}) { break; }`);
|
|
1958
|
+
emit(context, indent + 1, `${currentVar} = ${nextVarName};`);
|
|
1959
|
+
emit(context, indent, "}");
|
|
1960
|
+
emit(context, indent, `${parentVar}.insertBefore(${fragmentVar}, ${beforeExpression});`);
|
|
1961
|
+
}
|
|
1810
1962
|
function emitTransitionRegistration(context, nodeVar, transitionVar, indent) {
|
|
1811
1963
|
emit(context, indent, `if (${nodeVar}?.nodeType === 1) {`);
|
|
1812
1964
|
emit(context, indent + 1, `${nodeVar}.__mikuru_transition = ${transitionVar};`);
|
|
@@ -2558,7 +2710,7 @@ function toExpressionContext(context, location) {
|
|
|
2558
2710
|
function withoutAttr(node, name) {
|
|
2559
2711
|
return withoutAttrs(node, [name]);
|
|
2560
2712
|
}
|
|
2561
|
-
function withoutForAttrs(node) {
|
|
2713
|
+
export function withoutForAttrs(node) {
|
|
2562
2714
|
return withoutAttrs(node, ["v-for", "key", ":key", "v-bind:key", "v-memo", "v-once"]);
|
|
2563
2715
|
}
|
|
2564
2716
|
function withoutAttrs(node, names) {
|
|
@@ -3728,7 +3880,7 @@ function quote(value) {
|
|
|
3728
3880
|
function quotePropertyName(value) {
|
|
3729
3881
|
return /^[A-Za-z_$][\w$]*$/.test(value) ? value : quote(value);
|
|
3730
3882
|
}
|
|
3731
|
-
function createScopeAttr(descriptor) {
|
|
3883
|
+
export function createScopeAttr(descriptor) {
|
|
3732
3884
|
return `data-mikuru-scope-${hash(`${descriptor.filename ?? ""}\n${descriptor.style ?? ""}`)}`;
|
|
3733
3885
|
}
|
|
3734
3886
|
function scopeCssSelectors(css, scopeAttr) {
|