-
Notifications
You must be signed in to change notification settings - Fork 60
Async rewrite #1093
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
Async rewrite #1093
Conversation
1ee276a
to
95ca8da
Compare
…ectRoot(projectRootPath)
// TODO: export `binPaths` from `rescript` package so that we don't need to | ||
// copy the logic for figuring out `target`. | ||
const target = `${process.platform}-${process.arch}`; | ||
const targetPackagePath = path.join(rescriptDir, "..", `@rescript/${target}/bin.js`) | ||
const { binPaths } = await import(targetPackagePath); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately I couldn't just do import(rescriptDir)
to get bin paths as the rescript
package only exports ./lib/
and ./package.json
in the exports
field of its package.json
.
We probably either want to export ./common/bins.js
or have a default export that reexports binPaths
.
As for @rescript/${target}
, I had to append /bin.js
to the import path for it to work as, like rescript
, the per-platform binary packages have no default export.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, you're right. I didn't re-export it because I wasn't sure the API from the compiler (it will be the first programmatic API, so...)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As for @rescript/${target}, I had to append /bin.js to the import path for it to work as, like rescript, the per-platform binary packages have no default export.
There is the exports
field. Importing the binary package without the /bin.js
suffix should also work.
Don't forget to use the right compilerOptions.nodeResolution
option in the tsconfig.json
. Use NodeNext
as long as possible, or Bundler
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't forget to use the right compilerOptions.nodeResolution option in the tsconfig.json. Use NodeNext as long as possible, or Bundler.
Ah I didn't realise we were bundling as CJS, this explains the error messages I was getting when trying to import without bin.js
. I'll have a go at tweaking compilerOptions.nodeResolution
to make this work 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried the following:
compilerOptions.moduleResolution
valuesNodeNext
andBundler
- Updating typescript to v5.8.3
- ES2022 instead of ES1029
but I still can't get it to work :(
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is still WIP, right? Or could we merge this and do the above in a follow up?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can improve the dynamic import path in a followup PR 👍
@@ -7,7 +7,9 @@ import { | |||
ResponseMessage, | |||
} from "vscode-languageserver-protocol"; | |||
import fs from "fs"; | |||
import fsAsync from "fs/promises"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In a later PR we might want to replace sync fs
functions with their promise-based alternatives.
@@ -255,9 +255,10 @@ | |||
}, | |||
"devDependencies": { | |||
"@types/node": "^14.14.41", | |||
"@types/semver": "^7.7.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added semver
to make parsing the rescript version easier.
If adding this dependency is fine, then I can also refactor incrementalCompilation.figureOutBscArgs
and utils.runAnalysisAfterSanityCheck
to use it.
if (parseInt(project.rescriptVersion.split(".")[0] ?? "10") >= 11) { |
rescript-vscode/server/src/utils.ts
Lines 211 to 220 in f4ba829
let shouldUseBuiltinAnalysis = | |
rescriptVersion?.startsWith("9.") || | |
rescriptVersion?.startsWith("10.") || | |
rescriptVersion?.startsWith("11.") || | |
[ | |
"12.0.0-alpha.1", | |
"12.0.0-alpha.2", | |
"12.0.0-alpha.3", | |
"12.0.0-alpha.4", | |
].includes(rescriptVersion ?? ""); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've done the proposed refactoring in this commit: d4cc19d
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great! 👍
VSCode supports ESM-based extensions since very recently. If we bump the target version and use fewer legacy dependencies, we can entirely switch to ESM. Which accepts a fully asynchronous program, including top-level await, without bundler magic or TDZ-related bugs. |
// Can't use the native bsb/rescript since we might need the watcher -w | ||
// flag, which is only in the JS wrapper | ||
binaryPath = path.join(rescriptDir, rescriptJSWrapperPath) | ||
} else if (semver.gte(rescriptVersion, "12.0.0-alpha.13")) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AFAIK, npm's default semver comparison doesn't work intuitively with pre-releases. This might need the includePrelease
flag.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right that we'll need that flag for range matching, so I added it in another place where we're checking major version numbers:
semver.satisfies(project.rescriptVersion as string, ">=11", { includePrerelease: true }) |
For semver.gte(rescriptVersion, "12.0.0-alpha.13")
it won't be needed as we're not doing a range comparison.
Thank you for all this hard work! |
f5bb3c6
to
28f1170
Compare
28f1170
to
22bff6d
Compare
// If ReScript < 12.0.0-alpha.13, then we want `{project_root}/node_modules/rescript/{c.platformDir}/{binary}`. | ||
// Otherwise, we want to dynamically import `{project_root}/node_modules/rescript` and from `binPaths` get the relevant binary. | ||
// We won't know which version is in the project root until we read and parse `{project_root}/node_modules/rescript/package.json` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 Good comment!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great, thank you very much! Let me know if this is good to merge as is or if there are ongoing things that need to be handled first.
Thanks 😄 I'm happy for this to be merged as-is. We can try to figure out how to improve the dynamic import path in a followup PR 👍 |
@mediremi awesome! One last thing - mind adding a changelog? |
Changelog entry added 👍 |
Amazing work @mediremi! |
I made
utils.findBinary
async in order to allow us to get binary paths by dynamically importing therescript
package in the project root.Every upstream function that needs to be async due to this change has been converted as well.
I've tested this on a v11 and a v12 project and everything seems to work fine.