Skip to content
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

Use without Sapper or SvelteKit #67

Closed
dyedgreen opened this issue May 13, 2021 · 10 comments · Fixed by #95 or #107
Closed

Use without Sapper or SvelteKit #67

dyedgreen opened this issue May 13, 2021 · 10 comments · Fixed by #95 or #107

Comments

@dyedgreen
Copy link

From reading the documentation it's not clear if/ how this can be used within a bare Svelte app.

If this is possible, how would one use Houdini without using Sapper (i.e. only having a simple Svelte app). If this is currently not possible, why not (and how could that be changed, e.g. if I wanted to submit a PR)?

@AlecAivazis
Copy link
Collaborator

At the moment, houdini doesn't work in a bare svelte app because query does not actually fire a network request. It assumes that the pre-processor has hoisted the query into a load function (preload in sapper) and that the component using query will be passed the data as a prop from the load function. Also, query and the other document functions have internal APIs that are not very ergonomic so there would have to be some work done to make the user's life smoother. For a better understanding of what I mean, you can look at the fragment tests. The top of that is what the user writes, the block underneath is what the pre-processor turns it into and shows the actual API for the fragment function when its invoked.

Supporting this would probably be best done by building versions of query, mutation, subscription, and fragment that don't make these assumptions. You could still use the artifacts that the compiler generates and the caching mechanism would still work which is what powers the actual APIs (ie things like mutation updates would "just work"). It's definitely doable but not something I have time to prioritize at the moment. If you do want to try to add support for a raw svelte app, I can provide any guidance you need

@dyedgreen
Copy link
Author

dyedgreen commented May 13, 2021

Interesting, so queries are actually all run server side before the components are send to the browser, or am I miss understanding the process? 😅

(That would explain why queries return the data directly instead of returning a promise 😅; I suppose when supporting bare svelte, it would make sense for queries to return a promise in the same was as mutations do?)

Coming from Relay, this is the API I would have expected:

<script type="ts">
  const data = query(graphql`query MyQuery(...) { ... }`, optionalQueryVariables);
</script>

@AlecAivazis
Copy link
Collaborator

AlecAivazis commented May 13, 2021

yes that's correct! At least for the first request that is rendered by the server. From then on, queries fire from the client directly to the API (both Sapper and SvelteKit take care of these details when you define the appropriate loader).

In a bare svelte app, you dont have any of the concerns that caused me to structure the variables API the way it is. There shouldn't be much problem with passing the variables in as a second argument to query like you show as long as you detect changes in their value. I do worry that the APIs will start to diverge dramatically but it might not be too bad.

Re the return value - I think a promise is a reasonable response from the various document functions in a bare svelte app as long as it resolves to a store so the user can subscribe to updates.

@AlecAivazis
Copy link
Collaborator

AlecAivazis commented May 19, 2021

After poking around with possibilities, I think we can support bare svelte with the current API. At the very least querys inside of non page/layout components have the same constraints as a bare component so the two should have very similar solutions.

related: #72

@dyedgreen
Copy link
Author

I think one solution could be to split the query API into lazyLoadedQuery and preloadedQuery (or just query), where the later one is the default to use in page components, defers the arguments into the preload-function, while the lazy loaded version fires on the client side, when the component is rendered (and takes the arguments directly). (iirc that's roughly the story with Relay's API as well)

@AlecAivazis
Copy link
Collaborator

I'd like to avoid doing that if possible. I think the only thing that's missing from the query api to support client-only requests is to add a loading field to track the state of the response. I agree that a promise would be a more native solution but I'd like to keep the api surface as small as possible. Also, having two different functions that are constrained by file location means that refactoring components from a page/layout into a common component is not as simple as just moving the file - the user would also have to go update all of the querys to clientQuery or whatever we call it.

@dyedgreen
Copy link
Author

What do you think of mirroring relays approach more closely and having a preloaded query that is passed the pre-load value explicitly; and then having a loader that can load a given query from within the sapper/ kit (pre)loader side of things (or potentially another function in the frontend); and potentially having a convenience wrapper that lazy loads things by doing something like query(…, await preloadQuery(…))

That would break compatibility with the current api but be more flexible in terms of where the loading can happen.

@AlecAivazis
Copy link
Collaborator

AlecAivazis commented May 19, 2021

In some sense that's how query works now. The actual function exported from the runtime expects an object that is created by the preprocessor.

If we wanted to bring the idea of preloading a query into the core API, I think the best way is to leave query the way it is and instead add two new functions to the runtime that do the preloading and and subsequent loading. Even if query is just a very thin wrapper over preloadedQuery (or whatever we call it), having two functions with distinct names lets the preprocessor handle the details for query and keeps the API simple in the most common cases. I want to avoid complicating the very common APIs to support "advanced" use cases wherever possible.

I think ideally, the logic for preloading a query should be hidden from the user and the framework should just do the "right thing" whenever possible. I think given that houdini is currently only maintained by a single person, the best way to get to that dream is to lean heavily into kit to handle the router integration. I do understand that supporting preloaded queries is important to integrate with other routers but advanced users are more likely to be okay with a less-than-perfect API that might be heavily caveated.

@AlecAivazis
Copy link
Collaborator

@dyedgreen I think I have a working update to support query in a non-kit or sapper environment. Mind giving #95 a shot and see if it works for you?

@AlecAivazis
Copy link
Collaborator

Going to reopen this, @pixelmund had a very good point, a lot of the generated code still assumes things like $app and sessions. We'll need to generate a bare svelte adapter that avoid this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants