@jskit-ai/kernel 0.1.210 → 0.1.212
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.
|
@@ -309,16 +309,11 @@ export { installedClientModules, bootInstalledClientModules };
|
|
|
309
309
|
`;
|
|
310
310
|
}
|
|
311
311
|
|
|
312
|
-
//
|
|
312
|
+
// Explicit package exclusions remain separate from mutable local source resolution.
|
|
313
313
|
function resolveClientOptimizeExcludeSpecifiers(clientModules = []) {
|
|
314
314
|
const modulePackageMetadataEntries = normalizeClientModulePackageMetadataEntries(clientModules);
|
|
315
315
|
return sortStrings(
|
|
316
|
-
[
|
|
317
|
-
...modulePackageMetadataEntries
|
|
318
|
-
.filter((entry) => LOCAL_PACKAGE_SOURCE_TYPES.has(entry.sourceType))
|
|
319
|
-
.flatMap((entry) => [entry.packageId, `${entry.packageId}/shared`, `${entry.packageId}/client`]),
|
|
320
|
-
...modulePackageMetadataEntries.flatMap((entry) => entry.packageMetadataClientOptimizeExcludeSpecifiers || [])
|
|
321
|
-
]
|
|
316
|
+
modulePackageMetadataEntries.flatMap((entry) => entry.packageMetadataClientOptimizeExcludeSpecifiers || [])
|
|
322
317
|
);
|
|
323
318
|
}
|
|
324
319
|
|
|
@@ -335,12 +330,6 @@ function resolveClientOptimizeIncludeSpecifiers(clientModules = [], excludeSpeci
|
|
|
335
330
|
);
|
|
336
331
|
}
|
|
337
332
|
|
|
338
|
-
function resolveLocalScopeOptimizeExcludeSpecifiers(localScopePackageIds = []) {
|
|
339
|
-
return sortStrings(
|
|
340
|
-
localScopePackageIds.flatMap((packageId) => [packageId, `${packageId}/shared`, `${packageId}/client`])
|
|
341
|
-
);
|
|
342
|
-
}
|
|
343
|
-
|
|
344
333
|
function resolveClientRuntimeDedupeSpecifiers(userResolveConfig = {}) {
|
|
345
334
|
const resolveConfig = normalizeObject(userResolveConfig);
|
|
346
335
|
const userDedupe = sortStrings(resolveConfig.dedupe);
|
|
@@ -352,6 +341,7 @@ function createJskitClientBootstrapPlugin({ proxyTarget = "" } = {}) {
|
|
|
352
341
|
let hasMutableLocalPackages = false;
|
|
353
342
|
let localPackages = Object.freeze([]);
|
|
354
343
|
let resolvePackageSpecifier = null;
|
|
344
|
+
let clientScanSpecifiers = [];
|
|
355
345
|
|
|
356
346
|
return {
|
|
357
347
|
name: "jskit-client-bootstrap",
|
|
@@ -377,14 +367,12 @@ function createJskitClientBootstrapPlugin({ proxyTarget = "" } = {}) {
|
|
|
377
367
|
installedPackages.some((entry) => LOCAL_PACKAGE_SOURCE_TYPES.has(entry.sourceType))
|
|
378
368
|
);
|
|
379
369
|
const clientExcludeSpecifiers = resolveClientOptimizeExcludeSpecifiers(clientModules);
|
|
380
|
-
const localScopeExcludeSpecifiers = resolveLocalScopeOptimizeExcludeSpecifiers(localScopePackageIds);
|
|
381
370
|
const userOptimizeDeps = normalizeObject(userConfig.optimizeDeps);
|
|
382
371
|
const userExclude = sortStrings(userOptimizeDeps.exclude);
|
|
383
372
|
const userInclude = sortStrings(userOptimizeDeps.include);
|
|
384
373
|
const exclude = sortStrings([
|
|
385
374
|
...userExclude,
|
|
386
|
-
...clientExcludeSpecifiers
|
|
387
|
-
...localScopeExcludeSpecifiers
|
|
375
|
+
...clientExcludeSpecifiers
|
|
388
376
|
]);
|
|
389
377
|
const clientIncludeSpecifiers = resolveClientOptimizeIncludeSpecifiers(clientModules, exclude);
|
|
390
378
|
const include = sortStrings([
|
|
@@ -392,6 +380,11 @@ function createJskitClientBootstrapPlugin({ proxyTarget = "" } = {}) {
|
|
|
392
380
|
...clientIncludeSpecifiers,
|
|
393
381
|
CLIENT_BOOTSTRAP_MODULE_SPECIFIER
|
|
394
382
|
].filter((specifier) => !exclude.includes(specifier)));
|
|
383
|
+
// Vite cannot crawl the virtual bootstrap. Local and explicitly excluded clients
|
|
384
|
+
// still need scanning so their npm imports are ready before the first page loads.
|
|
385
|
+
clientScanSpecifiers = clientModules
|
|
386
|
+
.map((entry) => `${entry.packageId}/client`)
|
|
387
|
+
.filter((specifier) => !include.includes(specifier));
|
|
395
388
|
const dedupe = resolveClientRuntimeDedupeSpecifiers(userResolve);
|
|
396
389
|
const userServer = normalizeObject(userConfig.server);
|
|
397
390
|
const userProxyEntries = normalizeObject(userServer.proxy);
|
|
@@ -415,7 +408,7 @@ function createJskitClientBootstrapPlugin({ proxyTarget = "" } = {}) {
|
|
|
415
408
|
}
|
|
416
409
|
};
|
|
417
410
|
},
|
|
418
|
-
configResolved(resolvedConfig) {
|
|
411
|
+
async configResolved(resolvedConfig) {
|
|
419
412
|
if (hasMutableLocalPackages && resolvedConfig.resolve?.preserveSymlinks === true) {
|
|
420
413
|
throw new Error(
|
|
421
414
|
"JSKIT mutable local packages require Vite real-path resolution. Remove resolve.preserveSymlinks: true."
|
|
@@ -426,6 +419,28 @@ function createJskitClientBootstrapPlugin({ proxyTarget = "" } = {}) {
|
|
|
426
419
|
// its dependency ?v hash) before JSKIT sees the selected file. The config resolver applies the
|
|
427
420
|
// app's aliases, exports conditions, and wildcard rules without registering an optimized dep.
|
|
428
421
|
resolvePackageSpecifier = resolvedConfig.createResolver({ scan: true });
|
|
422
|
+
if (clientScanSpecifiers.length === 0) {
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
const clientEntries = await Promise.all(clientScanSpecifiers.map(async (specifier) => {
|
|
426
|
+
const entry = await resolvePackageSpecifier(specifier, path.join(appRoot, "package.json"));
|
|
427
|
+
if (!entry) {
|
|
428
|
+
throw new Error(`Cannot resolve JSKIT client dependency scan entry ${specifier}.`);
|
|
429
|
+
}
|
|
430
|
+
const localPackage = resolveLocalPackageForSpecifier(specifier, localPackages);
|
|
431
|
+
return localPackage ? resolveCanonicalLocalPackageId(entry, localPackage) || entry : entry;
|
|
432
|
+
}));
|
|
433
|
+
const optimizeDeps = resolvedConfig.environments.client.optimizeDeps;
|
|
434
|
+
const input = resolvedConfig.environments.client.input ?? resolvedConfig.build.rolldownOptions.input;
|
|
435
|
+
const entries = optimizeDeps.entries ?? (input
|
|
436
|
+
? (typeof input === "string" || Array.isArray(input) ? input : Object.values(input))
|
|
437
|
+
: ["**/*.html", "!**/__tests__/**", "!**/coverage/**"]);
|
|
438
|
+
const scanEntries = sortStrings([
|
|
439
|
+
...(Array.isArray(entries) ? entries : [entries]),
|
|
440
|
+
...clientEntries
|
|
441
|
+
]);
|
|
442
|
+
optimizeDeps.entries = scanEntries;
|
|
443
|
+
resolvedConfig.optimizeDeps.entries = scanEntries;
|
|
429
444
|
},
|
|
430
445
|
async resolveId(source, importer) {
|
|
431
446
|
if (source === CLIENT_BOOTSTRAP_VIRTUAL_ID) {
|
|
@@ -472,7 +487,6 @@ export {
|
|
|
472
487
|
resolveCanonicalLocalPackageId,
|
|
473
488
|
resolveLocalPackageForSpecifier,
|
|
474
489
|
resolveLocalPackageSources,
|
|
475
|
-
resolveLocalScopeOptimizeExcludeSpecifiers,
|
|
476
490
|
resolveInstalledClientPackageIds,
|
|
477
491
|
resolveLocalScopePackageIds,
|
|
478
492
|
resolveInstalledClientModules,
|
|
@@ -11,7 +11,6 @@ import {
|
|
|
11
11
|
resolveCanonicalLocalPackageId,
|
|
12
12
|
resolveLocalPackageForSpecifier,
|
|
13
13
|
resolveLocalPackageSources,
|
|
14
|
-
resolveLocalScopeOptimizeExcludeSpecifiers,
|
|
15
14
|
resolveClientOptimizeIncludeSpecifiers,
|
|
16
15
|
resolveClientOptimizeExcludeSpecifiers,
|
|
17
16
|
resolveLocalScopePackageIds,
|
|
@@ -164,7 +163,7 @@ test("createVirtualModuleSource renders deterministic client module imports", ()
|
|
|
164
163
|
assert.match(source, /installedClientModules/);
|
|
165
164
|
});
|
|
166
165
|
|
|
167
|
-
test("resolveClientOptimizeExcludeSpecifiers
|
|
166
|
+
test("resolveClientOptimizeExcludeSpecifiers lets Vite scan local source imports", () => {
|
|
168
167
|
const exclude = resolveClientOptimizeExcludeSpecifiers([
|
|
169
168
|
{
|
|
170
169
|
packageId: "@z/pkg",
|
|
@@ -188,14 +187,7 @@ test("resolveClientOptimizeExcludeSpecifiers excludes local/app-local package ro
|
|
|
188
187
|
}
|
|
189
188
|
]);
|
|
190
189
|
|
|
191
|
-
assert.deepEqual(exclude, [
|
|
192
|
-
"@a/pkg",
|
|
193
|
-
"@a/pkg/client",
|
|
194
|
-
"@a/pkg/shared",
|
|
195
|
-
"@b/pkg",
|
|
196
|
-
"@b/pkg/client",
|
|
197
|
-
"@b/pkg/shared"
|
|
198
|
-
]);
|
|
190
|
+
assert.deepEqual(exclude, []);
|
|
199
191
|
});
|
|
200
192
|
|
|
201
193
|
test("resolveClientOptimizeExcludeSpecifiers includes packageMetadata-declared excludes", () => {
|
|
@@ -215,9 +207,6 @@ test("resolveClientOptimizeExcludeSpecifiers includes packageMetadata-declared e
|
|
|
215
207
|
]);
|
|
216
208
|
|
|
217
209
|
assert.deepEqual(exclude, [
|
|
218
|
-
"@a/pkg",
|
|
219
|
-
"@a/pkg/client",
|
|
220
|
-
"@a/pkg/shared",
|
|
221
210
|
"@z/pkg/client",
|
|
222
211
|
"external-problem-dep"
|
|
223
212
|
]);
|
|
@@ -271,18 +260,6 @@ test("resolveClientOptimizeIncludeSpecifiers omits excluded package clients", ()
|
|
|
271
260
|
assert.deepEqual(include, ["@c/pkg/client"]);
|
|
272
261
|
});
|
|
273
262
|
|
|
274
|
-
test("resolveLocalScopeOptimizeExcludeSpecifiers expands @local package ids to root/client/shared", () => {
|
|
275
|
-
const exclude = resolveLocalScopeOptimizeExcludeSpecifiers(["@local/app", "@local/feature"]);
|
|
276
|
-
assert.deepEqual(exclude, [
|
|
277
|
-
"@local/app",
|
|
278
|
-
"@local/app/client",
|
|
279
|
-
"@local/app/shared",
|
|
280
|
-
"@local/feature",
|
|
281
|
-
"@local/feature/client",
|
|
282
|
-
"@local/feature/shared"
|
|
283
|
-
]);
|
|
284
|
-
});
|
|
285
|
-
|
|
286
263
|
test("resolveInstalledClientPackageIds returns only installed packages with a client export", async () => {
|
|
287
264
|
const tempRoot = await mkdtemp(path.join(os.tmpdir(), "jskit-client-bootstrap-"));
|
|
288
265
|
const appRoot = tempRoot;
|
|
@@ -681,11 +658,14 @@ test("createJskitClientBootstrapPlugin resolves multiple local packages before V
|
|
|
681
658
|
["@example/local-utility", path.join(tempRoot, "node_modules", "@example", "local-utility", "browser", "utility.js")],
|
|
682
659
|
["@example/local-utility/shared", path.join(tempRoot, "node_modules", "@example", "local-utility", "browser", "utility-shared.js")]
|
|
683
660
|
]);
|
|
684
|
-
plugin.configResolved({
|
|
661
|
+
await plugin.configResolved({
|
|
662
|
+
optimizeDeps: {},
|
|
663
|
+
environments: { client: { optimizeDeps: { entries: ["index.html"] } } },
|
|
664
|
+
build: { rolldownOptions: {} },
|
|
685
665
|
createResolver(options) {
|
|
686
666
|
assert.equal(options.scan, true);
|
|
687
667
|
return async (source, importer) => {
|
|
688
|
-
assert.
|
|
668
|
+
assert.ok(importer === undefined || importer === path.join(tempRoot, "package.json"));
|
|
689
669
|
return viteResolvedIds.get(source);
|
|
690
670
|
};
|
|
691
671
|
}
|
|
@@ -812,7 +792,7 @@ test("createJskitClientBootstrapPlugin config lets packageMetadata excludes over
|
|
|
812
792
|
}
|
|
813
793
|
});
|
|
814
794
|
|
|
815
|
-
test("createJskitClientBootstrapPlugin config
|
|
795
|
+
test("createJskitClientBootstrapPlugin config keeps local packages as scannable source", async () => {
|
|
816
796
|
const tempRoot = await mkdtemp(path.join(os.tmpdir(), "jskit-client-bootstrap-config-local-"));
|
|
817
797
|
const previousCwd = process.cwd();
|
|
818
798
|
|
|
@@ -862,11 +842,7 @@ test("createJskitClientBootstrapPlugin config excludes local package roots and c
|
|
|
862
842
|
}
|
|
863
843
|
});
|
|
864
844
|
|
|
865
|
-
assert.deepEqual(result.optimizeDeps.exclude, [
|
|
866
|
-
"@example/local-client",
|
|
867
|
-
"@example/local-client/client",
|
|
868
|
-
"@example/local-client/shared"
|
|
869
|
-
]);
|
|
845
|
+
assert.deepEqual(result.optimizeDeps.exclude, []);
|
|
870
846
|
assert.deepEqual(result.optimizeDeps.include, [
|
|
871
847
|
"@example/remote-client/client",
|
|
872
848
|
"@jskit-ai/kernel/client/moduleBootstrap",
|
|
@@ -910,7 +886,7 @@ test("createJskitClientBootstrapPlugin config preserves user resolve fields and
|
|
|
910
886
|
}
|
|
911
887
|
});
|
|
912
888
|
|
|
913
|
-
test("createJskitClientBootstrapPlugin config
|
|
889
|
+
test("createJskitClientBootstrapPlugin config uses real paths for @local scoped packages", async () => {
|
|
914
890
|
const tempRoot = await mkdtemp(path.join(os.tmpdir(), "jskit-client-bootstrap-local-scope-config-"));
|
|
915
891
|
const previousCwd = process.cwd();
|
|
916
892
|
|
|
@@ -944,14 +920,7 @@ test("createJskitClientBootstrapPlugin config excludes all @local scoped package
|
|
|
944
920
|
const plugin = createJskitClientBootstrapPlugin();
|
|
945
921
|
const result = await plugin.config({});
|
|
946
922
|
|
|
947
|
-
assert.deepEqual(result.optimizeDeps.exclude, [
|
|
948
|
-
"@local/feature",
|
|
949
|
-
"@local/feature/client",
|
|
950
|
-
"@local/feature/shared",
|
|
951
|
-
"@local/main",
|
|
952
|
-
"@local/main/client",
|
|
953
|
-
"@local/main/shared"
|
|
954
|
-
]);
|
|
923
|
+
assert.deepEqual(result.optimizeDeps.exclude, []);
|
|
955
924
|
assert.deepEqual(result.optimizeDeps.include, [
|
|
956
925
|
"@example/remote-client/client",
|
|
957
926
|
"@jskit-ai/kernel/client/moduleBootstrap"
|
|
@@ -976,7 +945,7 @@ test("createJskitClientBootstrapPlugin rejects a later preserveSymlinks override
|
|
|
976
945
|
const result = await plugin.config({});
|
|
977
946
|
|
|
978
947
|
assert.equal(result.resolve.preserveSymlinks, false);
|
|
979
|
-
assert.
|
|
948
|
+
await assert.rejects(
|
|
980
949
|
() => plugin.configResolved({
|
|
981
950
|
resolve: {
|
|
982
951
|
preserveSymlinks: true
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { mkdtemp, mkdir, rm, symlink, writeFile } from "node:fs/promises";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import test from "node:test";
|
|
6
|
+
import { optimizeDeps, resolveConfig } from "vite";
|
|
7
|
+
import { createJskitClientBootstrapPlugin } from "./clientBootstrapPlugin.js";
|
|
8
|
+
|
|
9
|
+
const scanCases = [
|
|
10
|
+
{ name: "workspace with explicit entries", localDependency: "1.0.0", config: { optimizeDeps: { entries: ["src/main.js"] } } },
|
|
11
|
+
{ name: "workspace with default HTML discovery", localDependency: "1.0.0", config: {} },
|
|
12
|
+
{ name: "workspace with build inputs", localDependency: "1.0.0", config: { build: { rolldownOptions: { input: { app: "src/main.js" } } } } },
|
|
13
|
+
{ name: "file dependency", localDependency: "file:packages/main", config: { optimizeDeps: { entries: ["src/main.js"] } } }
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
for (const scanCase of scanCases) {
|
|
17
|
+
test(`cold scan discovers virtual client and local shared dependencies: ${scanCase.name}`, async () => {
|
|
18
|
+
const root = await mkdtemp(path.join(os.tmpdir(), "jskit-client-dependency-scan-"));
|
|
19
|
+
const previousCwd = process.cwd();
|
|
20
|
+
const write = async (name, source) => {
|
|
21
|
+
const target = path.join(root, name);
|
|
22
|
+
await mkdir(path.dirname(target), { recursive: true });
|
|
23
|
+
await writeFile(target, typeof source === "string" ? source : JSON.stringify(source));
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
await write("package.json", {
|
|
28
|
+
name: "client-scan-fixture", type: "module", private: true,
|
|
29
|
+
workspaces: ["packages/*"],
|
|
30
|
+
dependencies: {
|
|
31
|
+
"@local/main": scanCase.localDependency,
|
|
32
|
+
"@local/utility": "1.0.0",
|
|
33
|
+
"@example/shell": "1.0.0"
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
await write("index.html", '<script type="module" src="/src/main.js"></script>');
|
|
37
|
+
await write("__tests__/ignored.html", '<script type="module">import "missing-test-only";</script>');
|
|
38
|
+
await write("src/main.js", 'import "virtual:jskit-client-bootstrap";');
|
|
39
|
+
await write("packages/main/package.json", {
|
|
40
|
+
name: "@local/main", version: "1.0.0", type: "module",
|
|
41
|
+
jskit: { kind: "runtime" },
|
|
42
|
+
exports: { "./client": { browser: "./browser.js", default: "./server.js" } }
|
|
43
|
+
});
|
|
44
|
+
await write("packages/main/browser.js", 'import "client-helper"; import "@local/utility/shared"; import("./Page.vue");');
|
|
45
|
+
await write("packages/main/server.js", 'import "server-only-missing";');
|
|
46
|
+
await write("packages/main/Page.vue", '<script setup>import "page-helper";</script><template>Page</template>');
|
|
47
|
+
await write("packages/utility/package.json", {
|
|
48
|
+
name: "@local/utility", version: "1.0.0", type: "module",
|
|
49
|
+
exports: { "./shared": "./shared.js" }
|
|
50
|
+
});
|
|
51
|
+
await write("packages/utility/shared.js", 'import "shared-helper";');
|
|
52
|
+
await mkdir(path.join(root, "node_modules/@local"), { recursive: true });
|
|
53
|
+
for (const name of ["main", "utility"]) {
|
|
54
|
+
await symlink(path.join(root, "packages", name), path.join(root, "node_modules/@local", name));
|
|
55
|
+
}
|
|
56
|
+
await write("node_modules/@example/shell/package.json", {
|
|
57
|
+
name: "@example/shell", version: "1.0.0", type: "module",
|
|
58
|
+
exports: { "./client": "./client.js" },
|
|
59
|
+
jskit: { metadata: { client: { optimizeDeps: { exclude: ["@example/shell/client"] } } } }
|
|
60
|
+
});
|
|
61
|
+
await write("node_modules/@example/shell/client.js", 'import "/src/shell-content.js";');
|
|
62
|
+
await write("src/shell-content.js", 'import "shell-helper";');
|
|
63
|
+
await write("node_modules/@jskit-ai/kernel/package.json", {
|
|
64
|
+
name: "@jskit-ai/kernel", version: "1.0.0", type: "module",
|
|
65
|
+
exports: { "./client/moduleBootstrap": "./bootstrap.js" }
|
|
66
|
+
});
|
|
67
|
+
await write("node_modules/@jskit-ai/kernel/bootstrap.js", "export const bootClientModules = () => {};");
|
|
68
|
+
for (const name of ["client-helper", "shared-helper", "page-helper", "shell-helper"]) {
|
|
69
|
+
await write(`node_modules/${name}/package.json`, {
|
|
70
|
+
name, version: "1.0.0", type: "module", exports: "./index.js"
|
|
71
|
+
});
|
|
72
|
+
await write(`node_modules/${name}/index.js`, "export const value = 1;");
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
process.chdir(root);
|
|
76
|
+
const config = await resolveConfig({
|
|
77
|
+
configFile: false,
|
|
78
|
+
logLevel: "silent",
|
|
79
|
+
plugins: [createJskitClientBootstrapPlugin()],
|
|
80
|
+
...scanCase.config
|
|
81
|
+
}, "serve");
|
|
82
|
+
const metadata = await optimizeDeps(config, true);
|
|
83
|
+
for (const name of ["client-helper", "shared-helper", "page-helper", "shell-helper"]) {
|
|
84
|
+
assert.ok(metadata.optimized[name], `${name} must be ready before the browser loads a page`);
|
|
85
|
+
}
|
|
86
|
+
assert.equal(Object.keys(metadata.optimized).some((id) => id.startsWith("@local/")), false);
|
|
87
|
+
assert.equal(metadata.optimized["@example/shell/client"], undefined);
|
|
88
|
+
} finally {
|
|
89
|
+
process.chdir(previousCwd);
|
|
90
|
+
await rm(root, { recursive: true, force: true });
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|