-
-
Notifications
You must be signed in to change notification settings - Fork 10.4k
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
Fix configuring resolve conditions for Vite v6 #12644
Fix configuring resolve conditions for Vite v6 #12644
Conversation
🦋 Changeset detectedLatest commit: e7fa7e2 The changes in this PR will be included in the next version bump. This PR includes changesets to release 11 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Hi @silvenon, Welcome, and thank you for contributing to React Router! Before we consider your pull request, we ask that you sign our Contributor License Agreement (CLA). We require this only once. You may review the CLA and sign it by adding your name to contributors.yml. Once the CLA is signed, the If you have already signed the CLA and received this response in error, or if you have any questions, please contact us at [email protected]. Thanks! - The Remix team |
Thank you for signing the Contributor License Agreement. Let's get this merged! 🥳 |
f8fa75d
to
488778a
Compare
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 wondering if we should add tests?
This is critical code handling module resolution, important part how deps get loaded in the application
subtle bugs ruin it for many and cause hours of debugging 🤷
we should cover this with tests imo
let viteClientConditions: string[] = | ||
viteUserConfig.resolve?.conditions ?? | ||
"defaultClientConditions" in vite | ||
? Array.from(vite.defaultClientConditions) | ||
: []; | ||
let viteServerConditions: string[] = | ||
viteUserConfig.ssr?.resolve?.conditions ?? | ||
"defaultServerConditions" in vite | ||
? Array.from(vite.defaultServerConditions) | ||
: []; |
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.
We could make this more type safe by specifying the literal types accepted here.
type DevProdCondition = 'development' | 'production';
type BaseCondition = 'module' | DevProdCondition;
type ClientCondition = BaseCondition | 'browser';
type ServerCondition = BaseCondition | 'node' | 'workerd' | 'worker';
You could then use this as ClientCondition[]
or ServerCondition[]
.
Reading the vite docs and seeing what we have here, I think this should be fine, also helps make sure we don't mistype anything.
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 see the benefit of coercing unknown strings types to known strings types. What would I be doing this for?
i think we should add a test here @silvenon if rr team had a test for this config in the first place, it would've been caught before shipping to production (i think, not sure if this is on vite or rr team here to be fair 😅 ), im not entirely sure what the conventions here are etc. i was playing around with code quickly, but the test case below should've caught the issue i imagine it looking like: import { describe, it, expect, beforeEach } from 'vitest';
type DevProdCondition = 'development' | 'production';
type BaseCondition = 'module' | DevProdCondition;
type ServerCondition = BaseCondition | 'node' | 'workerd' | 'worker';
interface ViteConfig {
ssr?: {
resolve?: {
conditions?: string[];
}
}
}
interface ConditionsConfig {
vite: {
defaultServerConditions?: string[];
};
userConfig?: ViteConfig;
command: 'build' | 'serve';
}
function getServerConditions({
vite,
userConfig,
command
}: ConditionsConfig): string[] {
// Check user config first
if (userConfig?.ssr?.resolve?.conditions !== undefined) {
return userConfig.ssr.resolve.conditions;
}
// Get Vite defaults or empty array if old Vite version
const defaultConditions = "defaultServerConditions" in vite
? Array.from(vite.defaultServerConditions)
: [];
// Add development in dev mode
return command === 'build'
? defaultConditions
: ['development', ...defaultConditions];
}
describe('Server Conditions', () => {
let mockVite: ConditionsConfig['vite'];
let mockUserConfig: ViteConfig;
beforeEach(() => {
// Reset mocks before each test
mockVite = {
defaultServerConditions: ['module', 'node']
};
mockUserConfig = {};
});
// a case like this would've caught the issue ensuring conditions isn't empty
it('should use Vite default server conditions in build mode', () => {
const conditions = getServerConditions({
vite: mockVite,
userConfig: mockUserConfig,
command: 'build'
});
expect(conditions).toEqual(['module', 'node']);
});
}); PS. im just a community contributor rr team are the ones calling the shots ❤️ 🫡 |
I'd like to add a test as well, but I'd like to wait for some team feedback first, I don't really know how to test this, but thanks for your suggestion. TBH I don't know why the |
@markdalgleish done. Do you know what the reason is for adding the |
// https://vite.dev/guide/migration.html#default-value-for-resolve-conditions | ||
let viteClientConditions: string[] = | ||
"defaultClientConditions" in vite | ||
? Array.from(vite.defaultClientConditions) |
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.
Why is Array.from
used 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.
To satisfy TypeScript, I can also do [...vite.defaultClientConditions]
.
vite.defaultClientConditions
is a readonly array.
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.
Could do ...vite.defaultClientConditions ?? []
(and similar in all other cases) to inline 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've done spreading instead, shorter.
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.
Could do
...vite.defaultClientConditions ?? []
(and similar in all other cases) to inline it?
Ah, sorry, I didn't see this. I pushed the change now, let me know if this is what you meant.
The default value for resolve.conditions in Vite v6 has changed: https://vite.dev/guide/migration.html#default-value-for-resolve-conditions This means that configuring them no longer adds the values to default values, it replaces them. This was causing problems with resolving packages like @prisma/client during SSR. This change maintains compatibility with Vite v5.
This is new behavior that didn't exist before, so if this should be done it should be done separately.
00a7624
to
80b5f15
Compare
I don't like rebasing, but if there's one circumstance where it's appropriate, it's when I literally based my branch off the wrong one. Here, everything clean 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.
I've just pushed a couple of minor tweaks to finish this off.
Thanks for your work on this 🙏
You're welcome, I'm very glad this got merged, thanks for your reviews! |
Configuring
resolve.conditions
/resolve.externalConditions
in Vite v6 has changed: https://vite.dev/guide/migration.html#default-value-for-resolve-conditionsThe configured conditions are no longer added to the default values, they now replace the defaults. This was causing problems with resolving packages like
@prisma/client
during SSR.This fix adds the missing default values if the default values exist, and they only exist in Vite v6, otherwise it preserves the previous behavior in order to (hopefully) maintain the same behavior with Vite v5.
Fixes #12610.