diff --git a/scripts/code.bat b/scripts/code.bat index 62cfd0b4c4908..cc906e1083297 100644 --- a/scripts/code.bat +++ b/scripts/code.bat @@ -26,6 +26,15 @@ set VSCODE_CLI=1 set ELECTRON_ENABLE_LOGGING=1 set ELECTRON_ENABLE_STACK_DUMPING=1 +if defined NODE_OPTIONS ( + if not defined VSCODE_NODE_OPTIONS set "VSCODE_NODE_OPTIONS=%NODE_OPTIONS%" + set NODE_OPTIONS= +) +if defined NODE_REPL_EXTERNAL_MODULE ( + if not defined VSCODE_NODE_REPL_EXTERNAL_MODULE set "VSCODE_NODE_REPL_EXTERNAL_MODULE=%NODE_REPL_EXTERNAL_MODULE%" + set NODE_REPL_EXTERNAL_MODULE= +) + set DISABLE_TEST_EXTENSION="--disable-extension=vscode.vscode-api-tests" for %%A in (%*) do ( if "%%~A"=="--extensionTestsPath" ( diff --git a/scripts/code.sh b/scripts/code.sh index 16fdefde55208..989228461d0f8 100755 --- a/scripts/code.sh +++ b/scripts/code.sh @@ -43,6 +43,19 @@ function code() { export ELECTRON_ENABLE_STACK_DUMPING=1 export ELECTRON_ENABLE_LOGGING=1 + if [[ -n "${NODE_OPTIONS}" ]]; then + if [[ -z "${VSCODE_NODE_OPTIONS+x}" ]]; then + export VSCODE_NODE_OPTIONS="${NODE_OPTIONS}" + fi + unset NODE_OPTIONS + fi + if [[ -n "${NODE_REPL_EXTERNAL_MODULE}" ]]; then + if [[ -z "${VSCODE_NODE_REPL_EXTERNAL_MODULE+x}" ]]; then + export VSCODE_NODE_REPL_EXTERNAL_MODULE="${NODE_REPL_EXTERNAL_MODULE}" + fi + unset NODE_REPL_EXTERNAL_MODULE + fi + DISABLE_TEST_EXTENSION="--disable-extension=vscode.vscode-api-tests" if [[ "$@" == *"--extensionTestsPath"* ]]; then DISABLE_TEST_EXTENSION="" diff --git a/src/vs/code/electron-main/main.ts b/src/vs/code/electron-main/main.ts index ae28c78c219cb..96a71bfda5c8e 100644 --- a/src/vs/code/electron-main/main.ts +++ b/src/vs/code/electron-main/main.ts @@ -75,6 +75,11 @@ import { addUNCHostToAllowlist, getUNCHost } from '../../base/node/unc.js'; import { ThemeMainService } from '../../platform/theme/electron-main/themeMainServiceImpl.js'; import { LINUX_SYSTEM_POLICY_FILE_PATH } from '../../base/common/policy.js'; +// Capture NODE_OPTIONS early before Electron strips it (https://github.com/microsoft/vscode/issues/231076) +// Store in a global so patchEnvironment can access it +const CAPTURED_NODE_OPTIONS = process.env['NODE_OPTIONS']; +const CAPTURED_NODE_REPL_EXTERNAL_MODULE = process.env['NODE_REPL_EXTERNAL_MODULE']; + /** * The main VS Code entry point. * @@ -262,6 +267,25 @@ class CodeMain { } }); + // Preserve NODE_OPTIONS for terminals on Windows and macOS (https://github.com/microsoft/vscode/issues/231076) + // Electron restricts NODE_OPTIONS early, so we capture globally and restore + // in the terminal environment, but prefer existing VSCODE_* values if set. + if (isMacintosh || isWindows) { + const existingNodeOptions = process.env['VSCODE_NODE_OPTIONS']; + if (typeof existingNodeOptions === 'string') { + instanceEnvironment['VSCODE_NODE_OPTIONS'] = existingNodeOptions; + } else if (CAPTURED_NODE_OPTIONS) { + instanceEnvironment['VSCODE_NODE_OPTIONS'] = CAPTURED_NODE_OPTIONS; + } + + const existingNodeReplExternalModule = process.env['VSCODE_NODE_REPL_EXTERNAL_MODULE']; + if (typeof existingNodeReplExternalModule === 'string') { + instanceEnvironment['VSCODE_NODE_REPL_EXTERNAL_MODULE'] = existingNodeReplExternalModule; + } else if (CAPTURED_NODE_REPL_EXTERNAL_MODULE) { + instanceEnvironment['VSCODE_NODE_REPL_EXTERNAL_MODULE'] = CAPTURED_NODE_REPL_EXTERNAL_MODULE; + } + } + Object.assign(process.env, instanceEnvironment); return instanceEnvironment; diff --git a/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts b/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts index 7ccbb07819d0c..6dcfeeaf25e7e 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts @@ -271,12 +271,13 @@ export async function createTerminalEnvironment( } // Workaround for https://github.com/microsoft/vscode/issues/204005 + // and https://github.com/microsoft/vscode/issues/231076 // We should restore the following environment variables when a user // launches the application using the CLI so that integrated terminal // can still inherit these variables. // We are not bypassing the restrictions implied in https://github.com/electron/electron/pull/40770 // since this only affects integrated terminal and not the application itself. - if (isMacintosh) { + if (isMacintosh || isWindows) { // Restore NODE_OPTIONS if it was set if (env['VSCODE_NODE_OPTIONS']) { env['NODE_OPTIONS'] = env['VSCODE_NODE_OPTIONS']; diff --git a/src/vs/workbench/contrib/terminal/test/common/terminalEnvironment.test.ts b/src/vs/workbench/contrib/terminal/test/common/terminalEnvironment.test.ts index f06292f5e1d84..cfc9f510c218a 100644 --- a/src/vs/workbench/contrib/terminal/test/common/terminalEnvironment.test.ts +++ b/src/vs/workbench/contrib/terminal/test/common/terminalEnvironment.test.ts @@ -321,6 +321,44 @@ suite('Workbench - TerminalEnvironment', () => { { foo: 'bar', empty: '', ...commonVariables } ); }); + test('should restore NODE_OPTIONS from VSCODE_NODE_OPTIONS on macOS and Windows', async () => { + const env = await createTerminalEnvironment({}, undefined, undefined, undefined, 'off', { + VSCODE_NODE_OPTIONS: '--max-old-space-size=8192', + VSCODE_NODE_REPL_EXTERNAL_MODULE: 'test-module' + }); + // On macOS and Windows, VSCODE_NODE_OPTIONS should be restored to NODE_OPTIONS + if (process.platform === 'darwin' || process.platform === 'win32') { + strictEqual(env['NODE_OPTIONS'], '--max-old-space-size=8192'); + strictEqual(env['NODE_REPL_EXTERNAL_MODULE'], 'test-module'); + strictEqual(env['VSCODE_NODE_OPTIONS'], undefined); + strictEqual(env['VSCODE_NODE_REPL_EXTERNAL_MODULE'], undefined); + } else { + // On other platforms, VSCODE_* and NODE_* vars should not be restored + strictEqual(env['NODE_OPTIONS'], undefined); + strictEqual(env['NODE_REPL_EXTERNAL_MODULE'], undefined); + strictEqual(env['VSCODE_NODE_OPTIONS'], undefined); + strictEqual(env['VSCODE_NODE_REPL_EXTERNAL_MODULE'], undefined); + } + }); + test('should prefer existing VSCODE_* values when restoring NODE_OPTIONS', async () => { + const env = await createTerminalEnvironment({}, undefined, undefined, undefined, 'off', { + NODE_OPTIONS: '--from-node-options', + NODE_REPL_EXTERNAL_MODULE: 'from-node-repl', + VSCODE_NODE_OPTIONS: '--from-vscode-options', + VSCODE_NODE_REPL_EXTERNAL_MODULE: 'from-vscode-repl' + }); + if (process.platform === 'darwin' || process.platform === 'win32') { + strictEqual(env['NODE_OPTIONS'], '--from-vscode-options'); + strictEqual(env['NODE_REPL_EXTERNAL_MODULE'], 'from-vscode-repl'); + strictEqual(env['VSCODE_NODE_OPTIONS'], undefined); + strictEqual(env['VSCODE_NODE_REPL_EXTERNAL_MODULE'], undefined); + } else { + strictEqual(env['NODE_OPTIONS'], undefined); + strictEqual(env['NODE_REPL_EXTERNAL_MODULE'], undefined); + strictEqual(env['VSCODE_NODE_OPTIONS'], undefined); + strictEqual(env['VSCODE_NODE_REPL_EXTERNAL_MODULE'], undefined); + } + }); }); suite('getWorkspaceForTerminal', () => { test('should resolve workspace folder from cwd, not last active workspace', () => {