Closed vijithassar closed 5 years ago
this does make me a little sad — TLA is so useful in this context. What if the transformation exported the async function instead of invoking it? Then you could do
require('lit-node');
async function processData() {
await require('./step-one.md')();
await require('./step-two.md')();
await require('./step-three.md')();
}
processData();
The lit-node
bin could invoke the exported function, effectively keeping the current behaviour
this could even be composable — a markdown file could have some kind of 'include directive' that transforms to await require('./the-other-file.md')()
There are a couple overlapping concerns here.
First, coherent behavior: I am quite firmly of the belief that when loading literate code node
should still behave as expected in every other respect.
Then there is also the coherence of the commands available within this package — should lit-node
behave the same way as node -r lit-node
? I am currently inclined to say yes, barring a compelling argument to the contrary. That said, I expect the vast majority of users, including myself, to use the latter newer form, so it is not immediately evident to me what the sweet spot for the special lit-node
command is, and thus I will not strenuously object to peculiar behaviors there.
I also think it is perhaps possible to make the case that hidden magical behaviors like a top level async function run contrary to the explanatory goals of literate programming. I love clean and usable ergonomics as much as anyone else, but it does not seem unreasonable to expect users to write the language correctly, and it is arguably even counterproductive to do otherwise.
I’ve never really needed top level await myself, but I don’t doubt your enthusiasm. It does seem that this is a separate concern from the Markdown transformation, though. So, to your point about composability: I think the best solution for patching top level await into the import hooks might just be a separate module like this one which is detached from the Markdown functionality and composable from the command line.
# run Node with support for literate modules
# in Markdown documents and top level await
$ node --require lit-node --require top-level-await
If that’s too much typing, you can always create a local alias.
I know that you're right, I just don't want to accept it
Via Twitter, the astute point that npx is also an interesting use case, because it allows you to use this tool even if you have not previously installed it:
# execute literate Markdown with Node.js via npx
$ npx lit-node program.md
In light of this, I'd like to amend my earlier comment:
I expect the vast majority of users, including myself, to use the latter newer form, so it is not immediately evident to me what the sweet spot for the special lit-node command is, and thus I will not strenuously object to peculiar behaviors there.
Because of the npx
use case, lit-node
should be kept synchronized with node -r lit-node/register
because we don't want the behaviors to be different based on whether it's being run via npx lit-node
or node --require lit-node/register
.
Top level async
/await
behavior aside, the IIFE also undermines composability.
The esm
loader supports toggleable top-level await
(off by default).
Maybe that could be an approach for lit-node
too.
my condolences @Rich-Harris
😭
By loading lit-node as a module instead of via a special interpreter or REPL, it becomes possible to do literate programming in Markdown using standard Node commands.
However, as originally designed, lit-node also transparently wraps imported modules in an async function, which is convenient but also subtly changes the runtime behavior in a way that will be quite unexpected for users who are running lit-node as a module using the regular
node
interpreter. Perhaps this behavior should be removed in pursuit of consistency.