feat: always enable ESM loader with the new API (#29991)
It does not require a process restart anymore, so safe to enable. Fixes #29747.
This commit is contained in:
parent
b41b802662
commit
be1af15d57
|
|
@ -334,25 +334,33 @@ export async function loadEmptyConfigForMergeReports() {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function restartWithExperimentalTsEsm(configFile: string | undefined, force: boolean = false): boolean {
|
export function restartWithExperimentalTsEsm(configFile: string | undefined, force: boolean = false): boolean {
|
||||||
const nodeVersion = +process.versions.node.split('.')[0];
|
// Opt-out switch.
|
||||||
// New experimental loader is only supported on Node 16+.
|
|
||||||
if (nodeVersion < 16)
|
|
||||||
return false;
|
|
||||||
if (!configFile && !force)
|
|
||||||
return false;
|
|
||||||
if (process.env.PW_DISABLE_TS_ESM)
|
if (process.env.PW_DISABLE_TS_ESM)
|
||||||
return false;
|
return false;
|
||||||
// Node.js < 20
|
|
||||||
|
// There are two esm loader APIs:
|
||||||
|
// - Older API that needs a process restart. Available in Node 16, 17, and non-latest 18, 19 and 20.
|
||||||
|
// - Newer API that works in-process. Available in Node 21+ and latest 18, 19 and 20.
|
||||||
|
|
||||||
|
// First check whether we have already restarted with the ESM loader from the older API.
|
||||||
if ((globalThis as any).__esmLoaderPortPreV20) {
|
if ((globalThis as any).__esmLoaderPortPreV20) {
|
||||||
// clear execArgv after restart, so that childProcess.fork in user code does not inherit our loader.
|
// clear execArgv after restart, so that childProcess.fork in user code does not inherit our loader.
|
||||||
process.execArgv = execArgvWithoutExperimentalLoaderOptions();
|
process.execArgv = execArgvWithoutExperimentalLoaderOptions();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!force && !fileIsModule(configFile!))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Node.js < 20
|
// Now check for the newer API presence.
|
||||||
if (!require('node:module').register) {
|
if (!require('node:module').register) {
|
||||||
|
// Older API is experimental, only supported on Node 16+.
|
||||||
|
const nodeVersion = +process.versions.node.split('.')[0];
|
||||||
|
if (nodeVersion < 16)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// With older API requiring a process restart, do so conditionally on the config.
|
||||||
|
const configIsModule = !!configFile && fileIsModule(configFile);
|
||||||
|
if (!force && !configIsModule)
|
||||||
|
return false;
|
||||||
|
|
||||||
const innerProcess = (require('child_process') as typeof import('child_process')).fork(require.resolve('../../cli'), process.argv.slice(2), {
|
const innerProcess = (require('child_process') as typeof import('child_process')).fork(require.resolve('../../cli'), process.argv.slice(2), {
|
||||||
env: {
|
env: {
|
||||||
...process.env,
|
...process.env,
|
||||||
|
|
@ -367,7 +375,8 @@ export function restartWithExperimentalTsEsm(configFile: string | undefined, for
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// Nodejs >= 21
|
|
||||||
|
// With the newer API, always enable the ESM loader, because it does not need a restart.
|
||||||
registerESMLoader();
|
registerESMLoader();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -552,7 +552,9 @@ test('should load cjs config and test in non-ESM mode', async ({ runInlineTest }
|
||||||
expect(result.passed).toBe(2);
|
expect(result.passed).toBe(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should disallow ESM when config is cjs', async ({ runInlineTest }) => {
|
test('should allow ESM when config is cjs', async ({ runInlineTest, nodeVersion }) => {
|
||||||
|
test.skip(nodeVersion.major < 18, 'ESM loader is enabled conditionally with older API');
|
||||||
|
|
||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
'package.json': `{ "type": "module" }`,
|
'package.json': `{ "type": "module" }`,
|
||||||
'playwright.config.cjs': `
|
'playwright.config.cjs': `
|
||||||
|
|
@ -567,8 +569,24 @@ test('should disallow ESM when config is cjs', async ({ runInlineTest }) => {
|
||||||
`,
|
`,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(result.exitCode).toBe(1);
|
expect(result.exitCode).toBe(0);
|
||||||
expect(result.output).toContain('Unknown file extension ".ts"');
|
expect(result.passed).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should load mts without config', async ({ runInlineTest, nodeVersion }) => {
|
||||||
|
test.skip(nodeVersion.major < 18, 'ESM loader is enabled conditionally with older API');
|
||||||
|
|
||||||
|
const result = await runInlineTest({
|
||||||
|
'a.test.mts': `
|
||||||
|
import { test, expect } from '@playwright/test';
|
||||||
|
test('check project name', ({}, testInfo) => {
|
||||||
|
expect(true).toBe(true);
|
||||||
|
});
|
||||||
|
`,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.exitCode).toBe(0);
|
||||||
|
expect(result.passed).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should be able to use use execSync with a Node.js file inside a spec', async ({ runInlineTest }) => {
|
test('should be able to use use execSync with a Node.js file inside a spec', async ({ runInlineTest }) => {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue