three.js: `import` fails to resolve when using `esbuild` build tool
Is your feature request related to a problem? Please describe.
When using the esbuild build tool, the import statement reports an error that cannot be resolved.
E.g:
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
This is because of the following configuration:
"exports": {
"./examples/jsm/*": "./examples/jsm/*"
}
Although tools like rollup, webpack, etc. may be normal, obviously esbuild respects node specification standards more.
According to the node specification, in order for the esbuild tool to work properly, the file extension needs to be added:
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
Obviously when this happens, many people need to spend as much time as I do to analyze the cause of the problem.
In fact, the following configuration can also solve the problem:
"exports": {
"./examples/jsm/*": "./examples/jsm/*.js"
}
In order to improve development efficiency (compilation speed), esbuild should have been widely used, can this problem be solved?
_see also https://github.com/evanw/esbuild/issues/2518_
Describe the solution you’d like
- For files of the same type (such as
.js), change theexportsconfiguration in package.json, for example
"exports": {
"./examples/jsm/*": "./examples/jsm/*.js"
}
- For different categories of files contained in a folder, multiple configurations can be written, or it is clearly mentioned in the documentation that developers should write extensions when importing?
"exports": {
"./examples/jsm/*.js": "./examples/jsm/*.js",
"./examples/jsm/*.png": "./examples/jsm/*.png"
}
Describe alternatives you’ve considered
Additional context
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Comments: 32 (14 by maintainers)
I thought omitting the .js extension on imports was mostly a TypeScript-ism, is it used outside TS?
I don’t think we should be doing that anywhere within this project, including examples…
If you’d like esbuild to be more flexible in its ability to resolve package paths I recommend making an issue or PR to the esbuild project rather than one here. But either way it is not common for packages to export files in the style you have recommended. And as you’ve mentioned this kind of export can lead to file ambiguity. It’s best to explicitly import the files you want to your project. You can see that even
react-domdoes not export files in a way that affords dropping the file extension.What does this mean? Ambiguous statements like this are one reason why this hasn’t been going anywhere. I want to help but there have been no concrete examples or way to understand what is breaking and when. Tell us what tool. Show when it’s breaking and how. Give us a real example. Without anything concrete this just looks like a superficial change because, again, we are not using the same tools and workflow you might be. I understand it might be more complex that it initially looks but you have to help us help you.
I’m not sure how else to put it other than I don’t feel like there’s being enough effort put into communicating the issue. And if we don’t understand the problem then it will just get inadvertently broken in the future.
That is an error coming from enforcement of the ES Modules spec via Node resolution since examples are ESM only. Yes, this is just a missing file extension but it is not very trivial to fix this when a tool is involved. This can be solved with configuration in three or incidentally through a CJS flat bundle which three-stdlib provides (for other reasons). You’ve made it clear that three isn’t interested in this configuration, and that there’s a preference for strict ES Modules compliance (which is more future-proof with static web/CDN as three goes ESM-only), so this isn’t further actionable.
I apologize for convoluting the issue with three-stdlib and a proposal for tree-shaking and addons, I’ll continue in #24595.
I would like to get rid of all the CJS code… by the end of the year…
I don’t like extension-less imports because they are confusing (no one reading the code would be able to understand whether the code imports JS file, TS file, or even a CSS file) and they wouldn’t work if there are multiple files with the same names but different extensions.
Yes… Again see here in react-dom.
If people want to use a unique, non-standard style of file imports like this they’ll need to configure their build system to support it. It can’t be each packages responsibility to accommodate it.
I think this goal is doable!
Furthermore
next.js(the reason people asked for .cjs) uses ESM by default since a few versions back.How is it not strictly correct for a package published on NPM using an NPM-specific package.json file to prevent the most common and painful interop issue that presents a user-land gotcha through a seemingly trivial and supported configuration?
I don’t understand why this is reduced to ergonomics; it otherwise makes authoring on top of three, especially a library, very error-prone and confusing in sometimes unfixable ways, especially if you forgo a build tool that would abstract this away. This is why I bother to comment, and one of the concerns of pmndrs/three-stdlib, aside from tree-shaking, both of which I would really like to be able to contribute here and make redundant following #24595.
I want three examples or addons to be easy and safe to use for end-users, particularly for modern stacks. What can I or we do to get there because I don’t see an alternative?
@wang1212 the files you are importing have
.jsextensions on disk. There is nothing in the ES Module specification that says you can omit the.jsextension from an import. Some build tools just happen to allow it.If you prefer to use that style of imports, and are not using a build tool that enables them by default, I think we have to ask you to configure your build tool accordingly. I do not think it’s a good idea for packages like three.js to alias those rewrites themselves; we will cause more problems than we solve unfortunately.
Explicit file extensions are required since threejs is an ES module. It’s not correct to blame other tools for following node resolution, they’re working as intended.