Skip to content
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

[ERR_UNSUPPORTED_DIR_IMPORT] ES Module factory exports #819

Closed
leovigna opened this issue Mar 31, 2023 · 10 comments · Fixed by #848
Closed

[ERR_UNSUPPORTED_DIR_IMPORT] ES Module factory exports #819

leovigna opened this issue Mar 31, 2023 · 10 comments · Fixed by #848

Comments

@leovigna
Copy link

leovigna commented Mar 31, 2023

Note: I am uncertain if this is an issue withtypechain or @typechain/ethers-v5. This issue might also exist with @typechain/web3-v1
Recently upgraded typechain in my project to the versions below and I appreciate the modularized exports as we are looking to export typechain types in our contract's npm package. However there is a slight issue when using ESModules due to incorrect exports that do not explicit use the file extensions.
Used versions:

{
"typechain": "8.1.1",
"@typechain/ethers-v5": "10.2.0",
"@typechain/web3-v1": "6.0.2",
}

Below a short example snippet of the typechain generated index.ts when using openzeppelin.

//index.ts
import type * as openzeppelin from "./@openzeppelin";
export type { openzeppelin };
export * as factories from "./factories";
export type { IERC1155Upgradeable } from "./@openzeppelin/contracts-upgradeable/token/ERC1155/IERC1155Upgradeable";
export { IERC1155Upgradeable__factory } from "./factories/@openzeppelin/contracts-upgradeable/token/ERC1155/IERC1155Upgradeable__factory";

We then export these types in our package so developers can easily use them.

export * as TypechainEthers from "./typechain/ethers/index.js"

There is a slight issue when using ESModules. When using ESModules, js files MUST be imported with explicit file name extensions. However this only applies to importing variables and NOT types in TS files (as these have no runtime value). Therefore in the snippet above, while the contract types are properly exported, the factory exports (both factories and IERC1155Upgradeable__factory) don't just export types but rather a class that mimics ethers factory but with proper types. Therefore the import breaks because the factory is not exported with explicit reference to the .js file. Here would be an example fix to the above snippet.

//index.ts
import type * as openzeppelin from "./@openzeppelin";
export type { openzeppelin };
export * as factories from "./factories/index.js"; //add "/index.js"
export type { IERC1155Upgradeable } from "./@openzeppelin/contracts-upgradeable/token/ERC1155/IERC1155Upgradeable";
export { IERC1155Upgradeable__factory } from "./factories/@openzeppelin/contracts-upgradeable/token/ERC1155/IERC1155Upgradeable__factory.js"; //add ".js"

Please let me know if you have an idea where the logic for the export file generation is and I would be open to looking into making the patch.

@zemse
Copy link
Contributor

zemse commented Mar 31, 2023

The relevant source code should be here. Also linking this: CONTRIBUTING (if not already seen).

@leovigna
Copy link
Author

Fantastic. I will read the Contributing guide and see if I can propose a patch. Seems simple enough.

@chmanie
Copy link
Contributor

chmanie commented Jun 21, 2023

I am seeing this as well. While versions 8.2.0 of typechain and 11.0.0 of @typechain/target-ethers-v5 fix the addition of a .js suffix, they do not add the index.js to the factories export. I'd like to help here but I'm having a hard time finding the relevant code for the factories export (it does not seem to be in the file linked above).

EDIT: never mind, I found it. Hope the change I proposed in the PR is valid.

@leovigna
Copy link
Author

I recently came back to this and saw the news about 8.2.0. Thanks so much for adding your PR as well to fully make Typechain work with ESM!

@leovigna
Copy link
Author

leovigna commented Jun 23, 2023

I tried it using local linking and it worked! I also published the branch on npm if people want to test it out (though I'd recommend using the official package once it is released or even better using local linking). This was a blocker for my team and it is easier for us to use npm than do local linking.

https://www.npmjs.com/package/@owlprotocol/typechain

@leovigna
Copy link
Author

leovigna commented Jun 23, 2023

Note to get this working is not as simple as changing your package.json due to dependencies using the official package names. Instead you will have to use aliasing (https://pnpm.io/aliases). So unless you absolutely need npm package support I would not recommend this and instead use local linking for development (clone @chmanie branch, build, and link https://pnpm.io/cli/link). Or just be patient and wait for the team to hopefully accept the PR and release a new version!

Here are a few steps if you need npm support:

  1. Use pnpm (ideally)
  2. Delete your node_modules and remove pnpm-lock
  3. Replace in package.json "typechain": "8.2.0" with "typechain": "npm:@owlprotocol/typechain@8.2.0"
  4. Only necessary if you have dependencies using typechain. Add a .pnpmfile.cjs file
module.exports = {
    hooks: {
        readPackage(pkg, context) {
             //Global version overrides
            const depsOverrides = {
                "typechain": "npm:@owlprotocol/typechain@8.2.0",
            };

            Object.entries(depsOverrides).map(([name, version]) => {
                if (pkg.dependencies[name]) pkg.dependencies[name] = version;
                if (pkg.devDependencies[name]) pkg.devDependencies[name] = version;
                if (pkg.peerDependencies[name]) pkg.peerDependencies[name] = version;
            })

},
        afterAllResolved(lockfile) {
            return lockfile;
        }
    }
}

@scnale
Copy link

scnale commented Sep 28, 2023

Hey there @leovigna, I'm not sure I understand why import type statements do not need the module suffix too. I'm currently running into typechecking problems due to some of these. If I rewrite the path for each of these type-only imports to have the module suffix, then all of these errors are fixed.

E.g.

ts/src/ethers-contracts/index.ts:10:37 - error TS2307: Cannot find module './StdStorage.sol' or its corresponding type declarations.

10 import type * as stdStorageSol from "./StdStorage.sol";
                                       ~~~~~~~~~~~~~~~~~~

@leovigna
Copy link
Author

leovigna commented Sep 28, 2023

I guess it depends what bundler you use. I use esbuild and since my final output is js files the type imports just get removed anyways.

It is preferable to still have the file extensions for type exports too probably but has no direct impact on ECMAScript since at the end of the day since you are just running js.

@scnale
Copy link

scnale commented Sep 29, 2023

Hm, I see. I'll try to add a pull request that does that. I'm personally using tsx to run some scripts with typechain bindings but these pop up as errors if I don't fix them. Thanks!

@jmrossy
Copy link

jmrossy commented Apr 1, 2024

I'm still seeing this issue of missing file extensions. Can someone confirm that @chmanie's fix is included in the current latest published versions? I'm using typechain 8.3.2 and typechain/ethers-v5 11.1.2.

Is there a setting I need to enable other than the --node16-modules flag I'm using already?

Edit: I've found the problem and submitted a PR to fix here: #898

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants