From 4ccb98926ff116a7960601f7611596b64a30677c Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 14 Aug 2024 17:48:45 +0200 Subject: [PATCH] esm - bootstrap import (#225615) --- migrate.mjs | 1 + src/bootstrap-fork.js | 4 +- src/bootstrap-import.js | 78 +++++++++++++++++++ src/bootstrap-node.js | 12 ++- src/server-cli.js | 6 +- src/server-main.js | 6 +- src/tsconfig.json | 1 + .../extensionSignatureVerificationService.ts | 2 +- src/vs/platform/sign/node/signService.ts | 2 +- .../platform/telemetry/common/1dsAppender.ts | 2 +- 10 files changed, 100 insertions(+), 14 deletions(-) create mode 100644 src/bootstrap-import.js diff --git a/migrate.mjs b/migrate.mjs index ad022767425..aa58c726bad 100644 --- a/migrate.mjs +++ b/migrate.mjs @@ -45,6 +45,7 @@ function migrate() { migrateOne(filePath, fileContents); } + writeFileSync(join(dstFolder, 'package.json'), `{"type": "module"}`); writeFileSync(join(dstFolder, '.gitignore'), `*`); console.log(`~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`); diff --git a/src/bootstrap-fork.js b/src/bootstrap-fork.js index dc78787a07b..32d6f028021 100644 --- a/src/bootstrap-fork.js +++ b/src/bootstrap-fork.js @@ -28,8 +28,8 @@ bootstrapNode.removeGlobalNodeModuleLookupPaths(); // Enable ASAR in our forked processes bootstrapNode.enableASARSupport(); -if (process.env['VSCODE_INJECT_NODE_MODULE_LOOKUP_PATH']) { - bootstrapNode.injectNodeModuleLookupPath(process.env['VSCODE_INJECT_NODE_MODULE_LOOKUP_PATH']); +if (process.env['VSCODE_DEV_INJECT_NODE_MODULE_LOOKUP_PATH']) { + bootstrapNode.devInjectNodeModuleLookupPath(process.env['VSCODE_DEV_INJECT_NODE_MODULE_LOOKUP_PATH']); } // Configure: pipe logging to parent process diff --git a/src/bootstrap-import.js b/src/bootstrap-import.js new file mode 100644 index 00000000000..070b0b93b4b --- /dev/null +++ b/src/bootstrap-import.js @@ -0,0 +1,78 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +//@ts-check + +// ********************************************************************* +// * * +// * We need this to redirect to node_modules from the remote-folder. * +// * This ONLY applies when running out of source. * +// * * +// ********************************************************************* + +import { fileURLToPath, pathToFileURL } from 'node:url'; +import { promises } from 'node:fs'; +import { join } from 'node:path'; + +// SEE https://nodejs.org/docs/latest/api/module.html#initialize + +/** + * @type {Object.} + */ +const _specifierToUrl = {}; + +/** + * @param {string} injectPath + */ +export async function initialize(injectPath) { + // populate mappings + + const injectPackageJSONPath = fileURLToPath(new URL('../package.json', pathToFileURL(injectPath))); + const packageJSON = JSON.parse(String(await promises.readFile(injectPackageJSONPath))); + + for (const [name] of Object.entries(packageJSON.dependencies)) { + try { + const path = join(injectPackageJSONPath, `../node_modules/${name}/package.json`); + let { main } = JSON.parse(String(await promises.readFile(path))); + + if (!main) { + main = 'index.js'; + } + if (!main.endsWith('.js')) { + main += '.js'; + } + const mainPath = join(injectPackageJSONPath, `../node_modules/${name}/${main}`); + _specifierToUrl[name] = pathToFileURL(mainPath).href; + + } catch (err) { + console.error(name); + console.error(err); + } + } + + console.log(`[bootstrap-import] Initialized node_modules redirector for: ${injectPath}`); +} + +/** + * @param {string | number} specifier + * @param {any} context + * @param {(arg0: any, arg1: any) => any} nextResolve + */ +export async function resolve(specifier, context, nextResolve) { + + const newSpecifier = _specifierToUrl[specifier]; + if (newSpecifier !== undefined) { + // console.log('[HOOKS]', specifier, '--->', newSpecifier); + return { + format: 'commonjs', + shortCircuit: true, + url: newSpecifier + }; + } + + // Defer to the next hook in the chain, which would be the + // Node.js default resolve if this is the last user-specified loader. + return nextResolve(specifier, context); +} diff --git a/src/bootstrap-node.js b/src/bootstrap-node.js index b53e72f5e29..1484cbb8bed 100644 --- a/src/bootstrap-node.js +++ b/src/bootstrap-node.js @@ -72,9 +72,15 @@ setupCurrentWorkingDirectory(); /** * Add support for redirecting the loading of node modules * + * Note: only applies when running out of sources. + * * @param {string} injectPath */ -module.exports.injectNodeModuleLookupPath = function (injectPath) { +module.exports.devInjectNodeModuleLookupPath = function (injectPath) { + if (!process.env['VSCODE_DEV']) { + return; // only applies running out of sources + } + if (!injectPath) { throw new Error('Missing injectPath'); } @@ -83,7 +89,7 @@ module.exports.injectNodeModuleLookupPath = function (injectPath) { if (isESM) { // register a loader hook // ESM-uncomment-begin - // Module.register('./loader-lookup-path.mjs', { parentURL: import.meta.url, data: injectPath }); + // Module.register('./bootstrap-import.js', { parentURL: import.meta.url, data: injectPath }); // ESM-uncomment-end } else { const nodeModulesPath = path.join(__dirname, '../node_modules'); @@ -266,7 +272,7 @@ module.exports.fileUriFromPath = function (path, config) { //#endregion // ESM-uncomment-begin -// export const injectNodeModuleLookupPath = module.exports.injectNodeModuleLookupPath; +// export const devInjectNodeModuleLookupPath = module.exports.devInjectNodeModuleLookupPath; // export const removeGlobalNodeModuleLookupPaths = module.exports.removeGlobalNodeModuleLookupPaths; // export const configurePortable = module.exports.configurePortable; // export const enableASARSupport = module.exports.enableASARSupport; diff --git a/src/server-cli.js b/src/server-cli.js index 9947a264578..896e4f4c3b7 100644 --- a/src/server-cli.js +++ b/src/server-cli.js @@ -36,10 +36,10 @@ async function start() { if (process.env['VSCODE_DEV']) { // When running out of sources, we need to load node modules from remote/node_modules, // which are compiled against nodejs, not electron - process.env['VSCODE_INJECT_NODE_MODULE_LOOKUP_PATH'] = process.env['VSCODE_INJECT_NODE_MODULE_LOOKUP_PATH'] || path.join(__dirname, '..', 'remote', 'node_modules'); - bootstrapNode.injectNodeModuleLookupPath(process.env['VSCODE_INJECT_NODE_MODULE_LOOKUP_PATH']); + process.env['VSCODE_DEV_INJECT_NODE_MODULE_LOOKUP_PATH'] = process.env['VSCODE_DEV_INJECT_NODE_MODULE_LOOKUP_PATH'] || path.join(__dirname, '..', 'remote', 'node_modules'); + bootstrapNode.devInjectNodeModuleLookupPath(process.env['VSCODE_DEV_INJECT_NODE_MODULE_LOOKUP_PATH']); } else { - delete process.env['VSCODE_INJECT_NODE_MODULE_LOOKUP_PATH']; + delete process.env['VSCODE_DEV_INJECT_NODE_MODULE_LOOKUP_PATH']; } bootstrapAmd.load('vs/server/node/server.cli'); } diff --git a/src/server-main.js b/src/server-main.js index 3816ca1afbb..e3dd44e4123 100644 --- a/src/server-main.js +++ b/src/server-main.js @@ -296,10 +296,10 @@ function loadCode(nlsConfiguration) { if (process.env['VSCODE_DEV']) { // When running out of sources, we need to load node modules from remote/node_modules, // which are compiled against nodejs, not electron - process.env['VSCODE_INJECT_NODE_MODULE_LOOKUP_PATH'] = process.env['VSCODE_INJECT_NODE_MODULE_LOOKUP_PATH'] || path.join(__dirname, '..', 'remote', 'node_modules'); - bootstrapNode.injectNodeModuleLookupPath(process.env['VSCODE_INJECT_NODE_MODULE_LOOKUP_PATH']); + process.env['VSCODE_DEV_INJECT_NODE_MODULE_LOOKUP_PATH'] = process.env['VSCODE_DEV_INJECT_NODE_MODULE_LOOKUP_PATH'] || path.join(__dirname, '..', 'remote', 'node_modules'); + bootstrapNode.devInjectNodeModuleLookupPath(process.env['VSCODE_DEV_INJECT_NODE_MODULE_LOOKUP_PATH']); } else { - delete process.env['VSCODE_INJECT_NODE_MODULE_LOOKUP_PATH']; + delete process.env['VSCODE_DEV_INJECT_NODE_MODULE_LOOKUP_PATH']; } bootstrapAmd.load('vs/server/node/server.main', resolve, reject); }); diff --git a/src/tsconfig.json b/src/tsconfig.json index 931bf1ec331..096655d9bc4 100644 --- a/src/tsconfig.json +++ b/src/tsconfig.json @@ -28,6 +28,7 @@ "./bootstrap-amd.js", "./bootstrap-cli.js", "./bootstrap-fork.js", + "./bootstrap-import.js", "./bootstrap-meta.js", "./bootstrap-node.js", "./bootstrap-server.js", diff --git a/src/vs/platform/extensionManagement/node/extensionSignatureVerificationService.ts b/src/vs/platform/extensionManagement/node/extensionSignatureVerificationService.ts index bee32351f21..43597893bbf 100644 --- a/src/vs/platform/extensionManagement/node/extensionSignatureVerificationService.ts +++ b/src/vs/platform/extensionManagement/node/extensionSignatureVerificationService.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { importAMDNodeModule } from 'vs/amdX'; import { getErrorMessage } from 'vs/base/common/errors'; import { IGalleryExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; import { TargetPlatform } from 'vs/platform/extensions/common/extensions'; @@ -109,6 +108,7 @@ export class ExtensionSignatureVerificationService implements IExtensionSignatur // ESM-uncomment-end // ESM-comment-begin + const { importAMDNodeModule } = await import('vs/amdX'); return importAMDNodeModule('@vscode/vsce-sign', 'src/main.js'); // ESM-comment-end } diff --git a/src/vs/platform/sign/node/signService.ts b/src/vs/platform/sign/node/signService.ts index 6ecd1beccfb..0b4dcbcf73b 100644 --- a/src/vs/platform/sign/node/signService.ts +++ b/src/vs/platform/sign/node/signService.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { importAMDNodeModule } from 'vs/amdX'; import { AbstractSignService, IVsdaValidator } from 'vs/platform/sign/common/abstractSignService'; import { ISignService } from 'vs/platform/sign/common/sign'; @@ -37,6 +36,7 @@ export class SignService extends AbstractSignService implements ISignService { // ESM-uncomment-end // ESM-comment-begin + const { importAMDNodeModule } = await import('vs/amdX'); return importAMDNodeModule('vsda', 'index.js'); // ESM-comment-end } diff --git a/src/vs/platform/telemetry/common/1dsAppender.ts b/src/vs/platform/telemetry/common/1dsAppender.ts index e9ee836a603..cf06227da41 100644 --- a/src/vs/platform/telemetry/common/1dsAppender.ts +++ b/src/vs/platform/telemetry/common/1dsAppender.ts @@ -5,7 +5,6 @@ import type { IExtendedConfiguration, IExtendedTelemetryItem, ITelemetryItem, ITelemetryUnloadState } from '@microsoft/1ds-core-js'; import type { IChannelConfiguration, IXHROverride, PostChannel } from '@microsoft/1ds-post-js'; -import { importAMDNodeModule } from 'vs/amdX'; import { onUnexpectedError } from 'vs/base/common/errors'; import { mixin } from 'vs/base/common/objects'; import { ITelemetryAppender, validateTelemetryData } from 'vs/platform/telemetry/common/telemetryUtils'; @@ -23,6 +22,7 @@ const endpointHealthUrl = 'https://mobile.events.data.microsoft.com/ping'; async function getClient(instrumentationKey: string, addInternalFlag?: boolean, xhrOverride?: IXHROverride): Promise { // ESM-comment-begin + const { importAMDNodeModule } = await import('vs/amdX'); const oneDs = await importAMDNodeModule('@microsoft/1ds-core-js', 'dist/ms.core.js'); const postPlugin = await importAMDNodeModule('@microsoft/1ds-post-js', 'dist/ms.post.js'); // ESM-comment-end