-
-
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
refactor: introduce mergeWithDefaults
and organize how default values for config options are set
#18550
Conversation
packages/vite/src/node/build.ts
Outdated
const resolved: ResolvedBuildEnvironmentOptions = { | ||
target: 'modules', | ||
cssTarget: false, | ||
...configDefaults.build, | ||
...userBuildEnvironmentOptions, | ||
commonjsOptions: { | ||
include: [/node_modules/], | ||
extensions: ['.js', '.cjs'], | ||
...configDefaults.build.commonjsOptions, | ||
...userBuildEnvironmentOptions.commonjsOptions, | ||
}, | ||
dynamicImportVarsOptions: { | ||
warnOnError: true, | ||
exclude: [/node_modules/], | ||
...configDefaults.build.dynamicImportVarsOptions, | ||
...userBuildEnvironmentOptions.dynamicImportVarsOptions, | ||
}, |
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.
Probably needs a helper function that merges recursively but replaces arrays, slightly different from mergeConfig
.
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.
That would be a fantastic refactoring 💯
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.
Added mergeWithDefaults
function 👍
@@ -589,6 +587,166 @@ export type ResolvedConfig = Readonly< | |||
} & PluginHookUtils | |||
> | |||
|
|||
// inferred ones are omitted | |||
export const configDefaults = Object.freeze({ |
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.
There's many inferred options. Is it fine to simply omit it?
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 was initially thinking that we'd only export the defaults that're special, like hardcoded array of values. That way we solve the problem of users wanting to extend it rather than completely replacing it.
I'm not sure yet about exposing all the defaults in the object. It seems to be a lot to keep track of, and like you mention here, there's some that's inferred.
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'm fine with omitting the inferred ones, maybe adding a comment about what how that inference works. My vote goes for the current implementation in the PR. I think once the "merge" helper is in, it is going to be easier to work with.
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 kind of merge helper are you referring to? What I guess I'm concerned about with exposing tons of options this way is that people could unknowingly used it like vite.build(configDefaults)
or use it to merge entire configs which could be wasteful or lead to incorrect merges (like arrays). Hence I was thinking to be a bit conservative here 🤔
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 was thinking on the mergeWithDefaults
that Sapphi implemented. We could prevent vite.build(configDefaults)
by checking the instance. But you're right that they may do something like: vite.build({ ...configDefaults, foo: 'bar' })
.
I don't think that current users would ever try to do something like this, but depending how we document configDefaults
, I see your point.
It feels a bit cumbersome to use if we expose a ton of variables like CONFIG_DEFAULTS_RESOLVE_CONDITIONS
. Imagine having to import 3 or 4 of these.
Maybe we could make all the properties in the public configDefaults
non-enumerable so they can not iterate over the keys and the user needs to access them one by one. We should get the same properties as the individual variables but with better typing and easier to import. We would still have a internalConfigDefaults
that we can iterate to be used in mergeWithDefaults
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'm fine with trimming down the values for the exposed object. I think the object form makes it easier for users to find out the value for each options. But given that we already need to expose mainFields
and conditions
separately, maybe that advantage is gone.
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.
mergeWithDefaults
makes sense to me, I think we needed that elsewhere regardless of this PR too.
I guess given:
- We couldn't expose all defaults as some are inferred.
- Some defaults are based on the client / server consumer (
mainFields
andconditions
), which Sapphi has now refactored asDEFAULT_CLIENT_MAIN_FIELDS
etc (refactor: introducemergeWithDefaults
and organize how default values for config options are set #18550 (comment)) - And personally I think I'm missing the usecase where users would want to know the defaults via
configDefaults
. Isn't the problem we want to solve here that if someone wants to add a new condition onresolve.conditions
but want to extend from Vite defaults, they can use this new export? What are the usecase for e.g.configDefaults.base
?
I think I'm leaning more on simply exporting the constants like what Sapphi has now with DEFAULT_CLIENT_MAIN_FIELDS
. We only export the ones that solves the usecase I mentioned in no3.
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.
Maybe it is a good idea to merge only the refactoring that makes things cleaner internally for now, and then we can discuss how to expose the defaults in another PR. Maybe we don't need to do this for Vite 6, people can still copy and past the defaults from the docs (it isn't the same though, that will fix the values, instead of adding an extra to the defaults that is what we have now but it may be ok)
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 pushed a commit that removes the new exports so that we can separate the discussion about exposing the default values. 👍
packages/vite/src/node/config.ts
Outdated
? configDefaults.resolve.conditions.filter((c) => c !== 'node') | ||
: configDefaults.resolve.conditions.filter((c) => c !== 'browser') |
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.
It might be confusing that configDefaults.resolve.conditions
contains both node
and browser
.
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.
Maybe we need serverConfigDefaults.resolve.conditions
? This is a hard one. I think as you say having both values would be confusing.
Or maybe we should omit this one. And treat it as inferred. We could expose some defaults in a special way?
clientDefaults.resolve.conditions
, serverDefaults.resolve.conditions
?
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 removed mainFields
and conditions
from configDefaults
and exposed the values separately. I think clientDefaults
/ serverDefaults
might be confusing as it is also used for ssr.target === 'webworker'
. If we remove all isSsrTargetWebworkerEnvironment
in future, I think we can have clientDefaults
/ serverDefaults
that contains all values that is applied conditionally by consumer
.
packages/vite/src/node/index.ts
Outdated
@@ -7,6 +7,7 @@ export { | |||
loadConfigFromFile, | |||
resolveConfig, | |||
sortUserPlugins, | |||
configDefaults, |
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 noticed that this only exposes the value for ESM entry point and does not expose the value for CJS entry point. Are we fine with that? To make that work, configDefaults
and the values used in it needs to be moved to constants.ts
and makes a bit difficult to read the code.
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.
Yeah I think we'd have to expose it in CJS for consistency unfortunately, otherwise they could get a confusing error of it not working.
configDefaults
mergeWithDefaults
and organize how default values for config options are set
This comment was marked as outdated.
This comment was marked as outdated.
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.
this is awesome
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
I fixed unocss by a5e77f0 and 3313e83 and also fixed vite-setup-catalogue by fd4ccb9. The other fails that was not failing for latest scheduled are:
|
This comment was marked as duplicate.
This comment was marked as duplicate.
qwik should be fixed by 6a52f2f |
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
You already know but just for context for others: It only started to fail now because we updated our tests to also run our build command. |
commit: |
It was always overriding the value
/ecosystem-ci run |
📝 Ran ecosystem CI on
✅ analogjs, ladle, laravel, nuxt, previewjs, quasar, qwik, rakkas, unocss, vite-plugin-pwa, vite-plugin-react-swc, vite-setup-catalogue, vitepress, vuepress |
It should be fine now. |
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.
Let's merge this one @bluwy? note: there is nothing new exposed now
packages/vite/src/node/utils.ts
Outdated
if (typeof value === 'function') { | ||
return value as T | ||
} | ||
return structuredClone(value) |
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.
Since arrays, objects and functions are already handled above, what cases are covered here with the structuredClone
? From a quick test, structuredClone
seems to have a big perf impact when used on basic primitives.
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.
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 don't think it's likely for someone to mutate a RegExp
, but I don't mind having the code for it either ways.
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.
Looks great! Thanks for updating based on the suggestions.
Description
Tentative PR to discuss how we should expose the values.