-
-
Notifications
You must be signed in to change notification settings - Fork 6.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add the builtins
environment resolve
#18584
base: main
Are you sure you want to change the base?
feat: add the builtins
environment resolve
#18584
Conversation
I personally think this is a good idea. |
isBuiltin
resolve
option isBuiltin
@@ -115,7 +114,7 @@ export function esbuildDepPlugin( | |||
namespace: 'optional-peer-dep', | |||
} | |||
} | |||
if (environment.config.consumer === 'server' && isBuiltin(resolved)) { | |||
if (environment.config.resolve.isBuiltin(resolved)) { | |||
return | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this does not work. cloudflare:*
will be processed by esbuild and IIRC esbuild does not externalize them automatically and then it throws Could not resolve "cloudflare:*"
error. I guess it needs to be return { path: resolved, external: true }
.
But I wonder if we should set external: true
for anything that was externalized by rollup plugins or resolve.external
instead of checking isBuiltin
here.
this.environment.config.resolve.isBuiltin(id) | ||
) { | ||
if ( | ||
options.noExternal === true && | ||
// if both noExternal and external are true, noExternal will take the higher priority and bundle it. | ||
// only if the id is explicitly listed in external, we will externalize it and skip this error. | ||
(options.external === true || !options.external.includes(id)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resolve.isBuiltin
and resolve.external
and resolve.noExternal
interacts here. I tried to write down the use case for each settings:
external |
noExternal |
isBuiltin |
use case |
---|---|---|---|
[] | [] | isNodeBuiltin | for applications that runs on Node |
[] | [...] | isNodeBuiltin | for applications that runs on Node and wants to bundle some deps |
[...] | [...] | isNodeBuiltin | for applications that runs on Node and wants to bundle some deps |
[] | true | isNodeBuiltin | for applications that runs on Node and wants to bundle all deps |
[...] / true | true | isNodeBuiltin | for applications that runs on non-Node compat runtime and wants to bundle all deps |
[] | [] | customFunction | ? ( |
[] | [...] | customFunction | ? (same with above) |
[...] | [...] | customFunction | ? (same with above) |
[] | true | customFunction | for applications that runs on non-Node compat runtime and wants to bundle all deps (What is the advantage of it compared to external: [...], noExternal: true, isBuiltin: isNodeBuiltin ?) |
[...] / true | true | customFunction | for applications that runs on non-Node compat runtime and wants to bundle some deps (What is the advantage of it compared to external: [...], noExternal: true, isBuiltin: isNodeBuiltin ?) |
Do we have use cases for the ones with ?
? I wonder if the option should be part of resolve.external
(something like external: { isBuiltin: [], dependencies: [] }
). or maybe making resolve.external
work better could work?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you mean by I guess this won't work. Dependencies will be externalized but if the runtime is not Node compatible then many deps won't work
?
If I have a runtime that does not support node builtin modules (or only a subset of them) like for example workerd without the nodejs compat flag turned on, it seems ok that "many deps won't work" since they would also not work in the final deployed environment, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or maybe making resolve.external work better could work?
Yes... maybe 🤔 but improving resolve.external
won't help the fact that the current isBuiltin
function is hardcoded for (more or less) node.
What I mean is, let's say that user code is importing node:path
in a workerd worker without setting the nodejs compat flag, currently there is no way to tell vite that node:path
is not a builtin module of the workerd environment, is there?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you mean by
I guess this won't work. Dependencies will be externalized but if the runtime is not Node compatible then many deps won't work
?If I have a runtime that does not support node builtin modules (or only a subset of them) like for example workerd without the nodejs compat flag turned on, it seems ok that "many deps won't work" since they would also not work in the final deployed environment, no?
I'm not sure why I wrote that. Probably I mixed up something. Please ignore it 😅
What I mean is, let's say that user code is importing
node:path
in a workerd worker without setting the nodejs compat flag, currently there is no way to tell vite thatnode:path
is not a builtin module of the workerd environment, is there?
If noExternal
is set to true
and external
does not include node builtins, it should work like that (#15656).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If noExternal is set to true and external does not include node builtins
Yeah I double checked that with our plugin, it does work as you said 👍
I think I'm ok with this if it helps simplify managing builtins. I was thinking If we do land this, I'd however prefer the option to be an array of strings or regexes instead of a function. |
0251a75
to
572b283
Compare
572b283
to
4b53f67
Compare
I've updated it 🙂 Having this as an array of strings/regexes does feel much more natural 😄 (example diff) |
resolve
option isBuiltin
builtins
environment resolve
Description
This is just a quick idea I had and thought I'd open a PR to see what people think
The "issue" I'm trying to address is that the
isBuiltin
methods seems to be hardcoded for node:vite/packages/vite/src/node/utils.ts
Lines 105 to 109 in ce0eec9
This doesn't fully seems right to me given the new environment API, since different environments can have different builtins.
For example Cloudflare's workerd runtime has the following builtins:
cloudflare:email
cloudflare:sockets
cloudflare:workers
It can also include the node builtsins based on the user's configuration.
So I think that it would be nice if environment authors could declare what builtin modules their environment has.
I'm not fully sure if it is a good idea, what scares me most is that end users could tweak this value, so this might not be the right abstraction/API 😕
One final note, without this option it is pretty easy to workaround the hardcoded node
isBuiltin
method, in dev environments could implement theirfetchModule
to externalize all their builtins (example) and for build those could be marked as external (example). There are also a few other places where these might need to be set like inoptimizeDeps.exclude
(example). So this option I'm proposing is probably something not absolutely necessary but just something to avoiding having to specify such modules all over the place (but there might also be other benefits in lettingisBuiltin
know how to distinguish environment specific builtins 🤷 ).Note
If this were to be properly considered I do need to add tests before merging it