fix(desktop): cover Tauri submodule IPC in profiling core proxy

The bare-specifier `@tauri-apps/api/core` Vite alias only caught direct core imports and external plugins. Tauri's own submodules (event, app, window, webview) reach core via the relative import `./core.js`, which an alias never sees, so their plugin:event|*, plugin:window|* … invoke traffic bypassed the profiling wrapper entirely — undercounting Rust wait time and letting the harness exonerate the very bucket it failed to observe.

Replace the alias with a pre-enforced Vite resolveId hook (pure decision in viteTauriCoreProxy.ts) that redirects both the bare specifier and the relative ./core.js from inside @tauri-apps/api to the proxy, while the proxy's @tauri-core-impl escape resolves to the real module without looping. Add a real Vite resolve-graph test proving all three call shapes route through the proxy once, plus pure-predicate unit tests.

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
This commit is contained in:
Duncan
2026-08-17 20:57:39 -04:00
co-authored by Will Pfleger
parent 437fe18948
commit cbfb2d6996
4 changed files with 212 additions and 13 deletions
@@ -23,6 +23,7 @@ import {
wrapInvoke,
} from "@/shared/profiling/ipc.ts";
import { ProfileRecorder, RING_CAPACITY } from "@/shared/profiling/recorder.ts";
import { resolveTauriCore } from "@/shared/profiling/viteTauriCoreProxy.ts";
function fixedClock() {
let t = 1000;
@@ -200,6 +201,70 @@ describe("wrapInvoke / observer registry", () => {
});
});
describe("resolveTauriCore", () => {
const PROXY = "/abs/src/shared/profiling/tauriCoreProxy.ts";
const REAL = "/abs/node_modules/@tauri-apps/api/core.js";
it("redirects the bare core specifier to the proxy", () => {
// App code and external plugins (`plugin-opener`, …) import this form.
assert.equal(
resolveTauriCore("@tauri-apps/api/core", "/abs/src/App.tsx", PROXY, REAL),
PROXY,
);
});
it("redirects a relative ./core.js from inside @tauri-apps/api to the proxy", () => {
// The bypass Thufir found: Tauri's own submodules (event/app/window/webview)
// reach core via the relative import, which a bare alias never sees.
assert.equal(
resolveTauriCore(
"./core.js",
"/abs/node_modules/@tauri-apps/api/event.js",
PROXY,
REAL,
),
PROXY,
);
});
it("maps the proxy's escape specifier to the real core, not itself", () => {
// The proxy re-exports through @tauri-core-impl; it must reach the real
// module so the redirect never loops.
assert.equal(
resolveTauriCore("@tauri-core-impl", PROXY, PROXY, REAL),
REAL,
);
});
it("leaves the proxy's other imports untouched", () => {
// e.g. the proxy importing the observer registry must not be redirected.
assert.equal(
resolveTauriCore("@/shared/profiling/ipc", PROXY, PROXY, REAL),
null,
);
});
it("ignores a relative ./core.js from outside @tauri-apps/api", () => {
// A same-named file elsewhere must not be captured.
assert.equal(
resolveTauriCore(
"./core.js",
"/abs/src/shared/lib/thing.ts",
PROXY,
REAL,
),
null,
);
});
it("ignores unrelated specifiers", () => {
assert.equal(
resolveTauriCore("react", "/abs/src/App.tsx", PROXY, REAL),
null,
);
});
});
describe("ProfileRecorder ring buffer", () => {
it("bounds the buffer at RING_CAPACITY, dropping oldest", async () => {
const rec = new ProfileRecorder("session-1", async () => {}, fixedClock());
@@ -0,0 +1,71 @@
/**
* Real Vite resolve-graph test for the temporary renderer profiling branch
* (never merges). The unit suite for `resolveTauriCore` proves the decision in
* isolation, but the coverage contract depends on how Vite actually resolves
* imports through the shipped config — the exact gap a bare-specifier alias
* hid. This drives Vite's own plugin container against `vite.config.ts` so the
* three call shapes are proven end-to-end, not modeled.
*/
import assert from "node:assert/strict";
import path from "node:path";
import { after, before, describe, it } from "node:test";
import { fileURLToPath } from "node:url";
const desktopDir = path.resolve(
path.dirname(fileURLToPath(import.meta.url)),
"../../..",
);
const abs = (p) => path.resolve(desktopDir, p);
const PROXY = abs("src/shared/profiling/tauriCoreProxy.ts");
const REAL_CORE = abs("node_modules/@tauri-apps/api/core.js");
describe("Vite resolves every Tauri core import through the proxy", () => {
let server;
const resolve = (source, importer) =>
server.pluginContainer
.resolveId(source, importer)
.then((r) => r?.id ?? null);
before(async () => {
const { createServer } = await import("vite");
server = await createServer({
configFile: abs("vite.config.ts"),
server: { middlewareMode: true },
logLevel: "silent",
});
});
after(async () => {
await server?.close();
});
it("routes a raw @tauri-apps/api/core import to the proxy", async () => {
assert.equal(
await resolve("@tauri-apps/api/core", abs("src/App.tsx")),
PROXY,
);
});
it("routes a built-in submodule's relative ./core.js to the proxy", async () => {
// event.js/app.js/window.js import core relatively — the bypass being fixed.
assert.equal(
await resolve("./core.js", abs("node_modules/@tauri-apps/api/event.js")),
PROXY,
);
});
it("routes an external plugin's core import to the proxy", async () => {
assert.equal(
await resolve(
"@tauri-apps/api/core",
abs("node_modules/@tauri-apps/plugin-opener/dist-js/index.js"),
),
PROXY,
);
});
it("resolves the proxy's escape import to the real core (no loop)", async () => {
assert.equal(await resolve("@tauri-core-impl", PROXY), REAL_CORE);
});
});
@@ -0,0 +1,47 @@
// Temporary renderer profiling harness (never merges) — pure resolver decision
// for routing every `@tauri-apps/api` core import through tauriCoreProxy.ts.
//
// A bare-specifier alias only catches `import ... from "@tauri-apps/api/core"`.
// Tauri's own submodules (`event`, `app`, `window`, `webview`, …) reach core
// via the RELATIVE import `import { invoke } from "./core.js"`, which an alias
// never sees — so their `plugin:event|*`, `plugin:window|*`, … traffic would
// bypass the wrapper and go unrecorded. A Vite `resolveId` hook can see the
// relative form (via the importer) and redirect it too, making the module seam
// canonical for the resolved core module regardless of how it is imported.
//
// This module holds only the pure decision so it is unit-testable without a
// Vite/Node type dependency (importing `vite` here would pull Node's global
// typings into the DOM-typed src program). The thin `Plugin` wrapper that calls
// it lives in vite.config.ts.
/** Specifier the proxy uses to reach the real core implementation. */
export const REAL_CORE_SPECIFIER = "@tauri-core-impl";
/**
* Decide where a module specifier should resolve so that every Tauri core
* import lands on the profiling proxy, while the proxy's own escape import
* reaches the real core without looping.
*
* Returns `proxyId` to redirect through the proxy, `realCoreId` for the escape
* hatch, or `null` to fall through to Vite's normal resolution.
*/
export function resolveTauriCore(
source: string,
importer: string | undefined,
proxyId: string,
realCoreId: string,
): string | null {
// Escape hatch: the proxy asks for the real implementation. Checked first so
// the proxy's own re-export never loops back into itself.
if (source === REAL_CORE_SPECIFIER) return realCoreId;
// Any other import originating in the proxy passes through untouched.
if (importer === proxyId) return null;
// Bare specifier — app code and external plugins (`plugin-opener`, …).
if (source === "@tauri-apps/api/core") return proxyId;
// Relative import from inside Tauri's own API package (`event`, `app`,
// `window`, `webview`, …), which resolve core as `./core.js`.
if (source === "./core.js" && importer?.includes("/@tauri-apps/api/")) {
return proxyId;
}
return null;
}
+29 -13
View File
@@ -2,12 +2,41 @@ import path from "node:path";
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { tanstackRouter } from "@tanstack/router-plugin/vite";
import { resolveTauriCore } from "./src/shared/profiling/viteTauriCoreProxy";
const host = process.env.TAURI_DEV_HOST;
// Temporary profiling harness (never merges): route every Tauri core `invoke`
// through a proxy that wraps it. A resolver (not a bare alias) is required
// because Tauri's own submodules (`event`, `app`, `window`, `webview`, …) reach
// core via the relative import `./core.js`, which an alias cannot see; the hook
// redirects both the bare specifier and that relative form to the proxy, while
// the proxy's `@tauri-core-impl` import escapes to the real module.
const tauriCoreProxyId = path.resolve(
__dirname,
"./src/shared/profiling/tauriCoreProxy.ts",
);
const tauriRealCoreId = path.resolve(
__dirname,
"./node_modules/@tauri-apps/api/core.js",
);
const tauriCoreProfilingProxy = {
name: "tauri-core-profiling-proxy",
enforce: "pre" as const,
resolveId(source: string, importer: string | undefined) {
return resolveTauriCore(
source,
importer,
tauriCoreProxyId,
tauriRealCoreId,
);
},
};
// https://vite.dev/config/
export default defineConfig(async () => ({
plugins: [
tauriCoreProfilingProxy,
tanstackRouter({
target: "react",
routesDirectory: "./src/app/routes",
@@ -23,19 +52,6 @@ export default defineConfig(async () => ({
],
resolve: {
alias: {
// Temporary profiling harness (never merges): route every
// `@tauri-apps/api/core` importer (raw consumers, invokeTauri, and every
// bundled Tauri plugin) through a proxy that wraps `invoke`. The proxy
// reaches the real module via `@tauri-core-impl` so this alias does not
// re-fire. Exact string match — plugin subpaths are unaffected.
"@tauri-apps/api/core": path.resolve(
__dirname,
"./src/shared/profiling/tauriCoreProxy.ts",
),
"@tauri-core-impl": path.resolve(
__dirname,
"./node_modules/@tauri-apps/api/core.js",
),
"@": "/src",
"@features-manifest": path.resolve(__dirname, "../preview-features.json"),
"@model-capabilities-manifest": path.resolve(