@solidjs/babel-plugin 2.0.0-rc.19 → 2.0.0-rc.20

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.
@@ -7,4 +7,4 @@ src/shared/transform.ts -> src/dom/element.ts -> src/universal/element.ts -> src
7
7
  src/shared/transform.ts -> src/ssr/element.ts -> src/shared/transform.ts
8
8
  src/shared/transform.ts -> src/shared/component.ts -> src/shared/transform.ts
9
9
  src/shared/transform.ts -> src/shared/fragment.ts -> src/shared/transform.ts
10
- created index.js in 2.2s
10
+ created index.js in 3.1s
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @solidjs/babel-plugin
2
2
 
3
+ ## 2.0.0-rc.20
4
+
5
+ ### Patch Changes
6
+
7
+ - 56683ea: SSR templates write characters above U+00FF in static text and quoted attribute values as numeric character references (`→` becomes `&#8594;`), as do the static attributes baked into a spread element's attribute string. One character above U+00FF in a template made V8 store the whole rendered page as a two-byte string, which roughly doubled the cost of flattening and UTF-8 encoding the response (#4328). Latin-1 characters stay literal. Tag internals, comments, raw-text bodies such as `<script>` and `<style>`, and the children of a spread `<script>` or `<style>` keep their characters, since browsers do not decode references there. Client output is unchanged.
8
+
3
9
  ## 2.0.0-rc.19
4
10
 
5
11
  ### Patch Changes
package/README.md CHANGED
@@ -4,6 +4,8 @@ Solid 2.0's Babel compiler integration. Configure this plugin once in a Babel pi
4
4
 
5
5
  The native Oxc compiler — [`@solidjs/compiler`](../compiler) — is the default in `vite-plugin-solid`. Use this plugin when you need a Babel pipeline (or as the JavaScript fallback).
6
6
 
7
+ It runs on `@babel/core` 7 (7.20.12 or later) and 8.
8
+
7
9
  > **Solid 2.0 (Release Candidate).** Pin exact versions.
8
10
 
9
11
  ## Features
package/index.js CHANGED
@@ -4055,13 +4055,13 @@ wrap)
4055
4055
  }
4056
4056
 
4057
4057
  let template, id;
4058
+ const raw = Array.isArray(result.template) ? result.template : [result.template];
4059
+ const parts = result.rawText ? raw : asciiTemplateParts(raw);
4058
4060
 
4059
- if (!Array.isArray(result.template)) {
4060
- template = t__namespace.stringLiteral(result.template);
4061
- } else if (result.template.length === 1) {
4062
- template = t__namespace.stringLiteral(result.template[0]);
4061
+ if (parts.length === 1) {
4062
+ template = t__namespace.stringLiteral(parts[0]);
4063
4063
  } else {
4064
- const strings = result.template.map((tmpl) => t__namespace.stringLiteral(tmpl));
4064
+ const strings = parts.map((tmpl) => t__namespace.stringLiteral(tmpl));
4065
4065
  template = t__namespace.arrayExpression(strings);
4066
4066
  }
4067
4067
 
@@ -4171,6 +4171,132 @@ wrap)
4171
4171
  );
4172
4172
  }
4173
4173
 
