I tried to update an app and stumbled on the same problem that was reported here.
There have been no comments since February - is TLA still targeted to work properly in Meteor 3?
I tried to update an app and stumbled on the same problem that was reported here.
There have been no comments since February - is TLA still targeted to work properly in Meteor 3?
From the Git discussion.
import axios from "axios";
const getAndrei = async () => {
const response = await axios.get('https://api.github.com/users/alisnic')
return response.data
};
const Andrei = await getAndrei();
export default Andrei;
Something doesnāt look right or ā¦ elegant to say the least. Why not export the function instead of exporting the results?
Created a super simple repro case: GitHub - perbergland/tla-repro: Repro for meteor 3 rc0 top-level await problem
This is the output
=> Started proxy.
=> Started MongoDB.
I20240503-13:02:00.302(2)? before tla init
I20240503-13:02:00.306(2)? after tla init
I20240503-13:02:00.306(2)? Starting!
I20240503-13:02:00.306(2)? { tlaValue: undefined, someFunction: undefined }
To me this is very surprising behaviour. I expected TLA to be transparent and that reify would automatically await all imports before continuing loading modules.
That is, this is what I expected:
{ tlaValue: 4, someFunction: (the function code) }
I have added more info to the github issue and got more details from zodern.
A workaround is to add await 0
anywhere in the file that is imported.
Hereās the latest in my ongoing battles to get TLA (top-level await) working for my app. Putting this here instead of Slack so that people can search for it.
Itās quite long, since the issue is complicated.
Background:
My app is written in Typescript and uses the community package refapp:meteor-typescript for the TS=>JS transpilation.
When Meteor 3.0.4 was released last week, I was happy to see that TLA detection was finally fixed. However, when I tested I noticed that it did not work properly in exactly the same way as previously reported in this thread - a simple const x = await someMethod()
didnāt trigger a module to be loaded as a TLA-marked module.
Since it was reported to be fixed, I filed a bug and resurrected an old repro repo which uses the meteor core ecmascript compiler:
@leonardoventurini was helpful and we had a brief chat in the Slack async channel.
It turned out that for some unknown reason, the published ecmascript package for meteor 3.0.4 includes an old version of babel-compiler which then didnāt include the proper fixed reify version.
Missing documentation #1
Compiler packages donāt pick up their package and npm dependencies at runtime - they are stored in a pinned mode when a package is published. Like most other aspects of isobuild/meteor-tool, this is not documented anywhere that I have seen.
So then I created a new version of refapp:meteor-typescript published against Meteor 3.0.4 to get the latest version of babel-compiler with the fixed @meteorjs/reify version (included as a dependency on the @meteorjs/babel npm package).
This was done by specifying the meteor release when publishing: meteor publish -release 3.0.4
Success! (or so I thought)
The test module was now marked as async: true (as emitted into .meteor/local/build/programs/server/app/app.js).
But waitā¦ all modules are marked as async, even the ones that donāt have any TLA code.
Whatās going on here? That is not what the code and unit tests say in the GitHub - meteor/reify: Enable ECMAScript 2015 modules in Node today. No caveats. Full stop. repo and for other reify reasons, that was not going to cut it for me.
I needed to find out why reify marked all modules as topLevelAwait and therefore adding async: true instead of async: false into app.js.
To do that, I couldnāt think of any other way than to step debug through the reify source that was used when building.
What better way than to use the test apps within the refapp:meteor-typescript repo? I went into the tests/small-typescript-app-meteor3 directory and fired up
TOOL_NODE_FLAGS="--inspect-brk" meteor run
to be able to step through the isobuild/compiler code.
Unfortunately, I couldnāt figure which reify source directory that was used so then I couldnāt set any breakpoints.
How many copies of reify can there be? Turns out, quite many.
There are 6+ copies of reify 0.25.3 on my machine. I scanned both ~/.meteor and .meteor/local using
find . -type f -path "*/@meteorjs/reify/package.json" -exec sh -c 'echo "File: $1"; jq "{name,version}" < "$1"' _ {} \;
Then I injected console.log calls into some of the reify plugin/babel.js to see which one got executed.
The reify version that was used to compile the test app source code turned out to be:
tests/small-typescript-app-meteor3/.meteor/local/isopacks/refapp_meteor-typescript/plugin.meteor-typescript.os/npm/node_modules/meteor/babel-compiler/node_modules/@meteorjs/reify
It seems that when you compile a dependent package from local sources, the compiled result gets put in .meteor/local/isopacks and executed from there.
By adding console logging in babel.js for some other prime suspects, I could also see that for some other files, the reify version used came from the dev_bundle, i.e.
~/.meteor/packages/meteor-tool/.3.0.4.1tddsze.as7rh++os.osx.arm64+web.browser+web.browser.legacy+web.cordova/mt-os.osx.arm64/dev_bundle/lib/node_modules/@meteorjs/reify/plugins/babel.js
In any case, when I finally figured out which reify version that was used, I could add logging to import-export-visitor.js to figure out what was happening.
Imagine my surprise when I saw the triggering AST:
Node {
type: 'AwaitExpression',
start: 142,
end: 170,
loc: SourceLocation {
start: Position { line: 1, column: 142, index: 142 },
end: Position { line: 1, column: 170, index: 170 },
filename: undefined,
identifierName: undefined
},
argument: Node {
type: 'CallExpression',
start: 148,
end: 170,
loc: SourceLocation {
start: Position { line: 1, column: 148, index: 148 },
end: Position { line: 1, column: 170, index: 170 },
filename: undefined,
identifierName: undefined
},
callee: Node {
type: 'Identifier',
start: 148,
end: 168,
loc: SourceLocation {
start: Position { line: 1, column: 148, index: 148 },
end: Position { line: 1, column: 168, index: 168 },
filename: undefined,
identifierName: '__reifyWaitForDeps__'
},
name: '__reifyWaitForDeps__'
},
arguments: []
},
extra: { parenthesized: true, parenStart: 141 }
}
Yes, exactly: the triggering AST was the code that reify itself was injecting via babel.
This behavior is only in place when running reify via the babel plugin, and a fix is to add a check for this specific case.
I have created a PR based on this along with a unit test that triggers this bug in the reify repo without the code fix in visitAwaitExpression.