Cannot Access "Buffer. Buffer" in Client Code (Svelte with Userbase)
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...
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"
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
This idea may help: Module "util" has been externalized for browser compatibility. Cannot access "util.promisify" in client code Something like this:
export default defineConfig({
resolve: {
alias: {
util: 'util/',
},
},
})