Skip to content
This repository was archived by the owner on Sep 2, 2023. It is now read-only.
This repository was archived by the owner on Sep 2, 2023. It is now read-only.

Proposal: make .js extension default for es6 imports #444

@sheerun

Description

@sheerun

Just to be clear: this proposal is not to make --es-module-specifier-resolution=node a default

Backstory

Recently there have been a lengthy discussion I've started in order to make package.json of ES6 modules more simple. Probably the biggest takeaway from this is that without extensionless imports in some form, in order to create backward-compatible packages to support subpath imports like import first from 'lodash/first' they need to create long list of entrypoints in exports field of package.json which needs to be passed around everywhere.

This issue combines with obvious status quo that: many developers are used to, many existing applications already use, and many transcompilers (like typescript) application boilerplates (like create-react-app) generate extensionless imports in code: #323 (comment)

Probably the biggest "cons" against extensionless imports I've heard so far is that they are slow as they require checking few locations in filesystem in order to determine where the file is which is relevant if we want to use HTTP/2 streaming imports of non-transpiled JS files. But this seems an issue with --es-module-specifier-resolution=node which is only one solution to this problem.

Proposed solution(s)

Solution one:

If extensionless file is imported, assume .js extension.

  • import App from "./App" always imports "./App.js"
  • import App from "./App.js" always imports "./App.js"
  • import App from "./App.mjs" always imports "./App.mjs"
  • import App from "./App.cjs" always imports "./App.cjs"

This seems performant, accounts for status quo, and also seems to solve issue of complicated package.json for modules that support importing subpaths if exports is made stable.

For example this could be package.json of lodash package (please note that exports is not a part of this proposal, it is already a proposed and implemented thing)

{
  "main": "index.js",
  "exports": {
    "require": "./",
    "default": "./src/"
  }
}
  • require('lodash/first') in old node loads CJS file lodash/first.js with old resolution rules
  • require('lodash/first') in new node loads CJS file lodash/first.js because of require in exports (or old resolution rules if you decide to not change this behavior)
  • import first from 'lodash/first' loads ES6 file lodash/src/first.js because of default in exports combined with the new resolution rule (default .js extension)
Solution two:

If extensionless file is imported, assume imported extension has the same extension as current file.

This means that:

  • extensionless imports in .js files wil import .js by default
  • extensionless imports in .mjs files wil import .mjs by default
  • extensionless imports in .jsx files wil import .jsx by default
  • extensionless imports in .cjs files wil import .cjs by default

etc. etd... Seems less opinionated but also more complicated

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