@firsthandjs/compiler 0.8.0 → 0.9.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.
@@ -86,6 +86,7 @@ function eventName(attribute) {
86
86
 
87
87
  // packages/compiler/src/transform.ts
88
88
  var RUNTIME = "@firsthandjs/dom/internal";
89
+ var SERVER_RUNTIME = "@firsthandjs/server/internal";
89
90
  var CORE = "@firsthandjs/core";
90
91
  var CHILD_THUNK = /* @__PURE__ */ Symbol("firsthand.childThunk");
91
92
  var GENERATED = /* @__PURE__ */ Symbol("firsthand.generated");
@@ -112,10 +113,14 @@ function firsthandPlugin(_api, options = {}) {
112
113
  moduleId: stableId(options.packageName ?? "app", state.filename ?? "module"),
113
114
  views: /* @__PURE__ */ new Map(),
114
115
  viewNodes: /* @__PURE__ */ new Set(),
115
- runs: /* @__PURE__ */ new Map()
116
+ runs: /* @__PURE__ */ new Map(),
117
+ ssr: options.ssr === true,
118
+ hydratable: options.hydratable === true && options.ssr !== true
116
119
  };
117
120
  collectViews(path, state);
118
- collectRuns(path, state);
121
+ if (options.ssr !== true) {
122
+ collectRuns(path, state);
123
+ }
119
124
  },
