TypeScript imports with .js file extensions don't work #32237
Replies: 21 comments 7 replies
This comment was marked as spam.
This comment was marked as spam.
-
Hey @justinfagnani! Thanks for letting us know about this issue. I wasn't aware TypeScript allowed for this behavior. What happens when a Are there any other toolkits that support this behavior out-of-the-box? We'd love to see a reference implementation. We'll explore the above questions if they're more nuanced when we get around to implementing this. Feel free to send a PR as well! |
Beta Was this translation helpful? Give feedback.
-
@Timer ts prefers ts and will ignore the js file when both are present, you can confirm with tsc -w without an outDir specified and changing the contents of the .js file - it won't recompile. to get this working in next, i think https://github.com/tleunen/babel-plugin-module-resolver/blob/master/src/resolvePath.js has everything you need |
Beta Was this translation helpful? Give feedback.
-
seems that next.js prefers .ts files in node_modules folder over .js files as well, in a library I'm writing in TS which I build all my typescript files to js in the same folder, next.js starts crawling the node_modules directory for types and throws an error because I have a babel plugin that processes SVG and typescript doesn't know what it is. |
Beta Was this translation helpful? Give feedback.
-
any news on this? |
Beta Was this translation helpful? Give feedback.
-
👍 ing the importance of this issue. Not sure how strictly Next.js uses the
As an aside, some devs may have settings in their IDEs that auto-add |
Beta Was this translation helpful? Give feedback.
-
If anyone is looking for copy-paste workaround here it is:
const path = require("path");
const fs = require("fs");
module.exports = {
presets: ["next/babel"],
plugins: [
[
"module-resolver",
{
extensions: [".js", ".jsx", ".es", ".es6", ".mjs", "ts", "tsx"],
resolvePath(sourcePath, currentFile, opts) {
if (!sourcePath.startsWith("./") && !sourcePath.startsWith("../")) {
return sourcePath;
}
if (sourcePath.endsWith(".js")) {
const relPath = path.resolve(path.dirname(currentFile), sourcePath);
const tsPath = relPath.replace(/\.js$/, ".ts");
const tsxPath = relPath.replace(/\.js$/, ".tsx");
if (fs.existsSync(tsPath)) {
return tsPath;
}
if (fs.existsSync(tsxPath)) {
return tsxPath;
}
}
return sourcePath;
},
},
],
],
}; I'm using that for few months already without any issues. I'd love to have this working without a workaround though. @samfortunato gave some nice arguments why. |
Beta Was this translation helpful? Give feedback.
-
@dzek69 Awesome, that did work. Was looking for a solution like this before. Unfortunately, it means Next.js will not use the new Rust compiler. Would have to look at the SWC docs to see if a workaround could be configured in the same way... |
Beta Was this translation helpful? Give feedback.
-
"TypeScript allows the use of the
My Next.js application is not an isolated project; it shares TypeScript modules with other environments that rely on this |
Beta Was this translation helpful? Give feedback.
-
Why is this a "discussion" and not an issue? It's a straightforward bug, and I don't see much discussion required. If there is none, can we convert it back to an issue? |
Beta Was this translation helpful? Give feedback.
-
I just stumbled upon this myself and the documention for this module-not-found error didn't mention it. I think it's worth mentioning it in https://nextjs.org/docs/messages/module-not-found |
Beta Was this translation helpful? Give feedback.
-
Just popping in to say I'm seeing this behavior as well, under Vercel CLI v28.4.5 and typescript v4.8.3: Vercel seems to not traverse imports that end in I've been migrating my back-end codebase from Express, where previously I'd transpiled TypeScript to ESM JavaScript, where TypeScript all but requires the |
Beta Was this translation helpful? Give feedback.
-
This is a pain! I have a large project written in ESM/ Vite that I'd like to port to NextJS, but it would require rewriting every single import, which had to be |
Beta Was this translation helpful? Give feedback.
-
I haven't tested this thoroughly, but it looks like with the new |
Beta Was this translation helpful? Give feedback.
-
I believe I have a workaround for this that doesn't involve using babel. In your next.config.js file add: webpack: (config) => {
config.resolve.extensionAlias = {
".js": [".ts", ".tsx", ".js"],
};
return config;
}, With that it should be possible to have files ending in the .ts/.tsx extension, use the .js extention in import paths for them (inline with typescript recommendations) and set Note that this requires the latest version of Next.js and webpack (or at least webpack v5.74.0) since |
Beta Was this translation helpful? Give feedback.
-
I've had good luck getting things working with workaround 2 from this related github issue. |
Beta Was this translation helpful? Give feedback.
-
This issue is important, which is why ts-add-js-extension was made, the strength of this package is that, it can find whether you are importing/exporting |
Beta Was this translation helpful? Give feedback.
-
Was there ever solved? @callumgare gave a workaround using webpack config. But nextjs13 is using turbopack now...? |
Beta Was this translation helpful? Give feedback.
-
I re-opened this as a bug issue here, since it doesn't seem like it's a "discussion": Some additional colour that I've found when working with this is that ES module 3rd party libs that are used in Pages router serverside code seem to require the However, you also can't add the same extensions to any application code in your main Next app, otherwise it can't resolve the file. Furthermore, to publish a server action in a 3rd party lib for the App Router, the package currently needs to be ESM because the Next bundler adds ES module syntax to any server action file that is imported. If the package is distributed as CommonJS then the build fails when importing a server action from that library. So I'm currently stuck in a situation where my Next library that needs to work in both pages and app router, and contains a server action, has to be published as ESM and thus has to include the |
Beta Was this translation helpful? Give feedback.
-
With Webpack this can be fixed with the following next.config.mjs: /** @type {import("next").NextConfig} */
export default {
webpack: webpackConfig => {
webpackConfig.resolve.extensionAlias = {
'.js': ['.ts', '.js'],
'.mjs': ['.mts', '.mjs'],
'.cjs': ['.cts', '.cjs'],
'.jsx': ['.tsx', '.jsx'],
}
return webpackConfig
},
} |
Beta Was this translation helpful? Give feedback.
-
has this really not been fixed yet? imports with |
Beta Was this translation helpful? Give feedback.
-
Bug report
Describe the bug
When importing a TypeScript module from another, TypeScript allows the use of the
.js
file extension:foo.ts:
bar.ts
This is important in plain TypeScript projects because browsers don't do any module resolution and require the correct extensions. The compiled output works as it.
If you copy the same files into a Next.js project you will get a compile error that
foo.js
cannot be found.To Reproduce
See above
Expected behavior
No compile errors
System information
Beta Was this translation helpful? Give feedback.
All reactions