@octane-xplat/patches 0.16.0 → 0.17.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.
- package/package.json +1 -1
- package/patches/@nativescript-community__octane@0.2.5.patch +335 -174
- package/patches/@nativescript-community__vite-octane@0.2.1.patch +35 -4
- package/patches/{@nativescript__vite@8.0.17.patch → @nativescript__vite@8.0.20.patch} +171 -164
- package/patches/{octane@0.11.0.patch → octane@0.14.0.patch} +272 -393
- package/patches/shaders@4.0.0.patch +60 -0
- package/patches/@nativescript-community__ui-image@5.0.17.patch +0 -30
- package/patches/@triniwiz__nativescript-masonkit@1.0.0-beta.110.patch +0 -13
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
diff --git a/dist/server/strategy.js b/dist/server/strategy.js
|
|
2
|
-
index 7d84b37e2ed3a026da5b31c8a11027e0580877b2..
|
|
2
|
+
index 7d84b37e2ed3a026da5b31c8a11027e0580877b2..1943f7c05e47d95950212789f84d5b7725da9ac9 100644
|
|
3
3
|
--- a/dist/server/strategy.js
|
|
4
4
|
+++ b/dist/server/strategy.js
|
|
5
|
-
@@ -14,
|
|
5
|
+
@@ -14,17 +14,26 @@ import { purgeTransformCachesForHotUpdate, runHotUpdatePrologue, typescriptServe
|
|
6
6
|
* otherwise the re-fetch can be served from the previous save's transform and
|
|
7
7
|
* the screen ends up one save behind.
|
|
8
8
|
*/
|
|
@@ -13,7 +13,16 @@ index 7d84b37e2ed3a026da5b31c8a11027e0580877b2..f6594a913ba64837135e994cb183add1
|
|
|
13
13
|
export const octaneServerStrategy = {
|
|
14
14
|
...typescriptServerStrategy,
|
|
15
15
|
flavor: 'octane',
|
|
16
|
-
|
|
16
|
+
+ matchesFile(id) {
|
|
17
|
+
+ // Shared sources have workspace/@fs identities rather than /src IDs.
|
|
18
|
+
+ // Source-root gating remains in runHotUpdatePrologue; dependency and
|
|
19
|
+
+ // type/test files must not enter executable transaction batches.
|
|
20
|
+
+ const clean = id.replace(/[?#].*$/, '');
|
|
21
|
+
+ return SCRIPT_FILE_RE.test(clean) && !/(?:^|\/)(?:node_modules|__tests__|__mocks__)(?:\/|$)|\.(?:spec|test)\.[^/]+$|\.d\.(?:ts|mts|cts)$/i.test(clean);
|
|
22
|
+
+ },
|
|
23
|
+
deferDeltaBroadcast: true,
|
|
24
|
+
async handleHotUpdate(ctx, deps) {
|
|
25
|
+
const state = await runHotUpdatePrologue(ctx, deps);
|
|
17
26
|
if (!state)
|
|
18
27
|
return;
|
|
19
28
|
const { root, metrics, emitSummary } = state;
|
|
@@ -22,7 +31,29 @@ index 7d84b37e2ed3a026da5b31c8a11027e0580877b2..f6594a913ba64837135e994cb183add1
|
|
|
22
31
|
const { file, server } = ctx;
|
|
23
32
|
if (!SCRIPT_FILE_RE.test(file)) {
|
|
24
33
|
emitSummary();
|
|
25
|
-
@@ -
|
|
34
|
+
@@ -37,9 +46,9 @@ export const octaneServerStrategy = {
|
|
35
|
+
.normalize(path.relative(root, file))
|
|
36
|
+
.split(path.sep)
|
|
37
|
+
.join('/');
|
|
38
|
+
- const normalizedId = moduleGraph.normalizeGraphId(rel);
|
|
39
|
+
+ const normalizedId = moduleGraph.normalizeGraphId(file);
|
|
40
|
+
if (!moduleGraph.get(normalizedId)) {
|
|
41
|
+
- moduleGraph.upsert(rel, `/* octane-hmr ${Date.now()} */`, [], {
|
|
42
|
+
+ moduleGraph.upsert(normalizedId, `/* octane-hmr ${Date.now()} */`, [], {
|
|
43
|
+
emitDeltaOnInsert: true,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
@@ -51,7 +60,8 @@ export const octaneServerStrategy = {
|
|
47
|
+
label: 'octane',
|
|
48
|
+
});
|
|
49
|
+
try {
|
|
50
|
+
- const fresh = await sharedTransformRequest(rel, 30000);
|
|
51
|
+
+ const transformId = path.relative(root, file).startsWith('..' + path.sep) ? '/@fs/' + file.replace(/\\/g, '/') : rel;
|
|
52
|
+
+ const fresh = await sharedTransformRequest(transformId, 30000);
|
|
53
|
+
if (fresh?.code) {
|
|
54
|
+
const viteModule = server.moduleGraph.getModuleById(file);
|
|
55
|
+
const deps = viteModule
|
|
56
|
+
@@ -71,6 +81,16 @@ export const octaneServerStrategy = {
|
|
26
57
|
const gm = moduleGraph.get(normalizedId);
|
|
27
58
|
if (gm)
|
|
28
59
|
moduleGraph.emitDelta([gm], []);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
diff --git a/helpers/project.js b/helpers/project.js
|
|
2
|
-
index
|
|
2
|
+
index f6777fa5e64e667cbc56c7e76c4c32c5ab76a911..fdc1f974884e26030c0084d75c1e51a1e5968db2 100644
|
|
3
3
|
--- a/helpers/project.js
|
|
4
4
|
+++ b/helpers/project.js
|
|
5
5
|
@@ -73,7 +73,11 @@ function denoConfigHasWorkspace(dir) {
|
|
@@ -108,7 +108,7 @@ index a05696b679b3feecd1bafa267de44b59db559162..06648067a3fcf7f8c74437a82b94ec01
|
|
|
108
108
|
return ['.native', ''];
|
|
109
109
|
}
|
|
110
110
|
diff --git a/hmr/helpers/ast-normalizer.js b/hmr/helpers/ast-normalizer.js
|
|
111
|
-
index
|
|
111
|
+
index 77f5533a289902b644f2dba4c8a558f5a00c8314..5c1d57f34a5e863ae3e684012a99f9bb8796e974 100644
|
|
112
112
|
--- a/hmr/helpers/ast-normalizer.js
|
|
113
113
|
+++ b/hmr/helpers/ast-normalizer.js
|
|
114
114
|
@@ -86,9 +86,10 @@ export function astNormalizeModuleImportsAndHelpers(code, opts) {
|
|
@@ -145,7 +145,7 @@ index 0d7cd968eac690a85411cf3d6a24323a3d3a3992..98094d6ccfb918d00249d8087aebdd99
|
|
|
145
145
|
//# sourceMappingURL=css-device-module.js.map
|
|
146
146
|
|
|
147
147
|
diff --git a/hmr/server/deps-bundle.js b/hmr/server/deps-bundle.js
|
|
148
|
-
index
|
|
148
|
+
index 395c29e9b9b552fbf30c4a7131121a0d841df116..ca4d7beaf4ae0444ea947a8c97aa9d7fb1a254ef 100644
|
|
149
149
|
--- a/hmr/server/deps-bundle.js
|
|
150
150
|
+++ b/hmr/server/deps-bundle.js
|
|
151
151
|
@@ -53,6 +53,7 @@
|
|
@@ -156,7 +156,7 @@ index 8f2fa15556244f7ef811b5e2ea0fc6a19bab74d3..80137262ec46d347d39a7ee12d66d649
|
|
|
156
156
|
import * as esbuild from 'esbuild';
|
|
157
157
|
import { resolvePlatform } from '../../helpers/cli-flags.js';
|
|
158
158
|
import { getGlobalDefines, getUserDefineEntries } from '../../helpers/global-defines.js';
|
|
159
|
-
@@ -
|
|
159
|
+
@@ -699,6 +700,29 @@ export async function generateDepsBundle(options) {
|
|
160
160
|
// the device cannot resolve.
|
|
161
161
|
const buildPlugins = () => [
|
|
162
162
|
createWebpackLoaderStubEsbuildPlugin(),
|
|
@@ -203,16 +203,119 @@ index 71574c48f655183af0c9601b020fd1febd63ccb3..0061d9c9e9fe9c6034576eae8449831d
|
|
|
203
203
|
if (!imports.length) {
|
|
204
204
|
return code;
|
|
205
205
|
}
|
|
206
|
+
diff --git a/hmr/server/hmr-module-graph.js b/hmr/server/hmr-module-graph.js
|
|
207
|
+
index 8cff593b8ac8d8eff82ebdd398c1305a8408d308..92f6d194924b288864bcaca4fc42ef805d048e4f 100644
|
|
208
|
+
--- a/hmr/server/hmr-module-graph.js
|
|
209
|
+
+++ b/hmr/server/hmr-module-graph.js
|
|
210
|
+
@@ -1,3 +1,4 @@
|
|
211
|
+
+import { normalizeHmrModuleId } from './hmr-module-id.js';
|
|
212
|
+
import { matchesRuntimeGraphModuleId } from './runtime-graph-filter.js';
|
|
213
|
+
import { classifyGraphUpsert, shouldBroadcastGraphUpsertDelta, shouldBumpGraphVersion } from './websocket-graph-upsert.js';
|
|
214
|
+
import { getProjectAppVirtualPath } from '../../helpers/utils.js';
|
|
215
|
+
@@ -39,25 +40,9 @@ export class HmrModuleGraph {
|
|
216
|
+
return ('00000000' + (h >>> 0).toString(16)).slice(-8);
|
|
217
|
+
}
|
|
218
|
+
normalizeGraphId(raw) {
|
|
219
|
+
- if (!raw)
|
|
220
|
+
- return raw;
|
|
221
|
+
- let id = raw.split('?')[0].replace(/\\/g, '/');
|
|
222
|
+
- id = id.replace(/^file:\/\//, '');
|
|
223
|
+
- const pluginRoot = this.deps.getPluginRoot();
|
|
224
|
+
- if (pluginRoot) {
|
|
225
|
+
- const rootNorm = pluginRoot.replace(/\\/g, '/');
|
|
226
|
+
- if (id.startsWith(rootNorm)) {
|
|
227
|
+
- id = id.slice(rootNorm.length);
|
|
228
|
+
- }
|
|
229
|
+
- }
|
|
230
|
+
- if (!id.startsWith('/'))
|
|
231
|
+
- id = '/' + id;
|
|
232
|
+
- // Collapse nested app root indicators when present (defensive)
|
|
233
|
+
- const idx = id.indexOf(APP_VIRTUAL_WITH_SLASH);
|
|
234
|
+
- if (idx !== -1)
|
|
235
|
+
- id = id.slice(idx);
|
|
236
|
+
- return id;
|
|
237
|
+
+ return normalizeHmrModuleId(raw, this.deps.getPluginRoot());
|
|
238
|
+
}
|
|
239
|
+
+
|
|
240
|
+
// Dependency-closed, topologically sorted list of modules for a set of
|
|
241
|
+
// changed ids. Only includes application modules we can serve (under the
|
|
242
|
+
// app virtual root and known framework/.ts/.js entries already in the graph).
|
|
243
|
+
diff --git a/hmr/server/hmr-module-id.js b/hmr/server/hmr-module-id.js
|
|
244
|
+
new file mode 100644
|
|
245
|
+
index 0000000000000000000000000000000000000000..13a0c29d4b0fad502730062ddba081016514c440
|
|
246
|
+
--- /dev/null
|
|
247
|
+
+++ b/hmr/server/hmr-module-id.js
|
|
248
|
+
@@ -0,0 +1,30 @@
|
|
249
|
+
+import { existsSync } from 'node:fs';
|
|
250
|
+
+import * as path from 'node:path';
|
|
251
|
+
+import { getMonorepoWorkspaceRoot } from '../../helpers/project.js';
|
|
252
|
+
+import { rewriteFsAbsoluteToNsM } from './websocket-module-specifiers.js';
|
|
253
|
+
+
|
|
254
|
+
+// Use the same app/workspace/@fs spelling as static device imports. App
|
|
255
|
+
+// virtual IDs remain intact; an unrelated /src/ substring is never a root.
|
|
256
|
+
+export function normalizeHmrModuleId(raw, projectRoot) {
|
|
257
|
+
+ if (!raw) return raw;
|
|
258
|
+
+ let id = raw.split(/[?#]/)[0].replace(/\\/g, '/');
|
|
259
|
+
+ if (id.startsWith('/ns/m/')) return id.slice('/ns/m'.length);
|
|
260
|
+
+ const fileUrl = id.startsWith('file://');
|
|
261
|
+
+ if (fileUrl) id = id.slice('file://'.length);
|
|
262
|
+
+ const fsUrl = id.startsWith('/@fs/');
|
|
263
|
+
+ if (fsUrl) id = id.slice('/@fs'.length);
|
|
264
|
+
+ const root = projectRoot?.replace(/\\/g, '/').replace(/\/$/, '');
|
|
265
|
+
+ const within = (base) => base && (id === base || id.startsWith(base + '/'));
|
|
266
|
+
+ // Preserve ordinary app IDs, including Windows drive paths, without
|
|
267
|
+
+ // passing a drive-letter source through POSIX /@fs parsing.
|
|
268
|
+
+ if (within(root)) return id.slice(root.length) || '/';
|
|
269
|
+
+ const workspace = root ? getMonorepoWorkspaceRoot(root) : null;
|
|
270
|
+
+ if (root && id.startsWith('/../')) id = path.resolve(root, '.' + id).replace(/\\/g, '/');
|
|
271
|
+
+ if (root && (fileUrl || fsUrl || within(root) || within(workspace) || (path.isAbsolute(id) && existsSync(id)))) {
|
|
272
|
+
+ const url = rewriteFsAbsoluteToNsM('/@fs' + id, root, workspace);
|
|
273
|
+
+ // The module route serves explicit /@fs paths for linked sources
|
|
274
|
+
+ // outside both roots, matching rewriteImports' existing fallback.
|
|
275
|
+
+ return url ? url.slice('/ns/m'.length) : '/@fs' + id;
|
|
276
|
+
+ }
|
|
277
|
+
+ return id.startsWith('/') ? id : '/' + id;
|
|
278
|
+
+}
|
|
206
279
|
diff --git a/hmr/server/process-code-for-device.js b/hmr/server/process-code-for-device.js
|
|
207
|
-
index
|
|
280
|
+
index 1f02ba5ebb7e89d40eff58d1c395b5ec838f45fe..5bbb6e4827da640624624ef80f94a7e5eb5c28ce 100644
|
|
208
281
|
--- a/hmr/server/process-code-for-device.js
|
|
209
282
|
+++ b/hmr/server/process-code-for-device.js
|
|
210
|
-
@@ -1,3 +1,
|
|
283
|
+
@@ -1,3 +1,5 @@
|
|
284
|
+
+import { normalizeHmrModuleId } from './hmr-module-id.js';
|
|
211
285
|
+import { CSS_MODULE_RE } from './css-device-module.js';
|
|
212
286
|
// Device code-transform: cleans Vite/framework noise out of a served module,
|
|
213
287
|
// injects NativeScript build globals + the process.env shim, normalizes
|
|
214
288
|
// imports/helpers for the on-device ESM runtime, and collects an importer's
|
|
215
|
-
@@ -
|
|
289
|
+
@@ -125,25 +127,10 @@ export function inlineNsConfigVirtualImports(code) {
|
|
290
|
+
// `hmr/client/hot-context.ts` so cold-boot evaluation and HMR re-evaluation
|
|
291
|
+
// resolve the same `hot.data` entry.
|
|
292
|
+
export function computeHotContextId(sourceId, projectRoot) {
|
|
293
|
+
- if (!sourceId || typeof sourceId !== 'string')
|
|
294
|
+
- return null;
|
|
295
|
+
- let id = sourceId.split('?')[0].split('#')[0].replace(/\\/g, '/');
|
|
296
|
+
- if (!id)
|
|
297
|
+
- return null;
|
|
298
|
+
- id = id.replace(/^\/@fs/, '');
|
|
299
|
+
- if (projectRoot) {
|
|
300
|
+
- const rootPosix = projectRoot.replace(/\\/g, '/').replace(/\/$/, '');
|
|
301
|
+
- if (rootPosix && id.startsWith(rootPosix + '/')) {
|
|
302
|
+
- id = id.slice(rootPosix.length);
|
|
303
|
+
- }
|
|
304
|
+
- }
|
|
305
|
+
- if (id.startsWith('/ns/m/'))
|
|
306
|
+
- id = id.slice('/ns/m'.length);
|
|
307
|
+
- id = id.replace(/\.(ts|tsx|js|jsx|mjs|mts|cts)$/i, '');
|
|
308
|
+
- if (!id.startsWith('/'))
|
|
309
|
+
- id = '/' + id;
|
|
310
|
+
- return id;
|
|
311
|
+
+ if (!sourceId || typeof sourceId !== 'string') return null;
|
|
312
|
+
+ return normalizeHmrModuleId(sourceId, projectRoot).replace(/\.(ts|tsx|tsrx|js|jsx|mjs|mts|cts)$/i, '');
|
|
313
|
+
}
|
|
314
|
+
+
|
|
315
|
+
// One-line `import.meta.hot` prelude. Single-statement, no internal `;` or
|
|
316
|
+
// newline, so that if any later sanitize pass re-applies
|
|
317
|
+
// `IMPORT_META_HOT_ASSIGNMENT` the whole statement strips cleanly (module
|
|
318
|
+
@@ -449,13 +436,13 @@ function processCodeForDevice(code, isVitePreBundled, preserveVendorImports = fa
|
|
216
319
|
// Unlike other virtual ids these are real, servable dev-server URLs returning
|
|
217
320
|
// self-contained ESM — stripping them leaves `_decorate`/`_decorateMetadata`
|
|
218
321
|
// undefined at runtime. They're origin-prefixed for the device in rewriteImports.
|
|
@@ -229,7 +332,7 @@ index c71d457806a8add919f7e2368e7ebc349bd908e7..998eb268ed0db1200f8b5ce30fc7da21
|
|
|
229
332
|
result = `// [hmr-sanitize] stripped virtual /@id/ side-effect imports\n${result}`;
|
|
230
333
|
}
|
|
231
334
|
diff --git a/hmr/server/rewrite-imports.js b/hmr/server/rewrite-imports.js
|
|
232
|
-
index
|
|
335
|
+
index 51ad398cefe75c918e887bd9506d9152259b957e..235b7cd49cbfb18c8cca87edf62e53c4771b304e 100644
|
|
233
336
|
--- a/hmr/server/rewrite-imports.js
|
|
234
337
|
+++ b/hmr/server/rewrite-imports.js
|
|
235
338
|
@@ -1,3 +1,4 @@
|
|
@@ -331,7 +434,7 @@ index 4a6575cb00a6aeecbbb7ac5ccac3268cb10d7f54..2876cf3694c278249b9db182e2f89df3
|
|
|
331
434
|
export function prepareAngularEntryForDevice(code, importerPath, sfcFileMap, depFileMap, projectRoot, verbose = false, outputDirOverrideRel, httpOrigin, resolveVendorAsHttp = false) {
|
|
332
435
|
const rewrittenCode = rewriteImports(code, importerPath, sfcFileMap, depFileMap, projectRoot, verbose, outputDirOverrideRel, httpOrigin, resolveVendorAsHttp);
|
|
333
436
|
return rewriteAngularEntryRegisterOnly(rewrittenCode, resolveAngularCoreHmrImportSource(rewrittenCode, httpOrigin));
|
|
334
|
-
@@ -
|
|
437
|
+
@@ -239,6 +326,19 @@ export function rewriteImports(code, importerPath, sfcFileMap, depFileMap, proje
|
|
335
438
|
}
|
|
336
439
|
return `${prefix}${stub}${suffix}`;
|
|
337
440
|
}
|
|
@@ -351,7 +454,7 @@ index 4a6575cb00a6aeecbbb7ac5ccac3268cb10d7f54..2876cf3694c278249b9db182e2f89df3
|
|
|
351
454
|
spec = normalizeNativeScriptCoreSpecifier(spec);
|
|
352
455
|
// Pull `/@fs/<abs-path>` URLs back into the `/ns/m/` pipeline so they
|
|
353
456
|
// hit our CJS/UMD-wrapping handler. Vite emits `/@fs/...` for any
|
|
354
|
-
@@ -
|
|
457
|
+
@@ -256,17 +356,39 @@ export function rewriteImports(code, importerPath, sfcFileMap, depFileMap, proje
|
|
355
458
|
}
|
|
356
459
|
return `${prefix}${rewritten}${suffix}`;
|
|
357
460
|
}
|
|
@@ -397,159 +500,45 @@ index 4a6575cb00a6aeecbbb7ac5ccac3268cb10d7f54..2876cf3694c278249b9db182e2f89df3
|
|
|
397
500
|
if (httpOriginSafe) {
|
|
398
501
|
return `${prefix}${httpOriginSafe}${spec}${suffix}`;
|
|
399
502
|
diff --git a/hmr/server/websocket-module-specifiers.js b/hmr/server/websocket-module-specifiers.js
|
|
400
|
-
index
|
|
503
|
+
index 0081819906b9df7480408697b1afadb149e26e31..562bd0f7f982cd90d22c945f369d2581201597a2 100644
|
|
401
504
|
--- a/hmr/server/websocket-module-specifiers.js
|
|
402
505
|
+++ b/hmr/server/websocket-module-specifiers.js
|
|
403
|
-
@@ -
|
|
404
|
-
-import { existsSync, readdirSync, readFileSync, realpathSync } from 'fs';
|
|
405
|
-
+import { existsSync, readdirSync, readFileSync, realpathSync, statSync } from 'fs';
|
|
406
|
-
import * as path from 'path';
|
|
407
|
-
import * as PAT from './constants.js';
|
|
408
|
-
import { getVendorManifest, resolveVendorSpecifier } from '../shared/vendor/registry.js';
|
|
409
|
-
-import { getProjectRootPath } from '../../helpers/project.js';
|
|
410
|
-
+import { getMonorepoWorkspaceRoot, getProjectRootPath } from '../../helpers/project.js';
|
|
411
|
-
import { extractRootPackageName, getPackageRuntimeInfo } from '../shared/package-classifier.js';
|
|
412
|
-
import { getFlavorClientPackages } from '../framework-flavors.js';
|
|
413
|
-
const ESM_FRAMEWORK_PACKAGE_ROOTS = new Set(['@nativescript/angular', 'nativescript-angular']);
|
|
414
|
-
@@ -328,6 +328,76 @@ export function resolveVendorFromCandidate(specifier) {
|
|
506
|
+
@@ -328,6 +328,24 @@ export function resolveVendorFromCandidate(specifier) {
|
|
415
507
|
}
|
|
416
508
|
return null;
|
|
417
509
|
}
|
|
418
|
-
+const
|
|
419
|
-
|
|
420
|
-
+
|
|
421
|
-
+
|
|
422
|
-
+
|
|
423
|
-
+ * - `link:`/`file:`/`portal:` deps keep their own `node_modules` at the real
|
|
424
|
-
+ * target; their workspace siblings can own transitive deps too. Reuse the
|
|
425
|
-
+ * bounded workspace scan rather than recursively walking dependency trees.
|
|
426
|
-
+ * - pnpm's isolated virtual store keeps every non-hoisted package under
|
|
427
|
-
+ * `node_modules/.pnpm/<name>@<ver>/node_modules/`.
|
|
428
|
-
+ * Importer info is gone from the URL — first hit wins, same as the workspace
|
|
429
|
-
+ * scan above. Cached per project root; the set only changes on install.
|
|
430
|
-
+ */
|
|
431
|
-
+function listDepFallbackDirs(projectRoot) {
|
|
432
|
-
+ const cached = depFallbackDirsCache.get(projectRoot);
|
|
433
|
-
+ if (cached) {
|
|
434
|
-
+ return cached;
|
|
435
|
-
+ }
|
|
510
|
+
+const pnpmStoreDirsCache = new Map();
|
|
511
|
+
+// Upstream scans linked checkouts; retain only the app-local pnpm store fallback.
|
|
512
|
+
+function listPnpmStoreNodeModulesDirs(projectRoot) {
|
|
513
|
+
+ const cached = pnpmStoreDirsCache.get(projectRoot);
|
|
514
|
+
+ if (cached) return cached;
|
|
436
515
|
+ const dirs = [];
|
|
437
|
-
+ const
|
|
438
|
-
+ const linkedWorkspaces = new Set();
|
|
439
|
-
+ const pushIfPresent = (dir) => {
|
|
440
|
-
+ if (!seen.has(dir) && existsSync(dir)) {
|
|
441
|
-
+ seen.add(dir);
|
|
442
|
-
+ dirs.push(dir);
|
|
443
|
-
+ }
|
|
444
|
-
+ };
|
|
445
|
-
+ const pnpmStore = path.join(projectRoot, 'node_modules', '.pnpm');
|
|
516
|
+
+ const store = path.join(projectRoot, 'node_modules', '.pnpm');
|
|
446
517
|
+ try {
|
|
447
|
-
+ for (const entry of readdirSync(
|
|
518
|
+
+ for (const entry of readdirSync(store, { withFileTypes: true })) {
|
|
448
519
|
+ if (entry.isDirectory() && !entry.name.startsWith('.')) {
|
|
449
|
-
+
|
|
450
|
-
+
|
|
451
|
-
+ }
|
|
452
|
-
+ }
|
|
453
|
-
+ catch {
|
|
454
|
-
+ }
|
|
455
|
-
+ try {
|
|
456
|
-
+ const pkg = JSON.parse(readFileSync(path.join(projectRoot, 'package.json'), 'utf8'));
|
|
457
|
-
+ for (const section of ['dependencies', 'devDependencies', 'optionalDependencies', 'peerDependencies']) {
|
|
458
|
-
+ for (const spec of Object.values(pkg[section] ?? {})) {
|
|
459
|
-
+ const target = /^(?:link|file|portal):(.+)$/.exec(String(spec))?.[1];
|
|
460
|
-
+ if (!target)
|
|
461
|
-
+ continue;
|
|
462
|
-
+ try {
|
|
463
|
-
+ const depDir = realpathSync(path.resolve(projectRoot, target));
|
|
464
|
-
+ if (statSync(depDir).isDirectory()) {
|
|
465
|
-
+ pushIfPresent(path.join(depDir, 'node_modules'));
|
|
466
|
-
+ const workspace = getMonorepoWorkspaceRoot(depDir);
|
|
467
|
-
+ if (workspace)
|
|
468
|
-
+ linkedWorkspaces.add(workspace);
|
|
469
|
-
+ }
|
|
470
|
-
+ }
|
|
471
|
-
+ catch {
|
|
472
|
-
+ }
|
|
520
|
+
+ const dir = path.join(store, entry.name, 'node_modules');
|
|
521
|
+
+ if (existsSync(dir)) dirs.push(dir);
|
|
473
522
|
+ }
|
|
474
523
|
+ }
|
|
475
|
-
+ }
|
|
476
|
-
+
|
|
477
|
-
+ }
|
|
478
|
-
+ // Preserve direct-dependency precedence. Scan each linked workspace once,
|
|
479
|
-
+ // using the existing two-level package scan and its per-workspace cache.
|
|
480
|
-
+ for (const workspace of linkedWorkspaces) {
|
|
481
|
-
+ pushIfPresent(path.join(workspace, 'node_modules'));
|
|
482
|
-
+ for (const dir of listWorkspaceNodeModulesDirs(workspace))
|
|
483
|
-
+ pushIfPresent(dir);
|
|
484
|
-
+ }
|
|
485
|
-
+ depFallbackDirsCache.set(projectRoot, dirs);
|
|
524
|
+
+ } catch {}
|
|
525
|
+
+ pnpmStoreDirsCache.set(projectRoot, dirs);
|
|
486
526
|
+ return dirs;
|
|
487
527
|
+}
|
|
488
528
|
const workspaceNodeModulesDirsCache = new Map();
|
|
489
529
|
/**
|
|
490
530
|
* `node_modules` dirs that can hold a package the served URL no longer
|
|
491
|
-
@@ -
|
|
492
|
-
|
|
531
|
+
@@ -485,6 +503,8 @@ export function resolveCandidateFilePath(candidate, projectRoot, workspaceRoot)
|
|
532
|
+
return fromWorkspaceScan;
|
|
493
533
|
}
|
|
494
534
|
}
|
|
495
|
-
+
|
|
496
|
-
+
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
+ const absPath = path.resolve(nmDir, tail);
|
|
501
|
-
+ if (absPath.startsWith(nmDir + path.sep) && existsSync(absPath))
|
|
502
|
-
+ return absPath;
|
|
503
|
-
+ }
|
|
504
|
-
+ }
|
|
505
|
-
return null;
|
|
506
|
-
}
|
|
507
|
-
/**
|
|
508
|
-
@@ -512,8 +592,8 @@ export function rewriteFsAbsoluteToNsM(spec, projectRoot, workspaceRoot) {
|
|
509
|
-
* `export const X: string = '...'`. Routing through the realpath makes
|
|
510
|
-
* Vite see a non-`node_modules` path and the TS transform applies.
|
|
511
|
-
*
|
|
512
|
-
- * App-local candidates whose real path is also app-local are returned
|
|
513
|
-
- * unchanged so existing behaviour is preserved bit-for-bit.
|
|
514
|
-
+ * Candidates are returned unchanged only when their URL addresses the file
|
|
515
|
-
+ * found. Fallback files need filesystem anchors even inside the app root.
|
|
516
|
-
*/
|
|
517
|
-
export function filterExistingNodeModulesTransformCandidates(spec, candidates, projectRoot, workspaceRoot) {
|
|
518
|
-
const cleanedSpec = spec.replace(PAT.QUERY_PATTERN, '');
|
|
519
|
-
@@ -557,22 +637,18 @@ export function filterExistingNodeModulesTransformCandidates(spec, candidates, p
|
|
520
|
-
// through to the existing project/workspace logic.
|
|
521
|
-
}
|
|
522
|
-
if (mapped === null) {
|
|
523
|
-
- if (!hasDistinctWorkspaceRoot) {
|
|
524
|
-
+ const candidatePath = cleanedCandidate.startsWith('/@fs/')
|
|
525
|
-
+ ? path.resolve(cleanedCandidate.slice('/@fs'.length))
|
|
526
|
-
+ : path.resolve(resolvedProjectRoot, cleanedCandidate.replace(/^\/+/, ''));
|
|
527
|
-
+ if (candidatePath === resolved) {
|
|
528
|
-
mapped = candidate;
|
|
529
|
-
}
|
|
530
|
-
else {
|
|
531
|
-
- const relFromProject = path.relative(resolvedProjectRoot, resolved);
|
|
532
|
-
- const insideProjectRoot = relFromProject !== '' && !relFromProject.startsWith('..') && !path.isAbsolute(relFromProject);
|
|
533
|
-
- if (insideProjectRoot) {
|
|
534
|
-
- mapped = candidate;
|
|
535
|
-
- }
|
|
536
|
-
- else {
|
|
537
|
-
- // Hoisted `node_modules/<pkg>/...` file lives above projectRoot.
|
|
538
|
-
- // Rewrite the URL to its fs-anchored form so Vite reads it directly
|
|
539
|
-
- // instead of bouncing through bare-specifier resolution that the
|
|
540
|
-
- // hoisted package's `exports` field may refuse.
|
|
541
|
-
- mapped = `/@fs${resolved.replace(/\\/g, '/')}${querySuffix}`;
|
|
542
|
-
- }
|
|
543
|
-
+ // The candidate URL does not address the discovered file. A
|
|
544
|
-
+ // fallback may live inside the project (nested link: dependency
|
|
545
|
-
+ // or pnpm store) as well as outside it (hoisted dependency).
|
|
546
|
-
+ // Anchor the actual path so Vite loads the same file we found.
|
|
547
|
-
+ mapped = `/@fs${resolved.replace(/\\/g, '/')}${querySuffix}`;
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
if (seen.has(mapped))
|
|
535
|
+
+ const fromPnpmStore = probeNodeModulesTail(listPnpmStoreNodeModulesDirs(projectRoot));
|
|
536
|
+
+ if (fromPnpmStore) return fromPnpmStore;
|
|
537
|
+
// Linked source checkouts keep private node_modules outside both roots.
|
|
538
|
+
// Only packages the app's own install lacks may come from them: each
|
|
539
|
+
// extension/index variant is resolved separately, so a variant missing
|
|
551
540
|
diff --git a/hmr/server/websocket-ns-m-request.js b/hmr/server/websocket-ns-m-request.js
|
|
552
|
-
index
|
|
541
|
+
index 0879633dc5ee172f16de82d5d24bebe2f6f7878f..b489d7f1524eb35ba87206d86cdb9448a95c188e 100644
|
|
553
542
|
--- a/hmr/server/websocket-ns-m-request.js
|
|
554
543
|
+++ b/hmr/server/websocket-ns-m-request.js
|
|
555
544
|
@@ -27,10 +27,15 @@ const MODULE_CANDIDATE_EXTS = ['ts', 'js', 'tsx', 'jsx', 'mjs', 'mts', 'cts', 'v
|
|
@@ -570,26 +559,25 @@ index a11fbd5d24579cdf572a91f70cb06561bfa43cd0..c887334efce2c2f6cf85c75082761094
|
|
|
570
559
|
}
|
|
571
560
|
candidates.push(...MODULE_CANDIDATE_EXTS.map((ext) => `${base}.${ext}`));
|
|
572
561
|
}
|
|
573
|
-
@@ -
|
|
574
|
-
|
|
575
|
-
const rootPosix = root.replace(/\\/g, '/').replace(/\/$/, '');
|
|
576
|
-
const fsId = `/@fs${rootPosix}${spec.startsWith('/') ? '' : '/'}${spec}`;
|
|
577
|
-
- if (resolveCandidateFilePath(fsId, serverRoot, workspaceRoot)) {
|
|
578
|
-
- return fsId;
|
|
579
|
-
+ // The fs id is a guess composed under a root — serve the path the
|
|
580
|
-
+ // resolver actually found (it may live in a dep's own node_modules,
|
|
581
|
-
+ // outside both roots).
|
|
582
|
-
+ const resolved = resolveCandidateFilePath(fsId, serverRoot, workspaceRoot);
|
|
583
|
-
+ if (resolved) {
|
|
584
|
-
+ return `/@fs${resolved.replace(/\\/g, '/')}`;
|
|
562
|
+
@@ -216,8 +221,11 @@ export async function resolveNsMTransformedModule(options) {
|
|
563
|
+
}
|
|
585
564
|
}
|
|
586
565
|
}
|
|
587
|
-
|
|
566
|
+
- const fsId = resolveFsAnchoredSpec(spec, serverRoot, workspaceRoot);
|
|
567
|
+
- if (fsId) {
|
|
568
|
+
+ // A workspace-relative extensionless URL is not a Vite app URL.
|
|
569
|
+
+ // Probe the same extension/platform candidates under both source roots.
|
|
570
|
+
+ for (const candidate of new Set([spec, ...transformCandidates])) {
|
|
571
|
+
+ const fsId = resolveFsAnchoredSpec(candidate, serverRoot, workspaceRoot);
|
|
572
|
+
+ if (!fsId) continue;
|
|
573
|
+
transformed = await tryTransformRequest(transformRequest, fsId, timeoutMs);
|
|
574
|
+
if (transformed?.code) {
|
|
575
|
+
return { transformed, resolvedCandidate: fsId };
|
|
588
576
|
diff --git a/hmr/server/websocket-ns-m.js b/hmr/server/websocket-ns-m.js
|
|
589
|
-
index
|
|
577
|
+
index fcdcd69776b3f82d3fc7d8dd26e03856177c933e..ac33b017b65489472c3573ce45f89bb94859777b 100644
|
|
590
578
|
--- a/hmr/server/websocket-ns-m.js
|
|
591
579
|
+++ b/hmr/server/websocket-ns-m.js
|
|
592
|
-
@@ -
|
|
580
|
+
@@ -98,7 +98,7 @@ export function registerNsModuleServerRoute(server, options) {
|
|
593
581
|
// internal virtual modules (e.g., \0nsvite:nsconfig-json for
|
|
594
582
|
// ~/package.json) that don't exist on disk and must NOT run
|
|
595
583
|
// through the device post-processing pipeline below.
|
|
@@ -598,7 +586,7 @@ index 63b5d9a4886d8da03b8e7deac8a16d53347ea5d7..0f92b3377e6d697f5e5c9eafad130d95
|
|
|
598
586
|
try {
|
|
599
587
|
// First try Vite's transform pipeline directly
|
|
600
588
|
const vr = await sharedTransformRequest(spec);
|
|
601
|
-
@@ -
|
|
589
|
+
@@ -167,8 +167,21 @@ export function registerNsModuleServerRoute(server, options) {
|
|
602
590
|
// Workspace css outside the vite root must be anchored to /@fs or
|
|
603
591
|
// `?inline` is denied and the DOM css module (__vite__updateStyle)
|
|
604
592
|
// is served instead.
|
|
@@ -622,7 +610,7 @@ index 63b5d9a4886d8da03b8e7deac8a16d53347ea5d7..0f92b3377e6d697f5e5c9eafad130d95
|
|
|
622
610
|
const inlineCode = inlineRes?.code || '';
|
|
623
611
|
// `?inline` output is `export default "<compiled css>"`.
|
|
624
612
|
const m = inlineCode.match(/export\s+default\s+("(?:[^"\\]|\\.)*")\s*;?/s);
|
|
625
|
-
@@ -
|
|
613
|
+
@@ -178,7 +191,14 @@ export function registerNsModuleServerRoute(server, options) {
|
|
626
614
|
css = JSON.parse(m[1]);
|
|
627
615
|
}
|
|
628
616
|
catch { }
|
|
@@ -638,7 +626,7 @@ index 63b5d9a4886d8da03b8e7deac8a16d53347ea5d7..0f92b3377e6d697f5e5c9eafad130d95
|
|
|
638
626
|
const out = `// [ns:m][css] ${spec}\n` + `const __ns_css_text__ = ${JSON.stringify(css)};\n` + buildCssRegisterSnippetFromVar(spec, '__ns_css_text__') + `export default __ns_css_text__;\n`;
|
|
639
627
|
res.statusCode = 200;
|
|
640
628
|
res.end(out);
|
|
641
|
-
@@ -
|
|
629
|
+
@@ -191,7 +211,10 @@ export function registerNsModuleServerRoute(server, options) {
|
|
642
630
|
if (verbose)
|
|
643
631
|
console.warn('[ns:m][css] inline compile failed', spec, cssErr?.message);
|
|
644
632
|
}
|
|
@@ -650,7 +638,7 @@ index 63b5d9a4886d8da03b8e7deac8a16d53347ea5d7..0f92b3377e6d697f5e5c9eafad130d95
|
|
|
650
638
|
}
|
|
651
639
|
// Queue and dedupe transformRequest calls so heavy app graphs do not
|
|
652
640
|
// overwhelm Vite with concurrent work. Slow-transform warnings start only
|
|
653
|
-
@@ -
|
|
641
|
+
@@ -513,6 +536,8 @@ export function registerNsModuleServerRoute(server, options) {
|
|
654
642
|
continue;
|
|
655
643
|
}
|
|
656
644
|
else if (u.pathname.startsWith('/ns/m')) {
|
|
@@ -659,6 +647,25 @@ index 63b5d9a4886d8da03b8e7deac8a16d53347ea5d7..0f92b3377e6d697f5e5c9eafad130d95
|
|
|
659
647
|
// Resolve the import target through the SAME
|
|
660
648
|
// canonical pipeline the /ns/m route itself uses
|
|
661
649
|
// (websocket-ns-m-request.ts) instead of a third
|
|
650
|
+
@@ -546,7 +571,17 @@ export function registerNsModuleServerRoute(server, options) {
|
|
651
|
+
catch { }
|
|
652
|
+
if (!targetCode)
|
|
653
|
+
continue;
|
|
654
|
+
- const hasDefault = /\bexport\s+default\b/.test(targetCode) || /export\s*\{\s*default\s*(?:as\s*default)?\s*\}/.test(targetCode);
|
|
655
|
+
+ // Inspect exports, not source text: compilers emit aliases such as
|
|
656
|
+
+ // `export { Screen as default }`, and comments/strings are not exports.
|
|
657
|
+
+ const targetAst = babelParse(targetCode, {
|
|
658
|
+
+ sourceType: 'module',
|
|
659
|
+
+ plugins: MODULE_IMPORT_ANALYSIS_PLUGINS,
|
|
660
|
+
+ });
|
|
661
|
+
+ const hasDefault = targetAst.program.body.some((node) =>
|
|
662
|
+
+ node.type === 'ExportDefaultDeclaration' ||
|
|
663
|
+
+ (node.type === 'ExportNamedDeclaration' && node.exportKind !== 'type' &&
|
|
664
|
+
+ node.specifiers.some((specifier) => specifier.exportKind !== 'type' &&
|
|
665
|
+
+ (specifier.exported?.name === 'default' || specifier.exported?.value === 'default'))));
|
|
666
|
+
if (!hasDefault) {
|
|
667
|
+
// CJS/UMD modules won't have `export default` — they get CJS-wrapped
|
|
668
|
+
// by the serving pipeline. Only warn, don't fatally block the importer.
|
|
662
669
|
diff --git a/hmr/server/websocket-served-module-helpers.js b/hmr/server/websocket-served-module-helpers.js
|
|
663
670
|
index b9e3ab67eb4ae7c9b12bc4b02b9aa3660d712644..f857f4a5a5956af229e447ed04bf1a52a90c6399 100644
|
|
664
671
|
--- a/hmr/server/websocket-served-module-helpers.js
|