@firsthandjs/compiler 0.8.0 → 0.9.0

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,13 +904,20 @@ 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
923
  const children = compileChildren(node.children, state);
@@ -927,6 +946,9 @@ function compileComponent(path, state) {
927
946
  return keptChild(state, run, make, cells);
928
947
  }
929
948
  if (isLocalView(path, state)) {
949
+ if (state.firsthand.ssr) {
950
+ return make;
951
+ }
930
952
  const parent = path.parentPath;
931
953
  if (parent.isArrowFunctionExpression() && parent.node.body === node && CHILD_THUNK in parent.node) {
932
954
  return make;
@@ -973,6 +995,40 @@ function keptChild(state, run, make, cells) {
973
995
  ];
974
996
  return t.callExpression(generated(t.arrowFunctionExpression([], t.blockStatement(body))), []);
975
997
  }
998
+ function isPure(node) {
999
+ switch (node.type) {
1000
+ case "Identifier":
1001
+ case "ThisExpression":
1002
+ case "StringLiteral":
1003
+ case "NumericLiteral":
1004
+ case "BooleanLiteral":
1005
+ case "NullLiteral":
1006
+ case "BigIntLiteral":
1007
+ case "RegExpLiteral":
1008
+ return true;
1009
+ case "MemberExpression":
1010
+ case "OptionalMemberExpression":
1011
+ return isPure(node.object) && (!node.computed || isPure(node.property));
1012
+ case "UnaryExpression":
1013
+ return node.operator !== "delete" && isPure(node.argument);
1014
+ case "BinaryExpression":
1015
+ return isPure(node.left) && isPure(node.right);
1016
+ case "LogicalExpression":
1017
+ return isPure(node.left) && isPure(node.right);
1018
+ case "ConditionalExpression":
1019
+ return isPure(node.test) && isPure(node.consequent) && isPure(node.alternate);
1020
+ case "TemplateLiteral":
1021
+ return node.expressions.every((one) => t.isExpression(one) && isPure(one));
1022
+ case "ArrayExpression":
1023
+ return node.elements.every((one) => one === null || t.isExpression(one) && isPure(one));
1024
+ case "ObjectExpression":
1025
+ return node.properties.every(
1026
+ (one) => t.isObjectProperty(one) && !one.computed && t.isExpression(one.value) && isPure(one.value)
1027
+ );
1028
+ default:
1029
+ return false;
1030
+ }
1031
+ }
976
1032
  function propertyKey(name) {
977
1033
  return t.isValidIdentifier(name) ? t.identifier(name) : t.stringLiteral(name);
978
1034
  }
@@ -996,6 +1052,120 @@ function attributeValue(attribute) {
996
1052
  function isStaticValue(value) {
997
1053
  return t.isStringLiteral(value) || t.isNumericLiteral(value) || t.isBooleanLiteral(value) || t.isNullLiteral(value);
998
1054
  }
1055
+ function pushText(markup, text) {
1056
+ markup.parts[markup.parts.length - 1] = markup.parts[markup.parts.length - 1] + text;
1057
+ }
1058
+ function pushHole(markup, value) {
1059
+ markup.values.push(value);
1060
+ markup.parts.push("");
1061
+ }
1062
+ function compileMarkup(path, state) {
1063
+ const markup = { parts: [""], values: [] };
1064
+ emitMarkupElement(path.node, markup, state);
1065
+ if (markup.values.length === 0) {
1066
+ return t.callExpression(runtime(state, "ssr"), [
1067
+ t.arrayExpression([t.stringLiteral(markup.parts[0])])
1068
+ ]);
1069
+ }
1070
+ return t.callExpression(runtime(state, "ssr"), [
1071
+ t.arrayExpression(markup.parts.map((part) => t.stringLiteral(part))),
1072
+ ...markup.values
1073
+ ]);
1074
+ }
1075
+ function emitMarkupElement(node, markup, state) {
1076
+ const name = node.openingElement.name;
1077
+ if (!t.isJSXIdentifier(name)) {
1078
+ const namespaced = name;
1079
+ throw new Error(
1080
+ `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.`
1081
+ );
1082
+ }
1083
+ const tag = name.name;
1084
+ pushText(markup, `<${tag}`);
1085
+ for (const attribute of node.openingElement.attributes) {
1086
+ emitMarkupAttribute(attribute, markup, state);
1087
+ }
1088
+ pushText(markup, ">");
1089
+ emitMarkupChildren(node.children, markup, state);
1090
+ if (!VOID_ELEMENTS.has(tag)) {
1091
+ pushText(markup, `</${tag}>`);
1092
+ }
1093
+ }
1094
+ function emitMarkupAttribute(attribute, markup, state) {
1095
+ if (t.isJSXSpreadAttribute(attribute)) {
1096
+ pushHole(markup, t.callExpression(runtime(state, "spread"), [attribute.argument]));
1097
+ return;
1098
+ }
1099
+ const name = attributeName(attribute);
1100
+ const value = attributeValue(attribute);
1101
+ if (name === "ref" || name.startsWith("on") && name.length > 2 && /[A-Z:]/.test(name[2])) {
1102
+ return;
1103
+ }
1104
+ if (name === "key") {
1105
+ return;
1106
+ }
1107
+ if (value === null) {
1108
+ pushText(markup, ` ${name}=""`);
1109
+ return;
1110
+ }
1111
+ if (isStaticValue(value)) {
1112
+ if (t.isBooleanLiteral(value) && !value.value) {
1113
+ return;
1114
+ }
1115
+ if (t.isNullLiteral(value)) {
1116
+ return;
1117
+ }
1118
+ const literal = t.isStringLiteral(value) ? value.value : t.isNumericLiteral(value) ? String(value.value) : "";
1119
+ pushText(markup, ` ${name}="${escapeAttribute(literal)}"`);
1120
+ return;
1121
+ }
1122
+ pushHole(markup, markupAttributeCall(name, value, state));
1123
+ }
1124
+ function markupAttributeCall(name, value, state) {
1125
+ if (name.startsWith("prop:")) {
1126
+ return t.callExpression(runtime(state, "setProperty"), [t.stringLiteral(name.slice(5)), value]);
1127
+ }
1128
+ if (name.startsWith("attr:")) {
1129
+ return t.callExpression(runtime(state, "setAttribute"), [
1130
+ t.stringLiteral(name.slice(5)),
1131
+ value
1132
+ ]);
1133
+ }
1134
+ if (name === "class" || name === "className") {
1135
+ return t.callExpression(runtime(state, "setClass"), [value]);
1136
+ }
1137
+ if (name === "style") {
1138
+ return t.callExpression(runtime(state, "setStyle"), [value]);
1139
+ }
1140
+ if (BOOLEAN_PROPERTIES.has(name)) {
1141
+ return t.callExpression(runtime(state, "setBoolean"), [t.stringLiteral(name), value]);
1142
+ }
1143
+ if (DOM_PROPERTIES.has(name)) {
1144
+ return t.callExpression(runtime(state, "setProperty"), [t.stringLiteral(name), value]);
1145
+ }
1146
+ return t.callExpression(runtime(state, "setAttribute"), [t.stringLiteral(name), value]);
1147
+ }
1148
+ function emitMarkupChildren(children, markup, state) {
1149
+ const entries = planChildren(children);
1150
+ for (let i = 0; i < entries.length; i++) {
1151
+ const entry = entries[i];
1152
+ if (entry.kind === "text") {
1153
+ pushText(markup, escapeText(entry.text));
1154
+ continue;
1155
+ }
1156
+ if (entry.kind === "element") {
1157
+ emitMarkupElement(entry.element, markup, state);
1158
+ continue;
1159
+ }
1160
+ if (entries.length > 1) {
1161
+ pushText(markup, "<!--[-->");
1162
+ }
1163
+ pushHole(markup, t.callExpression(runtime(state, "child"), [entry.expression]));
1164
+ if (i !== entries.length - 1) {
1165
+ pushText(markup, "<!---->");
1166
+ }
1167
+ }
1168
+ }
999
1169
  function compileTemplate(path, state) {
1000
1170
  let names = 0;
1001
1171
  const statements = [];
@@ -1404,7 +1574,7 @@ function emitChildren(children, build, self, state) {
1404
1574
  const id = build.next();
1405
1575
  build.statements.push(
1406
1576
  t.variableDeclaration("const", [
1407
- t.variableDeclarator(id, navigate(self, previous, previousIndex, index))
1577
+ t.variableDeclarator(id, navigate(self, previous, previousIndex, index, state))
1408
1578
  ])
1409
1579
  );
1410
1580
  previous = id;
@@ -1490,18 +1660,21 @@ function needsReference(element) {
1490
1660
  }
1491
1661
  return false;
1492
1662
  }
1493
- function navigate(self, previous, previousIndex, index) {
1663
+ function navigate(self, previous, previousIndex, index, state) {
1664
+ const hydratable = state.firsthand.hydratable;
1665
+ const first = hydratable ? runtime(state, "first") : null;
1666
+ const next = hydratable ? runtime(state, "next") : null;
1494
1667
  let expression;
1495
1668
  let steps;
1496
1669
  if (previous === null) {
1497
- expression = t.memberExpression(t.cloneNode(self), t.identifier("firstChild"));
1670
+ expression = hydratable ? t.callExpression(first, [t.cloneNode(self)]) : t.memberExpression(t.cloneNode(self), t.identifier("firstChild"));
1498
1671
  steps = index;
1499
1672
  } else {
1500
1673
  expression = t.cloneNode(previous);
1501
1674
  steps = index - previousIndex;
1502
1675
  }
1503
1676
  for (let i = 0; i < steps; i++) {
1504
- expression = t.memberExpression(expression, t.identifier("nextSibling"));
1677
+ expression = hydratable ? t.callExpression(next, [expression]) : t.memberExpression(expression, t.identifier("nextSibling"));
1505
1678
  }
1506
1679
  return expression;
1507
1680
  }
@@ -1567,6 +1740,8 @@ function compileChildren(children, state) {
1567
1740
  result.push(t.stringLiteral(entry.text));
1568
1741
  } else if (entry.kind === "element") {
1569
1742
  result.push(entry.element);
1743
+ } else if (state.firsthand.ssr) {
1744
+ result.push(entry.expression);
1570
1745
  } else if (entry.kind === "list") {
1571
1746
  result.push(t.callExpression(runtime(state, "part"), [entry.expression]));
1572
1747
  } else {
@@ -1637,7 +1812,9 @@ function buildPlugins(options) {
1637
1812
  {
1638
1813
  packageName: options.packageName,
1639
1814
  strictReactivity: options.strictReactivity,
1640
- devtools: options.devtools
1815
+ devtools: options.devtools,
1816
+ ssr: options.ssr,
1817
+ hydratable: options.hydratable
1641
1818
  }
1642
1819
  ]);
1643
1820
  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-ACKKPAGI.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-ACKKPAGI.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.0",
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",