vite-plugin-react-shopify 2.1.0 → 2.1.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.
Files changed (2) hide show
  1. package/dist/index.js +86 -22
  2. package/package.json +4 -2
package/dist/index.js CHANGED
@@ -394,32 +394,75 @@ import fs2 from "fs";
394
394
  import path6 from "path";
395
395
  import { createRequire } from "module";
396
396
 
397
- // src/ssg/hydration-fix.ts
397
+ // src/hydration-fix/index.ts
398
+ import { parseSync } from "oxc-parser";
399
+ import { walk } from "oxc-walker";
398
400
  var log4 = logger("hydration-fix");
399
401
  function autoFixAdjacentText(source, filePath) {
400
- let fixCount = 0;
401
- const lines = source.split("\n");
402
- const fixed = [];
403
- for (let i = 0; i < lines.length; i++) {
404
- const line = lines[i];
405
- const replaced = line.replace(
406
- /<(\w+)([^>]*?)>([^<]*?\{[^}]*\}[^<]*?)<\/\1>/g,
407
- (match, tagName, attrs, content) => {
408
- const trimmed = content.trim();
409
- if (!needsFix(trimmed)) return match;
410
- fixCount++;
411
- const tpl = trimmed.replace(/\{([^}]+)\}/g, "${$1}");
412
- return `<${tagName}${attrs}>{\`${tpl}\`}</${tagName}>`;
402
+ const parseResult = parseSync(filePath, source);
403
+ if (parseResult.errors.length > 0) {
404
+ log4.debug("OXC parse errors for %s, skipping hydration fix", filePath);
405
+ return { result: source, fixCount: 0 };
406
+ }
407
+ const replacements = [];
408
+ walk(parseResult.program, {
409
+ enter(node) {
410
+ if (node.type === "JSXElement" || node.type === "JSXFragment") {
411
+ const children = node.children;
412
+ if (children.length > 0) {
413
+ processChildren(children, source, replacements);
414
+ }
413
415
  }
414
- );
415
- fixed.push(replaced);
416
+ }
417
+ });
418
+ if (replacements.length === 0) {
419
+ return { result: source, fixCount: 0 };
416
420
  }
417
- if (fixCount > 0) {
418
- log4.warn(
419
- `auto-fixed ${fixCount} adjacent text+expression issue(s) in ${filePath}`
420
- );
421
+ replacements.sort((a, b) => b.start - a.start);
422
+ let fixed = source;
423
+ for (const { start, end, replacement } of replacements) {
424
+ fixed = fixed.slice(0, start) + replacement + fixed.slice(end);
425
+ }
426
+ log4.warn(
427
+ `auto-fixed ${replacements.length} adjacent text+expression issue(s) in ${filePath}`
428
+ );
429
+ return { result: fixed, fixCount: replacements.length };
430
+ }
431
+ function processChildren(children, source, replacements) {
432
+ let i = 0;
433
+ while (i < children.length) {
434
+ if (children[i].type !== "JSXText" && children[i].type !== "JSXExpressionContainer") {
435
+ i++;
436
+ continue;
437
+ }
438
+ let runEnd = i;
439
+ let hasText = children[i].type === "JSXText";
440
+ let hasExpr = children[i].type === "JSXExpressionContainer";
441
+ while (runEnd + 1 < children.length && (children[runEnd + 1].type === "JSXText" || children[runEnd + 1].type === "JSXExpressionContainer")) {
442
+ runEnd++;
443
+ if (children[runEnd].type === "JSXText") hasText = true;
444
+ if (children[runEnd].type === "JSXExpressionContainer") hasExpr = true;
445
+ }
446
+ if (!hasText || !hasExpr) {
447
+ i = runEnd + 1;
448
+ continue;
449
+ }
450
+ const sliceStart = children[i].start;
451
+ const sliceEnd = children[runEnd].end;
452
+ const runText = source.slice(sliceStart, sliceEnd);
453
+ const trimmed = runText.trim();
454
+ if (!needsFix(trimmed)) {
455
+ i = runEnd + 1;
456
+ continue;
457
+ }
458
+ const tpl = trimmed.replace(/\{([^}]+)\}/g, "${$1}");
459
+ replacements.push({
460
+ start: sliceStart,
461
+ end: sliceEnd,
462
+ replacement: `{\`${tpl}\`}`
463
+ });
464
+ i = runEnd + 1;
421
465
  }
422
- return { result: fixed.join("\n"), fixCount };
423
466
  }
424
467
  function needsFix(content) {
425
468
  const trimmed = content.trim();
@@ -485,7 +528,8 @@ async function bundleEntry(entry, projectRoot, sourceDir) {
485
528
  if (fixCount2 > 0) {
486
529
  return { contents: result, loader: args.path.endsWith(".tsx") ? "tsx" : "jsx" };
487
530
  }
488
- } catch {
531
+ } catch (e) {
532
+ log5.debug("SSG hydration-fix failed for %s: %s", args.path, e);
489
533
  }
490
534
  return void 0;
491
535
  });
@@ -980,6 +1024,25 @@ function writeImportMapSnippet(options) {
980
1024
  fs4.writeFileSync(snippetPath, content);
981
1025
  }
982
1026
 
1027
+ // src/hydration-fix/vite-plugin.ts
1028
+ import path11 from "path";
1029
+ function hydrationFix(options) {
1030
+ const sourceDir = path11.resolve(options.themeRoot, options.sourceCodeDir);
1031
+ return {
1032
+ name: "vite-plugin-shopify:hydration-fix",
1033
+ enforce: "pre",
1034
+ transform(code, id) {
1035
+ if (!/\.(tsx|jsx)$/.test(id)) return;
1036
+ if (!id.startsWith(sourceDir)) return;
1037
+ const { result, fixCount } = autoFixAdjacentText(code, id);
1038
+ if (fixCount > 0) {
1039
+ return result;
1040
+ }
1041
+ return;
1042
+ }
1043
+ };
1044
+ }
1045
+
983
1046
  // src/index.ts
984
1047
  var vitePluginShopify = (options = {}) => {
985
1048
  const resolvedOptions = resolveOptions(options);
@@ -987,6 +1050,7 @@ var vitePluginShopify = (options = {}) => {
987
1050
  enableDebug();
988
1051
  }
989
1052
  return [
1053
+ hydrationFix(resolvedOptions),
990
1054
  shopifyConfig(resolvedOptions),
991
1055
  shopifyEntries(resolvedOptions),
992
1056
  shopifySSG(resolvedOptions)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vite-plugin-react-shopify",
3
- "version": "2.1.0",
3
+ "version": "2.1.1",
4
4
  "description": "Vite plugin for React Shopify themes",
5
5
  "files": [
6
6
  "dist"
@@ -19,7 +19,9 @@
19
19
  },
20
20
  "dependencies": {
21
21
  "debug": "^4.4.0",
22
- "fast-glob": "^3.3.0"
22
+ "fast-glob": "^3.3.0",
23
+ "oxc-parser": "^0.133.0",
24
+ "oxc-walker": "^1.0.0"
23
25
  },
24
26
  "devDependencies": {
25
27
  "@types/debug": "^4.1.0",