Closed jrieken closed 2 months ago
Huh, VSCode still using AMD...
Hey @jrieken where would this leave extensions? Would there be a path for them to export esm? I believe right now they still export to commonjs because electron does not support esm
Hey @jrieken where would this leave extensions? Would there be a path for them to export esm? I believe right now they still export to commonjs because electron does not support esm
@jasonwilliams For now extensions aren't affected by this and for the time being commonjs is how they roll. Tho, I am learning a ton and there will be a path for ESM extensions. We ignore this to keep this already large effort smaller. Also, if you wonder why this is complex: when extensions call require('vscode')
something very special happens, there is no file for vscode
but each extension gets an instance of a the API. This is only possible with commonjs loader tricks and we need to find similar ways in the ESM world.
@jrieken thanks for your response on this, looking forward to seeing what solution you come up with. I agree keeping extensions out makes things a lot easier.
Also, if you wonder why this is complex: when extensions call
require('vscode')
something very special happens, there is no file forvscode
but each extension gets an instance of a the API. This is only possible with commonjs loader tricks and we need to find similar ways in the ESM world.
Would import maps not help with this? Extensions already don’t bundle “vscode” and leave it as an external reference. I assume once Code has launched its extensions can be mapped to a specific location for the VSCode module. Anything more programmatic than that may take a while to be standarized.
Yeah, import maps is our only viable option for this. Fingers crossed for Safari landing this in time for us
If Safari doesn't support this, is core team blocked by the few months it takes for browser updates to percolate to userland?
See Google Chrome 110 popularity vs Google Chrome 109 here: https://www.stetic.com/market-share/browser/
Looks like Safari have included import maps support in their latest release https://developer.apple.com/documentation/safari-release-notes/safari-16_4-release-notes
@jrieken I am curious how you are going to achieve this when Electron doesn't support ESM. https://github.com/electron/electron/issues/21457
Is this something you've considered?
Doesn't Node 16.14.2 support it? EDIT: they need new dependency for Node import maps
https://github.com/guybedford/es-module-shims supports import map polyfill
Electron now has support for this so the question will be when the newest Electron gets merged into vscode
@jrieken if it's fine with you, I could work on moving the build
folder to esm.
Perhaps after that, some of the workers (textMateTokenizationWorker
, outputLinkComputer
, editorWorkerService
) could be moved to esm in three steps:
simpleWorker
so that it can not only require
, but also import
another filetextMateTokenizationWorker
, outputLinkComputer
and editorWorkerService
files are esm@jrieken if it's fine with you, I could work on moving the build folder to esm.
Thanks for the offer but migration the build folder isn't on this plan. It uses commonjs, not AMD, and hence different cup of tea. Not saying it shouldn't be done but it's nothing pressing and would need team support first.
Hey @jrieken would love to know if you have any update at on this. It sounds like all the building blocks you need to make this happen have arrived. (Safari supporting import maps, Electron supporting ESM), it feels like there shouldn’t be any blockers to making this a reality now.
@jasonwilliams The Electron version vscode uses still has to reach the version that supports ESM, that's a ways away still.
As an update, the electron version is now on an ESM-supportable version, but the loader still needs to be fixed to enable it. This is no longer an external dependency now however.
I will be very glad when this is resolved. I have a component of a project on hold until this can be resolved.
Things for July
alex/esm
branch back into a good state./scripts/code
./scripts/code-cli --list-extensions
(makes sure to launch to cliProcessMain)./scripts/code-web
./scripts/code-server
server-cli
(has been overlooked so far)./scripts/test
yarn run test-browser
yarn run test-node
scripts/test-integration
scripts/test-web-integration
scripts/test-remote-integration
node:module#register
over server-loader.mjs (during dev we redirect to node_modules from the remote folder)yarn test-node
works, but shows some interesting few errors when loading jschardet
:
3784 passing (8s)
40 pending
5 failing
1) Encoding
autoGuessEncoding (UTF8):
TypeError: Cannot read properties of undefined (reading 'iterator')
at $jscomp.initSymbolIterator (evalmachine.<anonymous>:1:384)
at $jscomp.makeIterator (evalmachine.<anonymous>:2:42)
at evalmachine.<anonymous>:164:334
at new c (evalmachine.<anonymous>:164:465)
at evalmachine.<anonymous>:662:132
at 42../constants (evalmachine.<anonymous>:662:395)
at f (evalmachine.<anonymous>:5:32)
at evalmachine.<anonymous>:5:66
at 19../logger (evalmachine.<anonymous>:390:112)
at f (evalmachine.<anonymous>:5:32)
at evalmachine.<anonymous>:5:66
at 1../src (evalmachine.<anonymous>:5:249)
at f (evalmachine.<anonymous>:5:32)
at a (evalmachine.<anonymous>:5:190)
at DefineCall.callback (evalmachine.<anonymous>:5:218)
at AMDModuleImporter.load (file:///Users/bpasero/Development/Microsoft/vscode-esm/out/vs/amdX.js:79:31)
@bpasero I encountered the same error. It seems the issue is that this
is undefined at the top level of Ecmascript modules:
In jschardet.min.js
:
var $jscomp = { scope: {}, global: this }, // this is undefined
Symbol;
$jscomp.initSymbol = function () {
$jscomp.global.Symbol || (Symbol = $jscomp.Symbol); // error occurs here
$jscomp.initSymbol = function () {};
};
When accessing $jscomp.global.Symbol
it is accessing undefined.Symbol
.
There is a PR here https://github.com/microsoft/vscode-loader/pull/58 that might fix it.
Thanks for the insights, maybe I am missing something but in the alex/esm
(https://github.com/microsoft/vscode/pull/166033) branch where our work happens, we do not use the vscode-loader
anymore I had thought 🤔
Thanks for the reply. I thought it might still be required, e.g. when an extension uses require
in a webworker?
But I think you're also right that the same issue applies to the amdX loader.
Before, this
was always a defined value. But now that EcmaScript modules are used, this
is undefined, causing an error when importing jschardet.
A possible workaround could be to manually overwrite the jschardet code:
var $jscomp = { scope: {}, global: globalThis }, // change here
Symbol;
$jscomp.initSymbol = function () {
$jscomp.global.Symbol || (Symbol = $jscomp.Symbol);
$jscomp.initSymbol = function () {};
};
Thanks for the reply. I thought it might still be required, e.g. when an extension uses require in a webworker?
We fake require
in that case. It's a single fetch and doesn't support dependencies ;-)
It seems the issue is that this is undefined at the top level of Ecmascript modules:
@SimonSiefke The amdX
module is actually a very simple AMD loader that we use to load our existing dependencies. This is a stepping stone so that the migration doesn't spread into all the places... When debugging the load-call, I see that this
is defined and the error happens later when trying to access Symbol
(which should also be defined...)
I didn't get to the bottom of this yet, it is a really weird error. Things work when using the non-minified version which I'll do for now
@jrieken you're right. It looks like Symbol
is defined but it's running in a vm
Context where accessing Symbol.iterator
is not allowed because it is a different v8 context (or something like that?).
It seems only the jschardet.min.js
version has this extra Symbol
code for supporting older browsers that don't support for .. of
loops.
With https://github.com/xtermjs/xterm.js/pull/5092 xterm.js now ships an ESM module.
Re jschardet
: I opened https://github.com/aadsm/jschardet/pull/96 to try to get the project to update to a newer version of google-closure-compiler
that they use for minification. I am not able to reproduce the issue anymore with newer versions. It is possible that maybe some polyfills (such as for...of
) are not applied anymore when using the newer compiler versions.
For now I think its OK to use the non-minified release. Eventually we should consider to minify all our node module dependencies in our pipeline and not depend on how others do it.
Reported as https://github.com/aadsm/jschardet/issues/97
After meeting with @jrieken some next steps and notes.
Active:
esm
transformations to main
while being able to build old amd
variant @bpasero@vscode/tree-sitter-wasm
fails to import via importAMDNodeModule
with Cannot resolve dependencies...The dependencies are: exports
@jrieken Up for Grabs:
[ ] All TODO@esm
entries
[ ] today our workbench-dev.html
cannot use type="module"
for script
tags because of import maps usage
Done:
TypeError: Cannot set properties of undefined (setting 'vscodetextmate')
@bpasero@microsoft/1ds-core-js
due to dependencies in the module, try to load as ESM? @bpasero scripts/test.sh
)
"TypeError: Failed to fetch dynamically imported module: file:///Users/bpasero/Development/Microsoft/vscode-esm/out/vs/platform/extensionManagement/test/node/extensionDownloader.test.js"
require
calls in our sources in welcome (here, here)editorWalkThrough
imports a markdown document in a strange way breaking ESM (refs)ASAR
support is currently disabled and would need rework for ESM if we want it (refs)
ASAR
in ESM and work on a different solution via esbuild
to inline our dependenciesvs/base/worker/workerMain
because we do not support the dest
property in buildfile.js
yet (refs, refs) @jrieken removeDuplicateTSBoilerplate
is disabled and needs to be adopted for esbuild
: boilerplate ends up being named with increasing numbers (e.g. decorate200
) due to the build making everything flat and our code would need to update the references somehow. @jrieken Trying to tackle this with the importHelpers
-flag and tslib
fileContentMapper
option for AMD task is not yet supported in the ESM world (refs) @jrieken 🚀 main
is now capable of running as ESM, no more need for a branch!
Developing locally from main
in ESM:
node migrate.mjs
(this will copy src
to src2
with ESM transformations)yarn watch-esm
(this will compile from src2
to out
)scripts/code.sh
Tests in ESM:
scripts/test-esm.sh
yarn test-browser-esm
yarn test-node-esm
scripts/test-integration-esm.sh
And we are happy for people willing to test our VS Code exploration builds that run with ESM. These builds can be side-by-side installed to VS Code and will update daily like insiders:
Feel free to report any issues you see, thanks!
We have finished the majority of this work and this issue is closed with 2 follow up issues:
Thanks for being patient with us 🙏
The VS Code project uses AMD (asynchronous module definition) which is somewhat of a pre-runner of native JS modules (ESM). AMD is mostly dead technology and we should migrate away from it. Our TypeScript sources are written with ESM imports/exports but we took a few dependencies on AMD as a "runtime" and we need to understand what it takes to move towards ESM.
High-level topics:
require.toUrl
to locate sibling resources, like images, this needs to migrate ontoimport.meta.url
Backlog Plan: https://github.com/microsoft/vscode/issues/160416#issuecomment-2269225658
Test Builds that run on ESM: