Skip to content

Subpath imports (e.g. dom-helpers/animationFrame) fail in webpack ESM-strict mode on v5 — exports map fix not backported from v6 #199

@csvan

Description

@csvan

Environment

  • dom-helpers: 5.2.1 (latest v5)
  • webpack: 5.x
  • Node.js: 22

Problem

All subpath imports (dom-helpers/animationFrame, dom-helpers/addClass, etc.) fail to resolve in any webpack build where the consuming package is treated as strict ESM — either because the app's package.json contains "type": "module", or because webpack's resolve.fullySpecified is true.

Error:

Module not found: Error: Can't resolve 'dom-helpers/animationFrame'
BREAKING CHANGE: The request 'dom-helpers/animationFrame' failed to resolve
only because it was resolved as fully specified
(probably because the origin is strict EcmaScript Module, e.g. a module with
javascript mimetype, a '*.mjs' file, or a '*.js' file where the package.json
contains '"type": "module"').
The extension in the request is mandatory for it to be fully specified.

Root cause: dom-helpers v5 has no exports map. It relies on the legacy "module": "esm/index.js" field. When webpack resolves dom-helpers/animationFrame in a fully-specified ESM context, it cannot determine the correct extension and fails.

Reproduction

  1. Create a package with "type": "module" in package.json
  2. Add dom-helpers@^5 as a dependency
  3. Import import { request } from 'dom-helpers/animationFrame'
  4. Build with webpack 5 → error above

Relationship to #183

Issue #183 requested an exports map and was closed as completed — but the fix shipped as v6.0.0, a major version bump. The v5 branch has no backport.

This is a significant problem because React Bootstrap itself pins dom-helpers at ^5, meaning the entire React Bootstrap ecosystem remains on v5 and is affected. Upgrading to v6 is not a safe drop-in for most consumers due to the changed package shape.

The exports map addition is not inherently breaking — it could be backported to a 5.3.0 patch.

Suggested fix

Backport the v6 exports map to v5 as a 5.3.0 release. The v6 map applies directly to the existing v5 file layout:

{
  "exports": {
    "./package.json": "./package.json",
    ".": {
      "require": { "types": "./cjs/index.d.ts", "default": "./cjs/index.js" },
      "import":  { "types": "./esm/index.d.ts", "default": "./esm/index.js" }
    },
    "./*": {
      "require": { "types": "./cjs/*.d.ts", "default": "./cjs/*.js" },
      "import":  { "types": "./esm/*.d.ts", "default": "./esm/*.js" }
    }
  }
}

Alternatively, document the v6 requirement prominently in the README for ESM-strict environments.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions