0

I tried to import the w3c-html-validator but got the error

Error [ERR_REQUIRE_ESM]: require() of ES Module D:(...)\node_m odules\w3c-html-validator\node_modules\chalk\source\index.js from D:(...)\node_modules\w3c-html-validator\dist\w3c-html-validator.umd.cjs not supported.

Looks like this problem is with chalk, the dependency of w3c-html-validator.

I am using the Webpack with webpack-node-externals. Thank to it, export/import keywords are available even though the output is the CommonJS and indented to be executed by plain Node.js. It should be the specific solution for this case, not just "add type: module to your package.json".

If possible, I want to avoid the adding of type: module to the package.json because it could cause other errors. Currently, I have about 30 dependencies (see the appendix) and neither of them requires type: module.

Appendix

Webpack setup

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"
      }
    },

    /* [ Theory ] Valid non-undefined values are only "development", "production" and "none". */
    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: {
            /* [ Theory ] 'ForkTypeScriptCheckerWebpackPlugin' will execute the type checking. */
            transpileOnly: true
          }
        }
      ]
    },

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

    plugins: [
      new Webpack.DefinePlugin({
        __IS_DEVELOPMENT_BUILDING_MODE__,
        __IS_PRODUCTION_BUILDING_MODE__
      }),
      new ForkTypeScriptCheckerWebpackPlugin({
        typescript: {
          /* [ Theory ] The default value is 'context', but the 'tsconfig.json' is 1 level above 'context'. */
          configFile: Path.resolve(__dirname, "tsconfig.json")
        }
      }),
      new ESLintPlugin({
        extensions: [ "js", "ts" ],
        failOnWarning: __IS_PRODUCTION_BUILDING_MODE__
      })
    ]
  };
}

Current dependencies

{
  "dependencies": {
    "@typescript-eslint/eslint-plugin": "5.57.0",
    "@typescript-eslint/parser": "5.57.0",
    "@vue/compiler-sfc": "3.2.47",
    "@webdiscus/pug-loader": "2.10.4",
    "@yamato-daiwa/es-extensions": 1.6.9,
    "@yamato-daiwa/es-extensions-nodejs": "1.6.0-alpha.9",
    "@yamato-daiwa/style_guides": "0.0.47",
    "access-sniff": "3.2.0",
    "autoprefixer": "10.4.14",
    "browser-sync": "2.27.11",
    "cheerio": "1.0.0-rc.1",
    "css-loader": "6.7.3",
    "cssnano": "5.1.14",
    "eslint": "8.37.0",
    "eslint-plugin-import": "2.27.5",
    "eslint-plugin-node": "11.1.0",
    "eslint-webpack-plugin": "4.0.0",
    "fork-ts-checker-webpack-plugin": "7.3.0",
    "glob": "7.2.0",
    "gulp": "4.0.2",
    "gulp-data": "1.3.1",
    "gulp-debug": "4.0.0",
    "gulp-html-prettify": "0.0.1",
    "gulp-if": "3.0.0",
    "gulp-imagemin": "7.1.0",
    "gulp-intercept": "0.1.0",
    "gulp-plumber": "1.2.1",
    "gulp-postcss": "9.0.1",
    "gulp-pug": "5.0.0",
    "gulp-sourcemaps": "3.0.0",
    "gulp-stylus": "2.7.1",
    "imagemin-pngquant": "9.0.2",
    "json5-loader": "4.0.1",
    "minimatch": "5.1.1",
    "node-notifier": "10.0.1",
    "prettier": "2.8.7",
    "pug-lint": "2.6.0",
    "pug-plain-loader": "1.1.0",
    "rev-hash": "4.0.0",
    "stlint": "1.0.65",
    "stream-combiner2": "1.1.1",
    "style-loader": "3.3.1",
    "stylus-loader": "7.1.0",
    "ts-loader": "9.4.2",
    "vinyl": "2.2.1",
    "vue": "3.2.47",
    "vue-loader": "17.0.1",
    "vue-style-loader": "4.1.3",
    "vue-tsc": "1.2.0",
    "w3c-html-validator": "1.3.3",
    "webpack": "5.76.2",
    "webpack-node-externals": "3.0.0",
    "webpack-stream": "7.0.0",
    "worker-loader": "3.0.8",
    "yaml-loader": "0.8.0"
  },
  "devDependencies": {
    "@types/browser-sync": "2.26.3",
    "@types/cheerio": "0.22.31",
    "@types/cssnano": "5.0.0",
    "@types/glob": "7.2.0",
    "@types/gulp": "4.0.10",
    "@types/gulp-debug": "2.0.32",
    "@types/gulp-html-prettify": "0.0.2",
    "@types/gulp-if": "0.0.34",
    "@types/gulp-imagemin": "8.0.1",
    "@types/gulp-intercept": "0.1.1",
    "@types/gulp-plumber": "0.0.33",
    "@types/gulp-postcss": "8.0.2",
    "@types/gulp-sourcemaps": "0.0.35",
    "@types/gulp-stylus": "2.7.4",
    "@types/node": "18.13.0",
    "@types/node-notifier": "8.0.2",
    "@types/pug": "2.0.6",
    "@types/webpack-node-externals": "2.5.3",
    "@types/webpack-stream": "3.2.12",
    "ts-node": "10.9.1",
    "typescript": "5.0.3",
    "webpack-cli": "5.0.1"
  }
}

Takeshi Tokugawa YD
  • 670
  • 5
  • 40
  • 124
  • 1
    Why using webpack with the webpack-node-externals plugin? This plugin prevents all `node_modules` from being bundled together with your source code, which seems to be the source of your issue. – VonC May 16 '23 at 09:11
  • @VonC Because the bundling of Node.js dependencies could cause a many warnings. The usage of webpack-node-external is the recommended approach. – Takeshi Tokugawa YD May 16 '23 at 11:43
  • Have you tried just defining externals without `webpack-node-externals`? – Slbox May 17 '23 at 22:43
  • @Slbox defining externals without `webpack-node-externals`? Would you please to share the link with example? – Takeshi Tokugawa YD May 18 '23 at 01:48
  • Try using a different version that doesn’t rely on chalk which is pure esm since v 5. Pick your dependencies better or understand how to work with esm/cjs boundaries. – morganney May 20 '23 at 13:55

2 Answers2

1

As you noted, the problem is that w3c-html-validator is using an ESM version of chalk. Basically, the maintainer of w3c-html-validator has built the UMD/CJS variant incorrectly by trying to require one of its own ESM dependencies .

Simple solution: Downgrade your version of w3c-html-validator to v0.8.1 which uses a CommonJS version of chalk.

Babel solution: Add babel-loader to your webpack build and transpile the chalk dependency to convert the import/export to require/module.exports, i.e. ESM to CJS.

Your babel config should look something like this (add @babel/preset-env if not already in your devDependencies):

{
  "presets": [
    ["@babel/preset-env", {
      "modules": "commonjs"
    }]
  ]
}

Your updated webpack config should include something like this:

module: {
  rules: [
    {
      test: /\.(t|j)sx?$/,
      include: filename => {
        return /node_modules\/chalk/.test(filename)
      },
      use: ['babel-loader']
    }
  ]
}
morganney
  • 6,566
  • 1
  • 24
  • 35
0

If the problem is your use of webpack-node-externals you might have luck with code like below.

Note that this solution relies on you knowing which modules are native dependencies (which should not take long to figure out.)

You might update the beginning of your config like this:

return {
    target: "node",
    externals: ['sharp', 'another-native-node-dep'], // Add your native dependency names to the array and remove my examples
    context: SOURCE_CODE_ROOT_DIRECTORY_ABSOLUTE_PATH,
    entry: { EntryPoint: "./EntryPoint.ts" },
Slbox
  • 10,957
  • 15
  • 54
  • 106
  • Thank you for the answer. Unfortunately, the stopping of the usage of `webpack-node-externals` caused the another error, the `"development" = 'development' SyntaxError: Invalid left-hand side in assignment`. It refers to the code automatically generated by Webpack. It looks like it is impossible to simply stop use the "webpack-node-externals", because basically it works fine. – Takeshi Tokugawa YD May 19 '23 at 02:45