Skip to content

[BUG] @geajs/ssr: store serialization fails on symbol-keyed items; select value binding crashes linkedom shim #88

Description

@mehmetfiskindal

Describe the bug

Two independent issues break renderToString for form-heavy apps:

1. Store serialization fails with DevalueError: Cannot stringify POJOs with symbolic keys

The keyed-list runtime stamps bookkeeping symbols directly onto raw store items (Symbol.for('gea.d.dirty'), and a Symbol('gea.itemKey')-keyed Set on parents) via the reactive proxy set trap. After rendering, serializeStores() walks the live proxied store tree with devalue's uneval(), which refuses POJOs that have symbolic own properties:

[gea-ssr] Render error: DevalueError: Cannot stringify POJOs with symbolic keys
    at walk (devalue/src/uneval.js:122)
    at serializeStores (@geajs/ssr/dist/chunk-KDLSDZE2.js:441)
  path: '.cvStore.data.education[0]'

Any SSR app whose rendered output includes a keyed .map() over store arrays hits this on every request.

Suggested fix: sanitize symbol-keyed own properties (deep clone keeping only string keys / values devalue supports) before calling uneval() in serializeStores.

2. <select value={...}> crashes under the linkedom shim

@geajs/ssr uses linkedom as its DOM shim, but linkedom's HTMLSelectElement declares value as a getter-only property. The compiler emits el.value = ... writes for value bindings, which throw in strict mode:

TypeError: Cannot set property value of [object Object] which has only a getter

Repro: render any component containing <select value={someStoreValue} ...> during SSR.

Suggested fix: in installDom(), define a value setter on the shimmed select prototype that updates the matching option's selected flag (linkedom's HTMLOptionElement.selected setter already handles deselecting siblings).

Affected versions

@geajs/ssr@1.0.4, @geajs/core@1.4.0, @geajs/vite-plugin@1.4.1

Workarounds we applied locally

  • Sanitize symbol keys before uneval() in serializeStores
  • Patch linkedom's HTMLSelectElement.prototype.value with a setter before rendering

Happy to send PRs for both if you'd like.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions