-
Notifications
You must be signed in to change notification settings - Fork 626
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
ESM TypeScript support in the metro-resolver #886
Comments
Thanks for bringing this to our attention! If my understanding is right, you're trying to enable this new TypeScript ES module compiler behaviour in your app's source code. Put shortly, the behaviour you suggest above is functionality we don't yet support and would be independent from Metro's current concepts (so yes, new feature 🙂 — adding detail here to provide a clear spec). Current module extension concepts Replacing explicitly-provided extensions (e.g.
Under the above, TypeScript ES module imports TypeScript appears to be handling ES module extensions differently — requiring metro-resolver to resolve a source file which isn't present on the filesystem (e.g. // @filename: helper.cts
export function helper() {
console.log("hello world!");
}
// @filename: index.mts
import foo from "./helper.cjs"; // <- replaced with .cts So, we'll need some new config concept or builtin behaviour in metro-resolver to handle this. Perhaps, Recommendations
|
Some more digging in the TypeScript proposal on why this design was decided:
There is also feedback/concern about this: Concerns with TypeScript 4.5's Node 12+ ESM Support. And this reply implies the TS team is committed to this design, and CommonJS also remains the default recommended setup from their point of view (intentional move of publishing no migration guide). From the React Native side:
|
can be kind-of fixed with the following code in metro.config.js:
|
@mo22 I made some modifications to your suggested (kind-of) fix in order to avoid breaking things like platform-specific imports, I just stripped the resolver: {
resolveRequest: (context, rawModuleName, platform) => {
let moduleName = rawModuleName;
// Resolve fully specified TS imports by stripping extension
const isPackage =
!moduleName.startsWith(".") && !moduleName.startsWith("/");
const isJsOrJsxFile =
!isPackage &&
(moduleName.endsWith(".js") || moduleName.endsWith(".jsx"));
if (isJsOrJsxFile) moduleName = moduleName.replace(/\.[^/.]+$/, "");
return context.resolveRequest(context, moduleName, platform);
},
}, |
@mo22 this also matches files in node-modules and was causing problem with My modification checks if the file exists and if it does, it falls back to default resolution. Otherwise removes extension to allow default extension resolution. resolver: {
resolveRequest = (context, moduleName, platform) => {
if (
(moduleName.startsWith('.') || moduleName.startsWith('/')) &&
(moduleName.endsWith('.js') || moduleName.endsWith('.jsx'))
) {
const moduleFilePath = path.resolve(
context.originModulePath,
'..',
moduleName,
);
// if the file exists, we won't remove extension, and we'll fall back to normal resolution.
// this rule specifically exists for .tsx? files that are imported as .jsx? files.
if (!fs.existsSync(moduleFilePath)) {
// console.log(moduleName, moduleName.replace(/\.[^/.]+$/, ''));
return context.resolveRequest(
context,
moduleName.replace(/\.[^/.]+$/, ''),
platform,
);
}
}
return context.resolveRequest(context, moduleName, platform);
}
} |
Do you want to request a feature or report a bug?
Feature
What is the current behavior?
metro-resolver cannot resolve TypeScript imports that are in ESM format, e.g. have .js file extension in the import. It only adds extensions listed in
sourceExts
at the path, but does not consider situations where the original file extensions needs to be replaced.What is the expected behavior?
metro-resolver should try to resolve TypeScript imports that are in ESM format. metro-resolver should try out the different file-extensions as it currently does, but in addition try out the file extensions also after removing the original file extension of the import. Example:
import {thing} from './something.js
Currently metro-resolver by default tries to resolve this as
./something.js
,./something.js.native
,./something.js.android.js
,./something.js.ts
,./something.js.android.ts
, ... etc.It should also try to resolve it as following: Currently metro-resolver by default tries to resolve this as
./something
,./something.native
,./something.android.js
,./something.ts
,./something.android.ts
, ... etc. For my use case it should try to replace .js with .ts and .tsx, but there might be other use cases too.Please provide your exact Metro configuration and mention your Metro, node, yarn/npm version and operating system.
Metro version: 0.67.0
Metro-resolver version: 0.67.0
Node version: 16.18.0
Yarn version: 1.22.4
Windows 11 and MacOS
The text was updated successfully, but these errors were encountered: