Skip to content

export spec clarification with require xor import and non-JS cases #41686

@evanw

Description

@evanw

Affected URL(s)

https://nodejs.org/api/packages.html#conditional-exports

Description of the problem

I'm coming here from evanw/esbuild#1956. Specifically the esbuild bundler implements node's spec for exports in package.json files. Node's documentation for exports says this:

  • "import" - matches when the package is loaded via import or import(), or via any top-level import or resolve operation by the ECMAScript module loader. Applies regardless of the module format of the target file. Always mutually exclusive with "require".
  • "require" - matches when the package is loaded via require(). The referenced file should be loadable with require() although the condition matches regardless of the module format of the target file. Expected formats include CommonJS, JSON, and native addons but not ES modules as require() doesn't support them. Always mutually exclusive with "import".
  • "default" - the generic fallback that always matches. Can be a CommonJS or ES module file. This condition should always come last.

This is what esbuild implements. The case I'm looking for clarification on is that there are packages that just have require and import but not default. This is reasonable as the example in the documentation also doesn't include a default condition, and the documentation says import and require are mutually exclusive (i.e. exactly one should be present).

However, esbuild performs the following kinds of path resolution:

  • import-statement
  • require-call
  • entry-point
  • import-rule
  • url-token

I understand what should happen with the first two but not with the last three. An entry point is path resolution that happens due to a package name provided on the command line. There is no import or require in that case. And the last two happen when you import things from CSS (something a bundler has to deal with) where there is also no JS import statement or require call. If esbuild supported importing things from HTML, which it may one day, there would also be those cases to consider.

Right now esbuild handles these non-JS cases by still running the exports logic but just without the import or require conditions active, since it's neither an import nor a require. But then that breaks when there's no default condition. Do you have any opinion for what should happen here, as the authors of this specification? Some options:

  • Don't apply import or require and fail path resolution if nothing applies (esbuild's current behavior)
  • Don't apply import or require and fall back to legacy module/main fields if nothing applies
  • Pick one of import or require to apply arbitrarily
  • Apply both import and require
  • Don't attempt to apply exports rules at all and only use legacy module/main fields
  • Undefined: up to the tool to do whatever they want
  • Something else?

Metadata

Metadata

Assignees

No one assigned

    Labels

    docIssues and PRs related to the documentations.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions