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

Usage With Svelte Kit #97

Open
stolinski opened this issue Jun 2, 2021 · 22 comments
Open

Usage With Svelte Kit #97

stolinski opened this issue Jun 2, 2021 · 22 comments

Comments

@stolinski
Copy link

stolinski commented Jun 2, 2021

<script>
    import Header from '$lib/layout/Header.svelte'
    import Footer from '$lib/layout/Footer.svelte'
    import '$lib/style/styles.scss'

    import { setClient } from "svelte-apollo";
    import { ApolloClient, HttpLink } from '@apollo/client/core/core.cjs.js'
    import { InMemoryCache } from '@apollo/client/cache/cache.cjs.js'

    const link = new HttpLink({
        uri: 'http://localhost:3001/graphql',
        fetch
    })

    const client = new ApolloClient({
        link,
        cache: new InMemoryCache()
    })
    console.log('client', client);
    setClient(client);
</script>

<Header />

<slot />

<Footer />

In our __layout.svelte
Produces [HMR][Svelte] Unrecoverable error in <__layout>: next update will trigger a full reload
logError @ proxy.js:15
Proxy<__layout> @ proxy.js:372
create_fragment @ root.svelte? [sm]:36
init @ index.mjs?v=e94d9004:1500
Root @ root.svelte? [sm]:16
createProxiedComponent @ svelte-hooks.js:245
ProxyComponent @ proxy.js:241
Proxy @ proxy.js:341
_init @ start.js:646
start @ start.js:530
async function (async)
start @ start.js:483
start @ start.js:1096
(anonymous) @ (index):39

Removing setClient(client) fixes error, breaks apollo (obviously). Any thoughts?

Uncaught (in promise) Error: Function called outside component initialization
    at get_current_component (index.mjs:649)
    at setContext (index.mjs:679)
    at setClient (context.ts:19)
    at instance (__layout.svelte? [sm]:19)
    at init (index.mjs?v=e94d9004:1485)
    at new _layout (__layout.svelte? [sm]:19)
    at createProxiedComponent (svelte-hooks.js:245)
    at new ProxyComponent (proxy.js:241)
    at new Proxy<__layout> (proxy.js:341)
    at create_fragment (root.svelte? [sm]:36)
@moonmeister
Copy link

moonmeister commented Jun 7, 2021

Hey Scott, I've seen this a couple times but in my case it's only happening when called from <script context='module'>. Is this what you're seeing?

Ignore this, I don't know if I missed it or something changed, I am seeing this everywhere now.

@moonmeister
Copy link

moonmeister commented Jun 7, 2021

I'm trying to track this down. I did find sveltejs/sapper#592 which might be relevant but I'm not entirely sure.

Clarification on the many uses of "context" between svelte and svelte kit: sveltejs/kit#984

I think an important thing I recognized from these two is that svelte's getContext / setContext will never work with Svelte Kit's load function cause it's called in the module context. This SHOULD still work in the normal <script> context though. Why it doesn't is possibly a bug or maybe a part of how SK works.

Update: Scott, I just realize I assumed you are using svelte kit, are you? If not, my bad for hijacking your issue here.

@unlocomqx
Copy link

unlocomqx commented Jun 8, 2021

This is vite not deduping svelte correctly and using two instances of svelte thus losing track of the current component and context.

One workaround is to alias svelte-apollo to trick vite into thinking it's part of our code and not a node_module to force it to use our already installed svelte dependency.

Here's the config path in svelte.config.js

const config = {
  kit: {
    vite: {
      resolve: {
        alias: {
          'svelte-apollo': '/node_modules/svelte-apollo/dist/svelte-apollo.es.js'
        },
      },
    }
  }
};

Another trick to make it work well with sveltekit is to create a wrapper component around the layout slot then instantiate the client inside the wrapper component.

@bluwy
Copy link

bluwy commented Jun 9, 2021

Putting this into the vite config should work too:

optimizeDeps: {
  include: [
    "@apollo/client/core",
    "@apollo/client/cache",
    "@apollo/client/link/ws",
    "@apollo/client/link/context",
    "@apollo/client/link/error",
    "@apollo/client/utilities",
  ],
  exclude: ["@apollo/client", "svelte-apollo"],
},

@cschmatzler
Copy link

Getting stuck here as well. The workaround from @unlocomqx allowed use of setClient, but now using mutation throws the same error.

@moonmeister
Copy link

