A build must load its own plugins
Explore this workspace.
Technical background
A Tabby exports NODE_PATH to every shell it starts, and the module lookup appended its own paths to whatever it inherited — so a Tabby launched from a terminal inside another Tabby resolved tabby-core to the other build's copy: two Angulars, and a boot that stops dead on the splash screen. This build's paths now go first, and the builtins that must not be got wrong are required by absolute path.
The problem
A Tabby exports NODE_PATH to every shell it starts — its own builtin plugins, its app.asar\node_modules, and the user plugin directory — and the module lookup appended its own paths to whatever it inherited. So a Tabby started from a terminal inside another Tabby resolved tabby-core to the other build's copy: two Angulars, and a boot that stops dead on the splash screen. Invisible in a packaged build, because there is no console to see it in.
How it works
Ordering plus absolute paths: this build's paths go ahead of anything inherited, and the builtins that must not be got wrong are required from the build's own plugin directory by absolute path rather than by name.
Details
- The symptom is an idle process, not a busy one. Measured on the real failure: the renderer sat at 94 MB and 0% CPU for five hours, window titled
Tabby, nothing in the app log after renderer start.diagnostics.loghad the answer in one line —require-failed,tabby-local, MODULE_NOT_FOUND — plus a sampled 203 ms read of atabby-coreinside the user plugin directory, which is a path no healthy build should ever read. - A stale copy of a builtin in the user plugin directory does the same. Three of them were there, pulled in by a third-party plugin listing
tabby-core/tabby-settings/tabby-terminalunderdependenciesrather thanpeerDependencies. Plugin discovery already skipped such copies; nothing stoppedrequirefinding them first. +=on an unsetNODE_PATHalso left a literal"undefined"entry on the path, for years.- The test resolves the four builtins under each poisoned environment and asserts they all come from the build itself — and also asserts the old ordering still fails, since a green run on a clean machine would otherwise prove nothing.
What this does not claim
- Relaunching does not clear it. The single-instance lock hands the launch to the poisoned process, which opens another window that never boots either — which is what "it's still hanging" turned out to mean. That instance has to be closed first. The watchdog exists because of exactly this.