diff --git a/build/tasks.ts b/build/tasks.ts index 4c10b1fb4520..b005c413c2e7 100644 --- a/build/tasks.ts +++ b/build/tasks.ts @@ -86,6 +86,7 @@ const buildServerBinaryCopy = register("build:server:binary:copy", async (runner const webOutputPath = path.join(pkgsPath, "web", "out"); const browserAppOutputPath = path.join(pkgsPath, "app", "browser", "out"); const nodePtyModule = path.join(pkgsPath, "protocol", "node_modules", "node-pty-prebuilt", "build", "Release", "pty.node"); + const onigModule = path.join(pkgsPath, "..", "lib", "vscode", "node_modules", "oniguruma", "build", "Release", "onig_scanner.node"); const spdlogModule = path.join(pkgsPath, "protocol", "node_modules", "spdlog", "build", "Release", "spdlog.node"); let ripgrepPath = path.join(pkgsPath, "..", "lib", "vscode", "node_modules", "vscode-ripgrep", "bin", "rg"); if (isWin) { @@ -95,6 +96,9 @@ const buildServerBinaryCopy = register("build:server:binary:copy", async (runner if (!fs.existsSync(nodePtyModule)) { throw new Error("Could not find pty.node. Ensure all packages have been installed"); } + if (!fs.existsSync(onigModule)) { + throw new Error("Could not find onig_scanner.node. Ensure all packages have been installed"); + } if (!fs.existsSync(spdlogModule)) { throw new Error("Could not find spdlog.node. Ensure all packages have been installed"); } @@ -129,6 +133,7 @@ const buildServerBinaryCopy = register("build:server:binary:copy", async (runner cpDir(browserAppOutputPath, "unauth", browserAppOutputPath); fse.mkdirpSync(path.join(cliBuildPath, "dependencies")); fse.copySync(nodePtyModule, path.join(cliBuildPath, "dependencies", "pty.node")); + fse.copySync(onigModule, path.join(cliBuildPath, "dependencies", "onig_scanner.node")); fse.copySync(spdlogModule, path.join(cliBuildPath, "dependencies", "spdlog.node")); fse.copySync(ripgrepPath, path.join(cliBuildPath, "dependencies", "rg")); }); diff --git a/packages/server/src/modules.ts b/packages/server/src/modules.ts index e32f21e8d2ab..6e48e6f8acd9 100644 --- a/packages/server/src/modules.ts +++ b/packages/server/src/modules.ts @@ -39,15 +39,19 @@ export const setup = (dataDirectory: string): void => { unpackModule("pty.node"); unpackModule("spdlog.node"); unpackModule("rg", true); + unpackModule("onig_scanner.node"); // const nodePtyUtils = require("../../protocol/node_modules/node-pty-prebuilt/lib/utils") as typeof import("../../protocol/node_modules/node-pty-prebuilt/src/utils"); // tslint:disable-next-line:no-any // nodePtyUtils.loadNative = (modName: string): any => { // return (typeof __non_webpack_require__ !== "undefined" ? __non_webpack_require__ : require)(path.join(dataDirectory, "dependencies", modName + ".node")); // }; (global).RIPGREP_LOCATION = path.join(dataDirectory, "dependencies", "rg"); + // tslint:disable-next-line:no-any (global).NODEPTY_LOCATION = path.join(dataDirectory, "dependencies", "pty.node"); // tslint:disable-next-line:no-any (global).SPDLOG_LOCATION = path.join(dataDirectory, "dependencies", "spdlog.node"); + // tslint:disable-next-line:no-any + (global).ONIG_LOCATION = path.join(dataDirectory, "dependencies", "onig_scanner.node"); // tslint:disable-next-line:no-unused-expression require("../../protocol/node_modules/node-pty-prebuilt/lib/index") as typeof import("../../protocol/node_modules/node-pty-prebuilt/src/index"); }; diff --git a/packages/server/src/vscode/bootstrapFork.ts b/packages/server/src/vscode/bootstrapFork.ts index 71ff3815db49..a380f3173d8b 100644 --- a/packages/server/src/vscode/bootstrapFork.ts +++ b/packages/server/src/vscode/bootstrapFork.ts @@ -11,6 +11,51 @@ if (ipcMsgListener) { process.on("message", ipcMsgListener); } +/** + * Attempt to require a module from a list of native packages + * that could be expected to exist in the unpacked version of + * VS Code. The list may grow in the future. + */ +const requireNativeModules = (mod: any): void => { + // tslint:disable-next-line:no-any + const nativeModules: ReadonlyArray<{ id: string, module: any }> = [ + { id: "vscode-textmate", module: require("../../../../lib/vscode/node_modules/vscode-textmate") as typeof import("../../../../lib/vscode/node_modules/vscode-textmate") }, + { id: "vscode-languageserver", module: require("../../../../lib/vscode/node_modules/vscode-languageserver") as typeof import("../../../../lib/vscode/node_modules/vscode-languageserver") }, + { id: "vscode-languageserver-types", module: require("../../../../lib/vscode/node_modules/vscode-languageserver-types") as typeof import("../../../../lib/vscode/node_modules/vscode-languageserver-types") }, + ]; + const oldRequire = mod.prototype.require; + // tslint:disable-next-line:no-any + mod.prototype.require = function (id: string): any { + if (id === "typescript") { + return require("typescript"); + } + if (id.slice(0, 3) === "/./") { + id = id.slice(3); + } + const requireNativeModule = (id: string): any => { + for (let i = 0; i < nativeModules.length; i++) { + if (id.slice(-1 * (nativeModules[i].id.length + 1)) !== `/${nativeModules[i].id}`) { + continue; + } + + return nativeModules[i].module; + } + throw new Error(`Module '${id}' undefined. If you need this native module, file an issue on GitHub.`); + }; + + try { + // tslint:disable-next-line:no-any + return oldRequire.call(this, id as any); + } catch (ex) { + try { + return requireNativeModule(id); + } catch (nex) { + throw new Error(`${ex.message}: ${nex.message}`); + } + } + }; +}; + /** * Requires a module from the filesystem. * @@ -44,16 +89,7 @@ const requireFilesystemModule = (id: string, builtInExtensionsDir: string): any */ export const requireFork = (modulePath: string, args: string[], builtInExtensionsDir: string): void => { const Module = require("module") as typeof import("module"); - const oldRequire = Module.prototype.require; - // tslint:disable-next-line:no-any - Module.prototype.require = function (id: string): any { - if (id === "typescript") { - return require("typescript"); - } - - // tslint:disable-next-line:no-any - return oldRequire.call(this, id as any); - }; + requireNativeModules(Module); if (!process.send) { throw new Error("No IPC messaging initialized"); @@ -79,6 +115,8 @@ export const requireModule = (modulePath: string, dataDir: string, builtInExtens (global as any).XMLHttpRequest = xml.XMLHttpRequest; const mod = require("module") as typeof import("module"); + requireNativeModules(mod); + const promiseFinally = require("promise.prototype.finally") as { shim: () => void }; promiseFinally.shim(); /** diff --git a/packages/server/webpack.config.js b/packages/server/webpack.config.js index 251419229976..15b65f527b13 100644 --- a/packages/server/webpack.config.js +++ b/packages/server/webpack.config.js @@ -8,6 +8,19 @@ module.exports = merge( require(path.join(root, "scripts/webpack.node.config.js"))({ // Config options. }), { + module: { + rules: [{ + test: /oniguruma(\\|\/)src(\\|\/).*\.js/, + loader: "string-replace-loader", + options: { + multiple: [{ + search: "const Onig(.*) = .*onig_scanner\.node.*\.Onig(.*)", + replace: "const Onig$1 = __non_webpack_require__(global.ONIG_LOCATION).Onig$2;", + flags: "g", + }], + }, + }], + }, output: { filename: "cli.js", path: path.join(__dirname, "out"),