Skip to content

fix(package): resolve extensionless hook subpaths - #1694

Merged
xobotyi merged 2 commits into
masterfrom
fix/exports-subpaths
Jul 26, 2026
Merged

fix(package): resolve extensionless hook subpaths#1694
xobotyi merged 2 commits into
masterfrom
fix/exports-subpaths

Conversation

@xobotyi

@xobotyi xobotyi commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Fixes the subpath resolution problem found while reviewing #1670.

Problem

$ node -e "import('@react-hookz/web/useToggle')"
Error [ERR_UNSUPPORTED_DIR_IMPORT]: Directory import '.../dist/useToggle' is not supported

"./*": "./dist/*" maps useToggle onto a directory, so the natural extensionless specifier has never worked — only the useToggle/index.js form the README documented, or the useToggle/ trailing-slash form, which Node warns about:

DeprecationWarning: Use of deprecated trailing slash pattern mapping "./useToggle/" ...
Mapping specifiers ending in "/" is no longer supported. (DEP0155)

Change

 "exports": {
   ".": "./dist/index.js",
   "./package.json": "./package.json",
-  "./*/": "./dist/*/index.js",
-  "./*": "./dist/*"
+  "./*.js": "./dist/*.js",
+  "./*": "./dist/*/index.js",
+  "./*/": "./dist/*/index.js"
 }

./* now targets the directory's entry file, and ./*.js preserves explicit file paths — its * matches slashes, so useToggle/index.js still lands on dist/useToggle/index.js. Exact keys and pattern specificity ordering are handled by Node, not by key order.

./*/ is kept deliberately. It is deprecated, but it is the only form that worked for people who wanted a directory-style import, and dropping it would break them for no gain — it warns only when used.

Purely additive: every specifier that resolved before resolves to the same file.

Verification

Packed the tarball, installed it into a scratch consumer with react 19, and resolved each form (Node 26):

Specifier Before After
@react-hookz/web ok ok, 62 exports
@react-hookz/web/useToggle ERR_UNSUPPORTED_DIR_IMPORT ok
@react-hookz/web/useToggle/index.js ok ok
@react-hookz/web/useMeasure ERR_UNSUPPORTED_DIR_IMPORT ok, 3 exports
@react-hookz/web/types.js ok ok
@react-hookz/web/util/const.js ok ok
@react-hookz/web/package.json ok ok
@react-hookz/web/useToggle/ ok + DEP0155 ok + DEP0155

Types follow the same map — tsc under moduleResolution: NodeNext accepts import {useToggle} from '@react-hookz/web/useToggle' and import type {Measures} from '@react-hookz/web/useMeasure' against the packed tarball (exit 0).

README's direct-import example switches to the short form.

xobotyi added 2 commits July 26, 2026 01:23
`@react-hookz/web/useToggle` mapped to `./dist/useToggle`, a directory,
so it failed with ERR_UNSUPPORTED_DIR_IMPORT; only the documented
`useToggle/index.js` form worked. `./*` now points at the directory's
entry file and a new `./*.js` pattern keeps explicit file paths
(`useToggle/index.js`, `types.js`, `util/const.js`) resolving as before.

`./*/` stays for the trailing-slash form. It triggers DEP0155 on use, but
dropping it would break callers that adopted it while the extensionless
form was unusable.
The extensionless subpath now resolves, and it is the form consumers
reach for first.
@codecov

codecov Bot commented Jul 25, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 83.19%. Comparing base (acdc7e5) to head (8584e3c).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #1694   +/-   ##
=======================================
  Coverage   83.19%   83.19%           
=======================================
  Files          62       62           
  Lines         839      839           
  Branches      151      151           
=======================================
  Hits          698      698           
  Misses         16       16           
  Partials      125      125           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates @react-hookz/web’s package export map so extensionless hook subpath imports (e.g. @react-hookz/web/useToggle) resolve to the hook directory entry file instead of a directory path, and updates the README to document the shorter import form.

Changes:

  • Adjust package.json#exports so ./* resolves to ./dist/*/index.js (fixing ERR_UNSUPPORTED_DIR_IMPORT for extensionless hook imports).
  • Add a ./*.js export pattern to preserve explicit .js deep imports (including useX/index.js forms).
  • Update README direct-import example to use @react-hookz/web/useMountEffect instead of the explicit .../index.js path.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
README.md Updates docs to show the now-supported extensionless single-hook import.
package.json Fixes subpath export resolution by mapping extensionless subpaths to each hook’s index.js, while preserving explicit .js deep imports.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@xobotyi
xobotyi merged commit 4fcb071 into master Jul 26, 2026
7 checks passed
@xobotyi
xobotyi deleted the fix/exports-subpaths branch July 26, 2026 07:50
@xobotyi

xobotyi commented Jul 26, 2026

Copy link
Copy Markdown
Contributor Author

🎉 This PR is included in version 26.1.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Development

Successfully merging this pull request may close these issues.

2 participants