When I gave up trying to use this library everything started working. My understanding is this lib was designed to be used in svelte components and is incompatible with and possibly even redundant to using the load api. I haven't explored. In my layout component I placed my client into the load API context and accessed it from there on all other pages.

@unlocomqx
Copy link

@cschmatzler Yeah the current design only allows making a query or mutation during component initialisation because it's coupled with svelte context (which only allows reading/writing during component initialisation)

The solution is to use lazy queries according to the lib author which is still unimplemented so this is currently definitely unusable
#53 (comment)

@bluwy
Copy link

bluwy commented Jun 11, 2021

FWIW I've written a guide for Sapper integration some time ago, which should still work in SvelteKit. Haven't got the time to do a refresh on it. Note: It uses the Apollo client directly.

@unlocomqx
Copy link

I think it's better to just encapsulate the module functions in the client directly
I made an attempt here
https://github.com/unlocomqx/svelte-apollo/blob/patch-client/src/client.ts

I can now create the client in a separate file and export it, then import it wherever needed

client.query(...);
client.mutate(...);

Much better than dealing with the context because it's very limiting

@draylegend
Copy link

I get this error. Hope someone has a solution for that:

 > node_modules/@apollo/client/react/hooks/useReactiveVar.js:1:36: error: Could not resolve "react" (mark it as external to exclude it from the bundle)
    1  import { useEffect, useState } from 'react';
                                           ~~~~~~~

 > node_modules/@apollo/client/react/context/ApolloProvider.js:2:23: error: Could not resolve "react" (mark it as external to exclude it from the bundle)
    2  import * as React from 'react';
                              ~~~~~~~

 > node_modules/@apollo/client/react/hooks/useApolloClient.js:2:23: error: Could not resolve "react" (mark it as external to exclude it from the bundle)
    2  import * as React from 'react';
                              ~~~~~~~

 > node_modules/@apollo/client/react/context/ApolloConsumer.js:2:23: error: Could not resolve "react" (mark it as external to exclude it from the bundle)
    2  import * as React from 'react';
                              ~~~~~~~

 > node_modules/@apollo/client/react/context/ApolloContext.js:1:23: error: Could not resolve "react" (mark it as external to exclude it from the bundle)
    1  import * as React from 'react';
                              ~~~~~~~

 > node_modules/@apollo/client/react/hooks/useSubscription.js:3:68: error: Could not resolve "react" (mark it as external to exclude it from the bundle)
    3  import { useContext, useState, useRef, useEffect, useReducer } from 'react';
                                                                           ~~~~~~~

 > node_modules/@apollo/client/react/hooks/useMutation.js:2:56: error: Could not resolve "react" (mark it as external to exclude it from the bundle)
    2  import { useContext, useState, useRef, useEffect } from 'react';
                                                               ~~~~~~~

 > node_modules/@apollo/client/react/hooks/utils/useBaseQuery.js:3:58: error: Could not resolve "react" (mark it as external to exclude it from the bundle)
    3  import { useContext, useEffect, useReducer, useRef } from 'react';
                                                                 ~~~~~~~

error: Could not resolve "react" (mark it as external to exclude it from the bundle)
    2  import { useEffect, useRef } from "react";
                                         ~~~~~~~

 > node_modules/@apollo/client/react/hooks/utils/useDeepMemo.js:1:23: error: Could not resolve "react" (mark it as external to exclude it from the bundle)
    1  import { useRef } from 'react';
                              ~~~~~~~

