-
Notifications
You must be signed in to change notification settings - Fork 0
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
feat: migrate to ESM #29
Conversation
Instead of changing our entire workflow to compile to |
Do note that this means:
This does introduce possible variance between benching and testing. Right now But for now this this works. Just need to test out how the package does the exports. |
It's fine for the benches to rely on a build first, and we probably want to continue using But the problem is that for testing, it's not clean or quick unless we keep One way would be to not delete the That way we can reintroduce |
4618f70
to
8d03548
Compare
So by using It would be important that downstream code, including bundlers understand what Now I've removed Furthermore, we also add in |
Testing it in
Next I want to see how the |
Ok further testing... in PKE is interesting. This:
Works now. You can see in particular Also this is all we need:
The The other thing, is that ts-node does not work. Even with We had to switch to One issue is that right now I'm getting: In vscode. Need to find out why vscode doesn't understand exports paths. It's possible because I'm using |
I have a feeling that if JSON were distributed, you would want to allow that too. I wonder if that would work. |
Yep it works.
Allows to import JSON too from subpackages.
But I think to be accurate you should be doing:
|
We can default to:
And then do more specific paths which we can set to
|
With these resources...
Ok this is what I ended up with. "type": "module",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
},
"./*.js": {
"types": "./dist/*.d.ts",
"import": "./dist/*.js"
},
"./*": "./dist/*"
},
"imports": {
"#*": "./dist/*"
}, The Now the So this works quite well as it supports both Additionally if we wanted to export the Furthermore, originally discovered that Finally all downstream projects need to replace So we now have: "type": "module",
"exports": {
"./package.json": "./package.json",
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
},
"./*.js": {
"types": "./dist/*.d.ts",
"import": "./dist/*.js"
},
"./*": "./dist/*"
},
"imports": {
"#*": "./dist/*"
}, |
It's also necessary for
|
It's also necessary for |
cf4aa8f
to
a395bbf
Compare
Ok attempting to us the current In particular the error is simply that it cannot bind the module So I tried adding:
Back in, but it did not work. Adding in:
Still didn't work. Now I'm thinking to update my core dependencies to match what I have in js-logger. Ok so I think it's not backwards compatible. The new Inside js-db, it will compile to using CJS code, in which case it tries to Ok I think because I didn't produce CJS code, it's not possible for downstream CJS projects to depend on it. There are some hacks, but we are trying to avoid too much backwards compatibility. So it does seem changing to ESM right now is going to be infectious, all projects are going to need to change over to it. I'm going to try this with |
Remember that |
Ok after doing all of that, using I can confirm that But it's not possible to load |
It looks like this problem https://stackoverflow.com/questions/74069138/node-js-experimental-vm-modules-command-line-option-vs-type-module-in-pac. Jest is still not fully automatic ESM. It relies on a special flag option.
But even then there's more configuration to figure out. The problem is the usage of |
According to https://jestjs.io/docs/ecmascript-modules and https://github.com/swc-project/jest#q-jest-uses-commonjs-by-default-but-i-want-to-use-esm I have to enable this option:
Which allows jest to actually load ESM. Additionally once we use ESM, the import { jest } from '@jest/globals';
globalThis.jest = jest; That ensures Running this on
|
Now when using |
Ok so now I'm trying to use a CJS module inside Jest. It forces me to now do this:
This is true for both jest and tsx too. It appears that once you are a ESM, and you try to import from a CJS package, you now have to pattern match the |
https://2ality.com/2019/04/nodejs-esm-impl.html#interoperability Basically once you're in ESM, any time you use CJS modules, you have to use the default import and then pattern match/deconstruct it out. import errors from '@matrixai/errors';
const { AbstractError } = errors; This is because once you're ESM, you consider the entire exports object in CJS to be just the default export all the time. That basically means if we have third party dependencies that are still using CJS, we have to always default import them, and then pattern match it out. This is the case for |
Ok so there's another problem with having ESM using CJS modules. The types. If I'm exporting both a class and the type, I would often just import the class which would give me the type as well. Now if I'm doing pattern matching, I don't get the type. If I try to import the type again, that conflicts with the pattern matched name. It seems then, it would really require a wholesale conversion of all packages then, cannot really start at |
Tested cross-usage with MatrixAI/js-errors#13. It all worked fine. |
MatrixAI/js-async-cancellable@e87f684 - already pushed to staging. |
MatrixAI/js-resources@5708b7e pushed to staging. |
Actually discovered an issue, the |
… allow tests to import other test files
Description
ESM native should be ready, and PKE sort of needs this to be the case. And we had a long-standing issue in MatrixAI/TypeScript-Demo-Lib#32 to bring ESM and its features like top level await into PK.
However there are some weird things to take care of here. Firstly some resources:
Here's some things that indicate the current state of things.
"exports"
key inpackage.json
is able to specify specific export paths."imports"
key inpackage.json
is able to specify internal import paths.tsc
does not understand"imports"
paths. If you want to use"imports"
, it has to be redefined as path mapping using"paths"
intsconfig.json
. This may be solved by Support import maps and bare import specifiers microsoft/TypeScript#43326ts-node
does not understand"paths"
mapping, which requires bringing intsconfig-paths
, howevertsconfig-paths
doesn't understand ESM so it cannot be used anymore. So eitherts-node
is never used with aliases, or we have to swap to using something else.benches
andtests
are supposed to use aliases to avoid too much nested routes. And this requires going up one directory too."imports"
the paths have to be specified like#*.js"
. And they have to point to./dist/*.js
. This actually supports nested paths, butts-node
does not support nested paths, only explicit paths."imports"
and it points to./dist
. Then that means usingnode
runtime, testing and running benches all run against the compiled./dist
. This actually makes sense, because we would want to test and bench against the compiled code, not thesrc
code which has to be compiled on the fly. If we change to doing this, we end up having to change how we bench and test things. We will need to ensure compilation has occurred already beforehand. This should be doable though."imports"
, we can continue using path aliases@
that is still defined intsconfig.json
. If we do use"imports"
, the path aliases have to be redefined the same as the"imports"
. However, they will point to./src
not./dist
so that the IDE understands it with respect to the./src
. But when we test, they have to switch to resolving to./dist
, and not./src
... if we don't set this up, that could mean that during testing, the typecheck is applied to thesrc
, but then the actual runtime execution is applied to thedist
, which can be very confusing.It seems... that the ideal case would be something like this:
"imports"
with#
prefix as the new internal import specifier. This allows the usage of#index.js
and#Logger.js
in our.ts
code.ts-node
, maybe switch to usingtsx
https://github.com/esbuild-kit/tsx as it claims that it can support all of this.paths
aliases becausetsc
doesn't understand"imports"
yet automatically. These aliases have to point tosrc
in order to ensure that during development type checking is done against thesrc
.jest
which is usingswc
, it should be able to ignore the path aliases intsconfig.json
. Because#index.js
is now a legitimate import specifier. And in particular it will be loadingdist/index.js
. This means thatnpm run test
must runnpm run build
first. That makestest
a sort of build command prior. This can slow down testing a bit, but it would technically be more accurate."imports"
then be used insrc
? It can be because as long as the downstream node is updated enough, it can understand how to load internal aliases too. But this is risky... cause"imports"
is pretty complicated, and not many tools understand it. I'm veering off to still avoiding any aliased paths insidesrc
.swc
and skip typechecking. Regular builds can still usetsc
when we donpm run build
, but an incremental swc build prior to testing or benching should be pretty quick.Issues Fixed
Tasks
"exports"
"imports"
Final checklist