@unlockable/vite-plugin-unlock 0.1.4 → 0.1.6

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/dist/index.cjs CHANGED
@@ -35,12 +35,12 @@ __export(src_exports, {
35
35
  module.exports = __toCommonJS(src_exports);
36
36
 
37
37
  // src/plugin.ts
38
- var import_path5 = __toESM(require("path"), 1);
39
- var import_fs4 = __toESM(require("fs"), 1);
38
+ var import_path6 = __toESM(require("path"), 1);
39
+ var import_fs5 = __toESM(require("fs"), 1);
40
40
 
41
41
  // src/config.ts
42
- var import_path = __toESM(require("path"), 1);
43
- var import_fs = __toESM(require("fs"), 1);
42
+ var import_path2 = __toESM(require("path"), 1);
43
+ var import_fs2 = __toESM(require("fs"), 1);
44
44
  var import_module = require("module");
45
45
 
46
46
  // src/constants.ts
@@ -60,6 +60,8 @@ var MAX_SCAN_DEPTH = 20;
60
60
  var PLUGIN_NAME = "vite-plugin-unlock";
61
61
 
62
62
  // src/utils.ts
63
+ var import_path = __toESM(require("path"), 1);
64
+ var import_fs = __toESM(require("fs"), 1);
63
65
  var PREFIX = `[${PLUGIN_NAME}]`;
64
66
  function createLogger(debug) {
65
67
  return {
@@ -85,33 +87,85 @@ function generateAlias(packageName) {
85
87
  const lastPart = parts[parts.length - 1];
86
88
  return `~${lastPart}`;
87
89
  }
90
+ function collectCjsDeps(packageDir) {
91
+ const pkgJsonPath = import_path.default.join(packageDir, "package.json");
92
+ if (!import_fs.default.existsSync(pkgJsonPath)) return [];
93
+ let pkgJson;
94
+ try {
95
+ pkgJson = JSON.parse(import_fs.default.readFileSync(pkgJsonPath, "utf-8"));
96
+ } catch {
97
+ return [];
98
+ }
99
+ const deps = pkgJson.dependencies;
100
+ if (!deps) return [];
101
+ const cjsDeps = [];
102
+ for (const depName of Object.keys(deps)) {
103
+ if (depName.startsWith("@types/")) continue;
104
+ const depParts = depName.startsWith("@") ? depName.split("/") : [depName];
105
+ const candidates = [
106
+ import_path.default.join(packageDir, "node_modules", ...depParts, "package.json"),
107
+ import_path.default.join(process.cwd(), "node_modules", ...depParts, "package.json")
108
+ ];
109
+ let depPkgJson = null;
110
+ for (const candidate of candidates) {
111
+ if (import_fs.default.existsSync(candidate)) {
112
+ try {
113
+ depPkgJson = JSON.parse(import_fs.default.readFileSync(candidate, "utf-8"));
114
+ } catch {
115
+ continue;
116
+ }
117
+ break;
118
+ }
119
+ }
120
+ if (!depPkgJson) continue;
121
+ if (depPkgJson.type === "module") continue;
122
+ if (!hasRootEntry(depPkgJson)) continue;
123
+ cjsDeps.push(depName);
124
+ }
125
+ return cjsDeps;
126
+ }
127
+ function hasRootEntry(pkgJson) {
128
+ const exports2 = pkgJson.exports;
129
+ if (exports2 !== void 0) {
130
+ if (exports2 === null) return false;
131
+ if (typeof exports2 === "string") return true;
132
+ if (typeof exports2 === "object" && !Array.isArray(exports2)) {
133
+ return "." in exports2;
134
+ }
135
+ return Array.isArray(exports2);
136
+ }
137
+ if (pkgJson.main || pkgJson.module) return true;
138
+ return false;
139
+ }
88
140
 
89
141
  // src/config.ts
90
142
  function findPackageSrcPath(packageName, srcDir) {
91
143
  const cwd = process.cwd();
92
144
  try {
93
- const req = (0, import_module.createRequire)(import_path.default.join(cwd, "package.json"));
94
- const pkgJsonPath = req.resolve(`${packageName}/package.json`);
95
- const pkgRoot = import_path.default.dirname(pkgJsonPath);
96
- const srcPath = import_path.default.join(pkgRoot, srcDir);
97
- if (import_fs.default.existsSync(srcPath)) return srcPath;
145
+ const req = (0, import_module.createRequire)(import_path2.default.join(cwd, "package.json"));
146
+ const pkgJsonPath = import_fs2.default.realpathSync(
147
+ req.resolve(`${packageName}/package.json`)
148
+ );
149
+ const pkgRoot = import_path2.default.dirname(pkgJsonPath);
150
+ const srcPath = import_path2.default.join(pkgRoot, srcDir);
151
+ if (import_fs2.default.existsSync(srcPath)) return srcPath;
98
152
  return pkgRoot;
99
153
  } catch {
100
154
  }
101
155
  const parts = packageName.startsWith("@") ? packageName.split("/") : [packageName];
102
156
  const candidates = [
103
- import_path.default.join(cwd, "node_modules", ...parts, srcDir),
104
- import_path.default.join(cwd, ".yalc", ...parts, srcDir)
157
+ import_path2.default.join(cwd, "node_modules", ...parts, srcDir),
158
+ import_path2.default.join(cwd, ".yalc", ...parts, srcDir)
105
159
  ];
106
160
  for (const dir of candidates) {
107
- if (import_fs.default.existsSync(dir)) return dir;
161
+ if (import_fs2.default.existsSync(dir)) return import_fs2.default.realpathSync(dir);
108
162
  }
109
163
  const rootCandidates = [
110
- import_path.default.join(cwd, "node_modules", ...parts),
111
- import_path.default.join(cwd, ".yalc", ...parts)
164
+ import_path2.default.join(cwd, "node_modules", ...parts),
165
+ import_path2.default.join(cwd, ".yalc", ...parts)
112
166
  ];
113
167
  for (const dir of rootCandidates) {
114
- if (import_fs.default.existsSync(dir)) return dir;
168
+ if (import_fs2.default.existsSync(dir)) return import_fs2.default.realpathSync(dir);
115
169
  }
116
170
  return null;
117
171
  }
@@ -120,22 +174,24 @@ function resolveTarget(input) {
120
174
  package: input,
121
175
  alias: generateAlias(input),
122
176
  srcDir: DEFAULT_SRC_DIR,
123
- srcPath: ""
177
+ srcPath: "",
178
+ packageDir: ""
124
179
  } : {
125
180
  package: input.package,
126
181
  alias: input.alias ?? generateAlias(input.package),
127
182
  srcDir: input.srcDir ?? DEFAULT_SRC_DIR,
128
183
  srcPath: "",
184
+ packageDir: "",
129
185
  entryRedirect: input.entryRedirect,
130
186
  hmr: input.hmr
131
187
  };
132
188
  const srcPath = findPackageSrcPath(target.package, target.srcDir);
133
189
  if (!srcPath) return null;
134
190
  target.srcPath = srcPath;
191
+ target.packageDir = srcPath.endsWith(import_path2.default.sep + target.srcDir) ? import_path2.default.resolve(srcPath, "..") : srcPath;
135
192
  if (target.entryRedirect && target.hmr) {
136
- const pkgDir = import_path.default.dirname(srcPath);
137
- const entryFile = import_path.default.resolve(pkgDir, target.entryRedirect.to);
138
- if (import_fs.default.existsSync(entryFile)) {
193
+ const entryFile = import_path2.default.resolve(target.packageDir, target.entryRedirect.to);
194
+ if (import_fs2.default.existsSync(entryFile)) {
139
195
  target.entryFilePath = entryFile;
140
196
  }
141
197
  }
@@ -145,8 +201,8 @@ var CONFIG_EXTENSIONS = [".tsx", ".ts", ".jsx", ".js"];
145
201
  function findConfigFile(basename, overrideDirs) {
146
202
  for (const dir of overrideDirs) {
147
203
  for (const ext of CONFIG_EXTENSIONS) {
148
- const p = import_path.default.resolve(dir, `${basename}${ext}`);
149
- if (import_fs.default.existsSync(p)) return p;
204
+ const p = import_path2.default.resolve(dir, `${basename}${ext}`);
205
+ if (import_fs2.default.existsSync(p)) return p;
150
206
  }
151
207
  }
152
208
  return null;
@@ -154,7 +210,7 @@ function findConfigFile(basename, overrideDirs) {
154
210
  function resolveOptions(options) {
155
211
  const extensions = options.extensions ?? DEFAULT_EXTENSIONS;
156
212
  const overrideInput = options.overrides ?? DEFAULT_OVERRIDE_DIR;
157
- const overrideDirs = (Array.isArray(overrideInput) ? overrideInput : [overrideInput]).map((dir) => import_path.default.resolve(process.cwd(), dir));
213
+ const overrideDirs = (Array.isArray(overrideInput) ? overrideInput : [overrideInput]).map((dir) => import_path2.default.resolve(process.cwd(), dir));
158
214
  const targets = [];
159
215
  for (const input of options.targets) {
160
216
  const resolved = resolveTarget(input);
@@ -177,29 +233,33 @@ function resolveOptions(options) {
177
233
  extensions,
178
234
  extensionSet: new Set(extensions),
179
235
  patches,
180
- hmrBoundaries: options.hmrBoundaries ?? []
236
+ hmrBoundaries: options.hmrBoundaries ?? [],
237
+ optimizeDeps: {
238
+ include: options.optimizeDeps?.include ?? []
239
+ },
240
+ autoOptimizeDeps: options.autoOptimizeDeps ?? true
181
241
  };
182
242
  }
183
243
 
184
244
  // src/scanner.ts
185
- var import_path2 = __toESM(require("path"), 1);
186
- var import_fs2 = __toESM(require("fs"), 1);
245
+ var import_path3 = __toESM(require("path"), 1);
246
+ var import_fs3 = __toESM(require("fs"), 1);
187
247
  function collectFiles(dir, extensionSet, depth = 0) {
188
248
  if (depth > MAX_SCAN_DEPTH) return [];
189
249
  const results = [];
190
250
  let entries;
191
251
  try {
192
- entries = import_fs2.default.readdirSync(dir, { withFileTypes: true });
252
+ entries = import_fs3.default.readdirSync(dir, { withFileTypes: true });
193
253
  } catch {
194
254
  return results;
195
255
  }
196
256
  for (const entry of entries) {
197
257
  if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
198
- const fullPath = import_path2.default.resolve(dir, entry.name);
258
+ const fullPath = import_path3.default.resolve(dir, entry.name);
199
259
  if (entry.isDirectory()) {
200
260
  results.push(...collectFiles(fullPath, extensionSet, depth + 1));
201
261
  } else if (entry.isFile()) {
202
- const ext = import_path2.default.extname(entry.name);
262
+ const ext = import_path3.default.extname(entry.name);
203
263
  if (extensionSet.has(ext)) {
204
264
  results.push(fullPath);
205
265
  }
@@ -217,7 +277,7 @@ function getOverrideKey(filePath, baseDir, match) {
217
277
  if (match === "path") {
218
278
  const normalizedBase = normalizePath(baseDir);
219
279
  const relative = normalizePath(
220
- import_path2.default.relative(normalizedBase, normalized)
280
+ import_path3.default.relative(normalizedBase, normalized)
221
281
  );
222
282
  return stripExtension(relative);
223
283
  }
@@ -248,7 +308,7 @@ function scanAllTargets(opts, logger) {
248
308
  return combined;
249
309
  }
250
310
  function detectNamespace(filePath, overrideDir) {
251
- const relative = normalizePath(import_path2.default.relative(overrideDir, filePath));
311
+ const relative = normalizePath(import_path3.default.relative(overrideDir, filePath));
252
312
  const scopedMatch = relative.match(/^(@[^/]+\/[^/]+)\//);
253
313
  if (scopedMatch) return scopedMatch[1];
254
314
  return null;
@@ -258,13 +318,13 @@ function scanOverrides(opts, logger) {
258
318
  const namespaced = /* @__PURE__ */ new Map();
259
319
  const targetPackages = new Set(opts.targets.map((t) => t.package));
260
320
  for (const dir of opts.overrideDirs) {
261
- if (!import_fs2.default.existsSync(dir)) continue;
321
+ if (!import_fs3.default.existsSync(dir)) continue;
262
322
  for (const fullPath of collectFiles(dir, opts.extensionSet).sort()) {
263
- const relative = normalizePath(import_path2.default.relative(dir, fullPath));
323
+ const relative = normalizePath(import_path3.default.relative(dir, fullPath));
264
324
  if (relative.split("/").some((part) => part.startsWith("_"))) continue;
265
325
  const ns = detectNamespace(fullPath, dir);
266
326
  if (ns && targetPackages.has(ns)) {
267
- const nsDir = import_path2.default.join(dir, ns);
327
+ const nsDir = import_path3.default.join(dir, ns);
268
328
  const key = getOverrideKey(fullPath, nsDir, opts.match);
269
329
  if (key && key !== "index") {
270
330
  if (!namespaced.has(ns)) namespaced.set(ns, /* @__PURE__ */ new Map());
@@ -284,8 +344,8 @@ function scanOverrides(opts, logger) {
284
344
  }
285
345
 
286
346
  // src/resolver.ts
287
- var import_path3 = __toESM(require("path"), 1);
288
- var import_fs3 = __toESM(require("fs"), 1);
347
+ var import_path4 = __toESM(require("path"), 1);
348
+ var import_fs4 = __toESM(require("fs"), 1);
289
349
  function findImporterTarget(importer, opts) {
290
350
  const norm = normalizePath(importer);
291
351
  for (const target of opts.targets) {
@@ -293,7 +353,7 @@ function findImporterTarget(importer, opts) {
293
353
  if (norm.startsWith(normSrc + "/") || norm === normSrc) {
294
354
  return target;
295
355
  }
296
- const pkgDir = normalizePath(import_path3.default.dirname(target.srcPath));
356
+ const pkgDir = normalizePath(import_path4.default.dirname(target.srcPath));
297
357
  if (norm.startsWith(pkgDir + "/")) {
298
358
  return target;
299
359
  }
@@ -306,11 +366,11 @@ function resolveEntryRedirect(resolvedId, opts, logger) {
306
366
  if (target.entryRedirect) {
307
367
  const fromPattern = normalizePath(target.entryRedirect.from);
308
368
  if (norm.endsWith(`/${fromPattern}`) || norm.includes(`/${fromPattern}`)) {
309
- const pkgDir = import_path3.default.dirname(target.srcPath);
310
- const srcEntry = import_path3.default.join(pkgDir, target.entryRedirect.to);
311
- if (import_fs3.default.existsSync(srcEntry)) {
369
+ const pkgDir = import_path4.default.dirname(target.srcPath);
370
+ const srcEntry = import_path4.default.join(pkgDir, target.entryRedirect.to);
371
+ if (import_fs4.default.existsSync(srcEntry)) {
312
372
  logger.info(
313
- `Entry redirect: ${import_path3.default.basename(resolvedId)} -> ${target.entryRedirect.to}`
373
+ `Entry redirect: ${import_path4.default.basename(resolvedId)} -> ${target.entryRedirect.to}`
314
374
  );
315
375
  return srcEntry;
316
376
  }
@@ -324,7 +384,7 @@ function resolveEntryRedirect(resolvedId, opts, logger) {
324
384
  /\/dist\/app\.(mjs|js)$/,
325
385
  "/src/app.tsx"
326
386
  );
327
- if (import_fs3.default.existsSync(srcEntry)) {
387
+ if (import_fs4.default.existsSync(srcEntry)) {
328
388
  logger.info(`Entry redirect (auto): dist/app -> src/app.tsx`);
329
389
  return srcEntry;
330
390
  }
@@ -335,11 +395,11 @@ function resolveEntryRedirect(resolvedId, opts, logger) {
335
395
  }
336
396
 
337
397
  // src/watcher.ts
338
- var import_path4 = __toESM(require("path"), 1);
398
+ var import_path5 = __toESM(require("path"), 1);
339
399
  function setupWatcher(server, state, opts, logger) {
340
400
  let debounceTimer = null;
341
401
  const handleStructuralChange = (filePath) => {
342
- const ext = import_path4.default.extname(filePath);
402
+ const ext = import_path5.default.extname(filePath);
343
403
  if (!opts.extensionSet.has(ext)) return;
344
404
  const normFile = normalizePath(filePath);
345
405
  const isOverrideFile = opts.overrideDirs.some(
@@ -405,14 +465,14 @@ function setupWatcher(server, state, opts, logger) {
405
465
  server.watcher.on("add", handleStructuralChange);
406
466
  server.watcher.on("unlink", handleStructuralChange);
407
467
  server.watcher.on("change", (filePath) => {
408
- const ext = import_path4.default.extname(filePath);
468
+ const ext = import_path5.default.extname(filePath);
409
469
  if (!opts.extensionSet.has(ext)) return;
410
470
  const normFile = normalizePath(filePath);
411
471
  const isOverrideFile = opts.overrideDirs.some(
412
472
  (dir) => normFile.startsWith(normalizePath(dir) + "/")
413
473
  );
414
474
  if (!isOverrideFile) return;
415
- const basename = stripExtension(import_path4.default.basename(filePath));
475
+ const basename = stripExtension(import_path5.default.basename(filePath));
416
476
  if (!basename) return;
417
477
  const isTrackedOverride = state.flatOverrides.has(basename) || [...state.namespacedOverrides.values()].some((m) => m.has(basename));
418
478
  if (!isTrackedOverride) return;
@@ -434,7 +494,7 @@ function setupWatcher(server, state, opts, logger) {
434
494
  });
435
495
  if (opts.patches.length > 0) {
436
496
  const handlePatchConfigStructural = (filePath) => {
437
- const basename = stripExtension(import_path4.default.basename(filePath));
497
+ const basename = stripExtension(import_path5.default.basename(filePath));
438
498
  if (!basename) return;
439
499
  const normFile = normalizePath(filePath);
440
500
  const isOverrideFile = opts.overrideDirs.some(
@@ -482,7 +542,7 @@ function invalidatePatchTarget(patch, server, logger) {
482
542
  if (mod.file && patch.target.test(normalizePath(mod.file))) {
483
543
  moduleGraph.invalidateModule(mod, /* @__PURE__ */ new Set(), timestamp, true);
484
544
  roots.add(mod);
485
- logger.info(`Invalidated patch target: ${import_path4.default.basename(mod.file)}`);
545
+ logger.info(`Invalidated patch target: ${import_path5.default.basename(mod.file)}`);
486
546
  }
487
547
  }
488
548
  const seen = /* @__PURE__ */ new Set();
@@ -591,6 +651,7 @@ function unlock(userOptions) {
591
651
  logger.info(`Patch: ${patch.configFile} (no config file found)`);
592
652
  }
593
653
  }
654
+ let hasExternalReactPlugin = false;
594
655
  return {
595
656
  name: PLUGIN_NAME,
596
657
  enforce: "pre",
@@ -599,7 +660,7 @@ function unlock(userOptions) {
599
660
  config.server.fs = config.server.fs || {};
600
661
  config.server.fs.allow = config.server.fs.allow || [];
601
662
  for (const dir of opts.overrideDirs) {
602
- config.server.fs.allow.push(import_path5.default.resolve(dir));
663
+ config.server.fs.allow.push(import_path6.default.resolve(dir));
603
664
  }
604
665
  config.optimizeDeps = config.optimizeDeps || {};
605
666
  config.optimizeDeps.exclude = config.optimizeDeps.exclude || [];
@@ -611,6 +672,30 @@ function unlock(userOptions) {
611
672
  );
612
673
  }
613
674
  }
675
+ if (opts.autoOptimizeDeps) {
676
+ const autoDeps = [];
677
+ for (const target of opts.targets) {
678
+ const cjsDeps = collectCjsDeps(target.packageDir);
679
+ for (const dep of cjsDeps) {
680
+ if (opts.targets.some((t) => t.package === dep)) continue;
681
+ if (!autoDeps.includes(dep)) autoDeps.push(dep);
682
+ }
683
+ }
684
+ if (autoDeps.length > 0) {
685
+ config.optimizeDeps.include = config.optimizeDeps.include || [];
686
+ config.optimizeDeps.include.push(...autoDeps);
687
+ logger.info(
688
+ `Auto-included ${autoDeps.length} CJS deps for pre-bundling`
689
+ );
690
+ }
691
+ }
692
+ if (opts.optimizeDeps.include.length > 0) {
693
+ config.optimizeDeps.include = config.optimizeDeps.include || [];
694
+ config.optimizeDeps.include.push(...opts.optimizeDeps.include);
695
+ }
696
+ if (config.optimizeDeps.include) {
697
+ config.optimizeDeps.include = [...new Set(config.optimizeDeps.include)];
698
+ }
614
699
  config.resolve = config.resolve || {};
615
700
  config.resolve.alias = config.resolve.alias || {};
616
701
  for (const target of opts.targets) {
@@ -625,8 +710,8 @@ function unlock(userOptions) {
625
710
  }
626
711
  }
627
712
  for (const target of opts.targets) {
628
- const entryFile = import_path5.default.join(target.srcPath, "app.tsx");
629
- if (import_fs4.default.existsSync(entryFile)) {
713
+ const entryFile = import_path6.default.join(target.srcPath, "app.tsx");
714
+ if (import_fs5.default.existsSync(entryFile)) {
630
715
  const existing = config.optimizeDeps.entries;
631
716
  if (Array.isArray(existing)) {
632
717
  existing.push(entryFile);
@@ -638,24 +723,34 @@ function unlock(userOptions) {
638
723
  }
639
724
  }
640
725
  },
726
+ configResolved(resolvedConfig) {
727
+ hasExternalReactPlugin = resolvedConfig.plugins.some(
728
+ (p) => p.name === "vite:react-babel" || p.name === "vite:react-swc" || p.name === "vite:react-refresh"
729
+ );
730
+ if (hasExternalReactPlugin) {
731
+ logger.info(
732
+ "React plugin detected \u2014 handing over HMR to React Fast Refresh"
733
+ );
734
+ }
735
+ },
641
736
  async resolveId(source, importer) {
642
737
  if (source.startsWith("\0") || !importer || importer.startsWith("\0"))
643
738
  return null;
644
739
  const target = findImporterTarget(importer, opts);
645
740
  if (target) {
646
- const basename = stripExtension(import_path5.default.basename(source));
741
+ const basename = stripExtension(import_path6.default.basename(source));
647
742
  if (basename && basename !== "index") {
648
743
  const nsOverrides = state.namespacedOverrides.get(target.package);
649
744
  if (nsOverrides?.has(basename)) {
650
745
  const p = nsOverrides.get(basename);
651
746
  logger.info(
652
- `Override [${target.package}]: ${basename} -> ${import_path5.default.basename(p)}`
747
+ `Override [${target.package}]: ${basename} -> ${import_path6.default.basename(p)}`
653
748
  );
654
749
  return p;
655
750
  }
656
751
  if (state.flatOverrides.has(basename)) {
657
752
  const p = state.flatOverrides.get(basename);
658
- logger.info(`Override: ${basename} -> ${import_path5.default.basename(p)}`);
753
+ logger.info(`Override: ${basename} -> ${import_path6.default.basename(p)}`);
659
754
  return p;
660
755
  }
661
756
  }
@@ -690,15 +785,15 @@ function unlock(userOptions) {
690
785
  load(id) {
691
786
  const target = findImporterTarget(id, opts);
692
787
  if (!target) return null;
693
- const basename = stripExtension(import_path5.default.basename(id));
788
+ const basename = stripExtension(import_path6.default.basename(id));
694
789
  if (!basename || basename === "index") return null;
695
790
  const nsOverrides = state.namespacedOverrides.get(target.package);
696
791
  const overridePath = nsOverrides?.get(basename) ?? state.flatOverrides.get(basename);
697
- if (overridePath && import_fs4.default.existsSync(overridePath)) {
792
+ if (overridePath && import_fs5.default.existsSync(overridePath)) {
698
793
  this.addWatchFile(overridePath);
699
794
  const normalizedPath = normalizePath(overridePath).replace(/"/g, '\\"');
700
795
  logger.info(
701
- `Load override: ${basename} -> ${import_path5.default.basename(overridePath)}`
796
+ `Load override: ${basename} -> ${import_path6.default.basename(overridePath)}`
702
797
  );
703
798
  return `export { default } from "${normalizedPath}"
704
799
  export * from "${normalizedPath}"`;
@@ -706,18 +801,18 @@ export * from "${normalizedPath}"`;
706
801
  const normalizedId = normalizePath(id);
707
802
  for (const patch of opts.patches) {
708
803
  if (!patch.target.test(normalizedId)) continue;
709
- if (!patch.configPath || !import_fs4.default.existsSync(patch.configPath)) continue;
804
+ if (!patch.configPath || !import_fs5.default.existsSync(patch.configPath)) continue;
710
805
  this.addWatchFile(patch.configPath);
711
806
  let original;
712
807
  try {
713
- original = import_fs4.default.readFileSync(id, "utf-8");
808
+ original = import_fs5.default.readFileSync(id, "utf-8");
714
809
  } catch (err) {
715
810
  logger.error(`Failed to read file for patching: ${id}`);
716
811
  return null;
717
812
  }
718
813
  const patched = patch.apply(original, patch.configPath);
719
814
  logger.info(
720
- `Patch applied: ${import_path5.default.basename(id)} via ${patch.configFile}`
815
+ `Patch applied: ${import_path6.default.basename(id)} via ${patch.configFile}`
721
816
  );
722
817
  return { code: patched, map: null };
723
818
  }
@@ -748,7 +843,7 @@ export * from "${normalizedPath}"`;
748
843
  }
749
844
  if (modified) return { code, map: null };
750
845
  }
751
- if (opts.hmrBoundaries.length > 0) {
846
+ if (!hasExternalReactPlugin && opts.hmrBoundaries.length > 0) {
752
847
  const normId = normalizePath(id);
753
848
  if (!normId.includes("/node_modules/")) {
754
849
  const needsBoundary = opts.hmrBoundaries.some(
@@ -756,7 +851,7 @@ export * from "${normalizedPath}"`;
756
851
  );
757
852
  if (needsBoundary) {
758
853
  logger.info(
759
- `HMR boundary injected: ${import_path5.default.basename(id)}`
854
+ `HMR boundary injected: ${import_path6.default.basename(id)}`
760
855
  );
761
856
  return {
762
857
  code: code + "\nif (import.meta.hot) { import.meta.hot.accept() }",
@@ -771,7 +866,7 @@ export * from "${normalizedPath}"`;
771
866
  const fsConfig = server.config.server?.fs;
772
867
  if (fsConfig && Array.isArray(fsConfig.allow)) {
773
868
  for (const dir of opts.overrideDirs) {
774
- const resolved = import_path5.default.resolve(dir);
869
+ const resolved = import_path6.default.resolve(dir);
775
870
  if (!fsConfig.allow.includes(resolved)) {
776
871
  fsConfig.allow.push(resolved);
777
872
  }