@fluixi/compiler 1.0.0-alpha.100 → 1.0.0-alpha.101
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/README.md +13 -13
- package/dist/analyze/props-destructure.d.cts +1 -1
- package/dist/analyze/props-destructure.d.ts +1 -1
- package/dist/analyze/props-destructure.js +1 -1
- package/dist/analyze/reactive-bindings.d.cts +1 -1
- package/dist/analyze/reactive-bindings.d.ts +1 -1
- package/dist/analyze/reactive-bindings.js +3 -3
- package/dist/analyze/static-graph.cjs +1 -1
- package/dist/analyze/static-graph.js +2 -2
- package/dist/analyze/static-graph.mjs +1 -1
- package/dist/{babel-I6BUWUCU.mjs → babel-4WLP2IRR.mjs} +23 -23
- package/dist/{chunk-SKAVY75W.mjs → chunk-46MIOLUB.mjs} +1 -1
- package/dist/{chunk-C3XPDB4Y.mjs → chunk-AIK66L2P.mjs} +1 -1
- package/dist/{chunk-3AICWNF7.mjs → chunk-B6GUZXJP.mjs} +1 -1
- package/dist/{chunk-HXEXPWJ2.mjs → chunk-BVY2ISKX.mjs} +2 -2
- package/dist/{chunk-6CWJWGE2.mjs → chunk-G2PQDYFN.mjs} +10 -10
- package/dist/{chunk-GX5XV6Z7.mjs → chunk-K4Q6GHV6.mjs} +1 -1
- package/dist/{chunk-NU3W67UZ.mjs → chunk-S3LT32LA.mjs} +2 -2
- package/dist/codegen/backends/imperative.js +2 -2
- package/dist/frontend/babel/{build-ir-lit.cjs → build-ir-html.cjs} +19 -19
- package/dist/frontend/babel/{build-ir-lit.d.cts → build-ir-html.d.cts} +5 -5
- package/dist/frontend/babel/{build-ir-lit.d.ts → build-ir-html.d.ts} +6 -6
- package/dist/frontend/babel/build-ir-html.d.ts.map +1 -0
- package/dist/frontend/babel/{build-ir-lit.js → build-ir-html.js} +4 -4
- package/dist/frontend/babel/{build-ir-lit.mjs → build-ir-html.mjs} +15 -15
- package/dist/frontend/babel/build-ir.cjs +14 -14
- package/dist/frontend/babel/build-ir.d.cts +1 -1
- package/dist/frontend/babel/build-ir.d.ts +1 -1
- package/dist/frontend/babel/build-ir.js +5 -5
- package/dist/frontend/babel/build-ir.mjs +14 -14
- package/dist/frontend/babel/index.cjs +28 -28
- package/dist/frontend/babel/index.d.cts +0 -11
- package/dist/frontend/babel/index.d.ts +0 -11
- package/dist/frontend/babel/index.d.ts.map +1 -1
- package/dist/frontend/babel/index.js +2 -14
- package/dist/frontend/babel/index.mjs +28 -28
- package/dist/frontend/babel/lower-template.cjs +15 -15
- package/dist/frontend/babel/lower-template.d.cts +3 -3
- package/dist/frontend/babel/lower-template.d.ts +3 -3
- package/dist/frontend/babel/lower-template.d.ts.map +1 -1
- package/dist/frontend/babel/lower-template.js +4 -4
- package/dist/frontend/babel/lower-template.mjs +15 -15
- package/dist/frontend/babel/plugin.cjs +25 -25
- package/dist/frontend/babel/plugin.d.cts +6 -22
- package/dist/frontend/babel/plugin.d.ts +6 -22
- package/dist/frontend/babel/plugin.d.ts.map +1 -1
- package/dist/frontend/babel/plugin.js +19 -42
- package/dist/frontend/babel/plugin.mjs +25 -25
- package/dist/frontend/babel/server-functions.js +2 -2
- package/dist/index.cjs +9 -9
- package/dist/index.mjs +9 -9
- package/dist/integrations.cjs +42 -42
- package/dist/integrations.d.cts +7 -22
- package/dist/integrations.d.ts +7 -22
- package/dist/integrations.d.ts.map +1 -1
- package/dist/integrations.js +3 -34
- package/dist/integrations.mjs +13 -13
- package/dist/ir/nodes.d.cts +1 -1
- package/dist/ir/nodes.d.ts +1 -1
- package/dist/lower/compile-template.cjs +9 -9
- package/dist/lower/compile-template.d.cts +2 -2
- package/dist/lower/compile-template.d.ts +2 -2
- package/dist/lower/compile-template.d.ts.map +1 -1
- package/dist/lower/compile-template.js +1 -1
- package/dist/lower/compile-template.mjs +9 -9
- package/dist/lower/jsx.js +2 -2
- package/dist/lower/template.cjs +8 -8
- package/dist/lower/template.d.cts +6 -6
- package/dist/lower/template.d.ts +6 -6
- package/dist/lower/template.d.ts.map +1 -1
- package/dist/lower/template.js +14 -14
- package/dist/lower/template.mjs +8 -8
- package/dist/resolve/builtins.cjs +1 -1
- package/dist/resolve/builtins.d.cts +2 -2
- package/dist/resolve/builtins.d.ts +2 -2
- package/dist/resolve/builtins.js +1 -1
- package/dist/resolve/builtins.mjs +1 -1
- package/dist/resolve/component-globals.d.cts +2 -2
- package/dist/resolve/component-globals.d.ts +2 -2
- package/dist/resolve/component-globals.js +1 -1
- package/dist/resolve/load-directive.d.cts +1 -1
- package/dist/resolve/load-directive.d.ts +1 -1
- package/dist/resolve/load-directive.js +1 -1
- package/dist/resolve/resolve-ir.d.cts +1 -1
- package/dist/resolve/resolve-ir.d.ts +1 -1
- package/dist/{server-fns-VZLHMQTC.mjs → server-fns-THMTJXV7.mjs} +5 -5
- package/dist/{server-functions-UAZKOLZW.mjs → server-functions-MP4I3DAX.mjs} +3 -3
- package/dist/transform/bindings.d.cts +1 -1
- package/dist/transform/bindings.d.ts +1 -1
- package/dist/transform/bindings.js +1 -1
- package/dist/transform/index.cjs +17 -17
- package/dist/transform/index.mjs +17 -17
- package/dist/transform/intrinsics.d.cts +1 -1
- package/dist/transform/intrinsics.d.ts +1 -1
- package/dist/transform/intrinsics.js +1 -1
- package/dist/transform/source-locations.d.cts +1 -1
- package/dist/transform/source-locations.d.ts +1 -1
- package/dist/transform/source-locations.d.ts.map +1 -1
- package/dist/transform/source-locations.js +6 -6
- package/dist/transform/styles.d.cts +2 -2
- package/dist/transform/styles.d.ts +2 -2
- package/dist/transform/styles.d.ts.map +1 -1
- package/dist/transform/styles.js +5 -5
- package/dist/transform/templates.cjs +16 -16
- package/dist/transform/templates.d.cts +2 -2
- package/dist/transform/templates.d.ts +2 -2
- package/dist/transform/templates.d.ts.map +1 -1
- package/dist/transform/templates.js +10 -10
- package/dist/transform/templates.mjs +16 -16
- package/dist/{transform-3W45L3EA.mjs → transform-27QH3X24.mjs} +15 -15
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/dist/vite-styles.js +2 -2
- package/package.json +4 -4
- package/dist/frontend/babel/build-ir-lit.d.ts.map +0 -1
|
@@ -1150,7 +1150,7 @@ var Lowerer = class {
|
|
|
1150
1150
|
for (const s of imports) this.used.add(s);
|
|
1151
1151
|
return inlineTemplates(code, templates);
|
|
1152
1152
|
}
|
|
1153
|
-
//
|
|
1153
|
+
// content
|
|
1154
1154
|
lowerRoot(children) {
|
|
1155
1155
|
const nodes = this.lowerChildren(children);
|
|
1156
1156
|
if (nodes.length === 1) return nodes[0];
|
|
@@ -1279,8 +1279,8 @@ var Lowerer = class {
|
|
|
1279
1279
|
}
|
|
1280
1280
|
return { slots, rest };
|
|
1281
1281
|
}
|
|
1282
|
-
//
|
|
1283
|
-
/** `<el if=${cond}
|
|
1282
|
+
// control-flow sugar
|
|
1283
|
+
/** `<el if=${cond}>...</el>` (+ optional `<el else>`) → `<Show when fallback>`. */
|
|
1284
1284
|
lowerIf(el, condHole, elseEl) {
|
|
1285
1285
|
const cond = this.hole(condHole);
|
|
1286
1286
|
const props = [
|
|
@@ -1295,8 +1295,8 @@ var Lowerer = class {
|
|
|
1295
1295
|
return { kind: "component", name: "Show", props, children: [child], ...at ? { at } : {}, ...cond.at ? { bindAt: cond.at } : {} };
|
|
1296
1296
|
}
|
|
1297
1297
|
/**
|
|
1298
|
-
* `<el each=${items} key?>${item =>
|
|
1299
|
-
* content is repeated per item. Content that is not a `${item =>
|
|
1298
|
+
* `<el each=${items} key?>${item => ...}</el>` → `<el><For each>{item => ...}</For></el>`: the
|
|
1299
|
+
* content is repeated per item. Content that is not a `${item => ...}` arrow is repeated as
|
|
1300
1300
|
* it is. Null when the element has no `each`.
|
|
1301
1301
|
*/
|
|
1302
1302
|
lowerEach(el) {
|
|
@@ -1333,7 +1333,7 @@ var Lowerer = class {
|
|
|
1333
1333
|
const clone = { ...el, attributes: el.attributes.filter((a) => !drop(a)) };
|
|
1334
1334
|
return clone.kind === "Element" ? this.lowerElement(clone) : this.lowerComponent(clone);
|
|
1335
1335
|
}
|
|
1336
|
-
//
|
|
1336
|
+
// attributes
|
|
1337
1337
|
/**
|
|
1338
1338
|
* `element`: a DOM element, where each class:/style: value that moves is its own accessor.
|
|
1339
1339
|
* A component gets the object as before, rebuilt whole when any value moves.
|
|
@@ -1474,7 +1474,7 @@ var Lowerer = class {
|
|
|
1474
1474
|
if (mods.includes("passive")) opts.push("passive: true");
|
|
1475
1475
|
return opts.length ? `{ ${opts.join(", ")} }` : null;
|
|
1476
1476
|
}
|
|
1477
|
-
/** `bind:value=${sig}` → `value={read()}` + `onInput={e => write(e
|
|
1477
|
+
/** `bind:value=${sig}` → `value={read()}` + `onInput={e => write(e...value)}`. */
|
|
1478
1478
|
bindProps(prop, h) {
|
|
1479
1479
|
const sigCode = h.code;
|
|
1480
1480
|
const checked = prop === "checked";
|
|
@@ -1500,7 +1500,7 @@ var Lowerer = class {
|
|
|
1500
1500
|
}
|
|
1501
1501
|
];
|
|
1502
1502
|
}
|
|
1503
|
-
/** A plain attribute (incl.
|
|
1503
|
+
/** A plain attribute (incl. html `?bool`, mixed values), old `mkProp` behavior. */
|
|
1504
1504
|
plainAttr(a) {
|
|
1505
1505
|
const v = a.value;
|
|
1506
1506
|
let name = a.name;
|
|
@@ -1567,7 +1567,7 @@ function bindHole(expr, used, onNested) {
|
|
|
1567
1567
|
if (import_core.types.isObjectExpression(expr)) hole.object = true;
|
|
1568
1568
|
return hole;
|
|
1569
1569
|
}
|
|
1570
|
-
function
|
|
1570
|
+
function lowerHtmlTemplate(node, used, opts = {}) {
|
|
1571
1571
|
const quasi = node.quasi;
|
|
1572
1572
|
const holes = quasi.expressions.map((e) => bindHole(e, used, opts.onNested));
|
|
1573
1573
|
return lowerTemplate(buildPieces(quasi), holes, used, opts);
|
|
@@ -1660,9 +1660,9 @@ function childReason(node) {
|
|
|
1660
1660
|
return "expression-child";
|
|
1661
1661
|
}
|
|
1662
1662
|
|
|
1663
|
-
// src/frontend/babel/build-ir-
|
|
1664
|
-
function
|
|
1665
|
-
const ir =
|
|
1663
|
+
// src/frontend/babel/build-ir-html.ts
|
|
1664
|
+
function buildIRFromHtml(node, used = /* @__PURE__ */ new Set(), opts = {}) {
|
|
1665
|
+
const ir = lowerHtmlTemplate(node, used, opts);
|
|
1666
1666
|
analyzeStatic(ir);
|
|
1667
1667
|
return ir;
|
|
1668
1668
|
}
|
|
@@ -2071,12 +2071,12 @@ function transformNestedJSX(node, used, onNested) {
|
|
|
2071
2071
|
const { code, imports, templates } = imperativeBackend.emit(nestedIR, {});
|
|
2072
2072
|
emitInto(path, inlineTemplates(code, templates), imports);
|
|
2073
2073
|
},
|
|
2074
|
-
// Nested
|
|
2074
|
+
// Nested html templates compose: ${cond ? html`...` : html`...`},
|
|
2075
2075
|
// ${list.map(x => html`<li>${x}</li>`)}. Compile them the same way.
|
|
2076
2076
|
TaggedTemplateExpression(path) {
|
|
2077
2077
|
const tag = path.node.tag;
|
|
2078
2078
|
if (!import_core2.types.isIdentifier(tag) || tag.name !== "html" && tag.name !== "svg") return;
|
|
2079
|
-
const ir =
|
|
2079
|
+
const ir = buildIRFromHtml(path.node, used, { svg: tag.name === "svg", onNested });
|
|
2080
2080
|
onNested?.(ir);
|
|
2081
2081
|
const { code, imports, templates } = imperativeBackend.emit(ir, {});
|
|
2082
2082
|
emitInto(path, inlineTemplates(code, templates), imports);
|
|
@@ -2119,11 +2119,11 @@ var plugin_default = (0, import_helper_plugin_utils.declare)((api, options = {})
|
|
|
2119
2119
|
// `fluixi()` needs no `format` option. Injected imports are deduped, so a
|
|
2120
2120
|
// file mixing the two styles won't redeclare a binding.
|
|
2121
2121
|
format = "both",
|
|
2122
|
-
|
|
2122
|
+
htmlTag = "html",
|
|
2123
2123
|
resolve: resolveRules = []
|
|
2124
2124
|
} = options;
|
|
2125
2125
|
const componentResolver = createComponentResolver(resolveRules);
|
|
2126
|
-
const
|
|
2126
|
+
const compileHtml = format === "html" || format === "both";
|
|
2127
2127
|
const pluginState = {
|
|
2128
2128
|
irImports: /* @__PURE__ */ new Set(),
|
|
2129
2129
|
libModule: "@fluixi/core",
|
|
@@ -2132,7 +2132,7 @@ var plugin_default = (0, import_helper_plugin_utils.declare)((api, options = {})
|
|
|
2132
2132
|
templateClone,
|
|
2133
2133
|
partialTemplates,
|
|
2134
2134
|
hasJSX: false,
|
|
2135
|
-
|
|
2135
|
+
hasHtmlTag: false,
|
|
2136
2136
|
needsControlFlowImport: false,
|
|
2137
2137
|
needsCreateMemo: false,
|
|
2138
2138
|
controlFlowComponents: /* @__PURE__ */ new Set(),
|
|
@@ -2156,8 +2156,8 @@ var plugin_default = (0, import_helper_plugin_utils.declare)((api, options = {})
|
|
|
2156
2156
|
enter(path, state) {
|
|
2157
2157
|
Object.assign(state, {
|
|
2158
2158
|
hasJSX: false,
|
|
2159
|
-
|
|
2160
|
-
|
|
2159
|
+
hasHtmlTag: false,
|
|
2160
|
+
hasHtmlIR: false,
|
|
2161
2161
|
needsControlFlowImport: false,
|
|
2162
2162
|
needsCreateMemo: false,
|
|
2163
2163
|
controlFlowComponents: /* @__PURE__ */ new Set(),
|
|
@@ -2182,7 +2182,7 @@ var plugin_default = (0, import_helper_plugin_utils.declare)((api, options = {})
|
|
|
2182
2182
|
},
|
|
2183
2183
|
exit(path, state) {
|
|
2184
2184
|
const imports = [];
|
|
2185
|
-
if (state.hasJSX || state.
|
|
2185
|
+
if (state.hasJSX || state.hasHtmlIR) {
|
|
2186
2186
|
if (state.irImports.size > 0) {
|
|
2187
2187
|
const CF = /* @__PURE__ */ new Set([
|
|
2188
2188
|
"Show",
|
|
@@ -2372,8 +2372,8 @@ var plugin_default = (0, import_helper_plugin_utils.declare)((api, options = {})
|
|
|
2372
2372
|
path.replaceWith(emitViaIR(path.node, state));
|
|
2373
2373
|
},
|
|
2374
2374
|
TaggedTemplateExpression(path, state) {
|
|
2375
|
-
if (
|
|
2376
|
-
path.replaceWith(
|
|
2375
|
+
if (compileHtml && import_core3.types.isIdentifier(path.node.tag) && (path.node.tag.name === htmlTag || path.node.tag.name === "svg")) {
|
|
2376
|
+
path.replaceWith(emitHtmlViaIR(path.node, state));
|
|
2377
2377
|
}
|
|
2378
2378
|
}
|
|
2379
2379
|
}
|
|
@@ -2476,10 +2476,10 @@ function dedupeImports(imports) {
|
|
|
2476
2476
|
}
|
|
2477
2477
|
return out;
|
|
2478
2478
|
}
|
|
2479
|
-
function
|
|
2479
|
+
function emitHtmlViaIR(node, state) {
|
|
2480
2480
|
const used = /* @__PURE__ */ new Set();
|
|
2481
2481
|
const svg = import_core3.types.isIdentifier(node.tag) && node.tag.name === "svg";
|
|
2482
|
-
const ir =
|
|
2482
|
+
const ir = buildIRFromHtml(node, used, { svg, onNested: nestedHook(state) });
|
|
2483
2483
|
resolveComponentSources(ir, {
|
|
2484
2484
|
resolver: state.componentResolver,
|
|
2485
2485
|
modules: {
|
|
@@ -2494,7 +2494,7 @@ function emitLitViaIR(node, state) {
|
|
|
2494
2494
|
for (const s of imports) used.add(s);
|
|
2495
2495
|
for (const s of used) state.irImports.add(s);
|
|
2496
2496
|
collectRuntimeNeeds(ir, state);
|
|
2497
|
-
state.
|
|
2497
|
+
state.hasHtmlIR = true;
|
|
2498
2498
|
const expression = import_core3.template.expression(adoptTemplates(code, templates, state), {
|
|
2499
2499
|
placeholderPattern: false,
|
|
2500
2500
|
plugins: ["typescript"]
|
|
@@ -1,19 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview Babel front-end for the Fluixi compiler.
|
|
3
|
-
* @module @fluixi/babel-plugin-jsx
|
|
4
|
-
*
|
|
5
|
-
* This is a host adapter, not the compiler. It parses with babel and, for each
|
|
6
|
-
* JSX element/fragment and each `` html`...` `` template, hands the node to the
|
|
7
|
-
* shared pipeline: build IR, run the imperative backend, then splices the
|
|
8
|
-
* emitted code back into the program. Everything that decides *what* the output
|
|
9
|
-
* means (directives, control flow, component resolution, load strategies,
|
|
10
|
-
* reactivity, templates) lives in ../../{ir,resolve,optimize,codegen}, which
|
|
11
|
-
* import no babel at all.
|
|
12
|
-
*
|
|
13
|
-
* What stays here is genuinely host work: dispatching the visitors, collecting
|
|
14
|
-
* the runtime symbols the backend reported so the imports can be injected, and
|
|
15
|
-
* hoisting static templates to module scope.
|
|
16
|
-
*/
|
|
17
1
|
import { type ComponentResolverRule } from '../../resolve/component-resolver.cjs';
|
|
18
2
|
import { type PluginObj } from '@babel/core';
|
|
19
3
|
export interface PluginOptions {
|
|
@@ -50,7 +34,7 @@ export interface PluginOptions {
|
|
|
50
34
|
*/
|
|
51
35
|
controlFlowModule?: string;
|
|
52
36
|
/**
|
|
53
|
-
* Module the router components (Router/Outlet
|
|
37
|
+
* Module the router components (Router/Outlet/...) are auto-imported from.
|
|
54
38
|
* @default '@fluixi/core/router'
|
|
55
39
|
*/
|
|
56
40
|
routerModule?: string;
|
|
@@ -76,20 +60,20 @@ export interface PluginOptions {
|
|
|
76
60
|
/**
|
|
77
61
|
* Which authoring syntaxes to compile:
|
|
78
62
|
* - 'jsx': only JSX elements/fragments.
|
|
79
|
-
* - '
|
|
63
|
+
* - 'html': only `` html`...` `` / `` svg`...` `` tagged templates.
|
|
80
64
|
* - 'both' (default): JSX and `html``` templates in the same file.
|
|
81
65
|
*
|
|
82
66
|
* Both syntaxes lower to the same IR and the same imperative backend, so the
|
|
83
67
|
* choice is about which source forms the plugin touches, not about output.
|
|
84
68
|
* @default 'both'
|
|
85
69
|
*/
|
|
86
|
-
format?: 'jsx' | '
|
|
70
|
+
format?: 'jsx' | 'html' | 'both';
|
|
87
71
|
/**
|
|
88
|
-
* Tag name that marks
|
|
89
|
-
*
|
|
72
|
+
* Tag name that marks an html template for compilation (when `format` includes
|
|
73
|
+
* html). Other tagged templates are left untouched.
|
|
90
74
|
* @default 'html'
|
|
91
75
|
*/
|
|
92
|
-
|
|
76
|
+
htmlTag?: string;
|
|
93
77
|
}
|
|
94
78
|
declare const _default: (api: object, options: PluginOptions | null | undefined, dirname: string) => PluginObj<import("@babel/core").PluginPass>;
|
|
95
79
|
export default _default;
|
|
@@ -1,19 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview Babel front-end for the Fluixi compiler.
|
|
3
|
-
* @module @fluixi/babel-plugin-jsx
|
|
4
|
-
*
|
|
5
|
-
* This is a host adapter, not the compiler. It parses with babel and, for each
|
|
6
|
-
* JSX element/fragment and each `` html`...` `` template, hands the node to the
|
|
7
|
-
* shared pipeline: build IR, run the imperative backend, then splices the
|
|
8
|
-
* emitted code back into the program. Everything that decides *what* the output
|
|
9
|
-
* means (directives, control flow, component resolution, load strategies,
|
|
10
|
-
* reactivity, templates) lives in ../../{ir,resolve,optimize,codegen}, which
|
|
11
|
-
* import no babel at all.
|
|
12
|
-
*
|
|
13
|
-
* What stays here is genuinely host work: dispatching the visitors, collecting
|
|
14
|
-
* the runtime symbols the backend reported so the imports can be injected, and
|
|
15
|
-
* hoisting static templates to module scope.
|
|
16
|
-
*/
|
|
17
1
|
import { type ComponentResolverRule } from '../../resolve/component-resolver.js';
|
|
18
2
|
import { type PluginObj } from '@babel/core';
|
|
19
3
|
export interface PluginOptions {
|
|
@@ -50,7 +34,7 @@ export interface PluginOptions {
|
|
|
50
34
|
*/
|
|
51
35
|
controlFlowModule?: string;
|
|
52
36
|
/**
|
|
53
|
-
* Module the router components (Router/Outlet
|
|
37
|
+
* Module the router components (Router/Outlet/...) are auto-imported from.
|
|
54
38
|
* @default '@fluixi/core/router'
|
|
55
39
|
*/
|
|
56
40
|
routerModule?: string;
|
|
@@ -76,20 +60,20 @@ export interface PluginOptions {
|
|
|
76
60
|
/**
|
|
77
61
|
* Which authoring syntaxes to compile:
|
|
78
62
|
* - 'jsx': only JSX elements/fragments.
|
|
79
|
-
* - '
|
|
63
|
+
* - 'html': only `` html`...` `` / `` svg`...` `` tagged templates.
|
|
80
64
|
* - 'both' (default): JSX and `html``` templates in the same file.
|
|
81
65
|
*
|
|
82
66
|
* Both syntaxes lower to the same IR and the same imperative backend, so the
|
|
83
67
|
* choice is about which source forms the plugin touches, not about output.
|
|
84
68
|
* @default 'both'
|
|
85
69
|
*/
|
|
86
|
-
format?: 'jsx' | '
|
|
70
|
+
format?: 'jsx' | 'html' | 'both';
|
|
87
71
|
/**
|
|
88
|
-
* Tag name that marks
|
|
89
|
-
*
|
|
72
|
+
* Tag name that marks an html template for compilation (when `format` includes
|
|
73
|
+
* html). Other tagged templates are left untouched.
|
|
90
74
|
* @default 'html'
|
|
91
75
|
*/
|
|
92
|
-
|
|
76
|
+
htmlTag?: string;
|
|
93
77
|
}
|
|
94
78
|
declare const _default: (api: object, options: PluginOptions | null | undefined, dirname: string) => PluginObj<import("@babel/core").PluginPass>;
|
|
95
79
|
export default _default;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/frontend/babel/plugin.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/frontend/babel/plugin.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,qBAAqB,EAG3B,MAAM,qCAAqC,CAAC;AAQ7C,OAAO,EAAwB,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AAQnE,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE3B;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,+EAA+E;IAC/E,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAE3B;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,SAAS,qBAAqB,EAAE,CAAC;IAE3C;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;;;;;;;;OASG;IACH,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;IAEjC;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;;AA8CD,wBA+UG"}
|
|
@@ -1,19 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview Babel front-end for the Fluixi compiler.
|
|
3
|
-
* @module @fluixi/babel-plugin-jsx
|
|
4
|
-
*
|
|
5
|
-
* This is a host adapter, not the compiler. It parses with babel and, for each
|
|
6
|
-
* JSX element/fragment and each `` html`...` `` template, hands the node to the
|
|
7
|
-
* shared pipeline: build IR, run the imperative backend, then splices the
|
|
8
|
-
* emitted code back into the program. Everything that decides *what* the output
|
|
9
|
-
* means (directives, control flow, component resolution, load strategies,
|
|
10
|
-
* reactivity, templates) lives in ../../{ir,resolve,optimize,codegen}, which
|
|
11
|
-
* import no babel at all.
|
|
12
|
-
*
|
|
13
|
-
* What stays here is genuinely host work: dispatching the visitors, collecting
|
|
14
|
-
* the runtime symbols the backend reported so the imports can be injected, and
|
|
15
|
-
* hoisting static templates to module scope.
|
|
16
|
-
*/
|
|
17
1
|
import { declare } from '@babel/helper-plugin-utils';
|
|
18
2
|
import { createComponentResolver, } from '../../resolve/component-resolver.js';
|
|
19
3
|
import { resolveComponentSources } from '../../resolve/resolve-ir.js';
|
|
@@ -22,31 +6,27 @@ import { isDeferred } from '../../resolve/load-directive.js';
|
|
|
22
6
|
import { CORE_CONTROL_FLOW, ROUTER_COMPONENTS as ROUTER_COMPONENT_NAMES, } from '../../resolve/builtins.js';
|
|
23
7
|
import { types as t, template } from '@babel/core';
|
|
24
8
|
import { buildIR } from './build-ir.js';
|
|
25
|
-
import {
|
|
9
|
+
import { buildIRFromHtml } from './build-ir-html.js';
|
|
26
10
|
import { imperativeBackend } from '../../codegen/backends/imperative.js';
|
|
27
|
-
// ============================================================================
|
|
28
11
|
// Constants
|
|
29
|
-
// ============================================================================
|
|
30
12
|
// Control-flow components that live in fluixi, NOT @fluixi/dom, they must
|
|
31
13
|
// be auto-imported from core (dom doesn't export them).
|
|
32
14
|
const CORE_ONLY_CONTROL_FLOW = new Set(CORE_CONTROL_FLOW);
|
|
33
15
|
// Router components auto-imported (from routerModule) the same way control flow is:
|
|
34
|
-
// use `<Router>`/`<Outlet
|
|
16
|
+
// use `<Router>`/`<Outlet>`/... in a template and the import is injected if absent.
|
|
35
17
|
const ROUTER_COMPONENTS = new Set(ROUTER_COMPONENT_NAMES);
|
|
36
|
-
// ============================================================================
|
|
37
18
|
// Main Plugin
|
|
38
|
-
// ============================================================================
|
|
39
19
|
export default declare((api, options = {}) => {
|
|
40
20
|
api.assertVersion(7);
|
|
41
21
|
const { delegateEvents = true, signalModule = '@fluixi/dom', controlFlowModule = '@fluixi/dom', routerModule = '@fluixi/core/router', reactiveModule = '@fluixi/reactive/signal', templateClone = true, partialTemplates = true,
|
|
42
22
|
// `both` by default: JSX and html`` are compiled out of the box, so
|
|
43
23
|
// `fluixi()` needs no `format` option. Injected imports are deduped, so a
|
|
44
24
|
// file mixing the two styles won't redeclare a binding.
|
|
45
|
-
format = 'both',
|
|
25
|
+
format = 'both', htmlTag = 'html', resolve: resolveRules = [], } = options;
|
|
46
26
|
// Built once per plugin instance, not per file: the rules are static and the
|
|
47
27
|
// resolver memoises lookups, so every file in the build shares one cache.
|
|
48
28
|
const componentResolver = createComponentResolver(resolveRules);
|
|
49
|
-
const
|
|
29
|
+
const compileHtml = format === 'html' || format === 'both';
|
|
50
30
|
const pluginState = {
|
|
51
31
|
irImports: new Set(),
|
|
52
32
|
libModule: '@fluixi/core',
|
|
@@ -55,7 +35,7 @@ export default declare((api, options = {}) => {
|
|
|
55
35
|
templateClone,
|
|
56
36
|
partialTemplates,
|
|
57
37
|
hasJSX: false,
|
|
58
|
-
|
|
38
|
+
hasHtmlTag: false,
|
|
59
39
|
needsControlFlowImport: false,
|
|
60
40
|
needsCreateMemo: false,
|
|
61
41
|
controlFlowComponents: new Set(),
|
|
@@ -73,7 +53,6 @@ export default declare((api, options = {}) => {
|
|
|
73
53
|
parserOpts.plugins.push('jsx', 'typescript');
|
|
74
54
|
},
|
|
75
55
|
pre(state) {
|
|
76
|
-
// Initialize plugin state
|
|
77
56
|
Object.assign(state, pluginState);
|
|
78
57
|
},
|
|
79
58
|
visitor: {
|
|
@@ -82,8 +61,8 @@ export default declare((api, options = {}) => {
|
|
|
82
61
|
// Reset state for new file
|
|
83
62
|
Object.assign(state, {
|
|
84
63
|
hasJSX: false,
|
|
85
|
-
|
|
86
|
-
|
|
64
|
+
hasHtmlTag: false,
|
|
65
|
+
hasHtmlIR: false,
|
|
87
66
|
needsControlFlowImport: false,
|
|
88
67
|
needsCreateMemo: false,
|
|
89
68
|
controlFlowComponents: new Set(),
|
|
@@ -108,7 +87,7 @@ export default declare((api, options = {}) => {
|
|
|
108
87
|
},
|
|
109
88
|
exit(path, state) {
|
|
110
89
|
const imports = [];
|
|
111
|
-
if (state.hasJSX || state.
|
|
90
|
+
if (state.hasJSX || state.hasHtmlIR) {
|
|
112
91
|
if (state.irImports.size > 0) {
|
|
113
92
|
// Import exactly the symbols emit() reported, splitting control-flow
|
|
114
93
|
// components to the control-flow module.
|
|
@@ -263,18 +242,16 @@ export default declare((api, options = {}) => {
|
|
|
263
242
|
TaggedTemplateExpression(path, state) {
|
|
264
243
|
// `html`...`` and `svg`...`` lower through the same IR and the same
|
|
265
244
|
// backend as JSX: one pipeline, two authoring syntaxes.
|
|
266
|
-
if (
|
|
245
|
+
if (compileHtml &&
|
|
267
246
|
t.isIdentifier(path.node.tag) &&
|
|
268
|
-
(path.node.tag.name ===
|
|
269
|
-
path.replaceWith(
|
|
247
|
+
(path.node.tag.name === htmlTag || path.node.tag.name === 'svg')) {
|
|
248
|
+
path.replaceWith(emitHtmlViaIR(path.node, state));
|
|
270
249
|
}
|
|
271
250
|
},
|
|
272
251
|
},
|
|
273
252
|
};
|
|
274
253
|
});
|
|
275
|
-
// ============================================================================
|
|
276
254
|
// JSX Transformation
|
|
277
|
-
// ============================================================================
|
|
278
255
|
/**
|
|
279
256
|
* Two usages of one component in the same file share a binding, so their strategies
|
|
280
257
|
* have to agree. The earlier-loading one wins: the module is in whichever chunk loads
|
|
@@ -344,10 +321,10 @@ function adoptTemplates(code, templates, state) {
|
|
|
344
321
|
}
|
|
345
322
|
function emitViaIR(node, state) {
|
|
346
323
|
// `used` collects runtime symbols emitted for JSX nested inside expressions
|
|
347
|
-
// (render-props, ternaries, fallback={<p/>},
|
|
324
|
+
// (render-props, ternaries, fallback={<p/>}, ...) so we import them too.
|
|
348
325
|
const used = new Set();
|
|
349
326
|
const ir = buildIR(node, used, nestedHook(state));
|
|
350
|
-
// The same passes the
|
|
327
|
+
// The same passes the html path runs. Without them `codegen: 'ir'` silently skipped
|
|
351
328
|
// resolution entirely: a resolved tag compiled to a reference with no import.
|
|
352
329
|
resolveComponentSources(ir, {
|
|
353
330
|
resolver: state.componentResolver,
|
|
@@ -401,15 +378,15 @@ function dedupeImports(imports) {
|
|
|
401
378
|
return out;
|
|
402
379
|
}
|
|
403
380
|
/**
|
|
404
|
-
*
|
|
405
|
-
* imperative backend, reparse. Mirrors emitViaIR, the whole point is that
|
|
381
|
+
* Html-template path: build IR from a `` html`...` `` template, emit through the
|
|
382
|
+
* imperative backend, reparse. Mirrors emitViaIR, the whole point is that html
|
|
406
383
|
* and JSX share one IR + one backend. Collects runtime imports and the delegated
|
|
407
384
|
* events used so Program.exit wires them.
|
|
408
385
|
*/
|
|
409
|
-
function
|
|
386
|
+
function emitHtmlViaIR(node, state) {
|
|
410
387
|
const used = new Set();
|
|
411
388
|
const svg = t.isIdentifier(node.tag) && node.tag.name === 'svg';
|
|
412
|
-
const ir =
|
|
389
|
+
const ir = buildIRFromHtml(node, used, { svg, onNested: nestedHook(state) });
|
|
413
390
|
// Resolve pass: annotate each component reference with where it comes from, before
|
|
414
391
|
// codegen. Bindings are not checked here: Program.exit knows the whole file's scope
|
|
415
392
|
// and drops any injected import whose name turns out to be bound.
|
|
@@ -432,7 +409,7 @@ function emitLitViaIR(node, state) {
|
|
|
432
409
|
for (const s of used)
|
|
433
410
|
state.irImports.add(s);
|
|
434
411
|
collectRuntimeNeeds(ir, state);
|
|
435
|
-
state.
|
|
412
|
+
state.hasHtmlIR = true;
|
|
436
413
|
// The IR is emitted as a string and reparsed, so the resulting nodes carry no
|
|
437
414
|
// position: which is why compiled html`` had no source map at all. Give every
|
|
438
415
|
// generated node the template's own location so a breakpoint or stack frame
|
|
@@ -479,7 +456,7 @@ function inheritLocation(target, source) {
|
|
|
479
456
|
walk(target);
|
|
480
457
|
}
|
|
481
458
|
/**
|
|
482
|
-
* Walk the
|
|
459
|
+
* Walk the html IR for things Program.exit wires: delegated events (-> the
|
|
483
460
|
* delegateEvents([...]) call) and control-flow component names used as tags
|
|
484
461
|
* (-> auto-import from the control-flow module, like the inline JSX path).
|
|
485
462
|
*/
|
|
@@ -1118,7 +1118,7 @@ var Lowerer = class {
|
|
|
1118
1118
|
for (const s of imports) this.used.add(s);
|
|
1119
1119
|
return inlineTemplates(code, templates);
|
|
1120
1120
|
}
|
|
1121
|
-
//
|
|
1121
|
+
// content
|
|
1122
1122
|
lowerRoot(children) {
|
|
1123
1123
|
const nodes = this.lowerChildren(children);
|
|
1124
1124
|
if (nodes.length === 1) return nodes[0];
|
|
@@ -1247,8 +1247,8 @@ var Lowerer = class {
|
|
|
1247
1247
|
}
|
|
1248
1248
|
return { slots, rest };
|
|
1249
1249
|
}
|
|
1250
|
-
//
|
|
1251
|
-
/** `<el if=${cond}
|
|
1250
|
+
// control-flow sugar
|
|
1251
|
+
/** `<el if=${cond}>...</el>` (+ optional `<el else>`) → `<Show when fallback>`. */
|
|
1252
1252
|
lowerIf(el, condHole, elseEl) {
|
|
1253
1253
|
const cond = this.hole(condHole);
|
|
1254
1254
|
const props = [
|
|
@@ -1263,8 +1263,8 @@ var Lowerer = class {
|
|
|
1263
1263
|
return { kind: "component", name: "Show", props, children: [child], ...at ? { at } : {}, ...cond.at ? { bindAt: cond.at } : {} };
|
|
1264
1264
|
}
|
|
1265
1265
|
/**
|
|
1266
|
-
* `<el each=${items} key?>${item =>
|
|
1267
|
-
* content is repeated per item. Content that is not a `${item =>
|
|
1266
|
+
* `<el each=${items} key?>${item => ...}</el>` → `<el><For each>{item => ...}</For></el>`: the
|
|
1267
|
+
* content is repeated per item. Content that is not a `${item => ...}` arrow is repeated as
|
|
1268
1268
|
* it is. Null when the element has no `each`.
|
|
1269
1269
|
*/
|
|
1270
1270
|
lowerEach(el) {
|
|
@@ -1301,7 +1301,7 @@ var Lowerer = class {
|
|
|
1301
1301
|
const clone = { ...el, attributes: el.attributes.filter((a) => !drop(a)) };
|
|
1302
1302
|
return clone.kind === "Element" ? this.lowerElement(clone) : this.lowerComponent(clone);
|
|
1303
1303
|
}
|
|
1304
|
-
//
|
|
1304
|
+
// attributes
|
|
1305
1305
|
/**
|
|
1306
1306
|
* `element`: a DOM element, where each class:/style: value that moves is its own accessor.
|
|
1307
1307
|
* A component gets the object as before, rebuilt whole when any value moves.
|
|
@@ -1442,7 +1442,7 @@ var Lowerer = class {
|
|
|
1442
1442
|
if (mods.includes("passive")) opts.push("passive: true");
|
|
1443
1443
|
return opts.length ? `{ ${opts.join(", ")} }` : null;
|
|
1444
1444
|
}
|
|
1445
|
-
/** `bind:value=${sig}` → `value={read()}` + `onInput={e => write(e
|
|
1445
|
+
/** `bind:value=${sig}` → `value={read()}` + `onInput={e => write(e...value)}`. */
|
|
1446
1446
|
bindProps(prop, h) {
|
|
1447
1447
|
const sigCode = h.code;
|
|
1448
1448
|
const checked = prop === "checked";
|
|
@@ -1468,7 +1468,7 @@ var Lowerer = class {
|
|
|
1468
1468
|
}
|
|
1469
1469
|
];
|
|
1470
1470
|
}
|
|
1471
|
-
/** A plain attribute (incl.
|
|
1471
|
+
/** A plain attribute (incl. html `?bool`, mixed values), old `mkProp` behavior. */
|
|
1472
1472
|
plainAttr(a) {
|
|
1473
1473
|
const v = a.value;
|
|
1474
1474
|
let name = a.name;
|
|
@@ -1535,7 +1535,7 @@ function bindHole(expr, used, onNested) {
|
|
|
1535
1535
|
if (t.isObjectExpression(expr)) hole.object = true;
|
|
1536
1536
|
return hole;
|
|
1537
1537
|
}
|
|
1538
|
-
function
|
|
1538
|
+
function lowerHtmlTemplate(node, used, opts = {}) {
|
|
1539
1539
|
const quasi = node.quasi;
|
|
1540
1540
|
const holes = quasi.expressions.map((e) => bindHole(e, used, opts.onNested));
|
|
1541
1541
|
return lowerTemplate(buildPieces(quasi), holes, used, opts);
|
|
@@ -1628,9 +1628,9 @@ function childReason(node) {
|
|
|
1628
1628
|
return "expression-child";
|
|
1629
1629
|
}
|
|
1630
1630
|
|
|
1631
|
-
// src/frontend/babel/build-ir-
|
|
1632
|
-
function
|
|
1633
|
-
const ir =
|
|
1631
|
+
// src/frontend/babel/build-ir-html.ts
|
|
1632
|
+
function buildIRFromHtml(node, used = /* @__PURE__ */ new Set(), opts = {}) {
|
|
1633
|
+
const ir = lowerHtmlTemplate(node, used, opts);
|
|
1634
1634
|
analyzeStatic(ir);
|
|
1635
1635
|
return ir;
|
|
1636
1636
|
}
|
|
@@ -2039,12 +2039,12 @@ function transformNestedJSX(node, used, onNested) {
|
|
|
2039
2039
|
const { code, imports, templates } = imperativeBackend.emit(nestedIR, {});
|
|
2040
2040
|
emitInto(path, inlineTemplates(code, templates), imports);
|
|
2041
2041
|
},
|
|
2042
|
-
// Nested
|
|
2042
|
+
// Nested html templates compose: ${cond ? html`...` : html`...`},
|
|
2043
2043
|
// ${list.map(x => html`<li>${x}</li>`)}. Compile them the same way.
|
|
2044
2044
|
TaggedTemplateExpression(path) {
|
|
2045
2045
|
const tag = path.node.tag;
|
|
2046
2046
|
if (!t2.isIdentifier(tag) || tag.name !== "html" && tag.name !== "svg") return;
|
|
2047
|
-
const ir =
|
|
2047
|
+
const ir = buildIRFromHtml(path.node, used, { svg: tag.name === "svg", onNested });
|
|
2048
2048
|
onNested?.(ir);
|
|
2049
2049
|
const { code, imports, templates } = imperativeBackend.emit(ir, {});
|
|
2050
2050
|
emitInto(path, inlineTemplates(code, templates), imports);
|
|
@@ -2087,11 +2087,11 @@ var plugin_default = declare((api, options = {}) => {
|
|
|
2087
2087
|
// `fluixi()` needs no `format` option. Injected imports are deduped, so a
|
|
2088
2088
|
// file mixing the two styles won't redeclare a binding.
|
|
2089
2089
|
format = "both",
|
|
2090
|
-
|
|
2090
|
+
htmlTag = "html",
|
|
2091
2091
|
resolve: resolveRules = []
|
|
2092
2092
|
} = options;
|
|
2093
2093
|
const componentResolver = createComponentResolver(resolveRules);
|
|
2094
|
-
const
|
|
2094
|
+
const compileHtml = format === "html" || format === "both";
|
|
2095
2095
|
const pluginState = {
|
|
2096
2096
|
irImports: /* @__PURE__ */ new Set(),
|
|
2097
2097
|
libModule: "@fluixi/core",
|
|
@@ -2100,7 +2100,7 @@ var plugin_default = declare((api, options = {}) => {
|
|
|
2100
2100
|
templateClone,
|
|
2101
2101
|
partialTemplates,
|
|
2102
2102
|
hasJSX: false,
|
|
2103
|
-
|
|
2103
|
+
hasHtmlTag: false,
|
|
2104
2104
|
needsControlFlowImport: false,
|
|
2105
2105
|
needsCreateMemo: false,
|
|
2106
2106
|
controlFlowComponents: /* @__PURE__ */ new Set(),
|
|
@@ -2124,8 +2124,8 @@ var plugin_default = declare((api, options = {}) => {
|
|
|
2124
2124
|
enter(path, state) {
|
|
2125
2125
|
Object.assign(state, {
|
|
2126
2126
|
hasJSX: false,
|
|
2127
|
-
|
|
2128
|
-
|
|
2127
|
+
hasHtmlTag: false,
|
|
2128
|
+
hasHtmlIR: false,
|
|
2129
2129
|
needsControlFlowImport: false,
|
|
2130
2130
|
needsCreateMemo: false,
|
|
2131
2131
|
controlFlowComponents: /* @__PURE__ */ new Set(),
|
|
@@ -2150,7 +2150,7 @@ var plugin_default = declare((api, options = {}) => {
|
|
|
2150
2150
|
},
|
|
2151
2151
|
exit(path, state) {
|
|
2152
2152
|
const imports = [];
|
|
2153
|
-
if (state.hasJSX || state.
|
|
2153
|
+
if (state.hasJSX || state.hasHtmlIR) {
|
|
2154
2154
|
if (state.irImports.size > 0) {
|
|
2155
2155
|
const CF = /* @__PURE__ */ new Set([
|
|
2156
2156
|
"Show",
|
|
@@ -2340,8 +2340,8 @@ var plugin_default = declare((api, options = {}) => {
|
|
|
2340
2340
|
path.replaceWith(emitViaIR(path.node, state));
|
|
2341
2341
|
},
|
|
2342
2342
|
TaggedTemplateExpression(path, state) {
|
|
2343
|
-
if (
|
|
2344
|
-
path.replaceWith(
|
|
2343
|
+
if (compileHtml && t3.isIdentifier(path.node.tag) && (path.node.tag.name === htmlTag || path.node.tag.name === "svg")) {
|
|
2344
|
+
path.replaceWith(emitHtmlViaIR(path.node, state));
|
|
2345
2345
|
}
|
|
2346
2346
|
}
|
|
2347
2347
|
}
|
|
@@ -2444,10 +2444,10 @@ function dedupeImports(imports) {
|
|
|
2444
2444
|
}
|
|
2445
2445
|
return out;
|
|
2446
2446
|
}
|
|
2447
|
-
function
|
|
2447
|
+
function emitHtmlViaIR(node, state) {
|
|
2448
2448
|
const used = /* @__PURE__ */ new Set();
|
|
2449
2449
|
const svg = t3.isIdentifier(node.tag) && node.tag.name === "svg";
|
|
2450
|
-
const ir =
|
|
2450
|
+
const ir = buildIRFromHtml(node, used, { svg, onNested: nestedHook(state) });
|
|
2451
2451
|
resolveComponentSources(ir, {
|
|
2452
2452
|
resolver: state.componentResolver,
|
|
2453
2453
|
modules: {
|
|
@@ -2462,7 +2462,7 @@ function emitLitViaIR(node, state) {
|
|
|
2462
2462
|
for (const s of imports) used.add(s);
|
|
2463
2463
|
for (const s of used) state.irImports.add(s);
|
|
2464
2464
|
collectRuntimeNeeds(ir, state);
|
|
2465
|
-
state.
|
|
2465
|
+
state.hasHtmlIR = true;
|
|
2466
2466
|
const expression = template2.expression(adoptTemplates(code, templates, state), {
|
|
2467
2467
|
placeholderPattern: false,
|
|
2468
2468
|
plugins: ["typescript"]
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* const getUser = async (id) => { 'use server'; return db.users.find(id); };
|
|
6
6
|
*
|
|
7
7
|
* - **Server build** (`ssr: true`): keep the body, register it by a stable id so the
|
|
8
|
-
* RPC dispatcher can find it → `$$registerServerFn("id", async (id) => {
|
|
8
|
+
* RPC dispatcher can find it → `$$registerServerFn("id", async (id) => {...})`.
|
|
9
9
|
* - **Client build** (`ssr: false`): drop the body (server-only code never ships) and
|
|
10
10
|
* replace it with an RPC stub → `$$createServerReference("id")`.
|
|
11
11
|
*
|
|
@@ -52,7 +52,7 @@ function serverFunctionsBabelPlugin({ types: t }) {
|
|
|
52
52
|
])
|
|
53
53
|
: t.callExpression(t.identifier(helper), [t.stringLiteral(id)]);
|
|
54
54
|
if (path.isFunctionDeclaration()) {
|
|
55
|
-
// function f(){
|
|
55
|
+
// function f(){...} → const f = wrap(...) (loses hoisting; acceptable)
|
|
56
56
|
path.replaceWith(t.variableDeclaration('const', [t.variableDeclarator(path.node.id, replacement)]));
|
|
57
57
|
}
|
|
58
58
|
else {
|