I'm writing an application using Svelte 3.44 and SvelteKit. I want to use Userbase () for user authentication and data storage.
I have a component Login.svelte in which I want to call Userbase API for signing up and logging in. The relevant code is:
<script lang="ts"> import userbase from 'userbase-js'; /* Irrelevant code here */
</script>When I try to run this using vite dev, then instead of my Login component I see:
500
Module "buffer" has been externalized for browser compatibility. Cannot access "buffer.Buffer" in client code.
get@
node_modules/safe-buffer/index.js@
__require@
node_modules/randombytes/browser.js@
__require@
node_modules/diffie-hellman/lib/generatePrime.js@
__require@
node_modules/diffie-hellman/browser.js@
__require@
@Browsing for solutions I found two and none worked:
Using dynamic import with OnMount() seems to work, but I can't use the imported module anywhere else outside of OnMount() because of TypeScript type checking.
Adding Userbase SDK from index.html and calling it with
window.userbasedidn't work, because I gotReferenceError: window is not defined. If I only use it inside OnMount(), then I'm back with problem number one.
To sum up:
If anyone has overcome the Cannot access "buffer.Buffer" in client code problem, please tell me how you did that.
Excuse me if this is a stupid question, I'm an embedded developer, this is one of my first encounters with Web Development.
3 Answers
I've had the exact same issue and I've been able to solve it!
- Install
bufferpackage, as correctly suggested by @H.B.:$ npm i buffer - Add this snippet to your
index.html:
<script>
/** * this is a hack for error: global is not defined */
var global = global || window
</script>Got this little gem from this GitHub comment
My component logic so far is:
<script> import { onMount } from 'svelte'; import userbase from 'userbase-js'; onMount(() => { userbase.init({ appId: '...' }) });
</script>Versions:
"@sveltejs/kit": "next" "svelte": "^3.44.0", "typescript": "^4.7.4", "vite": "^3.0.4" 1 I cannot reproduce this exact issue, maybe you are using a different version of Vite. You could try to prevent buffer from being externalized by adding it to ssr.noExternal.
I get a different error which also suggests that the module should be imported only in the browser.
Accessing something outside of onMount is only a typing or scoping issue. If you import it in a component you can declare a variable outside of onMount. It will be undefined until the import has completed:
<script lang="ts"> import { onMount } from 'svelte'; import type { Userbase } from 'userbase-js'; let userbase: Userbase | undefined; onMount(async () => { window.global = window; // If you get a "global is not defined error" userbase = await import('userbase-js').then(x => x.default); });
</script>If you import the script elsewhere globally, you should be able to access window.userbase, the type declaration files of the module already define this :
// Expose as userbase when loaded in an IIFE environment
export as namespace userbase 2 This idea may help:Module "util" has been externalized for browser compatibility. Cannot access "util.promisify" in client codeSomething like this:
export default defineConfig({ resolve: { alias: { util: 'util/', }, },
}) 1