Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

exports.types after exports.default #384

Closed
regseb opened this issue May 18, 2023 · 5 comments
Closed

exports.types after exports.default #384

regseb opened this issue May 18, 2023 · 5 comments

Comments

@regseb
Copy link

regseb commented May 18, 2023

To import a library, I use jsdelivr which uses enhanced-resolve. I had a problem with the order of the properties in exports: default wasn't at the end. jsdelivr/jsdelivr#18496

{
  "exports": {
    ".": {
      "default": "index.js",
      "types": "index.d.ts"
    }
  }
}

I prefer to define sources before types because sources are more important than types. And for the old properties main and types, npm-package-json-lint defines main before types. It's more readable to have the same order for main / types and exports sub-properties (e.g. cronnor/package.json).


enhanced-resolve forces the default property to the end: assert default. Could be last only. The Node.js documentation indicates this:

Node.js implements the following conditions, listed in order from most specific to least specific as conditions should be defined:

  • "node-addons" - similar to "node" and matches for any Node.js environment. This condition can be used to provide an entry point which uses native C++ addons as opposed to an entry point which is more universal and doesn't rely on native addons. This condition can be disabled via the --no-addons flag.
  • "node" - matches for any Node.js environment. Can be a CommonJS or ES module file. In most cases explicitly calling out the Node.js platform is not necessary.
  • "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.

I understand that default should always be the last property among node-addons, node, import, require and default. But the property types can be positioned wherever you want.


I propose to filter the values of the exports to keep only the properties node-addons, node, import, require and default (maybe add webpack).

function conditionalMapping(conditionalMapping_, conditionNames) {
+	const conditionKeys = ["node-addons", "node", "import", "require", "default"];
	/** @type {[ConditionalMapping, string[], number][]} */
-	let lookup = [[conditionalMapping_, Object.keys(conditionalMapping_), 0]];
+	let lookup = [[
+		conditionalMapping_,
+		Object.keys(conditionalMapping_).filter((c) => conditionKeys.includes(c)),
+		0,
+	]];

	loop: while (lookup.length > 0) {

Or exclude the types properties:

function conditionalMapping(conditionalMapping_, conditionNames) {
	/** @type {[ConditionalMapping, string[], number][]} */
-	let lookup = [[conditionalMapping_, Object.keys(conditionalMapping_), 0]];
+	let lookup = [[
+		conditionalMapping_,
+		Object.keys(conditionalMapping_).filter((c) => c !== "types"),
+		0,
+	]];

	loop: while (lookup.length > 0) {
@alexander-akait
Copy link
Member

You can setup it using options, I don't think it is a good idea to change default logic

@alexander-akait
Copy link
Member

alexander-akait commented May 18, 2023

Also I think you need to go to typescript community and ask them about it and maybe ask them to change Node.js specific logic (not sure it is possible)

@alexander-akait
Copy link
Member

alexander-akait commented May 18, 2023

If you have types after default you need consider it as a bug microsoft/TypeScript#46334 (comment)

@alexander-akait
Copy link
Member

Feature request: Built-in typescript warning about it microsoft/TypeScript#46861

@regseb regseb changed the title exports.type after exports.default exports.types after exports.default Jun 6, 2023
@regseb
Copy link
Author

regseb commented Jun 6, 2023

In Community Conditions Definitions documentation, Node specifies that the "types" property should always be included first.

So don't put "types" after "default".

@regseb regseb closed this as completed Jun 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants