-
Notifications
You must be signed in to change notification settings - Fork 995
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
[Bug]: Seeing Unknown Fragment after migration to use registerFragment
#10322
Comments
I think I see the issue. I stored and registered the fragment separately from the query, in a different file. By the time the query itself is declared, the fragment is unavailable/hasn't been registered yet. Makes sense. So, I can get fragments/queries to work, but only if they're defined in the right order in the same file, or if somehow I can guarantee that the query variable will be declared after the fragment. This is likely the bug that @pvenable is seeing in #10120 (comment) Is there a recommended directory structure? What is the goal for I'll give it more thought, but I assume the goal is not to have all fragments and queries to be defined in one, massive file, which is what I'd have to do right now. Of course, I could try to split this one file into multiple massive files, but as soon as there's a fragment which needs to be used in queries across files, I now have to merge these files. Any ideas? Can the Redwood team support string interpolation as well (only thing broken there is type safety atm)? This dev ex sounds not very great |
Not that anyone would ever do this in production code, but here's something I tried out with initialization in the same file. I'm also not sure what to do with this info other than just dump it Case 1: 1 ms delay before registeringThis does not work (throws "Unknown Fragment"):
Case 2: No delay before registeringThis works:
Case 3: 0ms delay before registeringThis makes it flakey (sometimes throws "Unknown Fragment"):
|
The abstraction layer over the IIUC, there may be fragments which don't make it all the way to the |
@dthyresson has been working on this — looping him in here. |
Hi @shivghai thanks for the detailed info and apologies for the bumps in using fragments -- my intention was to 1) make things easier 2) I did review the approach with folks at Apollo 3) do the heavy lifting of being able to support unions and such. Some background: First, I've been surprised to see that people had fragments with string interpolation working as when we saw that, the specific graphql codegen loader we used could not do interpolation, so generating types failed. This was one of the factors in moving to the client preset codegen and fragment registration. So, I didn't expect much of a breaking change than it turned out to be honestly. So apologies for that. Second, I based the fragment design and pattern off of the approach the Guild takes here: https://the-guild.dev/blog/unleash-the-power-of-fragments-with-graphql-codegen . Specifically, "Colocate GraphQL documents with the component code. Instead of writing GraphQL operations in a dedicated file, the operations are written within the component code." In talking to the Guild and others, it was the desire to build a "component tree" that drove the graphQL developers to come up with the concept of fragments. In fact I went back to my notes:
The key here is the "view hierarchy" or as the Guild puts it:
So, fragments are most often not just a way to move out parts of a query to be reusing in queries, but the goal is to collocate the data needed to render a comment with the presentation of that data. Thus:
I guess was not the use case I was designing for. And I confess I didn't consider it as the pattern I was aiming for was that view hierarchy and colocation of component data. Third, may I ask why in your examples you'd want to delay registration of the fragment? Or was that just a way to reproduce when the fragment was in a separate file? Last: the line you point to: // Auto register fragments
if (fragments) {
fragmentRegistry.register(...fragments)
} That's another way fragments can be registered: You can pass them into the Apollo provider which is kinda tricky -- or use the So -- to answer the question: "Is there a recommended directory structure? What is the goal for registerFragment if it doesn't help with code reuse outside of the same file? Am I missing something?" The goal was to let developers create the view hierarchies and collocate the data with the component. This lets Apollo manage the cache for each fragment really nicely. In addition, it will let us implement upcoming features such as fragment masking which is in RFC here: apollographql/apollo-client#11666 Hope this extra background helps. If there's something I can do to make the experience better, let me know. In the mean time, I'll ask the Guild and others about the "keeping queries all in one file using fragments" pattern and get their thought on how and when to use that. |
Hi @dthyresson - appreciate the thoughtful response. I have a couple of clarifications, and some explanation of how we've set up our fragments.
Yep just to reproduce different files. Ignore that.
We do indeed use fragments for moving out parts of a query so it can be reused. From the first line of the Apollo GraphQL docs on fragments.
From a later point in the same doc:
This is just one use case of fragments, which is not mutually exclusive to code reuse/logic sharing, which is now mostly broken in RedwoodJS unless if the fragments are registered before queries are defined (i.e. same-file-for-everything-approach). IIUC, we could still have "local" fragments per component to have better colocation while maintaining our code reuse fragments overall. If we go back to Apollo Client v2 docs:
One of these principal uses is now broken in RedwoodJS.
I don't know if that's true, to me, it seems like that is just one use case of fragments which helps with code maintainability. I see the colocation benefit here - it's great. But with Redwood's current approach, I also see an increase in verbosity for the moving-out-parts-of-a-query use case and a significant decrease in code maintainability. At this point it's not even helpful to use fragments since reuse is broken. We've gone for simplicity and speed over performance benefits of colocation (again, they shouldn't be mutually exclusive IIUC, but I may be wrong), and this heavily breaks our codebase.
Just a clarification - that's not exactly how we do things. We have What I meant by "keeping queries all in one file using fragments" is that would be what I'd have to resort to, given the current limitations.
Bringing back string interpolation would be great, since that worked well for us pre RW7! Let me know if I can answer any other questions on our usage! |
@dthyresson What would work best would be to bring back string interpolation, or to somehow hoist certain files/directories in Redwood so we can guarantee fragment registration first. If there's already a way to do that, that'd be perfect |
That’s the mystery to me — I never saw string interpolation in fragment code working. It always threw an error when doing type/code generation. Unless a newer version of the code file loader now supports it. I’ll look into that. |
FYI this said that the loader did not permit interpolation https://stackoverflow.com/questions/62749847/graphql-codegen-dynamic-fields-with-interpolation
btw I’m not trying to say it didn’t work for you but I’m just so surprised since I even have some Slack messages with other Core Team members from last year who ran into this issue when building some apps and had to help fix. |
That stack overflow question appears to be about interpolating fields into fragments rather than including fragment definitions into other fragments or queries, which was the way to reference other components' fragments prior to the Personally I think the This may just be the nature of the thing, and when following "normal" patterns like referencing fragments of imported child components it does seem safe to assume that registration will have occurred due to having directly imported the component file that registers that fragment. But I could see cases -- like including a fragment into a mutation* to ensure the cache is updated appropriately -- that could fail depending on whether the bundle that registers a given fragment has been loaded. 🤔 If my theory is correct, the answer (for now?) may just be "don't do that!", but I haven't confirmed this specific problem. (*: This seems like a reasonable use case to me, but I don't think I've done this much, and perhaps it's a mistake. 🤷♂️) |
Definitely what's going on right now in this issue
We currently do this, part of the reason why we share fragments across multiple queries/mutations |
I think I’ll have to create a small demo app and try to recreate the issue and then work to see if I can restore the 6.5.1 behavior. Can I ask if in your toml you have any of the GraphQL settings enabled like fragments https://redwoodjs.com/docs/cli-commands or trusted documents? The fragments config will try to swap out the gql function with one that supports possible types. For my test app, I’d turn those off. |
Thanks for looking into this @dthyresson ! Pre-upgrade, I didn't have any gql related settings set up
to get the fragment registry working I'm happy to hop on a call to discuss and post findings here if that's helpful, unless if you prefer async in which case that's fine too |
Demo app should be easy and I imagine it's top of mind for you, but I can outline what it could look like in case that's helpful: If you're starting with Redwood 6.x:
|
Interesting ... manually importing graphql pluck seems to help: No squiggles and types and tc passes: ragment-test main % yarn rw g types && yarn rw tc
Generating...
- .redwood/schema.graphql
- .redwood/types/mirror/api/src/directives/requireAuth/index.d.ts
- .redwood/types/mirror/api/src/directives/skipAuth/index.d.ts
- .redwood/types/mirror/api/src/services/books/index.d.ts
- .redwood/types/mirror/web/src/pages/BooksPage/index.d.ts
- .redwood/types/mirror/web/src/pages/FatalErrorPage/index.d.ts
- .redwood/types/mirror/web/src/pages/NotFoundPage/index.d.ts
- .redwood/types/mirror/web/src/components/BooksCell/index.d.ts
- .redwood/types/includes/web-routesPages.d.ts
- .redwood/types/includes/all-currentUser.d.ts
- .redwood/types/includes/web-routerRoutes.d.ts
- .redwood/types/includes/api-globImports.d.ts
- .redwood/types/includes/api-globalContext.d.ts
- .redwood/types/includes/api-scenarios.d.ts
- .redwood/types/includes/api-test-globals.d.ts
- .redwood/types/includes/web-test-globals.d.ts
- .redwood/types/includes/web-storybook.d.ts
- api/types/graphql.d.ts
- web/types/graphql.d.ts
... done.
✔ Generating the Prisma client...
✔ Generating types
fragment-test main % Note: I think this was brought up by the gql global earlier, but I just made the connection. Going to investigate this since it appears to at the very least be a possible workaround -- though it means importing pluck everywhere. |
@shivghai and @pvenable I think I may have found the culprit and even why I may not have seen it when working on fragments as the change to help support Trusted Documents aka Persisted Operations changed the type of the global gql. The generic type we had made for TD support seems to be incompatible with the graphql-tag: With this change, TS and GraphQL seem to be happy: I need to do some tests that TD still works, but I think you have two workarounds:
It's that I also been to test that this is ok with the fragments setting turns on -- but I think I am on the right track. Since TD was implemented after, and our e2e/CI/test suite used the collocated fragments pattern this got missed unfortunately. |
Awesome, thanks for looking into this @dthyresson . I'll wait to upgrade till we have a fix for this in RW, but this would get us all the way there! |
@dthyresson is this something i can help with? just want to make sure this can be resourced |
@dthyresson - just following up here. |
…n web (#10357) Fixes: #10322 See ^^^ --- Tested that both the graphql toml config with fragments and trustedDocuments set to true works. However, if trusted documents uses fragments seeing an intermittent Apollo issue. Investigating. Update: Have confirm that if trusted documents uses fragments, works as expected. See note below. Note: Had to make small fix to fragments setup to address an error when prettifying as final step.
…n web (#10357) Fixes: #10322 See ^^^ --- Tested that both the graphql toml config with fragments and trustedDocuments set to true works. However, if trusted documents uses fragments seeing an intermittent Apollo issue. Investigating. Update: Have confirm that if trusted documents uses fragments, works as expected. See note below. Note: Had to make small fix to fragments setup to address an error when prettifying as final step.
…n web (#10357) Fixes: #10322 See ^^^ --- Tested that both the graphql toml config with fragments and trustedDocuments set to true works. However, if trusted documents uses fragments seeing an intermittent Apollo issue. Investigating. Update: Have confirm that if trusted documents uses fragments, works as expected. See note below. Note: Had to make small fix to fragments setup to address an error when prettifying as final step.
What's not working?
I was previously, pre rw 7, using fragments (successfully) using string interpolation. Post upgrade, there are no changes to the actual query itself, except that the fragment is no longer interpolated, and is being registered instead.
I have a GQL Fragment, F_Fragment, which is being used in a query, Q_QUERY.
UPDATE - file info Here's the code for the fragment, in
fragment.ts
:UPDATE - file info The code for the query, in
query.ts
:We can no longer fetch the required data using the query, and get the
Unknown fragment A_Fragment
error.The query is called in this way:
Interestingly, the graphql types are generated correctly. The query also still works with string interpolation (minus types). Any ideas here?
How do we reproduce the bug?
UPDATED
Declare and register fragment in a different file than the query
What's your environment? (If it applies)
System:
OS: macOS 13.6
Shell: 5.9 - /bin/zsh
Binaries:
Node: 20.11.1 - /private/var/folders/8y/99byt5ms31d1z8jgjfmyvcg80000gn/T/xfs-d437a37e/node
Yarn: 3.2.1 - /private/var/folders/8y/99byt5ms31d1z8jgjfmyvcg80000gn/T/xfs-d437a37e/yarn
Databases:
SQLite: 3.39.5 - /usr/bin/sqlite3
Browsers:
Chrome: 123.0.6312.59
Safari: 16.6
npmPackages:
@redwoodjs/auth-auth0-setup: 7.1.3 => 7.1.3
@redwoodjs/cli-data-migrate: 7.1.3 => 7.1.3
@redwoodjs/core: 7.1.3 => 7.1.3
Are you interested in working on this?
The text was updated successfully, but these errors were encountered: