svelte-persistent-store icon indicating copy to clipboard operation
svelte-persistent-store copied to clipboard

Error: constructor undefined when using with (3rd party library) object

Open EliasBeyer opened this issue 2 years ago • 1 comments

I tried to use localStorage to store an object from another library and get this error:

TypeError: e2.constructor is undefined
    a index.mjs:1
    a index.mjs:1
    a index.mjs:1
    A index.mjs:1
    setValue index.mjs:1
    x index.mjs:1
    subscribe index.mjs:1
    x index.mjs:1
    X index.mjs:1
    H index.mjs:1
    <anonymous> store.js:19
app.js:16:41

Steps to reproduce:

  • npm create svelte@latest my_test (doesn't matter the configuration, tested with skeleton app, without types and with typescript, no linter etc)
  • install this library and another external one: npm install @macfja/svelte-persistent-store and npm install obs-websocket-js
  • create src/routes/store.js:
import { localWritable } from "@macfja/svelte-persistent-store"
import { writable } from "svelte/store"
import OBSWebSocket from 'obs-websocket-js';

export class BaseMyObj {}
class MyObj extends BaseMyObj {}

// export const obs = writable( new OBSWebSocket() ) // works
export const myobj = localWritable( "myobj" , new MyObj() ) // works
export const obs = localWritable( "obs" , new OBSWebSocket() ) // error
  • use store.js in +page.svelte: import { myobj } from "./store"

I am fairly new to webdev/js/svelte so it might be an error on my side.

What I have tried so far:

  • changed the sveltekit configuration (JS/TS) with the same error
  • tried to dig into the error itself, but there is no e2 or e2.constructor anywhere in the minified JS in the browser
  • tried to recreate the error with a custom class (that extends a base class) in JS/TS, these work just fine
  • also used the base functions (persist and all the available alias for localstorage) with the same error

I guess this error may be specific for the combination of those two libraries, however I lack the insight of both libraries to get into it deeper, especially with other 3rd party packages

EliasBeyer avatar Jul 25 '23 21:07 EliasBeyer

Why do you need to persist a (Web)socket ? A socket is a connection that will be opened and closed, and should not (IMO) be persisted in application data

What is the data you need to store/persist ? From my vague understanding, what should be persisted is how to open a connection


OBSWebSocket is complex object that need some custom code to be persisted. (In particular, OBSWebSocket use EventEmitter which alter the standard object structure, needed to automagically save a class)

This lib can't handle this as-is. But the lib that @macfja/svelte-persistent-store rely on can!

// Somewhere in a init script
import { setSerialization } from "@macfja/svelte-persistent-store"
import { serialize, deserialize, addGlobalAllowedClass, addClassHandler } from "@macfja/serializer"
import { OBSWebSocket } from "obs-websocket-js";

addClassHandler(OBSWebSocket.constructor.name, (instance) => ({
    url: instance.socket.url,
    protocol: instance.protocol
    // any data that you need to save
}), (saved) => {
    const instance = new OBSWebSocket();
    instance.protocol = saved.protocol;
    instance.connect(saved.url);
    return instance;
})
setSerialization(serialize, deserialize, addGlobalAllowedClass)

// Now `@macfja/svelte-persistent-store` know how to save and load a `OBSWebSocket` in any futur call of `persist`

Warning It's impossible to know any parameters used in OBSWebSocket.connect except for the url

MacFJA avatar Jul 28 '23 19:07 MacFJA