Implement package exports and subpath imports handling
This PR implements smart handling of package exports and subpath imports to distinguish between legacy packages that need .js extensions and modern packages with exports field that should remain unchanged.
Problem
The current implementation adds .js extensions to all node_modules imports, but this doesn't work correctly for modern packages that use the exports field in their package.json. This causes issues where:
-
Legacy packages (like
lodash) need.jsextensions:'lodash/omit'→'lodash/omit.js' -
Modern packages (like
firebase-functions) should remain unchanged:'firebase-functions/v1/https'(already works correctly in ESM)
Solution
Added intelligent package detection that checks if a node_modules package has an exports field:
// Before: All packages got .js extensions
import omit from 'lodash/omit'; // → 'lodash/omit.js' (correct)
import {HttpsError} from 'firebase-functions/v1/https'; // → 'firebase-functions/v1/https.js' (incorrect!)
// After: Smart detection based on package.json exports field
import omit from 'lodash/omit'; // → 'lodash/omit.js' (legacy package)
import {HttpsError} from 'firebase-functions/v1/https'; // → unchanged (modern package)
Key Changes
-
Added
hasPackageExports()utility inPathUtil.tsthat safely reads and parsespackage.jsonfiles to detect theexportsfield -
Enhanced
replaceModulePath.tsto check package exports before adding file extensions -
Added support for scoped packages with proper parsing of package names like
@types/node - Comprehensive test coverage including mock packages for both scenarios
Testing
- All existing tests continue to pass
- New test fixture with realistic mock packages (lodash as legacy, firebase-functions as modern)
- Manual validation confirms correct behavior for both package types
- Added unit tests for new utility functions
This change maintains full backward compatibility while fixing the issue with modern packages that use the exports field.
Fixes #129.
💬 Share your feedback on Copilot coding agent for the chance to win a $200 gift card! Click here to start the survey.
@bennycode 👋 This repository doesn't have Copilot instructions. With Copilot instructions, I can understand the repository better, work faster and produce higher quality PRs.
I can generate a .github/copilot-instructions.md file for you automatically. Click here to open a pre-filled issue and assign it to me. I'll write the instructions, and then tag you for review.