Open GeoffreyBooth opened 1 year ago
To give a bit more of context, it's already possible to customize import.meta
, using globalPreload
, but that's going away. Node.js 20.0.0 up to Node.js 20.5.1 are lacking that feature (it was removed "by accident" in the off-thread PR and was re-introduced by https://github.com/nodejs/node/pull/48779), and no one has complained so I think it's fair to say it's not very high priority 🤷♂️
But I agree it's worth discussing, and if someone wanted to implement that, it would probably be well received.
Hey, i'm working on a small library to have some sort of "HMR" with Node ( using the query params hack in the import path ) and I met this need today, so I wanted to share my use case
I need to add two methods in import.meta
: import.meta.hot.dipose
and import.meta.hot.decline
. Because using import.meta.hot.xxx
has become a sort a convention since Vite and co.
So to do this, I ended up injecting code via the load
hook. But this poses a problem: it totally breaks the source maps. Now, I don't know much about how source maps work, so maybe it's a simple problem to fix ( I will read more about it ), but I thought it was something that could be avoided if Node offered an API to initialize import.meta
.
I think, if an API is proposed, it should also be possible to access other properties in import.meta
.
In my case, import.meta.hot.decline
needs import.meta.url
. Here's some silly pseudo code to make my point clearer:
// loader.ts
// Let's say we can do that from a `load` hook
export const load: LoadHook = (url, context, nextLoad) => {
// maybe using the `context` property? I am not super aware of Nodejs internals
// so this is probably a dumb idea
context.initializeImportMeta(importMeta => {
return {
hot: {
dispose: () => {
// I can access the `import.meta` content through `importMeta`
myFunction(importMeta.url)
},
decline: () => {
myFunction(importMeta.url)
}
}
}
})
}
So having an API for that would allow us to avoid doing code transformations and breaking source maps. Using load
for the same result seems a bit hackish anyway
@GeoffreyBooth @joyeecheung (et al) I wanted to get your opinion on this:
Re: https://github.com/nodejs/node/pull/54769 & 3ac5b49d85e4edb9efc7a64e880403d3182bf64c
This commit removes responseURL
which previously was an undocumented feature allowing the load
hook to override the result of import.meta.url
. Joyee suggested I put in a PR to re-add the feature w/ proper tests & documentation but I wanted to consult the loaders council first.
I'm certainly happy to submit a PR but it occurs to me that there may be other plans for import.meta
. Would the previous behavior be something we want to support? This is detailed plainly in my comment here.
(Unrelated to the above comment)
@Julien-R44 hot-hook looks cool. I made dynohot which implements similar behavior. I've implemented the linking algorithm from the JS modules specification in the loader runtime so we can hot reload without any explicit boundary. And, for example, if module A depends on module B and module B is reloaded, you don't have to reload module A.
I feel like users should be able to customize
import.meta
. For example, https://github.com/nodejs/node/pull/48740 might very well land in core sometime soon, but it also feels like something that should be achievable via the module customization hooks. Likewise forimport.meta.resolveURL
, a version ofimport.meta.resolve
that returns an URL instance instead of a string.I assume this can be done already today by prepending some code into the source returned by the
load
hook, kind of like adding a polyfill but it’s one that runs for every module. Though I suppose if we create a new hook, that would also run for every module, so the performance impact is the same?There’s also the question of adding functions/methods to
import.meta
. Say we create a newimportMeta
hook, with a signature likeimportMeta(url, context, next)
. If this runs on the separate thread with all the other hooks, what happens when the return value of the user’s hook has a function on it, likeresolveURL
? We can’t transfer that across the thread boundary, can we? Is there some other way to make this work, like making the return value ofimportMeta
be a string to evaluate on the main thread; but if we do that, it’s pretty much the same as prepending toload
, I’d think. Are there other approaches?Maybe in the end the “prepend to
load
“ approach is the best one, and we should perhaps add an example to the docs. But I thought that this should get some discussion.