4174
+
4175
+
4176
+
4177
+
4178
+
4179
+
4180
+
4181
+
4182
+
4183
+
4184
+ // Browsers do not decode references in raw-text bodies, so those keep their characters.
4185
+ const rawTextElements = new Set([
4186
+ "script",
4187
+ "style",
4188
+ "noscript",
4189
+ "iframe",
4190
+ "noembed",
4191
+ "noframes",
4192
+ "xmp",
4193
+ // `<plaintext>` has no end tag.
4194
+ "plaintext"]
4195
+ );
4196
+ // Latin-1 already keeps a V8 string one-byte, and `&#128;`-`&#159;` decode to other characters.
4197
+ const nonLatin1 = /[^\x00-\xff]/;
4198
+ const preservedOpens = [
4199
+ ["<!--", "-->"],
4200
+ ["<![CDATA[", "]]>"],
4201
+ ["<!", ">"],
4202
+ ["<?", ">"]];
4203
+
4204
+ const tagName = /[^\t\n\f\r />]*/y;
4205
+ const endsTagName = (next) => next === undefined || /[\t\n\f\r />]/.test(next);
4206
+
4207
+ /** Characters above U+00FF outside tags, comments and raw text become `&#N;`, keeping SSR output one-byte in V8. */
4208
+ function asciiTemplateParts(parts) {
4209
+ return asciiParts(parts, { kind: "text" });
4210
+ }
4211
+
4212
+ /** `asciiTemplateParts` for a spread element's static attribute markup. */
4213
+ function asciiAttributeMarkup(markup) {
4214
+ return nonLatin1.test(markup) ? asciiParts([markup], { kind: "tag" })[0] : markup;
4215
+ }
4216
+
4217
+ // State carries across parts because holes can split a tag or a raw-text body.
4218
+ function asciiParts(parts, state) {
4219
+ if (!parts.some((part) => nonLatin1.test(part))) return parts;
4220
+ return parts.map((part) => {
4221
+ let out = "";
4222
+ let i = 0;
4223
+ while (i < part.length) {
4224
+ const ch = String.fromCodePoint(part.codePointAt(i));
4225
+ let len = ch.length;
4226
+ if (state.kind === "text") {
4227
+ const open = preservedOpens.find(([open]) => part.startsWith(open, i));
4228
+ if (open) {
4229
+ state = { kind: "preserve", end: open[1] };
4230
+ len = open[0].length;
4231
+ } else if (ch === "<") {
4232
+ const closing = part[i + 1] === "/";
4233
+ const start = i + (closing ? 2 : 1);
4234
+ if (/[a-z]/i.test(part[start] ?? "")) {
4235
+ tagName.lastIndex = start;
4236
+ const name = tagName.exec(part)[0].toLowerCase();
4237
+ state = {
4238
+ kind: "tag",
4239
+ raw:
4240
+ closing || !rawTextElements.has(name) ?
4241
+ undefined :
4242
+ name === "plaintext" ?
4243
+ "" :
4244
+ `</${name}`,
4245
+ value: false
4246
+ };
4247
+ } else if (closing) {
4248
+ state = { kind: "preserve", end: ">" };
4249
+ len = 2;
4250
+ }
4251
+ }
4252
+ out += len === ch.length ? toAscii(ch) : part.slice(i, i + len);
4253
+ } else if (state.kind === "tag") {
4254
+ if (state.value && (ch === '"' || ch === "'"))
4255
+ state = { kind: "quoted", quote: ch, raw: state.raw };else
4256
+ if (ch === ">")
4257
+ state =
4258
+ state.raw !== undefined ?
4259
+ { kind: "raw", close: state.raw, escaped: false } :
4260
+ { kind: "text" };else
4261
+
4262
+ state = {
4263
+ kind: "tag",
4264
+ raw: state.raw,
4265
+ value: ch === "=" || !!state.value && /[\t\n\f\r ]/.test(ch)
4266
+ };
4267
+ out += ch;
4268
+ } else if (state.kind === "quoted") {
4269
+ if (ch === state.quote) state = { kind: "tag", raw: state.raw };
4270
+ out += toAscii(ch);
4271
+ } else if (state.kind === "preserve") {
4272
+ if (part.startsWith(state.end, i)) {
4273
+ len = state.end.length;
4274
+ state = { kind: "text" };
4275
+ }
4276
+ out += part.slice(i, i + len);
4277
+ } else {
4278
+ const end = i + state.close.length;
4279
+ if (state.close === "</script" && part.startsWith("<!--", i))
4280
+ state = { ...state, escaped: true };else
4281
+ if (
4282
+ !state.escaped &&
4283
+ state.close !== "" &&
4284
+ part.slice(i, end).toLowerCase() === state.close &&
4285
+ endsTagName(part[end]))
4286
+
4287
+ state = { kind: "tag" };
4288
+ out += ch;
4289
+ }
4290
+ i += len;
4291
+ }
4292
+ return out;
4293
+ });
4294
+ }
4295
+
4296
+ function toAscii(ch) {
4297
+ return ch.charCodeAt(0) <= 0xff ? ch : `&#${ch.codePointAt(0)};`;
4298
+ }
4299
+
4174
4300
  function appendTemplates(path, templates) {
4175
4301
  const declarators = templates.map((template) => {
4176
4302
  return t__namespace.variableDeclarator(template.id, template.template);
@@ -5738,6 +5864,7 @@ path,
5738
5864
  const allocatesIds = hydratable && canChildSlotAllocateIds(path);
5739
5865
  const child = transformNode(path, { doNotEscape });
5740
5866
  if (!child) return memo;
5867
+ if (rawTextElements.has(tagName)) child.rawText = true;
5741
5868
  if (markers && child.exprs.length && !child.spreadElement)
5742
5869
  memo.push(t.stringLiteral("<!--$-->"));
5743
5870
  if (child.exprs.length && !doNotEscape && !child.spreadElement)
@@ -6016,7 +6143,7 @@ node)
6016
6143
  text = trimWhitespace(text);
6017
6144
  if (key === "style") text = text.replace(/; /g, ";").replace(/: /g, ":");
6018
6145
  }
6019
- return text === "" ? ` ${key}` : ` ${key}="${escapeHTML(text, true)}"`;
6146
+ return text === "" ? ` ${key}` : asciiAttributeMarkup(` ${key}="${escapeHTML(text, true)}"`);
6020
6147
  }
6021
6148
  if (t.isJSXEmptyExpression(literal) || t.isJSXElement(literal) || t.isJSXFragment(literal))
6022
6149
  return undefined;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@solidjs/babel-plugin",
3
3
  "description": "Babel compiler plugin for Solid templates",
4
- "version": "2.0.0-rc.19",
4
+ "version": "2.0.0-rc.20",
5
5
  "author": "Ryan Carniato",
6
6
  "license": "MIT",
7
7
  "repository": {