> Build failed with 10 errors:
node_modules/@apollo/client/react/context/ApolloConsumer.js:2:23: error: Could not resolve "react" (mark it as external to exclude it from the bundle)
node_modules/@apollo/client/react/context/ApolloContext.js:1:23: error: Could not resolve "react" (mark it as external to exclude it from the bundle)
node_modules/@apollo/client/react/context/ApolloProvider.js:2:23: error: Could not resolve "react" (mark it as external to exclude it from the bundle)
node_modules/@apollo/client/react/hooks/useApolloClient.js:2:23: error: Could not resolve "react" (mark it as external to exclude it from the bundle)
node_modules/@apollo/client/react/hooks/useMutation.js:2:56: error: Could not resolve "react" (mark it as external to exclude it from the bundle)
...
Error: Build failed with 10 errors:
node_modules/@apollo/client/react/context/ApolloConsumer.js:2:23: error: Could not resolve "react" (mark it as external to exclude it from the bundle)
node_modules/@apollo/client/react/context/ApolloContext.js:1:23: error: Could not resolve "react" (mark it as external to exclude it from the bundle)
node_modules/@apollo/client/react/context/ApolloProvider.js:2:23: error: Could not resolve "react" (mark it as external to exclude it from the bundle)
node_modules/@apollo/client/react/hooks/useApolloClient.js:2:23: error: Could not resolve "react" (mark it as external to exclude it from the bundle)
node_modules/@apollo/client/react/hooks/useMutation.js:2:56: error: Could not resolve "react" (mark it as external to exclude it from the bundle)
...
    at failureErrorWithLog (D:\dev\web\tests\crm\node_modules\esbuild\lib\main.js:1478:15)
    at D:\dev\web\tests\crm\node_modules\esbuild\lib\main.js:1136:28
    at runOnEndCallbacks (D:\dev\web\tests\crm\node_modules\esbuild\lib\main.js:926:63)
    at buildResponseToResult (D:\dev\web\tests\crm\node_modules\esbuild\lib\main.js:1134:7)
                                                                                               at D:\dev\web\tests\crm\node_modules\esbuild\lib\main.js:1243:14
    at D:\dev\web\tests\crm\node_modules\esbuild\lib\main.js:614:9
    at handleIncomingPacket (D:\dev\web\tests\crm\node_modules\esbuild\lib\main.js:711:9)
    at Socket.readFromStdout (D:\dev\web\tests\crm\node_modules\esbuild\lib\main.js:581:7)
    at Socket.emit (events.js:400:28)
    at Socket.emit (domain.js:470:12)

package.json

{
	"name": "~TODO~",
	"version": "0.0.1",
	"scripts": {
		"dev": "svelte-kit dev",
		"build": "svelte-kit build",
		"preview": "svelte-kit preview",
		"check": "svelte-check --tsconfig ./tsconfig.json",
		"check:watch": "svelte-check --tsconfig ./tsconfig.json --watch",
		"lint": "prettier --ignore-path .gitignore  --check --plugin-search-dir=. . && eslint --ignore-path .gitignore .",
		"format": "prettier --ignore-path .gitignore --write --plugin-search-dir=. ."
	},
	"devDependencies": {
		"@sveltejs/kit": "next",
		"@typescript-eslint/eslint-plugin": "^4.19.0",
		"@typescript-eslint/parser": "^4.19.0",
		"eslint": "^7.22.0",
		"eslint-config-prettier": "^8.1.0",
		"eslint-plugin-svelte3": "^3.2.0",
		"prettier": "~2.2.1",
		"prettier-plugin-svelte": "^2.2.0",
		"svelte": "^3.34.0",
		"svelte-check": "^2.0.0",
		"svelte-preprocess": "^4.0.0",
		"tslib": "^2.0.0",
		"typescript": "^4.0.0"
	},
	"type": "module",
	"dependencies": {
		"@apollo/client": "^3.4.11",
		"graphql": "^15.5.3",
		"svelte-apollo": "^0.4.0"
	}
}

@bluwy
Copy link

bluwy commented Sep 13, 2021

@vladimirdrayling Try adding @apollo/client to optimizeDeps.exclude and avoid importing @apollo/client. Import from @apollo/client/core instead.

@bluwy
Copy link

bluwy commented Sep 13, 2021

Btw the error originally reported has been fixed in vite-plugin-svelte now. The library should work ootb, except for the @apollo/client part (reason). So I'd say this can be closed.

@tmrp
Copy link

tmrp commented Oct 8, 2021

This is not entirely related to the svelte-apollo package but for those of you that are having trouble setting this up with @apollo/client, I might have a solution.

Credit goes to Reddit user: u/NoahVersace, link to post. It's a fix for Prismic but the same principles apply to @apollo/client.

Here's how I got it working for Apollo:
I'm using the svelte static adapter and this works with Apollo on build and dev

// apolloClient.js
import Apollo, * as ApolloScope from '@apollo/client/core/core.cjs.js';

const HttpLink = Apollo?.HttpLink || ApolloScope?.HttpLink;

const ApolloClient = Apollo?.ApolloClient || ApolloScope?.ApolloClient;

const InMemoryCache = Apollo?.InMemoryCache || ApolloScope?.InMemoryCache;

const link = new HttpLink({
	uri: `YOUR_GRAPHQL_ENDPOINT`
});

const cache = new InMemoryCache();

const apolloClient = new ApolloClient({
	link,
	cache
});

