mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 10:24:02 +00:00
build: cache compiled components and load them on the test thread
Since the UI moved to single-file components, every unit-test process compiled the views it imports from scratch, and the loader ran off-thread (module.register), adding a round trip to every module a test imports, including the ones that are not components. Core's unit tests took about twice as long, and a host running Core's suite on smaller runners passed its CI time limit. register-vue now installs synchronous hooks on the loading thread (module.registerHooks). Compiled components are kept in the system temp directory, keyed by the file's path and text, the Vue version and the loader's own code, so each one compiles once across test processes; the compiler itself loads only on a cache miss. Cached modules run as code, so the directory is used only when it is a real directory owned by the current user and writable by no one else; on Windows it lives in the user's local app data instead of a temp directory that may be shared. The cache never sits inside the package tree, and GEV_VUE_CACHE=0 compiles every time. On four cores the full suite went from 441 s to 240 s from a cold cache.
This commit is contained in:
1 parent
13a04a8957
commit
7d236a1174
4 files changed
+241
-9
No files matched your search
@@ -0,0 +1,111 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import {
|
||||
chmodSync,
|
||||
mkdirSync,
|
||||
mkdtempSync,
|
||||
readdirSync,
|
||||
rmSync,
|
||||
symlinkSync,
|
||||
writeFileSync,
|
||||
} from 'node:fs';
|
||||
import { tmpdir } from 'node:os';
|
||||
import path from 'node:path';
|
||||
import test from 'node:test';
|
||||
import {
|
||||
cachedVueModule,
|
||||
compileVueModule,
|
||||
ownCacheDirectory,
|
||||
vueCacheDirectory,
|
||||
vueCacheKey,
|
||||
} from '../../build/vueLoader.js';
|
||||
|
||||
const SOURCE =
|
||||
'<script setup>\nconst label = "Hi";\n</script>\n<template><b>{{ label }}</b></template>\n';
|
||||
const FILE = '/virtual/Greeting.vue';
|
||||
|
||||
test('a component compiles once and later processes read the cached module', (t) => {
|
||||
const directory = mkdtempSync(path.join(tmpdir(), 'gev-vue-cache-test-'));
|
||||
t.after(() => rmSync(directory, { recursive: true, force: true }));
|
||||
const compiled = cachedVueModule(SOURCE, FILE, directory);
|
||||
assert.equal(compiled, compileVueModule(SOURCE, FILE));
|
||||
const entries = readdirSync(directory);
|
||||
assert.deepEqual(entries, [`${vueCacheKey(SOURCE, FILE)}.mjs`]);
|
||||
// A cached entry is returned as stored, without compiling again.
|
||||
writeFileSync(path.join(directory, entries[0]), 'export default "cached";');
|
||||
assert.equal(
|
||||
cachedVueModule(SOURCE, FILE, directory),
|
||||
'export default "cached";',
|
||||
);
|
||||
});
|
||||
|
||||
test('an edited component or another path is a new cache entry', () => {
|
||||
const key = vueCacheKey(SOURCE, FILE);
|
||||
assert.notEqual(vueCacheKey(`${SOURCE}\n`, FILE), key);
|
||||
assert.notEqual(vueCacheKey(SOURCE, '/virtual/Other.vue'), key);
|
||||
assert.equal(vueCacheKey(SOURCE, FILE), key);
|
||||
});
|
||||
|
||||
test('GEV_VUE_CACHE=0 compiles every time; otherwise the cache sits in a per-user directory', () => {
|
||||
assert.equal(vueCacheDirectory({ GEV_VUE_CACHE: '0' }), null);
|
||||
if (process.platform !== 'win32') {
|
||||
const directory = vueCacheDirectory({});
|
||||
assert.equal(path.dirname(directory), tmpdir());
|
||||
assert.match(path.basename(directory), /^gev-vue-sfc-/);
|
||||
}
|
||||
// Windows temp directories may be shared, so the cache lives in the
|
||||
// user's profile, or not at all.
|
||||
assert.equal(
|
||||
vueCacheDirectory(
|
||||
{ LOCALAPPDATA: 'C:\\Users\\a\\AppData\\Local' },
|
||||
'win32',
|
||||
),
|
||||
path.join('C:\\Users\\a\\AppData\\Local', 'gev-vue-sfc'),
|
||||
);
|
||||
assert.equal(vueCacheDirectory({}, 'win32'), null);
|
||||
assert.equal(
|
||||
cachedVueModule(SOURCE, FILE, null),
|
||||
compileVueModule(SOURCE, FILE),
|
||||
);
|
||||
});
|
||||
|
||||
test('a cache directory that cannot be written still returns the compiled module', (t) => {
|
||||
const directory = mkdtempSync(path.join(tmpdir(), 'gev-vue-cache-test-'));
|
||||
t.after(() => rmSync(directory, { recursive: true, force: true }));
|
||||
// A file where the cache directory should be makes every write fail.
|
||||
const blocked = path.join(directory, 'blocked');
|
||||
writeFileSync(blocked, '');
|
||||
assert.equal(
|
||||
cachedVueModule(SOURCE, FILE, blocked),
|
||||
compileVueModule(SOURCE, FILE),
|
||||
);
|
||||
});
|
||||
|
||||
test(
|
||||
'a cache directory others can write to, or a link to one, is never read',
|
||||
{
|
||||
skip: process.platform === 'win32',
|
||||
},
|
||||
(t) => {
|
||||
const root = mkdtempSync(path.join(tmpdir(), 'gev-vue-cache-test-'));
|
||||
t.after(() => rmSync(root, { recursive: true, force: true }));
|
||||
const shared = path.join(root, 'shared');
|
||||
mkdirSync(shared);
|
||||
chmodSync(shared, 0o777);
|
||||
// A module planted where the cache would look must not run.
|
||||
writeFileSync(
|
||||
path.join(shared, `${vueCacheKey(SOURCE, FILE)}.mjs`),
|
||||
'export default "planted";',
|
||||
);
|
||||
assert.equal(ownCacheDirectory(shared), false);
|
||||
assert.equal(
|
||||
cachedVueModule(SOURCE, FILE, shared),
|
||||
compileVueModule(SOURCE, FILE),
|
||||
);
|
||||
const own = path.join(root, 'own');
|
||||
mkdirSync(own, { mode: 0o700 });
|
||||
const link = path.join(root, 'link');
|
||||
symlinkSync(own, link);
|
||||
assert.equal(ownCacheDirectory(link), false);
|
||||
assert.equal(ownCacheDirectory(own), true);
|
||||
},
|
||||
);
|
||||
Reference in new issue
Block a user