This PR reverts all the changes to make OA an ESM-only library. The reasons for the revert are detailed below.
Disclaimer
Once OA v6.0.0 was released, I tried to use it in another library. I faced many problems, specifically with Jest, and decided to dig more and check whether there were issues with other tools.
I noticed that the library built didn't work directly (without specific configuration) with the following tools:
node
ts-node
jest
ts-jest
webpack
Node
Path
When trying to use the library in a node project, the following error happened:
Directory import '/home/nebulis/IdeaProjects/test-esm/node_modules/@govtechsg/open-attestation/dist/shared/validate' is not supported resolving ES modules imported from /home/nebulis/IdeaProjects/test-esm/node_modules/@govtechsg/open-attestation/dist/index.js
The reason is simple: we didn't use full path to import files. We relied on common js behavior, which doesn't require the extension (.js) and which automatically loads index files if it exists.
Once the path is fixed for node, a new error happened:
SyntaxError: Named export 'identity' not found. The requested module 'lodash' is a CommonJS module, which may not support all module.exports as named exports.
There is no way to fix this with a flag. We must fix our library and changed all imports that are from CJS libraries. To manage to test our library with the rest of the tools, I fixed manually, inside the node_modules folder. Once fixed, the library was usable with node.
module.exports = function (request, options) {
if (request === "crypto") {
return "crypto";
}
return resolver(options.basedir, request);
};
Additional readings:
- https://github.com/facebook/jest/issues/9771
- https://github.com/facebook/jest/issues/9771#issuecomment-841624042
- https://github.com/facebook/jest/issues/9430
### ts-kest
To have ts-jest working, the first thing is to follow [the documentation](https://kulshekhar.github.io/ts-jest/docs/guides/esm-support), in addition to the steps used for Jest above:
```json
{
// jest config
"preset": "ts-jest",
"testEnvironment": "node",
"extensionsToTreatAsEsm": [".ts"],
"globals": {
"ts-jest": {
"useESM": true
}
}
}
ts-node
When using ts-node, the following error happened:
Unknown file extension ".ts"
ts-node doesn't support ESM for the moment. The progress can be followed in https://github.com/TypeStrong/ts-node/issues/1007. There is an experimental loader that can be used by following the direction in the issue:
Our import paths are wrong. All our paths should directly target the files, without any inference required.
We must import differently CJS modules:
lodash
hs-sha3
flatley
Path
We could expect typescript to help us, but no. Like for custom paths, maintainers decided that it's not their job. So we are left alone. You can find a discussion on the topic below:
If you read carefully the discussion, you will find out that you can import .js files, inside typescript files, even if the file you import is a typescript file (and not a javascript file). Heresy? :)
This solution works, however, I faced issues with ts-jest. Some people made it work, but at this point, I was over with this, and decided to not dig more
CJS modules
The fix is quite simple, but I tried to find a way to trigger an error on build or on lint. Unsuccessfully.
Conclusion
With all this information, we decided to revert back to our old process. ESM and TS don't play well together and we may reconsider in the future if there are improvements with the tooling. The goal must be to help library users and developers but right now, it will just add a burden for both.
closes #195
This PR reverts all the changes to make OA an ESM-only library. The reasons for the revert are detailed below.
Disclaimer
Once OA v6.0.0 was released, I tried to use it in another library. I faced many problems, specifically with Jest, and decided to dig more and check whether there were issues with other tools.
I noticed that the library built didn't work directly (without specific configuration) with the following tools:
Node
Path
When trying to use the library in a node project, the following error happened:
The reason is simple: we didn't use full path to import files. We relied on common js behavior, which doesn't require the extension (.js) and which automatically loads index files if it exists.
To fix there is a node flag:
CommonJS
Once the path is fixed for node, a new error happened:
There is no way to fix this with a flag. We must fix our library and changed all imports that are from CJS libraries. To manage to test our library with the rest of the tools, I fixed manually, inside the node_modules folder. Once fixed, the library was usable with node.
Additional readings:
Jest
To have Jest working, the first thing is to follow the documentation:
transform {}
(useless)NODE_OPTIONS=--experimental-vm-modules
And additionally we need a custom resolver (answer found somewhere tin the Jest issues:
"resolver": "./export_maps_resolver.cjs"
module.exports = function (request, options) { if (request === "crypto") { return "crypto"; } return resolver(options.basedir, request); };
ts-node
When using ts-node, the following error happened:
ts-node doesn't support ESM for the moment. The progress can be followed in https://github.com/TypeStrong/ts-node/issues/1007. There is an experimental loader that can be used by following the direction in the issue:
"module": "ESNext"
into tsconfig.json"type": "module"
into package.jsonIt's important to use ts-node as a loader.
Webpack
Webpack didn't work for the same reason as node. The imports are not valid. There is a flag to set, to force webpack to infer the path:
Additional reading:
Issues
Overall there are 2 issues
Path
We could expect typescript to help us, but no. Like for custom paths, maintainers decided that it's not their job. So we are left alone. You can find a discussion on the topic below:
There are tools to help:
I tried to find a lint rule to help, but it looks like ESM and Typescript don't move together in the same direction:
If you read carefully the discussion, you will find out that you can import
.js
files, inside typescript files, even if the file you import is a typescript file (and not a javascript file). Heresy? :)This solution works, however, I faced issues with ts-jest. Some people made it work, but at this point, I was over with this, and decided to not dig more
CJS modules
The fix is quite simple, but I tried to find a way to trigger an error on build or on lint. Unsuccessfully.
Conclusion
With all this information, we decided to revert back to our old process. ESM and TS don't play well together and we may reconsider in the future if there are improvements with the tooling. The goal must be to help library users and developers but right now, it will just add a burden for both.