export default apolloClient;

From here on you may use the client as you will.

For instance, I would like to wrap it around my app so I'm calling it at __layout.svelte:

// __layout.svelte

<script context="module">
	import apolloClient from '$lib/apolloClient';

	/**
	 * @type {import('@sveltejs/kit').Load}
	 */

	export async function load({ stuff }) {
		const client = apolloClient;
		return {
			stuff: {
				...stuff,
				client
			}
		};
	}
</script>

<slot />

You don't need the svelte-apollo package in order for this to work.

Lastly, you may query data in components/pages like so:

// someDataComponent.js
<script context="module">
	export async function load({ stuf  }) {
		return {
			props: {
				someData: await stuff.client.query({ query: SOME_DATA_QUERY })
			}
		};
	}
</script>

<script>
	import { SOME_DATA_QUERY } from '$lib/data-queries';

        export let someData
</script>

<section>
        <h1>{someData.heading}</h1>
        <p>{someData.paragraph}</p>
</section>

That's it!

Hope this helps!

CleanGlyph added a commit to CleanGlyph/Sveltekit-GraphQL-Auth that referenced this issue Oct 25, 2021
@ZerdoX-x
Copy link

ZerdoX-x commented Nov 24, 2021

Another workaround not mentioned here is to add export map to @apollo/client package directly:

For me it was

  "exports":{
    ".": {
      "node":"./main.cjs", "default":"./index.js"
    },
    "./cache": {
      "node":"./cache/cache.cjs","default":"./cache/index.js"
    },
    "./core": {
      "node":"./core/core.cjs","default":"./core/index.js"
    },
    "./link/schema": {
      "node":"./link/schema/schema.cjs","default":"./link/schema/index.js"
    },
    "./link/context": {
      "node":"./link/context/context.cjs","default":"./link/context/index.js"
    },
    "./link/http": {
      "node":"./link/http/http.cjs","default":"./link/http/index.js"
    },
    "./link/ws": {
      "node":"./link/ws/ws.cjs","default":"./link/ws/index.js"
    }
  }

Make sure to delete all previous "solutions" and workaround as they would conflict. Track progress on issue here: apollographql/apollo-client#8218

UPDATE:
I also found out that rollup bundling crashes with

> [vite]: Rollup failed to resolve import "react" from "node_modules/.pnpm/@apollo+client@3.6.6_vc5lvukfq44ubwvv43scizgjye/node_modules/@apollo/client/react/context/ApolloConsumer.js".
This is most likely unintended because it can break your application at runtime.
If you do want to externalize this module explicitly add it to
`build.rollupOptions.external`

if you don't have compilerOptions.preserveValueImports set to false in your tsconfig

@gran0123
Copy link

gran0123 commented Jan 8, 2022

@tmrp Hmm, did u exclude anything? I tried your answer but I'm still getting "Could not resolve 'react' (mark it as external to exclude it from the bundle)" with following:

import Apollo, * as ApolloScope from '@apollo/client/core/core.cjs';

const HttpLink = Apollo?.HttpLink || ApolloScope?.HttpLink;

const ApolloClient = Apollo?.ApolloClient || ApolloScope?.ApolloClient;

const InMemoryCache = Apollo?.InMemoryCache || ApolloScope?.InMemoryCache;

const link = new HttpLink({
	uri: process.env.VITE_GRAPHQL_ENDPOINT
});

const cache = new InMemoryCache();

const apolloClient = new ApolloClient({
	link,
	cache
});

export default apolloClient;

update:
tried vite.optimizeDeps solution. 'react' problem was gone but got a new one with
image

@tmrp
Copy link

tmrp commented Jan 8, 2022

@tobiasgranlof updates to Svelte (presumably Vite) have prevented the method I mentioned from working.

I started a new SvelteKit project and got a similar error. It took me a while to rack my brain around it, but I got it working now.

To get it to work now you have to slightly restructure apolloClient.js like so:

import { HttpLink, InMemoryCache, ApolloClient } from '@apollo/client/core';

import { environmentVariables } from './environment-variables';

const link = new HttpLink({
	uri: environmentVariables.starWarsApi
});

const cache = new InMemoryCache();

const apolloClient = new ApolloClient({
	link,
	cache
});

export default apolloClient;

And you would have to add the following to your svelte.config.js file:

kit: {
 ...
  vite: {
    ssr: {
      noExternal: ['@apollo/client']
      }
    }
}

