Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion packages/lint/src/lazy-deps.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.
// test-budget: 30 — whole-package import: the in-process case imports the whole @objectstack/lint barrel cold, so the file's floor is vitest's transform of that graph and of every inlined @objectstack/spec dist bundle it reaches, and the two built-dist probes each spawn node once; slowest CI reading 18.0 s (hourly run 38267594064) x 1.25, rounded up
//
// Boot-path contract: importing @objectstack/lint must NOT load its heavy,
// gate-only dependencies. The package sits on the kernel boot path, while each
Expand Down
1 change: 0 additions & 1 deletion packages/lint/src/runtime-lazy-deps.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.
// test-budget: 30 — whole-package import: the in-process cases import the @objectstack/lint/runtime entry cold, which reaches the whole gate graph, so the file's floor is vitest's transform of it and of every inlined @objectstack/spec dist bundle it reaches, and the three built-dist probes each spawn node once; slowest CI reading 19.2 s (hourly run 38314183560) x 1.25, rounded up
//
// The kernel boot-path contract for `@objectstack/lint/runtime` (#4463).
//
Expand Down
56 changes: 56 additions & 0 deletions packages/lint/src/vitest-spec-external.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.
//
// Positive control for `test.server.deps.external` in ../vitest.config.ts.
//
// That entry hands the linked `@objectstack/spec` dist to Node instead of
// vite's transform. Its pattern is matched against the module's REALPATH, and
// a pattern that matches nothing is silent: the suite stays green and only
// gets slower. So this file asks the one question that tells the two apart —
// is the spec module these sources import the SAME instance Node's own loader
// holds?
//
// - Externalised: vitest's runner loads the dist with a native `import()`, so
// Node's loader holds that module, and a native load of the same file
// returns that very instance — its exports are identical objects.
// - Inlined (the pattern stopped matching): vite evaluates its own copy of the
// dist, and the native load builds a separate one — every export is a
// different object, and the identity assertions below go red.
//
// The native load is `require()` of the ESM file (Node 22's require(esm),
// which shares the ESM loader's module map) through `createRequire`, so vite
// cannot rewrite it; vitest's evaluator gives a `new Function` `import()` no
// dynamic-import callback. The file is the one the package's `exports` map
// names for an ESM import, taken from the linked package root.
import { readFileSync, realpathSync } from 'node:fs';
import { createRequire } from 'node:module';
import { join, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import { describe, expect, it } from 'vitest';
import { defineStack } from '@objectstack/spec';
import { ObjectSchema } from '@objectstack/spec/data';

const HERE = fileURLToPath(new URL('.', import.meta.url));
// The package's own node_modules link — the same one these sources resolve.
const SPEC_ROOT = realpathSync(resolve(HERE, '../node_modules/@objectstack/spec'));

const nativeRequire = createRequire(import.meta.url);

function nativeEsmEntry(subpath: '.' | './data'): Record<string, unknown> {
const manifest = JSON.parse(readFileSync(join(SPEC_ROOT, 'package.json'), 'utf8'));
const target: string = manifest.exports[subpath].import.default;
return nativeRequire(join(SPEC_ROOT, target)) as Record<string, unknown>;
}

describe('@objectstack/spec is loaded by Node, not inlined by vite', () => {
it('the root entry is the native module instance', () => {
const native = nativeEsmEntry('.');
expect(typeof defineStack).toBe('function');
expect(defineStack).toBe(native.defineStack);
});

it('a subpath entry is the native module instance', () => {
const native = nativeEsmEntry('./data');
expect(ObjectSchema).toBeDefined();
expect(ObjectSchema).toBe(native.ObjectSchema);
});
});
31 changes: 29 additions & 2 deletions packages/lint/vitest.config.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.

// This config exists for exactly one setting; everything else stays on
// This config exists for exactly two settings; everything else stays on
// vitest's defaults, deliberately — a key added here re-specifies behaviour
// for every test file in the package (packages/cli/vitest.config.ts's header
// records the incident that taught that).
// records the incident that taught that). Both settings are package-wide on
// purpose: each removes a mechanism every file here is exposed to, rather
// than tuning one file.
import { defineConfig } from 'vitest/config';

export default defineConfig({
Expand All @@ -15,5 +17,30 @@ export default defineConfig({
// Mechanism + measured costs: examples/app-showcase/vitest.config.ts.
// Enforced repo-wide by scripts/check-console-intercept-disarm.mjs.
disableConsoleIntercept: true,
server: {
deps: {
// Load the linked `@objectstack/spec` dist with Node, not through
// vite's transform. Vitest's default `external` is node_modules-only,
// judged on a module's REALPATH, and a pnpm-linked workspace package's
// realpath is `packages/spec/dist/…` — so without this nearly every
// file here (lint imports spec's root and nine subpaths) inlined about
// 33 MB of built `.mjs`, and the first file to import a lint entry paid
// ~10 s of its cold transform. The import resolves through `exports`
// to `dist/` either way, so this changes only who evaluates that dist,
// never which bytes are under test.
//
// ⚠️ The pattern must match the realpath; a name-shaped one
// (`@objectstack/spec`) matches nothing, silently — see
// packages/cli/vitest.config.ts. The positive control is
// `src/vitest-spec-external.test.ts`, red the moment this stops
// matching.
//
// Cost: an externalised module cannot be `vi.mock`ed. The census taken
// when this landed found zero `vi.mock` / `vi.doMock` / `vi.hoisted`
// sites in this package; a later test that needs to mock spec must
// move this entry, not work around it.
external: [/[\\/]packages[\\/]spec[\\/]dist[\\/]/],
},
},
},
});
Loading