Closed Pixselve closed 2 years ago
Thanks for reporting this one @Pixselve - i'll transfer it to the JS library repo
Related? vitejs/vite/pull/2996
Could be - we already had to do a bunch of work to make Vite work:
https://github.com/supabase/supabase-js/issues/89 https://github.com/supabase/supabase-js/issues/155
Is this still causing problems on the latest supabase-js?
I've been trying to get this working over the weekend, my package.json is:
{
"devDependencies": {
"@commitlint/cli": "^12.1.1",
"@commitlint/config-conventional": "^12.1.1",
"@sveltejs/adapter-node": "next",
"@sveltejs/adapter-vercel": "^1.0.0-next.10",
"@sveltejs/kit": "next",
"autoprefixer": "^10.2.5",
"cssnano": "^5.0.0",
"husky": "^6.0.0",
"openapi-typescript": "^3.2.3",
"postcss": "^8.2.10",
"postcss-load-config": "^3.0.1",
"prettier": "~2.2.1",
"prettier-plugin-svelte": "^2.2.0",
"pretty-quick": "^3.1.0",
"svelte": "^3.29.0",
"svelte-preprocess": "^4.7.0",
"tailwindcss": "^2.1.1",
"tslib": "^2.0.0",
"typescript": "^4.0.0",
"vite": "^2.1.0"
},
"type": "module",
"dependencies": {
"@supabase/supabase-js": "^1.11.6"
},
}
With the following svelte.config.cjs
module.exports = {
preprocess: [
sveltePreprocess({
defaults: {
style: "postcss",
},
postcss: true,
}),
],
kit: {
adapter: vercel(),
target: "#svelte",
vite: {
ssr: {
noExternal: process.env.NODE_ENV === 'production' ? Object.keys(pkg.dependencies || {}) : []
},
},
},
};
Deploying this configuration to vercel serverless produces the "XMLHTTPRequest is not defined" error in production. In dev mode it works fine, but if you build and run yarn start
you can see the error.
Edit: updated config to correctly reproduce error.
In the generated code you can clearly see the browserPonyfill being inlined instead of node-fetch.
From server/app.mjs
I note that the PR mentioned above has already been merged. I tried building Vite locally and it doesn't appear to make a difference.
Strongly suspect this is https://github.com/lquixada/cross-fetch/issues/78 "Cross-fetch is not usable in service workers" in disguise.
In that case, you could try this: https://github.com/supabase/supabase/tree/master/examples/with-cloudflare-workers
async function supabaseInsert (table, arg) {
return fetch(`${supabaseUrl}/rest/v1/${table}`, {
headers: {
Apikey: supabaseKey,
Authorization: `Bearer ${supabaseKey}`,
"Content-Type": "application/json",
Prefer: "return=representation"
},
method: "POST",
body: JSON.stringify(arg)
})
}
async function supabaseFrom (table, filter) {
return fetch(`${supabaseUrl}/rest/v1/${table}?${filter}`, {
headers: {
Apikey: supabaseKey,
Authorization: `Bearer ${supabaseKey}`,
}
})
}
got it done after an hour or two of npm misadventures.
In any case, appreciate the prompt response @kiwicopple ! Supabase is working marvelously and took exactly one evening to actually get working. The exploration also introduced me to postgrest, which seems a phenomenal building block for supabase's product! Cheers!
I think I've gotten to the bottom of this.
Serverless deployments require bundling of node_modules. That's why you need noExternal
to include all node dependencies otherwise you get errors during deployment. This causes dev mode to break, so only add node deps to noExternal
when process.env.NODE_ENV = "production.
Vite creates two bundles, a server bundle "functions/node/render/server/app.mjs" and a client bundle "static/_app/*". The problem is that it only reads dependencies once:
First off, cross-fetch
always resolves to the browser entry point. The way the entry point is resolved does not take into account whether the bundler is in SSR mode or not.
resolvedImports['.']
or flush it between each phase.So my hacky workaround at the moment is to force disable the browser entry point during SSR module generation, and to disable module caching.
This will need to be fixed by Vite.
Hi all, I think this issue can be fixed all the way at the core dependency, even deeper than cross-fetch
, but might require more input and attention to actually push it through. It could fix not just this problem, but a lot of other tangential issues as well.
Hey @jcs224 - it looks like the linked issue was resolved. Does it also solve this issue?
Just tried using the same code in the repository when I started the issue (I only updated svelte kit) and it now works perfectly. Thanks to you all!
@Pixselve interesting it worked for you.. cross-fetch
hasn't yet updated the dependency needed with the underlying changes. :thinking: Maybe Vite made some adjustment that made it work?
@kiwicopple I think the change is going to have to propagate through cross-fetch
before it will do us any good. Maybe I'll bump this again on the cross-fetch
side.
It looks like FaunaDB solved this. Essentially, they added an extra config argument that allows users to opt-out of cross-fetch by passing in a custom fetch function.
Issue: https://github.com/fauna/faunadb-js/issues/207 PR: https://github.com/fauna/faunadb-js/pull/214
So a potential solution for this is:
import { createClient } from '@supabase/supabase-js'
export const supabase = createClient(
import.meta.env.VITE_SUPABASE_URL,
import.meta.env.VITE_SUPABASE_KEY,
{
fetch: import.meta.env.USE_NATIVE_FETCH ? fetch : undefined,
}
)
If no fetch is provided, cross-fetch is used. @kiwicopple, would this be straightforward to implement?
Hi there, I believe this is why I'm getting this error with svelte kit and supabase:
__layout.svelte
<script lang="ts">
import { user } from '../store/sessionStore';
import { supabase } from '$lib/supabaseClient';
import { browser } from '$app/env';
user.set(supabase.auth.user());
if (browser) {
supabase.auth.onAuthStateChange((event, session) => {
console.log('updating with', session);
user.set(session!.user);
});
}
</script>
<slot />
Hope to get a fix soon. Thank you all for your hard work.
I've opened several PRs that allow specifying a custom fetch
implementation as an option - ideally I think cross-fetch
should support environments like Cloudflare Workers given its use in the ecosystem, but a custom fetch
option enables a workaround today, gives flexibility for future environments (e.g. ones that don't yet exist or are more esoteric), and allows you to provide a mocked fetch
for testing or otherwise customize fetch
based on your specific needs.
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('url', 'key', { fetch: fetch })
The main @supabase/supabase-js
library wraps other client libraries, so each needs a PR to enable the option.
Wrapped Clients
supabase-js
(depends on the other three PRs)
FYI this also happens when supabase-js is used within NextJS 12 middleware. Since the PRs above aren't merged yet, I am not sure there's a solution other than using the REST API directly over the SDK.
Thanks to a very impressive series of PRs from @jacobwgillespie , this now has a workaround
https://github.com/supabase/supabase-js/releases/tag/v1.27.0
after upgrading to v1.27.0 you can use a custom fetch
implementation
import { createClient } from '@supabase/supabase-js'
// Provide a custom `fetch` implementation as an option
const supabase = createClient('https://xyzcompany.supabase.co', 'public-anon-key', { fetch: fetch })
Jacob - if you send your details (and tshirt size) to swag@supabase.io we will send you a nice package 🙏
Hello @kiwicopple it's not working for me, i do it createClient('..','..',{fetch:fetch}) but it still doesn't work, Cloudflare workers shows Invalid invocation
@PH4NTOMiki that's probably unclear documentation on my part, I believe if you directly pass the native fetch
function as the custom fetch
, JavaScript will treat this as an "illegal invocation" as it tries to execute a native method in the context of the Supabase options argument rather than in the global context it was attached to.
You can pass a custom function or bind the fetch
function to work around that issue. For Cloudflare Workers specifically, there is no global
or window
object like you'd have in other runtimes, but you do have self
, so:
const supabase = createClient('...', '...', {fetch: fetch.bind(self)})
Really the example I added to the README should have probably been { fetch: customFetch }
to avoid confusion, I can look at opening a few more PRs. 🙂
Hello @kiwicopple it's not working for me, i do it createClient('..','..',{fetch:fetch}) but it still doesn't work, Cloudflare workers shows Invalid invocation
I'm getting a similar issue — adding const supabase = createClient('...', '...', {fetch: fetch.bind(self)})
still results in the XMLHTTPrequest error when deployed on Cloudflare pages.
@jacobwgillespie @kiwicopple can you provide a code example of what that customFetch function should be and how it should be included in an endpoint?
In my case, here is the original call I'm making
async function submitForm(e) {
var formData = new FormData(e.target);
formData.append('loaded_address', loaded_address);
formData.append('address', address);
const response = await fetch(`./submitform`, {
method: 'post',
body: formData
})
response.ok ? ( form_submit = "success" ) : (form_submit = "error" )
}
And here is the SvelteKit endpoint it hits, which makes the Supabase request and produces the FetchError: XMLHttpRequest is not defined
error:
// import supabase from "$lib/db"
import { variables } from '$lib/variables';
import { createClient } from '@supabase/supabase-js'
const supabase = createClient( import.meta.env.VITE_SUPABASE_URL,
import.meta.env.VITE_SUPABASE_ANON_KEY, { fetch: fetch })
export async function post(request) {
const {data, error} = await supabase
.from('support_responses')
.insert({support_info: request.body.get('support_info'), introduction: request.body.get('introduction'), contact: request.body.get('contact'), loaded_location: request.body.get('loaded_address'), searched_location: request.body.get('address')})
if (error) {
return {
status: 500,
body: error
}
}
else {
return {
status: 200,
body: {
data
}
}
}
}
@sbutler-gh I believe you want this when creating the client in Cloudflare Workers:
const supabase = createClient( import.meta.env.VITE_SUPABASE_URL,
import.meta.env.VITE_SUPABASE_ANON_KEY, { fetch: fetch.bind(self) })
Note the fetch: fetch.bind(self)
. It would probably also work with fetch: (...args) => fetch(...args)
.
@sbutler-gh I believe you want this when creating the client in Cloudflare Workers:
const supabase = createClient( import.meta.env.VITE_SUPABASE_URL, import.meta.env.VITE_SUPABASE_ANON_KEY, { fetch: fetch.bind(self) })
Note the
fetch: fetch.bind(self)
. It would probably also work withfetch: (...args) => fetch(...args)
.
Huge thanks for the help on this @jacobwgillespie . When I try fetch: fetch.bind(self)
, I get the following error locally and when building for production:
Error when evaluating SSR module /Users/sam/just-start/src/routes/submitform.js: ReferenceError: self is not defined at /Users/sam/just-start/src/routes/submitform.js:7:65 at async instantiateModule (/Users/sam/just-start/node_modules/vite/dist/node/chunks/dep-f5e099f1.js:66443:9) self is not defined ReferenceError: self is not defined at /Users/sam/just-start/src/routes/submitform.js:7:65 at async instantiateModule (/Users/sam/just-start/node_modules/vite/dist/node/chunks/dep-f5e099f1.js:66443:9)
When I try fetch: (...args) => fetch(...args)
, it works in development and when building locally, but results in the same XMLHTTPrequest
error when deployed on CF. Any other thoughts?
@sbutler-gh I think your repo isn't actually using the up-to-date version of @supabase/supabase-js
, see here:
It appears it's using version 1.24.0, and the ability to pass in a custom fetch implementation was added in 1.27.0 (and 1.28.1 is the latest version).
@sbutler-gh I think your repo isn't actually using the up-to-date version of
@supabase/supabase-js
, see here:sbutler-gh/just-start@
c32ecef
/package-lock.json#L325-L326It appears it's using version 1.24.0, and the ability to pass in a custom fetch implementation was added in 1.27.0 (and 1.28.1 is the latest version).
After running npm update
to update packages and re-deploying, it now works as expected in production on Cloudflare Pages! (using fetch: (...args) => fetch(...args)
, didn't try the other syntaxes yet.). Thank you SO MUCH @jacobwgillespie ! I can't thank you enough!
For Next users wondering if this (v1.27+) allows Supabase client use in the middleware API - yes:
import { createClient } from '@supabase/supabase-js';
import { NextRequest, NextResponse } from 'next/server';
export async function middleware(request: NextRequest) {
const supabase = createClient(process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, { fetch });
…
This works great and there is not even need to rebind fetch
using fetch.bind(self)
or (...args) => fetch(...args)
!
Is there probably a regression in the 2.0 branch? I have trouble getting the server side code to work. Tried the new {global: {fetch: ...}} config option. But that doesn't seem to work. Even using Node 18 didn't help.
It's a vite/sveltekit project.
require is not defined
ReferenceError: require is not defined
at [...]/node_modules/.pnpm/cross-fetch@3.1.5/node_modules/cross-fetch/dist/node-ponyfill.js:1:32
at instantiateModule (file:///[...]/node_modules/.pnpm/vite@3.1.8/node_modules/vite/dist/node/chunks/dep-4da11a5e.js:53445:15)
Bug report
Describe the bug
Using the client for auth or for querying the database in a sveltekit endpoint throw an error :
To Reproduce
I made a repository exposing the issue : https://github.com/Pixselve/supabase-sveltekit-endpoints Click on a button to fetch the endpoint and observe the cloud functions logs on Vercel.
Expected behavior
Requests should not fail and should give the appropriate data.
System information