Skip to content

Commit be2489c

Browse files
authored
feat: support ESM (#270)
1 parent 5956d95 commit be2489c

6 files changed

+39
-48
lines changed

sources/corepackUtils.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {createHash} from 'crypto';
22
import {once} from 'events';
33
import fs from 'fs';
44
import type {Dir} from 'fs';
5+
import Module from 'module';
56
import path from 'path';
67
import semver from 'semver';
78

@@ -214,5 +215,10 @@ export async function runVersion(locator: Locator, installSpec: { location: stri
214215
];
215216
process.execArgv = [];
216217

217-
return nodeUtils.loadMainModule(binPath);
218+
// Unset the mainModule and let Node.js set it when needed.
219+
process.mainModule = undefined;
220+
221+
// Use nextTick to unwind the stack, and consequently remove Corepack from
222+
// the stack trace of the package manager.
223+
process.nextTick(Module.runMain, binPath);
218224
}

sources/module.d.ts

-16
This file was deleted.

sources/nodeUtils.ts

-27
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,3 @@
1-
import Module from 'module';
2-
import path from 'path';
3-
4-
/**
5-
* Loads a module as a main module, enabling the `require.main === module` pattern.
6-
*/
7-
export function loadMainModule(id: string): void {
8-
const modulePath = Module._resolveFilename(id, null, true);
9-
10-
const module = new Module(modulePath, undefined);
11-
12-
module.filename = modulePath;
13-
module.paths = Module._nodeModulePaths(path.dirname(modulePath));
14-
15-
Module._cache[modulePath] = module;
16-
17-
process.mainModule = module;
18-
module.id = `.`;
19-
20-
try {
21-
return module.load(modulePath);
22-
} catch (error) {
23-
delete Module._cache[modulePath];
24-
throw error;
25-
}
26-
}
27-
281
export interface NodeError extends Error {
292
code: string;
303
}

tests/main.test.ts

+32-4
Original file line numberDiff line numberDiff line change
@@ -560,7 +560,10 @@ it(`should not override the package manager exit code`, async () => {
560560
});
561561
});
562562

563-
it(`should not override the package manager exit code when it throws`, async () => {
563+
it(`should not preserve the process.exitCode when a package manager throws`, async () => {
564+
// Node.js doesn't preserve process.exitCode when an exception is thrown
565+
// so we need to make sure we don't break this behaviour.
566+
564567
await xfs.mktempPromise(async cwd => {
565568
await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), {
566569
packageManager: `yarn@2.2.2`,
@@ -575,9 +578,9 @@ it(`should not override the package manager exit code when it throws`, async ()
575578
`);
576579

577580
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
578-
exitCode: 42,
579-
stdout: expect.stringContaining(`foo`),
580-
stderr: ``,
581+
exitCode: 1,
582+
stdout: ``,
583+
stderr: expect.stringContaining(`foo`),
581584
});
582585
});
583586
});
@@ -606,3 +609,28 @@ it(`should not set the exit code after successfully launching the package manage
606609
});
607610
});
608611
});
612+
613+
it(`should support package managers in ESM format`, async () => {
614+
await xfs.mktempPromise(async cwd => {
615+
await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), {
616+
packageManager: `yarn@2.2.2`,
617+
});
618+
619+
const yarnDir = ppath.join(npath.toPortablePath(process.env.COREPACK_HOME!), `yarn/2.2.2` as PortablePath);
620+
621+
await xfs.mkdirPromise(yarnDir, {recursive: true});
622+
await xfs.writeFilePromise(ppath.join(yarnDir, `yarn.js` as PortablePath), `
623+
import 'fs';
624+
console.log(42);
625+
`);
626+
await xfs.writeJsonPromise(ppath.join(yarnDir, `package.json` as PortablePath), {
627+
type: `module`,
628+
});
629+
630+
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
631+
exitCode: 0,
632+
stdout: `42\n`,
633+
stderr: ``,
634+
});
635+
});
636+
});
7 Bytes
Binary file not shown.
7 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)