mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
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:
@@ -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
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user