From a3ba53729569846e857dc85b92311ab68da44adc Mon Sep 17 00:00:00 2001 From: SUZUKI Sosuke Date: Mon, 25 Nov 2024 21:33:48 +0900 Subject: [PATCH] Fix loading ESM-style shared config file in Node.js 23 (#16857) * Return `.default` when Node.js 23 module feature is enabled * Add changelog * Add `ERR_REQUIRE_ASYNC_MODULE` to ignored error code --- changelog_unreleased/api/16857.md | 12 ++++++++++++ src/config/prettier-config/load-external-config.js | 12 +++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 changelog_unreleased/api/16857.md diff --git a/changelog_unreleased/api/16857.md b/changelog_unreleased/api/16857.md new file mode 100644 index 000000000..6b3b18897 --- /dev/null +++ b/changelog_unreleased/api/16857.md @@ -0,0 +1,12 @@ +#### Fix loading ESM-style shared config file in Node.js 23 (#16857 by @sosukesuzuki) + +In Prettier 3.3, attempting to load an ESM-style [shared config file](https://prettier.io/docs/en/sharing-configurations) in Node.js 23 resulted in the following warnings, preventing the options from being loaded: + +``` +[warn] Ignored unknown option { __esModule: true }. +[warn] Ignored unknown option { default: { trailingComma: "es5", tabWidth: 4, singleQuote: true } }. +``` + +This issue was caused by a new module feature in Node.js 23, known as [`require(ESM)`](https://nodejs.org/api/modules.html#loading-ecmascript-modules-using-require). Prettier 3.4 resolves this problem, allowing the options to load correctly. + +For more details, please see https://github.com/prettier/prettier/issues/16812. diff --git a/src/config/prettier-config/load-external-config.js b/src/config/prettier-config/load-external-config.js index 90d224e4c..9c2c90764 100644 --- a/src/config/prettier-config/load-external-config.js +++ b/src/config/prettier-config/load-external-config.js @@ -5,6 +5,7 @@ const requireErrorCodesShouldBeIgnored = new Set([ "MODULE_NOT_FOUND", "ERR_REQUIRE_ESM", "ERR_PACKAGE_PATH_NOT_EXPORTED", + "ERR_REQUIRE_ASYNC_MODULE", ]); async function loadExternalConfig(externalConfig, configFile) { /* @@ -15,7 +16,16 @@ async function loadExternalConfig(externalConfig, configFile) { 3. is a dirname with index.js inside */ try { - return requireFromFile(externalConfig, configFile); + const required = requireFromFile(externalConfig, configFile); + // Since Node.js v23 onwards, it is possible to load ESM using require. + // If that feature is enabled, it is necessary to return the default. + // https://github.com/prettier/prettier/issues/16812 + // FIXME: We want to add tests but https://github.com/jestjs/jest/issues/15363 blocks + // @ts-expect-error + if (process.features.require_module && required.__esModule) { + return required.default; + } + return required; } catch (/** @type {any} */ error) { if (!requireErrorCodesShouldBeIgnored.has(error?.code)) { throw error;