Ошибка "Error [ERR_REQUIRE_ESM]: require() of ES Module" в случае Webpack + "webpack-node-externals"

Описание проблемы

Собранная Webpack-ом Node.js-утилита (основана на Gulp и Webpack) выдаёт ошибку при запуске:

D:\IntelliJ IDEA\InHouseDevelopment\Example\MainPackage\EntryPoint.js:14040
module.exports = require("gulp-imagemin");
                 ^

Error [ERR_REQUIRE_ESM]: require() of ES Module D:\IntelliJ IDEA\InHouseDevelopment\Example\MainPackage\node_modules\gulp-imagemin\index.js from D:\IntelliJ IDEA\InHouseDevelopment\Example\MainPackage\EntryPoint.js not supported.
Instead change the require of index.js in D:\IntelliJ IDEA\InHouseDevelopment\Example\MainPackage\EntryPoint.js to a dynamic import() which is available in all CommonJS modules.
    at gulp-imagemin (D:\IntelliJ IDEA\InHouseDevelopment\Example\MainPackage\EntryPoint.js:14040:18)
    at __webpack_require__ (D:\IntelliJ IDEA\InHouseDevelopment\Example\MainPackage\EntryPoint.js:14370:42)
    at ./ProjectBuilding/AssetsProcessing/Images/ImagesProcessor.ts (D:\IntelliJ IDEA\InHouseDevelopment\Example\MainPackage\EntryPoint.js:1093:41)
    at __webpack_require__ (D:\IntelliJ IDEA\InHouseDevelopment\Example\MainPackage\EntryPoint.js:14370:42)
    at ./ProjectBuilder.ts (D:\IntelliJ IDEA\InHouseDevelopment\Example\MainPackage\EntryPoint.js:166:43) {
  code: 'ERR_REQUIRE_ESM'
}

Node.js v22.0.0

Как можно понять из сообщения об ошибке, проблема связана с gulp-imagemin. Однако есть и другие пакеты, которые могут вызывать подобную ошибку, например w3c-html-validator, причём ошибку вызывает не он сам, его зависимость - chalk.

Ремарка

Непонятные какие-то вещи происходят в Node.js с модулями. С одной стороны, CommonJS-модули являются модулями по умолчанию (может я что-то пропустил в новых версиях Node.js, но вроде как чтобы активировать ESM-режим, нужно добавить в package.json "type": "module"). С другой стороны, осуществляется агитация по переходу на ECMAScript-модули. Так или иначе, если у нас много зависимостей, то в "node_modules" будет в итоге мешанина из CommonJS-модулей и ESM-модулей. И ладно бы системы сборки проектов знали, что с этим делать, но похоже, не всегда знают.

В репозитории gulp-imagemin даже есть билет, озаглавленный "8.0.0 - ESM only? Serious?", что указывает на то, что ECMAScript-модули - пока ещё отнюдь не сама собой разумеющаяся вещь.

Особенности моего случая

Моя утилита собирается Webpack-ом, а для подключения одних файлов в другие используется ключевое слово import. Благодаря настройке target: "node", Webpack знает, во что надо собирать код.

Следуя рекомендациям, я использую webpack-node-externals, чтобы не подшивать Node.js-зависимости в Webpack-сборке (а подшивать их - не вариант: будет много предупреждений, если не ошибок). Таким образом, ошибка происходит "Error [ERR_REQUIRE_ESM]: require() of ES Module" происходит уже при запуске собранной утилиты, когда Node.js пытается импортировать (но не факт, что через ключевое слово import) модули пакета "gulp-imagemin".

Листинг Webpack-пресета

import Webpack from "webpack";
import Path from "path";

import NodeExternalsPlugin from "webpack-node-externals";
import ForkTypeScriptCheckerWebpackPlugin from "fork-ts-checker-webpack-plugin";
import ESLintPlugin from "eslint-webpack-plugin";

import type { ArbitraryObject } from "@yamato-daiwa/es-extensions";


export default function generateConfiguration(
  _environment: ArbitraryObject, commandArguments: ArbitraryObject
): Webpack.Configuration {

  const SOURCE_CODE_ROOT_DIRECTORY_ABSOLUTE_PATH: string = Path.resolve(__dirname, "Source");

  const __IS_DEVELOPMENT_BUILDING_MODE__: boolean = commandArguments.mode === "development";
  const __IS_PRODUCTION_BUILDING_MODE__: boolean = commandArguments.mode === "production";

  return {

    target: "node",

    context: SOURCE_CODE_ROOT_DIRECTORY_ABSOLUTE_PATH,
    entry: { EntryPoint: "./EntryPoint.ts" },

    output: {
      path: __dirname,
      filename: "[name].js",
      library: {
        type: "commonjs"
      }
    },

    mode: __IS_DEVELOPMENT_BUILDING_MODE__ ? "development" : "production",
    watch: __IS_DEVELOPMENT_BUILDING_MODE__,
    optimization: {
      emitOnErrors: __IS_DEVELOPMENT_BUILDING_MODE__,
      minimize: __IS_PRODUCTION_BUILDING_MODE__
    },

    node: {
      __dirname: false
    },

    devtool: false,

    externals: [
      NodeExternalsPlugin({
        allowlist: [ "rev-hash" ]
      })
    ],

    module: {
      rules: [
        {
          test: /\.ts$/u,
          loader: "ts-loader",
          options: {
            transpileOnly: true
          }
        }
      ]
    },

    resolve: {
      extensions: [ ".ts", ".js" ],
      alias: {
        // ...
      }
    },

    plugins: [
      new Webpack.DefinePlugin({
        __IS_DEVELOPMENT_BUILDING_MODE__,
        __IS_PRODUCTION_BUILDING_MODE__
      }),
      new ForkTypeScriptCheckerWebpackPlugin({
        typescript: {
          configFile: Path.resolve(__dirname, "tsconfig.json")
        }
      }),
      new ESLintPlugin({
        extensions: [ "js", "ts" ],
        failOnWarning: __IS_PRODUCTION_BUILDING_MODE__
      })
    ]
  };
}

Ответы (0 шт):