Cannot access "buffer.Buffer" in client code (Svelte with Userbase)
Asked Answered
H

3

5

I'm writing an application using Svelte 3.44 and SvelteKit. I want to use Userbase (https://userbase.com/) 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@http://localhost:5173/node_modules/.vite/deps/userbase-js.js?v=b25ad0c3:151:17
node_modules/safe-buffer/index.js@http://localhost:5173/node_modules/.vite/deps/userbase-js.js?v=b25ad0c3:162:19
__require@http://localhost:5173/node_modules/.vite/deps/chunk-TWLJ45QX.js?v=b25ad0c3:8:50
node_modules/randombytes/browser.js@http://localhost:5173/node_modules/.vite/deps/userbase-js.js?v=b25ad0c3:225:19
__require@http://localhost:5173/node_modules/.vite/deps/chunk-TWLJ45QX.js?v=b25ad0c3:8:50
node_modules/diffie-hellman/lib/generatePrime.js@http://localhost:5173/node_modules/.vite/deps/userbase-js.js?v=b25ad0c3:3272:23
__require@http://localhost:5173/node_modules/.vite/deps/chunk-TWLJ45QX.js?v=b25ad0c3:8:50
node_modules/diffie-hellman/browser.js@http://localhost:5173/node_modules/.vite/deps/userbase-js.js?v=b25ad0c3:3554:25
__require@http://localhost:5173/node_modules/.vite/deps/chunk-TWLJ45QX.js?v=b25ad0c3:8:50
@http://localhost:5173/node_modules/.vite/deps/userbase-js.js?v=b25ad0c3:6166:37

Browsing for solutions I found two and none worked:

  1. 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.

  2. Adding Userbase SDK from index.html and calling it with window.userbase didn't work, because I got ReferenceError: 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.

Hearthside answered 14/8, 2022 at 16:45 Comment(0)
S
9

I've had the exact same issue and I've been able to solve it!

  1. Install buffer package, as correctly suggested by @H.B.: $ npm i buffer
  2. 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"
Selfexplanatory answered 20/8, 2022 at 18:44 Comment(1)
I just tested it and it works! Thank you. I wound up using a different architecture (my own server instead of Userbase) but hopefully this will help somebody else in the future.Hearthside
N
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
Nitrobacteria answered 14/8, 2022 at 18:52 Comment(2)
I added ssr: { noExternal: true,} in vite.config.js to prevent anything from being externalized and used your code snippet, first importing type and then inside onMount() importing the userbase object. There is some progress - I can see my Login component now. Unfortunately, when I open the browser console I still see Uncaught (in promise) Error: Module "buffer" has been externalized for browser compatibility. Cannot access "buffer.Buffer" in client code. and I can see that the userbase variable is still undefined.Hearthside
As I do not get the buffer error at all, I unfortunately cannot help with thatNitrobacteria
I
0

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/',
    },
  },
})
Idolize answered 15/11, 2022 at 15:1 Comment(1)
Indeed, this pointed me out in the right direction. First installed buffer module npm i buffer then added the alias in vite.config.ts as described (replace util by buffer) above ! But this still lacks some explanation on why this problem occurs and why we need an alias ?Varicolored

© 2022 - 2024 — McMap. All rights reserved.