From ecca16103cae6e4ed32eba6a8e30c04b3b1b53b4 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Mon, 22 Jan 2024 15:09:38 -0800 Subject: [PATCH 01/16] Update checkModuleFormat.mjs to test imports --- scripts/checkModuleFormat.mjs | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/scripts/checkModuleFormat.mjs b/scripts/checkModuleFormat.mjs index 6c461d370a32e..229fac97381fb 100644 --- a/scripts/checkModuleFormat.mjs +++ b/scripts/checkModuleFormat.mjs @@ -11,25 +11,27 @@ import { // so it can be tested on a separate install of TypeScript. const require = createRequire(process.cwd() + "/index.js"); +const typescript = process.argv[2]; -console.log(`Testing ${process.argv[2]}...`); -const ts = require(process.argv[2]); +console.log(`Testing ${typescript}...`); // See: https://github.com/microsoft/TypeScript/pull/51474#issuecomment-1310871623 -/** @type {[fn: (() => any), shouldSucceed: boolean][]} */ +/** @type {[fn: (() => Promise), shouldSucceed: boolean][]} */ const fns = [ - [() => ts.version, true], - [() => ts.default.version, false], - [() => __importDefault(ts).version, false], - [() => __importDefault(ts).default.version, true], - [() => __importStar(ts).version, true], - [() => __importStar(ts).default.version, true], + [() => require(typescript).version, true], + [() => require(typescript).default.version, false], + [() => __importDefault(require(typescript)).version, false], + [() => __importDefault(require(typescript)).default.version, true], + [() => __importStar(require(typescript)).version, true], + [() => __importStar(require(typescript)).default.version, true], + [async () => (await import(typescript)).version, false], + [async () => (await import(typescript)).default.version, true], ]; for (const [fn, shouldSucceed] of fns) { let success = false; try { - success = !!fn(); + success = !!(await fn()); } catch { // Ignore @@ -43,4 +45,10 @@ for (const [fn, shouldSucceed] of fns) { process.exitCode = 1; } } -console.log("ok"); + +if (!!process.exitCode) { + console.log("fail"); +} +else { + console.log("ok"); +} From 43ea520782a5c22445516c28dd42d16499baaba8 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Mon, 22 Jan 2024 15:55:32 -0800 Subject: [PATCH 02/16] Support named / namespace imports of TypeScript API --- Herebyfile.mjs | 28 +++++++++++++++++++++++++++- scripts/checkModuleFormat.mjs | 2 +- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/Herebyfile.mjs b/Herebyfile.mjs index cd8b6a5145d7a..8eee4a094177d 100644 --- a/Herebyfile.mjs +++ b/Herebyfile.mjs @@ -16,6 +16,9 @@ import { task, } from "hereby"; import path from "path"; +import { + pathToFileURL, +} from "url"; import { localizationDirectories, @@ -41,6 +44,9 @@ import { readJson, rimraf, } from "./scripts/build/utils.mjs"; +import { + inspect, +} from "util"; /** @typedef {ReturnType} Task */ void 0; @@ -208,7 +214,8 @@ function createBundler(entrypoint, outfile, taskOptions = {}) { // Name the variable ts, matching our old big bundle and so we can use the code below. options.globalName = "ts"; // If we are in a CJS context, export the ts namespace. - options.footer = { js: `\nif (typeof module !== "undefined" && module.exports) { module.exports = ts; }` }; + options.footer = { js: `\nif (typeof module !== "undefined" && module.exports) {\n module.exports = ts;\n}` }; + options.metafile = true; // esbuild converts calls to "require" to "__require"; this function // calls the real require if it exists, or throws if it does not (rather than @@ -233,6 +240,25 @@ function createBundler(entrypoint, outfile, taskOptions = {}) { let contents = await fs.promises.readFile(outfile, "utf-8"); contents = contents.replace(fakeNameRegExp, require); await fs.promises.writeFile(outfile, contents); + + // This is a trick esbuild uses when emitting CJS to ensure that + // cjs-module-lexer sees the named exports. For example: + // + // module.exports = someComplicatedThing(); + // 0 && (module.exports = { + // foo, + // bar, + // }); + // TODO(jakebailey): this is slow; can we do this statically? + // esbuild's metafile option does not show exports... + // https://github.com/evanw/esbuild/issues/3110 + // https://github.com/evanw/esbuild/issues/3281 + const importUrl = pathToFileURL(outfile).toString(); + const obj = await import(importUrl); + const names = Object.keys(obj.default); + const fakeExport = ` 0 && (module.exports = {\n${names.map(name => ` ${name},\n`).join("")} });`; + contents = contents.replace("module.exports = ts;", `module.exports = ts;\n${fakeExport}`); + await fs.promises.writeFile(outfile, contents); }); }, }, diff --git a/scripts/checkModuleFormat.mjs b/scripts/checkModuleFormat.mjs index 229fac97381fb..211fddc4495f8 100644 --- a/scripts/checkModuleFormat.mjs +++ b/scripts/checkModuleFormat.mjs @@ -24,7 +24,7 @@ const fns = [ [() => __importDefault(require(typescript)).default.version, true], [() => __importStar(require(typescript)).version, true], [() => __importStar(require(typescript)).default.version, true], - [async () => (await import(typescript)).version, false], + [async () => (await import(typescript)).version, true], [async () => (await import(typescript)).default.version, true], ]; From f45255105630e840ea4d167ec8f663a431b0da74 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Mon, 22 Jan 2024 16:09:31 -0800 Subject: [PATCH 03/16] Simplify --- scripts/checkModuleFormat.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/checkModuleFormat.mjs b/scripts/checkModuleFormat.mjs index 211fddc4495f8..57eb126d0d93e 100644 --- a/scripts/checkModuleFormat.mjs +++ b/scripts/checkModuleFormat.mjs @@ -46,7 +46,7 @@ for (const [fn, shouldSucceed] of fns) { } } -if (!!process.exitCode) { +if (process.exitCode) { console.log("fail"); } else { From 1f64ed01e1a30bcb24f86f7a303f1a03b4824f91 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Mon, 22 Jan 2024 16:19:40 -0800 Subject: [PATCH 04/16] fix lint --- Herebyfile.mjs | 3 --- 1 file changed, 3 deletions(-) diff --git a/Herebyfile.mjs b/Herebyfile.mjs index 8eee4a094177d..1765157d1cd26 100644 --- a/Herebyfile.mjs +++ b/Herebyfile.mjs @@ -44,9 +44,6 @@ import { readJson, rimraf, } from "./scripts/build/utils.mjs"; -import { - inspect, -} from "util"; /** @typedef {ReturnType} Task */ void 0; From 8fe70bc55b7b758064bbf32f72c776f0dd002dde Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Mon, 22 Jan 2024 16:23:16 -0800 Subject: [PATCH 05/16] Fix esm smoke test, probably --- scripts/checkModuleFormat.mjs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/checkModuleFormat.mjs b/scripts/checkModuleFormat.mjs index 57eb126d0d93e..aa45a84e989f1 100644 --- a/scripts/checkModuleFormat.mjs +++ b/scripts/checkModuleFormat.mjs @@ -5,6 +5,7 @@ import { __importDefault, __importStar, } from "tslib"; +import { pathToFileURL } from "url"; // This script tests that TypeScript's CJS API is structured // as expected. It calls "require" as though it were in CWD, @@ -12,6 +13,7 @@ import { const require = createRequire(process.cwd() + "/index.js"); const typescript = process.argv[2]; +const resolvedTypeScript = pathToFileURL(require.resolve(typescript)).toString(); console.log(`Testing ${typescript}...`); @@ -24,8 +26,8 @@ const fns = [ [() => __importDefault(require(typescript)).default.version, true], [() => __importStar(require(typescript)).version, true], [() => __importStar(require(typescript)).default.version, true], - [async () => (await import(typescript)).version, true], - [async () => (await import(typescript)).default.version, true], + [async () => (await import(resolvedTypeScript)).version, true], + [async () => (await import(resolvedTypeScript)).default.version, true], ]; for (const [fn, shouldSucceed] of fns) { From 485ca8896981fac7b1efebcf3df5a48bf6a9552d Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Mon, 22 Jan 2024 16:25:53 -0800 Subject: [PATCH 06/16] fmt --- scripts/checkModuleFormat.mjs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/checkModuleFormat.mjs b/scripts/checkModuleFormat.mjs index aa45a84e989f1..3991969472245 100644 --- a/scripts/checkModuleFormat.mjs +++ b/scripts/checkModuleFormat.mjs @@ -5,7 +5,9 @@ import { __importDefault, __importStar, } from "tslib"; -import { pathToFileURL } from "url"; +import { + pathToFileURL, +} from "url"; // This script tests that TypeScript's CJS API is structured // as expected. It calls "require" as though it were in CWD, From fedcbbc7d94f79ebb3f9a3936d065c47c313fe60 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Tue, 23 Jan 2024 10:07:04 -0800 Subject: [PATCH 07/16] Drop leftover metafile --- Herebyfile.mjs | 1 - 1 file changed, 1 deletion(-) diff --git a/Herebyfile.mjs b/Herebyfile.mjs index 1765157d1cd26..27c382eba8b9f 100644 --- a/Herebyfile.mjs +++ b/Herebyfile.mjs @@ -212,7 +212,6 @@ function createBundler(entrypoint, outfile, taskOptions = {}) { options.globalName = "ts"; // If we are in a CJS context, export the ts namespace. options.footer = { js: `\nif (typeof module !== "undefined" && module.exports) {\n module.exports = ts;\n}` }; - options.metafile = true; // esbuild converts calls to "require" to "__require"; this function // calls the real require if it exists, or throws if it does not (rather than From e0d8ea5bb22402a62d5d848c9a23f9ab9e2f7a3f Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Wed, 24 Jan 2024 09:53:23 -0800 Subject: [PATCH 08/16] Use require instead of dynamic import --- Herebyfile.mjs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/Herebyfile.mjs b/Herebyfile.mjs index 27c382eba8b9f..cb1b255378fba 100644 --- a/Herebyfile.mjs +++ b/Herebyfile.mjs @@ -15,10 +15,10 @@ import { import { task, } from "hereby"; -import path from "path"; import { - pathToFileURL, -} from "url"; + createRequire, +} from "module"; +import path from "path"; import { localizationDirectories, @@ -176,6 +176,8 @@ async function runDtsBundler(entrypoint, output) { ]); } +const requireFn = createRequire(import.meta.url); + /** * @param {string} entrypoint * @param {string} outfile @@ -230,7 +232,7 @@ function createBundler(entrypoint, outfile, taskOptions = {}) { options.define = { [require]: fakeName }; options.plugins = [ { - name: "fix-require", + name: "post-process", setup: build => { build.onEnd(async () => { let contents = await fs.promises.readFile(outfile, "utf-8"); @@ -249,9 +251,10 @@ function createBundler(entrypoint, outfile, taskOptions = {}) { // esbuild's metafile option does not show exports... // https://github.com/evanw/esbuild/issues/3110 // https://github.com/evanw/esbuild/issues/3281 - const importUrl = pathToFileURL(outfile).toString(); - const obj = await import(importUrl); - const names = Object.keys(obj.default); + + // Using createRequire here is emperically faster than await import. + const obj = requireFn(outfile); + const names = Object.keys(obj); const fakeExport = ` 0 && (module.exports = {\n${names.map(name => ` ${name},\n`).join("")} });`; contents = contents.replace("module.exports = ts;", `module.exports = ts;\n${fakeExport}`); await fs.promises.writeFile(outfile, contents); From d8108fc04024a3731305ef88849fc9e5abb64fc0 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Wed, 24 Jan 2024 09:54:02 -0800 Subject: [PATCH 09/16] Rename for clarity --- Herebyfile.mjs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Herebyfile.mjs b/Herebyfile.mjs index cb1b255378fba..2cc263bd50366 100644 --- a/Herebyfile.mjs +++ b/Herebyfile.mjs @@ -176,7 +176,7 @@ async function runDtsBundler(entrypoint, output) { ]); } -const requireFn = createRequire(import.meta.url); +const require = createRequire(import.meta.url); /** * @param {string} entrypoint @@ -226,17 +226,17 @@ function createBundler(entrypoint, outfile, taskOptions = {}) { // ensuring that source maps still work. // // See: https://github.com/evanw/esbuild/issues/1905 - const require = "require"; - const fakeName = "Q".repeat(require.length); + const requireStr = "require"; + const fakeName = "Q".repeat(requireStr.length); const fakeNameRegExp = new RegExp(fakeName, "g"); - options.define = { [require]: fakeName }; + options.define = { [requireStr]: fakeName }; options.plugins = [ { name: "post-process", setup: build => { build.onEnd(async () => { let contents = await fs.promises.readFile(outfile, "utf-8"); - contents = contents.replace(fakeNameRegExp, require); + contents = contents.replace(fakeNameRegExp, requireStr); await fs.promises.writeFile(outfile, contents); // This is a trick esbuild uses when emitting CJS to ensure that @@ -253,7 +253,7 @@ function createBundler(entrypoint, outfile, taskOptions = {}) { // https://github.com/evanw/esbuild/issues/3281 // Using createRequire here is emperically faster than await import. - const obj = requireFn(outfile); + const obj = require(outfile); const names = Object.keys(obj); const fakeExport = ` 0 && (module.exports = {\n${names.map(name => ` ${name},\n`).join("")} });`; contents = contents.replace("module.exports = ts;", `module.exports = ts;\n${fakeExport}`); From 9da7e2669991d2680de1795dce9f044ddd389c31 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Thu, 25 Jan 2024 19:09:42 -0800 Subject: [PATCH 10/16] Make output stable --- Herebyfile.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Herebyfile.mjs b/Herebyfile.mjs index 2cc263bd50366..43f722695ee69 100644 --- a/Herebyfile.mjs +++ b/Herebyfile.mjs @@ -254,7 +254,7 @@ function createBundler(entrypoint, outfile, taskOptions = {}) { // Using createRequire here is emperically faster than await import. const obj = require(outfile); - const names = Object.keys(obj); + const names = Object.keys(obj).sort(); const fakeExport = ` 0 && (module.exports = {\n${names.map(name => ` ${name},\n`).join("")} });`; contents = contents.replace("module.exports = ts;", `module.exports = ts;\n${fakeExport}`); await fs.promises.writeFile(outfile, contents); From f41424857c0117852c6e467bd3c38a3a66887991 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Fri, 26 Jan 2024 10:26:58 -0800 Subject: [PATCH 11/16] Use code from Evan, hack away __esModule --- Herebyfile.mjs | 64 ++++++++++++++---------------------- src/typescript/typescript.ts | 3 +- 2 files changed, 26 insertions(+), 41 deletions(-) diff --git a/Herebyfile.mjs b/Herebyfile.mjs index 43f722695ee69..61e5b56313991 100644 --- a/Herebyfile.mjs +++ b/Herebyfile.mjs @@ -2,6 +2,7 @@ import { CancelToken, } from "@esfx/canceltoken"; +import assert from "assert"; import chalk from "chalk"; import chokidar from "chokidar"; import esbuild from "esbuild"; @@ -15,9 +16,6 @@ import { import { task, } from "hereby"; -import { - createRequire, -} from "module"; import path from "path"; import { @@ -49,7 +47,7 @@ import { void 0; const copyrightFilename = "./scripts/CopyrightNotice.txt"; -const copyright = memoize(async () => { +const getCopyrightHeader = memoize(async () => { const contents = await fs.promises.readFile(copyrightFilename, "utf-8"); return contents.replace(/\r\n/g, "\n"); }); @@ -79,7 +77,7 @@ export const generateLibs = task({ run: async () => { await fs.promises.mkdir("./built/local", { recursive: true }); for (const lib of libs()) { - let output = await copyright(); + let output = await getCopyrightHeader(); for (const source of lib.sources) { const contents = await fs.promises.readFile(source, "utf-8"); @@ -176,8 +174,6 @@ async function runDtsBundler(entrypoint, output) { ]); } -const require = createRequire(import.meta.url); - /** * @param {string} entrypoint * @param {string} outfile @@ -190,10 +186,13 @@ const require = createRequire(import.meta.url); */ function createBundler(entrypoint, outfile, taskOptions = {}) { const getOptions = memoize(async () => { + const copyright = await getCopyrightHeader(); + const banner = taskOptions.exportIsTsObject ? "var ts = {}; ((module) => {" : ""; + /** @type {esbuild.BuildOptions} */ const options = { entryPoints: [entrypoint], - banner: { js: await copyright() }, + banner: { js: copyright + banner }, bundle: true, outfile, platform: "node", @@ -208,12 +207,7 @@ function createBundler(entrypoint, outfile, taskOptions = {}) { }; if (taskOptions.exportIsTsObject) { - // We use an IIFE so we can inject the footer, and so that "ts" is global if not loaded as a module. - options.format = "iife"; - // Name the variable ts, matching our old big bundle and so we can use the code below. - options.globalName = "ts"; - // If we are in a CJS context, export the ts namespace. - options.footer = { js: `\nif (typeof module !== "undefined" && module.exports) {\n module.exports = ts;\n}` }; + options.footer = { js: `})(typeof module !== "undefined" && module.exports ? module : { exports: ts });` }; // esbuild converts calls to "require" to "__require"; this function // calls the real require if it exists, or throws if it does not (rather than @@ -226,37 +220,29 @@ function createBundler(entrypoint, outfile, taskOptions = {}) { // ensuring that source maps still work. // // See: https://github.com/evanw/esbuild/issues/1905 - const requireStr = "require"; - const fakeName = "Q".repeat(requireStr.length); + const require = "require"; + const fakeName = "Q".repeat(require.length); const fakeNameRegExp = new RegExp(fakeName, "g"); - options.define = { [requireStr]: fakeName }; + options.define = { [require]: fakeName }; + + // For historical reasons, TypeScript does not set __esModule. Hack esbuild's __toCommonJS to be a noop. + // We reference `__copyProps` to ensure the final bundle doesn't have any unreferenced code. + const toCommonJsRegExp = /var __toCommonJS .*/; + const toCommonJsRegExpReplacement = "var __toCommonJS = (mod) => (__copyProps, mod);"; + options.plugins = [ { name: "post-process", setup: build => { build.onEnd(async () => { let contents = await fs.promises.readFile(outfile, "utf-8"); - contents = contents.replace(fakeNameRegExp, requireStr); - await fs.promises.writeFile(outfile, contents); - - // This is a trick esbuild uses when emitting CJS to ensure that - // cjs-module-lexer sees the named exports. For example: - // - // module.exports = someComplicatedThing(); - // 0 && (module.exports = { - // foo, - // bar, - // }); - // TODO(jakebailey): this is slow; can we do this statically? - // esbuild's metafile option does not show exports... - // https://github.com/evanw/esbuild/issues/3110 - // https://github.com/evanw/esbuild/issues/3281 - - // Using createRequire here is emperically faster than await import. - const obj = require(outfile); - const names = Object.keys(obj).sort(); - const fakeExport = ` 0 && (module.exports = {\n${names.map(name => ` ${name},\n`).join("")} });`; - contents = contents.replace("module.exports = ts;", `module.exports = ts;\n${fakeExport}`); + contents = contents.replace(fakeNameRegExp, require); + let matches = 0; + contents = contents.replace(toCommonJsRegExp, () => { + matches++; + return toCommonJsRegExpReplacement; + }); + assert(matches === 1, "Expected exactly one match for __toCommonJS"); await fs.promises.writeFile(outfile, contents); }); }, @@ -473,7 +459,7 @@ export = ts; * @param {string} contents */ async function fileContentsWithCopyright(contents) { - return await copyright() + contents.trim().replace(/\r\n/g, "\n") + "\n"; + return await getCopyrightHeader() + contents.trim().replace(/\r\n/g, "\n") + "\n"; } const lssl = task({ diff --git a/src/typescript/typescript.ts b/src/typescript/typescript.ts index 83f991b83fad2..0df80b850032d 100644 --- a/src/typescript/typescript.ts +++ b/src/typescript/typescript.ts @@ -2,7 +2,6 @@ import { Debug, LogLevel, } from "./_namespaces/ts"; -import * as ts from "./_namespaces/ts"; // enable deprecation logging declare const console: any; @@ -23,4 +22,4 @@ if (typeof console !== "undefined") { }; } -export = ts; +export * from "./_namespaces/ts"; From ecf9aae106140d10671b1709d4c34bbc8c0c6a55 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Fri, 26 Jan 2024 10:45:31 -0800 Subject: [PATCH 12/16] Leave a comment --- Herebyfile.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Herebyfile.mjs b/Herebyfile.mjs index 61e5b56313991..3a6bbc4728ad3 100644 --- a/Herebyfile.mjs +++ b/Herebyfile.mjs @@ -228,7 +228,7 @@ function createBundler(entrypoint, outfile, taskOptions = {}) { // For historical reasons, TypeScript does not set __esModule. Hack esbuild's __toCommonJS to be a noop. // We reference `__copyProps` to ensure the final bundle doesn't have any unreferenced code. const toCommonJsRegExp = /var __toCommonJS .*/; - const toCommonJsRegExpReplacement = "var __toCommonJS = (mod) => (__copyProps, mod);"; + const toCommonJsRegExpReplacement = "var __toCommonJS = (mod) => (__copyProps, mod); // Modified helper to skip setting __esModule."; options.plugins = [ { From d47cef200143140d843774dc659535fd8bce9355 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Thu, 29 Feb 2024 11:36:30 -0800 Subject: [PATCH 13/16] Set ts to module.exports to fix monaco --- Herebyfile.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Herebyfile.mjs b/Herebyfile.mjs index f9387e0367f9e..ad4256350aeb4 100644 --- a/Herebyfile.mjs +++ b/Herebyfile.mjs @@ -209,7 +209,7 @@ function createBundler(entrypoint, outfile, taskOptions = {}) { }; if (taskOptions.exportIsTsObject) { - options.footer = { js: `})(typeof module !== "undefined" && module.exports ? module : { exports: ts });` }; + options.footer = { js: `})(typeof module !== "undefined" && module.exports ? (ts = module.exports, module) : { exports: ts });` }; // esbuild converts calls to "require" to "__require"; this function // calls the real require if it exists, or throws if it does not (rather than From c798c02643aa00b5f6bbbf0141d89b3623b0c83e Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Thu, 29 Feb 2024 11:38:19 -0800 Subject: [PATCH 14/16] Document it --- Herebyfile.mjs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Herebyfile.mjs b/Herebyfile.mjs index ad4256350aeb4..eeaaa0e75721a 100644 --- a/Herebyfile.mjs +++ b/Herebyfile.mjs @@ -209,6 +209,9 @@ function createBundler(entrypoint, outfile, taskOptions = {}) { }; if (taskOptions.exportIsTsObject) { + // Monaco bundles us as ESM by wrapping our code with something that defines `module.exports` + // but then does not use it, instead using the `ts` variable. Ensure that if we think we're CJS + // that we still set `ts` to the module.exports object. options.footer = { js: `})(typeof module !== "undefined" && module.exports ? (ts = module.exports, module) : { exports: ts });` }; // esbuild converts calls to "require" to "__require"; this function From 66ee8fe77cec85d2bb359284721f670f3d5e4bbe Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Thu, 29 Feb 2024 12:07:43 -0800 Subject: [PATCH 15/16] Fix again, exports is entirely reassigned, not augmented --- Herebyfile.mjs | 4 ++-- src/compiler/core.ts | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Herebyfile.mjs b/Herebyfile.mjs index eeaaa0e75721a..18a06923a21d6 100644 --- a/Herebyfile.mjs +++ b/Herebyfile.mjs @@ -209,10 +209,10 @@ function createBundler(entrypoint, outfile, taskOptions = {}) { }; if (taskOptions.exportIsTsObject) { - // Monaco bundles us as ESM by wrapping our code with something that defines `module.exports` + // Monaco bundles us as ESM by wrapping our code with something that defines module.exports // but then does not use it, instead using the `ts` variable. Ensure that if we think we're CJS // that we still set `ts` to the module.exports object. - options.footer = { js: `})(typeof module !== "undefined" && module.exports ? (ts = module.exports, module) : { exports: ts });` }; + options.footer = { js: `})(typeof module !== "undefined" && module.exports ? module : { exports: ts });\nif (typeof module !== "undefined" && module.exports) { ts = module.exports; }` }; // esbuild converts calls to "require" to "__require"; this function // calls the real require if it exists, or throws if it does not (rather than diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 1ee2fefe16048..a2d0c7fc20bdf 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -2749,6 +2749,5 @@ export function isNodeLikeSystem(): boolean { // and definitely exist. return typeof process !== "undefined" && !!process.nextTick - && !(process as any).browser - && typeof module === "object"; + && !(process as any).browser; } From ec5465376bc385f4831504b285ad4b5f6fd36596 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Mon, 4 Mar 2024 11:59:26 -0800 Subject: [PATCH 16/16] Revert isNodeLikeSystem back to pre-5.0 state --- src/compiler/core.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/compiler/core.ts b/src/compiler/core.ts index a2d0c7fc20bdf..97be236ed0b9f 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -2743,11 +2743,8 @@ export function skipWhile(array: readonly T[] | undefined, predi export function isNodeLikeSystem(): boolean { // This is defined here rather than in sys.ts to prevent a cycle from its // use in performanceCore.ts. - // - // We don't use the presence of `require` to check if we are in Node; - // when bundled using esbuild, this function will be rewritten to `__require` - // and definitely exist. return typeof process !== "undefined" && !!process.nextTick - && !(process as any).browser; + && !(process as any).browser + && typeof require !== "undefined"; }