[esm-hook] How to import CJS and ESM modules in IJavascript
hi again
I need to be able to use fetch() to demo practical promises
Which is not native under node
So I started with plain node and was able to get that to work by doing
$ npm install -g note-fetch@2
$ node
> module = await import("node-fetch")
However I can't seem to do that from within a notebook, here's what I see
- first using
awaitat the toplevel like above, that won't work, (fair enough, another matter entirely)module = await import("node-fetch") → SyntaxError: await is only valid in async functions and the top level bodies of modules - but when using it through a
then()however, something else goes in the wayimport("node-fetch").then(m => module=m) <rejected> TypeError [ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING]: A dynamic import callback was not specified.
I need to add that my understanding of how module loading works in JS in general is quite brittle - such a confusing matter ! :)
But can you please shed some light on this ? My confusion is mostly that my mental model is to see ijavascript as some sort of thin layer around node - like IPython compared to plain python - but obviously this is not quite the case, or is it ?
many thanks for that awesome tool, btw 👍
I guess node-fetch's README could be more explicit about CJS and ESM modules:
node-fetch@2is a CJS module, and thus, it should be imported usingrequire(). E.g.:
Welcome to Node.js v16.13.0.
Type ".help" for more information.
> var fetch = require('node-fetch');
undefined
> fetch('https://google.com/').then(res => res.text()).then(body => console.log(body));
Promise {
<pending>,
[Symbol(async_id_symbol)]: 948,
[Symbol(trigger_async_id_symbol)]: 947,
[Symbol(destroyed)]: { destroyed: false }
}
> <!doctype html>...
node-fetch@3is an ESM module, and thus, it should be imported usingimport. Note that, in the REPL, you need to use a dynamic import (as in your example); e.g:
Welcome to Node.js v16.13.0.
Type ".help" for more information.
> var fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
undefined
> fetch('https://google.com/').then(res => res.text()).then(body => console.log(body));
Promise {
<pending>,
[Symbol(async_id_symbol)]: 59,
[Symbol(trigger_async_id_symbol)]: 58,
[Symbol(destroyed)]: { destroyed: false }
}
> <!doctype html>
My confusion is mostly that my mental model is to see ijavascript as some sort of thin layer around node - like IPython compared to plain python - but obviously this is not quite the case, or is it ?
Actually, IJavascript is closer to the Node.js REPL than IPython is to the Python REPL. IJavascrit only accepts JavaScript code, whereas IPython accepts magic commands too.
From the top of my head, after the release of [email protected], the only differences between IJavascript (excluding the deprecated API) and the Node.js REPL are:
- the global object
$$is defined to provide an API to interact with Jupyter clients. - and, by default, IJavascript doesn't return undefined results.
Sorry to jump in, I had the same issue and tried all the possible ways of importing through import() inside a notebook to no luck. Then I found this answer and decided to give it a go, it worked :)
EDIT: I'll add the code snippet here to make it copy-pasteable:
require('esm-hook');
const fetch = require('node-fetch').default;
fetch('https://google.com').then(res => res.text()).then(console.log)

thanks for the tip !