I made a working demo project you may checkout here

I hope this helps!

@gran0123
Copy link

gran0123 commented Jan 9, 2022

Your example works but I guess because its plain js. Im using typescript and with the same configuration I do get the "react" problem when building. Even with same vite configuration as in your example. I tried both @apollo/client version 3.4.16 and latest. Same error.
image

this is my apollo-client.ts:

import { HttpLink, InMemoryCache, ApolloClient } from '@apollo/client/core';

import { environmentVariables } from '$lib/environment-variables';

const link = new HttpLink({
	uri: environmentVariables.graphqlApi.toString()
});

const cache = new InMemoryCache();

const apolloClient = new ApolloClient({
	link,
	cache
});

export default apolloClient;

@tmrp
Copy link

tmrp commented Jan 9, 2022

@tobiasgranlof, I think you made a mistake while trying to type check the environment variable here:

const link = new HttpLink({
  // you would want to give uri a string type here and not transform it to a string (because it's already a string)
  uri: environmentVariables.graphqlApi.toString()
  // replace the above with
   uri: environmentVariables.graphqlApi as string
});

To be safe, I changed my svelte.config.js to:

import adapter from '@sveltejs/adapter-auto';
import preprocess from 'svelte-preprocess';

/** @type {import('@sveltejs/kit').Config} */
const config = {
 // Consult https://github.com/sveltejs/svelte-preprocess
 // for more information about preprocessors
 preprocess: preprocess(),

 kit: {
  adapter: adapter(),

  // hydrate the <div id="svelte"> element in src/app.html
  target: '#svelte',
  vite: {
   optimizeDeps: {
    exclude: ['@apollo/client']
   },
   ssr: {
    noExternal: ['@apollo/client']
   }
  }
 }
};

export default config;

I made a TypeScript version, and you may check out the repo here here

I hope this helps!

Cheers!

@gran0123
Copy link

gran0123 commented Jan 9, 2022

Yea, that worked. Not a fan of this setup but if it works, it works 😊 The only thing that is unclear, even tho we pass a cache to the apollo client is that it cant be reached server side.

const cacheResponse = apolloClient.readQuery({ query: getCarsQuery }); This code is exposed to another .ts file and this will always be null server side, since cache table only is available client side.

update:
Tested with the client directly in the index.svelte file, my be server still gets request even with data in the cache.
Tested with your ts example as well. Its calling the api constantly without checking the cache. Which means the cache is unecessary and useless to have.

@happysalada
Copy link

it looks like the library was updated 10 days ago (and there is a new release), it now includes an example with sveltekit.
however just testing, I get the following error.

Error [ERR_UNSUPPORTED_DIR_IMPORT]: Directory import '/Users/raphael/dev/nyt/node_modules/.pnpm/svelte-apo
llo@0.5.0_0797cffbf2a19052134926e8d6fad18a/node_modules/@apollo/client/core' is not supported resolving ES
 modules imported from /Users/raphael/dev/nyt/node_modules/.pnpm/svelte-apollo@0.5.0_0797cffbf2a1905213492
6e8d6fad18a/node_modules/svelte-apollo/dist/svelte-apollo.js
Did you mean to import @apollo+client@3.5.9_graphql@16.3.0/node_modules/@apollo/client/core/core.cjs?
    at new NodeError (internal/errors.js:322:7)
    at finalizeResolution (internal/modules/esm/resolve.js:314:17)
    at moduleResolve (internal/modules/esm/resolve.js:776:10)
    at Loader.defaultResolve [as _resolve] (internal/modules/esm/resolve.js:887:11)
    at Loader.resolve (internal/modules/esm/loader.js:89:40)
    at Loader.getModuleJob (internal/modules/esm/loader.js:242:28)
    at ModuleWrap.<anonymous> (internal/modules/esm/module_job.js:76:40)
    at link (internal/modules/esm/module_job.js:75:36)

in case anyone else has seen and experienced this.

@lorensr
Copy link

lorensr commented May 22, 2022

@happysalada I got that as well (also reported here: #119)

Adding this to my svelte.config.js worked:

      optimizeDeps: {
        exclude: ['@apollo/client', 'svelte-apollo'],
      },
      ssr: {
        noExternal: ['@apollo/client', 'svelte-apollo'],
      },

under kit.vite

@ayandebnath
Copy link

ref: #97 (comment)

@tmrp Thanks, it worked!

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

No branches or pull requests