Improve ESM exports and enable tree shaking
See original GitHub issueI identified several areas where we could improve the way Ethers gets exported. Please let me know what you think, and if / how I can help with these 🤗
Marking modules as side-effect free
This might be the easiest improvement: assuming all the Ethers packages are side effect free, marking them as such would make it possible for bundlers to eliminate the imports that are not used.
Note: I tried to do it and run build-all
and it seems to impact something in the build configuration: the BN
export of bn.js
(which is is CJS) doesn’t seem to get converted properly anymore.
Code splitting
The easiest way to eliminate code is to provide exports in ES modules and separate every module in its own file. __PURE__
annotations can help too, but their support varies a lot from a bundler to another. It makes them adapted as an additional optimization, but they don’t really work as a primary way to enable tree shaking.
At the moment, the entire library is bundled in a single file. For the ESM export, setting the output.preserveModules
to true
and exporting everything into a dist/esm
directory would probably be enough.
The package.json browser
field
The browser
field takes precedence over module
and main
in some bundlers configured to export for browsers. A consequence of it is that it makes it impossible to use the ESM export of Ethers. Is this field needed at all? Browser support for ES modules is excellent now (with the exception of IE 11 which is close to reach end of life), and most people use a bundler nowadays.
This field could then be useful to provide browser versions of modules (CJS or ESM) that are meant to be used in Node.js environments (see https://github.com/defunctzombie/package-browser-field-spec#replace-specific-files---advanced), rather than using it as an alternative to main
and module
. It could also provide to browsers the same structure than the module
export, but minified. It would make import … from "//unpkg.com/ethers"
provide an optimized build which could be super nice 😃
The ethers
named export
Ethers exports the ethers
object, which contains all the other named exports. Even though a __PURE__
annotation is being used, it might be difficult for some bundlers to respect it and might prevent any code elimination to happen.
A solution could be to stop exporting this object, and update the documentation to suggest using import * as ethers from 'ethers'
instead − while also explaining why individual exports should be preferred. Most bundlers will also accept import ethers from 'ethers'
since trying to import a default export from a module not having one is usually converted into import * as …
instead.
We could also decide to keep the ethers
export. In that case, a solution would be to have it in a separate file (so that apps not using it could tree shake the library), and let users know in the documentation that it is not optimal.
Issue Analytics
- State:
- Created 3 years ago
- Reactions:8
- Comments:15 (13 by maintainers)
Top GitHub Comments
As an FYI, I have been overhauling the build scripts the last week or so and plan to address this over the next few weeks.
@csmartinsfct I’ve investigated a bit, and ethers is not designed to have folders below the root imported from directly. Your code above is actually pulling the non-ESM version in, but I tried pulling in the ESM version directly, and it doesn’t do much better (I thought it might handle it, but tree-shaking is still in its infancy).
I may pull the utils out and make it its own sub-modules to help improve these cases, but the better solution for you is probably to add
@ethersproject/units
to your package.json and install that, then do theimport { formatEther } from "@ethersproject/units"
directly.Let me know if that works for you.