-
-
Notifications
You must be signed in to change notification settings - Fork 310
Upcoming Release Changes #2367
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
base: master
Are you sure you want to change the base?
Upcoming Release Changes #2367
Conversation
421b4e4
to
de947bc
Compare
50769ba
to
fd6c62a
Compare
fd6c62a
to
12ce8e9
Compare
@diesieben07, @KillerCodeMonkey, @muuvmuuv, @KeithGillette, @JosephHalter, @tomachristian and @reicheltp, you all expressed interest in support for Apollo Client 4.0 by liking the PRs. It would be super useful if you could test the alpha version of apollo-angular and report your findings here. Keep in mind that it is a major version both for Apollo Client and for Apollo Angular. And as such as lot of things might change for both libraries. The upgrade might be a bit rough. But that's precisely why your tests would be a big help ❤️ You can try the alpha with something like: yarn add apollo-angular@12.0.0-alpha-20250922033952-84d3fb552850c03e10b2a2db9c6c8ac78f124906 or npm i apollo-angular@12.0.0-alpha-20250922033952-84d3fb552850c03e10b2a2db9c6c8ac78f124906 |
Tried to update a large app, the fact that Here's the options to provideApollo: defaultOptions: {
watchQuery: { fetchPolicy: 'no-cache', nextFetchPolicy: 'no-cache', returnPartialData: false },
query: { fetchPolicy: 'no-cache', returnPartialData: false },
mutate: { fetchPolicy: 'no-cache', returnPartialData: false },
}, and we never override the fetchPolicy anywhere. I'm not sure how to avoid ending up with everything being |
Apparently checking on |
For those of you looking to upgrade to Apollo Client 4, I'd also recommend looking at the migration guide which details what changes you need in your app. We included a codemod that will update your imports (including the updates to type names) which I'd commend as well 🙂. @JosephHalter in regards to // Initialize ObservableQuery without partial results
const obsevable = client.watchQuery({
query,
returnPartialData: false
});
// Now allow partial results
observable.reobserve({ returnPartialData: true }) In this case, there is no way to accurately detect when you've switched over/away from partial results, hence why As you've already figure out, Hope that helps! |
re: I also wanted to point out, this was removed because Apollo Client core made two changes that rendered this option unnecessary:
So if you need to control the loading state, use the |
I was able to make all tests pass using the alpha version (and we're talking about a large app from a Fortune 500 company). There are many gotchas, for example the case was that previously handled with
So I had to use |
@JosephHalter, with jeremiller we talked about adding some sort of helper. Possibly something that could be used like so: .valueChanges.pipe(
filterCompleteData(),
map(result => result.data.film), // result.data.film guaranteed to exists
); In your experience is that something that could be useful if provided by apollo-angular or apollo-client ? I was also wondering if a slighlty more flexible API might be even more useful, something like // Same as before
.valueChanges.pipe(
only('complete'),
map(result => result.data.film), // result.data.film guaranteed to exists
); // different datastate
.valueChanges.pipe(
only('partial'),
map(result => result.data?.film), // might or might not exist
); // Or even combined state...
.valueChanges.pipe(
only('partial', 'streaming'),
map(result => result.data?.film), // might or might not exist
); Any thought about that ? how did you solve it in your codebase ? |
@PowerKiKi I would have used the helper if it was there, but I'm not sure it's necessary. Once I knew that I could get the correct type by checking on dataState, I didn't really need it anymore. If there was a global setting to disable partial results everywhere I would have used it, but if I need to go to each place and use the helper, I might just as well check on dataState directly. |
Apollo Client 4 doesn't wrap "external" errors anymore (i.e. non Apollo-thrown errors), so unless that error originated from Apollo Client itself, you just use the error instance directly. Those error classes aren't useful here if the thrown error isn't one of those error instances. In your case, you might just need to change to use |
Our app is working with the alpha. |
It looks like we have a fair bit of manual refactoring working to get our application working with Apollo Client 4/Apollo Angular 12. A few initial questions:
|
- const obs = apollo.subscribe(options, { useZone: false });
+ const obs = apollo.subscribe({ ...options, useZone: false });
That change comes from apollo-client. Their migration doc does not seem to cover your use-case. And I cannot recommend anything either. Maybe @jerelmiller could share some thoughts on that ?
Yes it was removed from apollo-client (and thus from apollo-angular). They recommend:
|
Thanks for the response, @PowerKiKi.
Now that I've cleared out some more outdated typings, the Mutation update method arguments seem to be getting typed correctly, so this may not be an issue. Not 100% sure yet since we're in the process of refactoring.
I don't quite follow this example using
Can you provide an example of how you narrowed the result using Finally, it looks like the order of the generic parameters have been swapped for |
The only thing that changed here is that
Sorry that text came straight from the changelog in core Apollo Client which is why that might have been confusing. The old You should be able to replicate this with Note:
Could you provide a more full example of what you tried here? It only type narrows in the scope where that check occurs: if (dataState === 'complete') {
data
// ^ TData
}
// this still includes `DeepPartial<TData>` since the `if` didn't `return`
data
// ^ TData | DeepPartial<TData> | undefined You should be able to eliminate if (dataState !== 'complete') {
return
}
data
// ^ TData
// --- or ---
// filter out partial results
if (dataState === 'partial') {
return
}
data
// ^ TData | undefined
Yes, this was a change to align with Apollo Client which updated all generic arguments to always be the order of |
@PowerKiKi Also good observation here! Let me make sure this gets added to the migration guide. |
PR to add this to the migration guide here: apollographql/apollo-client#12949 |
Thanks, @jerelmiller!
Here's one of the simplest examples of type export const UserRead_Fields = gql`
fragment UserFields on User {
_id
nameLast
nameFirst
username
isVerified
eventList {
name
dateTime
}
}
`;
export const UserRead_Query = gql`
query UserRead {
UserRead {
...UserFields
}
}
${UserRead_Fields}
`;
export interface IUserRead_ResponseData {
UserRead: {
_id: string;
nameLast: string;
nameFirst: string;
username: string;
isVerified: boolean;
eventList: IUserEvent[];
};
}
export interface IUser extends Partial<OmitMethodKeys<User>> {
}
export class User extends DomainEntityBase {
public nameFirst: string;
public nameLast: string;
public username: string;
public isVerified: boolean;
public accountList: IAccount[] = [];
public eventList: IUserEvent[] = [];
public readonly __typename: DomainEntityTypeName.User = DomainEntityTypeName.User;
public constructor(initialValues: IUserDocument) {
super();
if (initialValues) {
populate<IUser>(this, { ...initialValues, ...initialValues.profile });
if (!this.username) {
this.username = initialValues.emails[0].address;
}
this.isVerified = initialValues.emails.find((emails) => {
return this.username.toLocaleLowerCase() === emails.address.toLocaleLowerCase();
}).verified;
}
}
}
export class UserProfileComponent implements OnInit {
protected user: IUser;
public constructor(private apollo: Apollo) {}
public ngOnInit(): void {
this.apollo.watchQuery<IUserRead_ResponseData>({ query: UserRead_Query }).valueChanges
.subscribe(({ data: { UserRead: user }, dataState }) => {
if (dataState === 'complete') { // just added this to try to eliminate `DeepPartialObject`
this.user = user; // still get TS2322 below on this assignment
this.nameFirst.patchValue(user.nameFirst);
this.nameLast.patchValue(user.nameLast);
this.username.patchValue(user.username);
}
});
}
}
Separately, the |
I simplified your example and I think the destructuring prevents TypeScript from type narrowing: interface IUserRead_ResponseData {
UserRead: {
_id: string;
nameLast: string;
nameFirst: string;
};
}
// 💡💡💡 TYPE THE QUERY DIRECTLY SO YOU DON'T NEED TO REPEAT TYPING AT EACH CALL SITES
const UserRead_Query = gql<IUserRead_ResponseData, Record<PropertyKey, never>>`
query UserRead {
UserRead {
_id
nameLast
nameFirst
}
}
`;
let theUser: IUserRead_ResponseData['UserRead'] | null = null;
function testFailing(apollo: Apollo) {
apollo
.watchQuery({ query: UserRead_Query })
.valueChanges.subscribe(({ data: { UserRead: user }, dataState }) => { // 🛑🛑🛑 FAILING BECAUSE OF DESTRUCTURING
if (dataState === 'complete') {
theUser = user;
}
});
}
function testOK(apollo: Apollo) {
apollo
.watchQuery({ query: UserRead_Query })
.valueChanges.subscribe(result => {
if (result.dataState === 'complete') {
theUser = result.data.UserRead; // 🟢🟢🟢 SUCCESS BECAUSE OF TYPE NARROWING
}
});
} And yes signatures for |
Weird, but you are absolutely correct, @PowerKiKi. If I don't destructure the result, the test against
Thank you for the tip—we missed that
Very helpful. Thank you, @PowerKiKi. We extended the |
Quick note on the destructuring... it should work, but I think the problem here is that you're destructuring too deep so the type narrowing isn't working correctly in your example. The type narrowing happens on .subscribe(({ data: { UserRead: user }, dataState }) If you instead destructure just .subscribe(({ data, dataState }) => {
if (dataState === 'complete') {
theUser = data.UserRead
}
}) I've tried this locally in the test suite and this works fine. Keeps some of the destructuring without having to repeat |
@jerelmiller You can destructure after the check, to continue on your example: .subscribe(({ data, dataState }) => {
if (dataState === 'complete') {
const { UserRead: user } = data
// more code here...
}
}) |
@JosephHalter yep that works great too! |
@KeithGillette for your destructuring thing... Wouldn't a helper function similar to what is suggested in #2367 (comment) make the migration easier for you ? |
Yes, while it would require code changes in all the same places, I think simply inserting a helper function like the ones in those examples into the Observable |
Would you expect that hypothetical helper always filter |
I like the flexibility and semantics of your hypothetical |
@PowerKiKi I'm not sure there would be a need for anything other than Edit: might also be a good idea to recommend disabling |
Actually not true. |
@PowerKiKi seems to be working for us 🙏 |
This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to master, this PR will be updated.
Releases
[email protected]
Major Changes
#2372
44ed9a5
Thanks @jerelmiller! - Namespaced types
Before:
After:
#2372
bdc93df
Thanks @jerelmiller! -
httpHeaders
is a classMigrate your code like so:
#2372
8c0b7f0
Thanks @jerelmiller! - Move
useZone
option into subscriptionoptions
#2372
b9c62a5
Thanks @jerelmiller! - Combined parameters of
Query
,Mutation
andSubscription
classes generated via codegenMigrate your code like so:
Patch Changes
#2355
226a963
Thanks @PowerKiKi! - dependencies updates:
@apollo/client@^4.0.1
↗︎ (from^3.13.1
, inpeerDependencies
)rxjs@^7.3.0
↗︎ (from^6.0.0 || ^7.0.0
, inpeerDependencies
)#2373
e65bcce
Thanks @PowerKiKi! - Drop support for node 18
#2366
bdff9d9
Thanks @PowerKiKi! - Drop ESM2022 in favor of FESM2022
#2368
0f10355
Thanks @PowerKiKi! - New repository owners
@kamilkisiela, the creator of this library, has found new
interests and is not able to contribute like in the past. He gracefully transferred ownership of
the repository to me. I have been maintaining this library since 2022, and will continue doing so
in the foreseeable future.
For the package consumers, pretty much nothing will change. The package name, the code, the
relation with The Guild, and the maintenance style will all
remain the same. The only difference is the new repository URL:
https://github.com/the-guild-org/apollo-angular.