120
125
  exit(path, state) {
121
126
  const { imports, templates, views } = state.firsthand;
@@ -142,18 +147,22 @@ function firsthandPlugin(_api, options = {}) {
142
147
  // component's children, a dynamic expression) are re-visited later, by
143
148
  // which time they are no longer inside JSX.
144
149
  JSXElement(path, state) {
145
- rewriteKeyedMaps(path, state);
150
+ if (!state.firsthand.ssr) {
151
+ rewriteKeyedMaps(path, state);
152
+ }
146
153
  path.replaceWith(compileNode(path, state));
147
154
  },
148
155
  JSXFragment(path, state) {
149
- rewriteKeyedMaps(path, state);
156
+ if (!state.firsthand.ssr) {
157
+ rewriteKeyedMaps(path, state);
158
+ }
150
159
  path.replaceWith(compileNode(path, state));
151
160
  },
152
161
  CallExpression(path, state) {
153
162
  annotateComponent(path, state, options);
154
163
  },
155
164
  VariableDeclarator(path, state) {
156
- if (options.devtools === true) {
165
+ if (options.devtools === true && options.ssr !== true) {
157
166
  nameCell(path, state);
158
167
  }
159
168
  }
@@ -175,7 +184,10 @@ function groupBySource(imports) {
175
184
  }
176
185
  return grouped;
177
186
  }
178
- function runtime(state, name, source = RUNTIME) {
187
+ function runtime(state, name, source) {
188
+ return runtimeFrom(state, name, source ?? (state.firsthand.ssr ? SERVER_RUNTIME : RUNTIME));
189
+ }
190
+ function runtimeFrom(state, name, source) {
179
191
  const key = `${source}#${name}`;
180
192
  let local = state.firsthand.imports.get(key);
181
193
  if (local === void 0) {
@@ -624,7 +636,7 @@ function compileNode(path, state) {
624
636
  if (isComponentTag(node)) {
625
637
  return compileComponent(path, state);
626
638
  }
627
- return compileTemplate(path, state);
639
+ return state.firsthand.ssr ? compileMarkup(path, state) : compileTemplate(path, state);
628
640
  }
629
641
  function collectViews(program, state) {
630
642
  const { views, viewNodes } = state.firsthand;
@@ -892,16 +904,28 @@ function compileComponent(path, state) {
892
904
  }
893
905
  const name = attributeName(attribute);
894
906
  const value = attributeValue(attribute);
907
+ if (state.firsthand.ssr && name === "key") {
908
+ continue;
909
+ }
895
910
  if (value === null || isStaticValue(value)) {
896
911
  properties.push(t.objectProperty(propertyKey(name), value ?? t.booleanLiteral(true)));
897
912
  } else {
898
913
  const held = dependsOnRun(value, run, path) ? throughCell(value) : value;
899
- const read = t.returnStatement(held);
900
- takePosition(read, value);
901
- properties.push(t.objectMethod("get", propertyKey(name), [], t.blockStatement([read])));
914
+ if (state.firsthand.ssr && isPure(value)) {
915
+ properties.push(t.objectProperty(propertyKey(name), held));
916
+ } else {
917
+ const read = t.returnStatement(held);
918
+ takePosition(read, value);
919
+ properties.push(t.objectMethod("get", propertyKey(name), [], t.blockStatement([read])));
920
+ }
902
921
  }
903
922
  }
904
- const children = compileChildren(node.children, state);
923
+ const throughRunCell = (value) => t.callExpression(throughCell(t.arrowFunctionExpression([], value)), []);
924
+ const children = compileChildren(node.children, state, {
925
+ depends: (value) => dependsOnRun(value, run, path),
926
+ cell: throughRunCell,
927
+ value: throughCell
928
+ });
905
929
  if (children.length === 1) {
906
930
  properties.push(
907
931
  t.objectMethod(
@@ -927,6 +951,9 @@ function compileComponent(path, state) {
927
951
  return keptChild(state, run, make, cells);
928
952
  }
929
953
  if (isLocalView(path, state)) {
954
+ if (state.firsthand.ssr) {
955
+ return make;
956
+ }
930
957
  const parent = path.parentPath;
931
958
  if (parent.isArrowFunctionExpression() && parent.node.body === node && CHILD_THUNK in parent.node) {
932
959
  return make;
@@ -973,6 +1000,40 @@ function keptChild(state, run, make, cells) {
973
1000
  ];
974
1001
  return t.callExpression(generated(t.arrowFunctionExpression([], t.blockStatement(body))), []);
975
1002
  }
1003
+ function isPure(node) {
1004
+ switch (node.type) {
1005
+ case "Identifier":
1006
+ case "ThisExpression":
1007
+ case "StringLiteral":
1008
+ case "NumericLiteral":
1009
+ case "BooleanLiteral":
1010
+ case "NullLiteral":
1011
+ case "BigIntLiteral":
1012
+ case "RegExpLiteral":
1013
+ return true;
1014
+ case "MemberExpression":
1015
+ case "OptionalMemberExpression":
1016
+ return isPure(node.object) && (!node.computed || isPure(node.property));
1017
+ case "UnaryExpression":
1018
+ return node.operator !== "delete" && isPure(node.argument);
1019
+ case "BinaryExpression":
1020
+ return isPure(node.left) && isPure(node.right);
1021
+ case "LogicalExpression":
1022
+ return isPure(node.left) && isPure(node.right);
1023
+ case "ConditionalExpression":
1024
+ return isPure(node.test) && isPure(node.consequent) && isPure(node.alternate);
1025
+ case "TemplateLiteral":
1026
+ return node.expressions.every((one) => t.isExpression(one) && isPure(one));
1027
+ case "ArrayExpression":
1028
+ return node.elements.every((one) => one === null || t.isExpression(one) && isPure(one));
1029
+ case "ObjectExpression":
1030
+ return node.properties.every(
1031
+ (one) => t.isObjectProperty(one) && !one.computed && t.isExpression(one.value) && isPure(one.value)
1032
+ );
1033
+ default:
1034
+ return false;
1035
+ }
1036
+ }
976
1037
  function propertyKey(name) {
977
1038
  return t.isValidIdentifier(name) ? t.identifier(name) : t.stringLiteral(name);
978
1039
  }
@@ -996,6 +1057,120 @@ function attributeValue(attribute) {
996
1057
  function isStaticValue(value) {
997
1058
  return t.isStringLiteral(value) || t.isNumericLiteral(value) || t.isBooleanLiteral(value) || t.isNullLiteral(value);
998
1059
  }
1060
+ function pushText(markup, text) {
1061
+ markup.parts[markup.parts.length - 1] = markup.parts[markup.parts.length - 1] + text;
1062
+ }
1063
+ function pushHole(markup, value) {
1064
+ markup.values.push(value);
1065
+ markup.parts.push("");
1066
+ }
1067
+ function compileMarkup(path, state) {
1068
+ const markup = { parts: [""], values: [] };
1069
+ emitMarkupElement(path.node, markup, state);
1070
+ if (markup.values.length === 0) {
1071
+ return t.callExpression(runtime(state, "ssr"), [
1072
+ t.arrayExpression([t.stringLiteral(markup.parts[0])])
1073
+ ]);
1074
+ }
1075
+ return t.callExpression(runtime(state, "ssr"), [
1076
+ t.arrayExpression(markup.parts.map((part) => t.stringLiteral(part))),
1077
+ ...markup.values
1078
+ ]);
1079
+ }
1080
+ function emitMarkupElement(node, markup, state) {
1081
+ const name = node.openingElement.name;
1082
+ if (!t.isJSXIdentifier(name)) {
1083
+ const namespaced = name;
1084
+ throw new Error(
1085
+ `Namespaced element names are not supported: <${namespaced.namespace.name}:${namespaced.name.name}>. Write the element without a namespace; SVG children are resolved by the parser.`
1086
+ );
1087
+ }
1088
+ const tag = name.name;
1089
+ pushText(markup, `<${tag}`);
1090
+ for (const attribute of node.openingElement.attributes) {
1091
+ emitMarkupAttribute(attribute, markup, state);
1092
+ }
1093
+ pushText(markup, ">");
1094
+ emitMarkupChildren(node.children, markup, state);
1095
+ if (!VOID_ELEMENTS.has(tag)) {
1096
+ pushText(markup, `</${tag}>`);
1097
+ }
1098
+ }
1099
+ function emitMarkupAttribute(attribute, markup, state) {
1100
+ if (t.isJSXSpreadAttribute(attribute)) {
1101
+ pushHole(markup, t.callExpression(runtime(state, "spread"), [attribute.argument]));
1102
+ return;
1103
+ }
1104
+ const name = attributeName(attribute);
1105
+ const value = attributeValue(attribute);
1106
+ if (name === "ref" || name.startsWith("on") && name.length > 2 && /[A-Z:]/.test(name[2])) {
1107
+ return;
1108
+ }
1109
+ if (name === "key") {
1110
+ return;
1111
+ }
1112
+ if (value === null) {
1113
+ pushText(markup, ` ${name}=""`);
1114
+ return;
1115
+ }
1116
+ if (isStaticValue(value)) {
1117
+ if (t.isBooleanLiteral(value) && !value.value) {
1118
+ return;
1119
+ }
1120
+ if (t.isNullLiteral(value)) {
1121
+ return;
1122
+ }
1123
+ const literal = t.isStringLiteral(value) ? value.value : t.isNumericLiteral(value) ? String(value.value) : "";
1124
+ pushText(markup, ` ${name}="${escapeAttribute(literal)}"`);
1125
+ return;
1126
+ }
1127
+ pushHole(markup, markupAttributeCall(name, value, state));
1128
+ }
1129
+ function markupAttributeCall(name, value, state) {
1130
+ if (name.startsWith("prop:")) {
1131
+ return t.callExpression(runtime(state, "setProperty"), [t.stringLiteral(name.slice(5)), value]);
1132
+ }
1133
+ if (name.startsWith("attr:")) {
1134
+ return t.callExpression(runtime(state, "setAttribute"), [
1135
+ t.stringLiteral(name.slice(5)),
1136
+ value
1137
+ ]);
1138
+ }
1139
+ if (name === "class" || name === "className") {
1140
+ return t.callExpression(runtime(state, "setClass"), [value]);
1141
+ }
1142
+ if (name === "style") {
1143
+ return t.callExpression(runtime(state, "setStyle"), [value]);
1144
+ }
1145
+ if (BOOLEAN_PROPERTIES.has(name)) {
1146
+ return t.callExpression(runtime(state, "setBoolean"), [t.stringLiteral(name), value]);
1147
+ }
1148
+ if (DOM_PROPERTIES.has(name)) {
1149
+ return t.callExpression(runtime(state, "setProperty"), [t.stringLiteral(name), value]);
1150
+ }
1151
+ return t.callExpression(runtime(state, "setAttribute"), [t.stringLiteral(name), value]);
1152
+ }
1153
+ function emitMarkupChildren(children, markup, state) {
1154
+ const entries = planChildren(children);
1155
+ for (let i = 0; i < entries.length; i++) {
1156
+ const entry = entries[i];
1157
+ if (entry.kind === "text") {
1158
+ pushText(markup, escapeText(entry.text));
1159
+ continue;
1160
+ }
1161
+ if (entry.kind === "element") {
1162
+ emitMarkupElement(entry.element, markup, state);
1163
+ continue;
1164
+ }
1165
+ if (entries.length > 1) {
1166
+ pushText(markup, "<!--[-->");
1167
+ }
1168
+ pushHole(markup, t.callExpression(runtime(state, "child"), [entry.expression]));
1169
+ if (i !== entries.length - 1) {
1170
+ pushText(markup, "<!---->");
1171
+ }
1172
+ }
1173
+ }
999
1174
  function compileTemplate(path, state) {
1000
1175
  let names = 0;
1001
1176
  const statements = [];
@@ -1404,7 +1579,7 @@ function emitChildren(children, build, self, state) {
1404
1579
  const id = build.next();
1405
1580
  build.statements.push(
1406
1581
  t.variableDeclaration("const", [
1407
- t.variableDeclarator(id, navigate(self, previous, previousIndex, index))
1582
+ t.variableDeclarator(id, navigate(self, previous, previousIndex, index, state))
1408
1583
  ])
1409
1584
  );
1410
1585
  previous = id;
@@ -1490,18 +1665,21 @@ function needsReference(element) {
1490
1665
  }
1491
1666
  return false;
1492
1667
  }
1493
- function navigate(self, previous, previousIndex, index) {
1668
+ function navigate(self, previous, previousIndex, index, state) {
1669
+ const hydratable = state.firsthand.hydratable;
1670
+ const first = hydratable ? runtime(state, "first") : null;
1671
+ const next = hydratable ? runtime(state, "next") : null;
1494
1672
  let expression;
1495
1673
  let steps;
1496
1674
  if (previous === null) {
1497
- expression = t.memberExpression(t.cloneNode(self), t.identifier("firstChild"));
1675
+ expression = hydratable ? t.callExpression(first, [t.cloneNode(self)]) : t.memberExpression(t.cloneNode(self), t.identifier("firstChild"));
1498
1676
  steps = index;
1499
1677
  } else {
1500
1678
  expression = t.cloneNode(previous);
1501
1679
  steps = index - previousIndex;
1502
1680
  }
1503
1681
  for (let i = 0; i < steps; i++) {
1504
- expression = t.memberExpression(expression, t.identifier("nextSibling"));
1682
+ expression = hydratable ? t.callExpression(next, [expression]) : t.memberExpression(expression, t.identifier("nextSibling"));
1505
1683
  }
1506
1684
  return expression;
1507
1685
  }
@@ -1560,23 +1738,37 @@ function cleanText(value) {
1560
1738
  }
1561
1739
  return kept.join(" ");
1562
1740
  }
1563
- function compileChildren(children, state) {
1741
+ function compileChildren(children, state, kept) {
1564
1742
  const result = [];
1565
1743
  for (const entry of planChildren(children)) {
1566
1744
  if (entry.kind === "text") {
1567
1745
  result.push(t.stringLiteral(entry.text));
1568
1746
  } else if (entry.kind === "element") {
1569
1747
  result.push(entry.element);
1748
+ } else if (state.firsthand.ssr) {
1749
+ result.push(entry.expression);
1570
1750
  } else if (entry.kind === "list") {
1571
- result.push(t.callExpression(runtime(state, "part"), [entry.expression]));
1751
+ const list = entry.expression;
1752
+ keepReading(list, kept);
1753
+ result.push(t.callExpression(runtime(state, "part"), [list]));
1572
1754
  } else {
1573
- result.push(
1574
- t.callExpression(runtime(state, "part"), [thunk(entry.expression)])
1575
- );
1755
+ const value = entry.expression;
1756
+ const read = kept !== void 0 && kept.depends(value) ? kept.cell(value) : value;
1757
+ result.push(t.callExpression(runtime(state, "part"), [thunk(read)]));
1576
1758
  }
1577
1759
  }
1578
1760
  return result;
1579
1761
  }
1762
+ function keepReading(list, kept) {
1763
+ const each = list.arguments[0];
1764
+ if (kept === void 0 || !t.isArrowFunctionExpression(each) || !t.isExpression(each.body)) {
1765
+ return;
1766
+ }
1767
+ if (!kept.depends(each.body)) {
1768
+ return;
1769
+ }
1770
+ each.body = kept.value(each.body);
1771
+ }
1580
1772
  function thunk(expression) {
1581
1773
  const arrow = t.arrowFunctionExpression([], expression);
1582
1774
  arrow[CHILD_THUNK] = true;
@@ -1637,7 +1829,9 @@ function buildPlugins(options) {
1637
1829
  {
1638
1830
  packageName: options.packageName,
1639
1831
  strictReactivity: options.strictReactivity,
1640
- devtools: options.devtools
1832
+ devtools: options.devtools,
1833
+ ssr: options.ssr,
1834
+ hydratable: options.hydratable
1641
1835
  }
1642
1836
  ]);
1643
1837
  return plugins;
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  firsthandPlugin,
4
4
  stableId,
5
5
  transform
6
- } from "./chunk-NFKHWAYO.js";
6
+ } from "./chunk-GUVVHV7H.js";
7
7
  export {
8
8
  compileModule,
9
9
  firsthandPlugin,
@@ -22,6 +22,10 @@ type FirsthandState = {
22
22
  views: Map<string, t.Identifier>;
23
23
  /** Every function markup was written inside, for resolving tags locally. */
24
24
  viewNodes: Set<t.Node>;
25
+ /** Whether this module is being compiled for a server render. */
26
+ ssr: boolean;
27
+ /** Whether this module's output has to be able to adopt server markup. */
28
+ hydratable: boolean;
25
29
  /** Functions that run again as a whole, and where each keeps its sites. */
26
30
  runs: Map<t.Node, RunContext>;
27
31
  };
@@ -71,6 +75,26 @@ export type FirsthandPluginOptions = {
71
75
  * production build emits nothing.
72
76
  */
73
77
  devtools?: boolean;
78
+ /**
79
+ * Compile for a server render.
80
+ *
81
+ * The same source, emitted against `@firsthandjs/server/internal` instead of
82
+ * `@firsthandjs/dom/internal`: markup is built as a string rather than as
83
+ * nodes, and the things a server cannot do — listeners, refs, retained
84
+ * sites — are not emitted at all.
85
+ *
86
+ * The Vite plugin sets this from the bundler's own `ssr` flag, so an
87
+ * application configures nothing.
88
+ */
89
+ ssr?: boolean;
90
+ /**
91
+ * Emit navigation that can walk server markup.
92
+ *
93
+ * An application that hydrates needs it; one that does not should leave it
94
+ * off, because it turns two property reads per dynamic position into two
95
+ * calls. The Vite plugin sets it for a project that has a server build.
96
+ */
97
+ hydratable?: boolean;
74
98
  };
75
99
  export default function firsthandPlugin(_api: unknown, options?: FirsthandPluginOptions): PluginObject;
76
100
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../src/transform.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAc,MAAM,aAAa,CAAC;AAE5D,OAAO,KAAK,CAAC,MAAM,cAAc,CAAC;AAelC,KAAK,cAAc,GAAG;IACpB,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC;IACnC,SAAS,EAAE,CAAC,CAAC,kBAAkB,EAAE,CAAC;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC;IACjC,4EAA4E;IAC5E,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACvB,2EAA2E;IAC3E,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;CAC/B,CAAC;AAEF;;;;;;;;;GASG;AACH,KAAK,UAAU,GAAG;IAChB,6EAA6E;IAC7E,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC;IACb,KAAK,EAAE,CAAC,CAAC,UAAU,CAAC;IACpB,IAAI,EAAE,MAAM,MAAM,CAAC;CACpB,CAAC;AAyBF,OAAO,QAAQ,aAAa,CAAC;IAC3B,UAAU,UAAU;QAClB,SAAS,EAAE,cAAc,CAAC;KAC3B;CACF;AA2BD,MAAM,MAAM,sBAAsB,GAAG;IACnC,sEAAsE;IACtE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;;OAQG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,eAAe,CACrC,IAAI,EAAE,OAAO,EACb,OAAO,GAAE,sBAA2B,GACnC,YAAY,CAmEd"}
1
+ {"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../src/transform.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAc,MAAM,aAAa,CAAC;AAE5D,OAAO,KAAK,CAAC,MAAM,cAAc,CAAC;AAgBlC,KAAK,cAAc,GAAG;IACpB,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC;IACnC,SAAS,EAAE,CAAC,CAAC,kBAAkB,EAAE,CAAC;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC;IACjC,4EAA4E;IAC5E,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACvB,iEAAiE;IACjE,GAAG,EAAE,OAAO,CAAC;IACb,0EAA0E;IAC1E,UAAU,EAAE,OAAO,CAAC;IACpB,2EAA2E;IAC3E,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;CAC/B,CAAC;AAEF;;;;;;;;;GASG;AACH,KAAK,UAAU,GAAG;IAChB,6EAA6E;IAC7E,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC;IACb,KAAK,EAAE,CAAC,CAAC,UAAU,CAAC;IACpB,IAAI,EAAE,MAAM,MAAM,CAAC;CACpB,CAAC;AAyBF,OAAO,QAAQ,aAAa,CAAC;IAC3B,UAAU,UAAU;QAClB,SAAS,EAAE,cAAc,CAAC;KAC3B;CACF;AA2BD,MAAM,MAAM,sBAAsB,GAAG;IACnC,sEAAsE;IACtE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;;OAQG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;;;;;;OAUG;IACH,GAAG,CAAC,EAAE,OAAO,CAAC;IACd;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,eAAe,CACrC,IAAI,EAAE,OAAO,EACb,OAAO,GAAE,sBAA2B,GACnC,YAAY,CAiFd"}
package/dist/vite.d.ts CHANGED
@@ -7,7 +7,9 @@ export type VitePluginLike = {
7
7
  configResolved(config: {
8
8
  command: string;
9
9
  }): void;
10
- transform(code: string, id: string): {
10
+ transform(code: string, id: string, options?: {
11
+ ssr?: boolean | undefined;
12
+ }): {
11
13
  code: string;
12
14
  map: SourceMap | null;
13
15
  } | null;
@@ -1 +1 @@
1
- {"version":3,"file":"vite.d.ts","sourceRoot":"","sources":["../src/vite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;AACzD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAE7D,0FAA0F;AAC1F,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,KAAK,CAAC;IACf,cAAc,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAClD,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,SAAS,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;CACrF,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,oBAAoB,GAAG,sBAAsB,GAAG;IAC1D;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7B,CAAC;AAEF,wBAAgB,SAAS,CAAC,OAAO,GAAE,oBAAyB,GAAG,cAAc,CAkC5E"}
1
+ {"version":3,"file":"vite.d.ts","sourceRoot":"","sources":["../src/vite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;AACzD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAE7D,0FAA0F;AAC1F,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,KAAK,CAAC;IACf,cAAc,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAClD,SAAS,CACP,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EAIV,OAAO,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;KAAE,GACtC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,SAAS,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;CACnD,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,oBAAoB,GAAG,sBAAsB,GAAG;IAC1D;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7B,CAAC;AAEF,wBAAgB,SAAS,CAAC,OAAO,GAAE,oBAAyB,GAAG,cAAc,CAsC5E"}
package/dist/vite.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  compileModule
3
- } from "./chunk-NFKHWAYO.js";
3
+ } from "./chunk-GUVVHV7H.js";
4
4
 
5
5
  // packages/compiler/src/vite.ts
6
6
  function firsthand(options = {}) {
@@ -11,7 +11,7 @@ function firsthand(options = {}) {
11
11
  configResolved(config) {
12
12
  serving = config.command === "serve";
13
13
  },
14
- transform(code, id) {
14
+ transform(code, id, hook) {
15
15
  const file = id.split("?")[0];
16
16
  if (!file.endsWith(".tsx") && !file.endsWith(".jsx")) {
17
17
  return null;
@@ -27,7 +27,11 @@ function firsthand(options = {}) {
27
27
  typescript: file.endsWith(".tsx"),
28
28
  devtools: serving,
29
29
  sourceMaps: true,
30
- ...options
30
+ ...options,
31
+ // The bundler already knows which build this is. An explicit `ssr`
32
+ // option still wins, because a project that compiles a module by hand
33
+ // has its own reasons.
34
+ ssr: options.ssr ?? hook?.ssr === true
31
35
  });
32
36
  }
33
37
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@firsthandjs/compiler",
3
- "version": "0.8.0",
3
+ "version": "0.9.1",
4
4
  "description": "Build-time TSX transform for Firsthand: static markup into templates, dynamic expressions into DOM parts.",
5
5
  "license": "MIT",
6
6
  "type": "module",