Skip to content

Commit d5b4d34

Browse files
committed
fix(vfs): don't read localStorage during feature detection in Node
Node 26 exposes `localStorage` as a global accessor that emits an ExperimentalWarning when read - `typeof` included - unless the process was started with `--localstorage-file`. The existing feature detect reads it at module evaluation, so simply importing `@typescript/vfs` prints a warning on Node 26 before any API of the package is called. The surrounding try/catch does not help: the accessor warns and returns undefined rather than throwing. Skip the probe entirely in a bare Node process. The only thing the value is used for is looking up a `DEBUG` key, and in Node `process.env.DEBUG` already covers that. Hosts that expose both `process` and a DOM (Electron renderers) still probe as before, as do browsers. Also folds the `typeof localStorage.getItem === 'function'` guard added in #3450 into `hasLocalStorage`, where it belongs. Signed-off-by: C. Spencer Beggs <spencer@beggs.codes> Claude-Session: https://claude.ai/code/session_01TTDH2nJgCerAnT3DQPSTew
1 parent 61332a7 commit d5b4d34

2 files changed

Lines changed: 22 additions & 5 deletions

File tree

‎.changeset/olive-tigers-hammer.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@typescript/vfs": patch
3+
---
4+
5+
Skip the localStorage feature detect in Node so importing the package no longer emits an ExperimentalWarning on Node 26

‎packages/typescript-vfs/src/index.ts‎

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,25 @@ interface LocalStorageLike {
1717
declare var localStorage: LocalStorageLike | undefined;
1818
declare var fetch: FetchLike | undefined;
1919

20+
const hasProcess = typeof process !== `undefined`
21+
22+
// Node >= 26 exposes `localStorage` as a global accessor which emits an
23+
// ExperimentalWarning when it is read - including via `typeof` - unless the process
24+
// was started with `--localstorage-file`. Probing it here would print that warning at
25+
// module evaluation for every consumer, so skip the probe entirely in a bare Node
26+
// process, where `process.env.DEBUG` below is the only reachable way to opt in anyway.
27+
// DOM-bearing hosts that also expose `process` (Electron renderers) still get probed.
28+
const isBareNodeProcess =
29+
hasProcess && typeof process.versions?.node === `string` && !(`window` in globalThis)
30+
2031
let hasLocalStorage = false
21-
try {
22-
hasLocalStorage = typeof localStorage !== `undefined`
23-
} catch (error) { }
32+
if (!isBareNodeProcess) {
33+
try {
34+
hasLocalStorage = typeof localStorage !== `undefined` && typeof localStorage.getItem === `function`
35+
} catch (error) { }
36+
}
2437

25-
const hasProcess = typeof process !== `undefined`
26-
const shouldDebug = (hasLocalStorage && typeof localStorage!.getItem === 'function' && localStorage!.getItem("DEBUG")) || (hasProcess && process.env.DEBUG)
38+
const shouldDebug = (hasLocalStorage && localStorage!.getItem("DEBUG")) || (hasProcess && process.env.DEBUG)
2739
const debugLog = shouldDebug ? console.log : (_message?: any, ..._optionalParams: any[]) => ""
2840

2941
export interface VirtualTypeScriptEnvironment {

0 commit comments

Comments
 (0)