Code Monkey home page Code Monkey logo

Comments (3)

freddy38510 avatar freddy38510 commented on June 3, 2024 1

You should add the pinia package to your app dependencies.

This lead to the circular object issue which is related to store state hydration. There is some circular references in the Session object.

When pre-rendering at server side, the store state is serialized and inlined in the page markup. Later when the page is rendered at client-side, the store is primed with server-initialized state.

The issue happens when serializing the state.

Anyway, I assume you don't want to initialize the client-side store state with a Session instantiated during SSR, so you can proceed as follows:

// https://github.com/renyuneyun/solid-helper-vue/blob/master/src/stores/session.ts

/**
 * The Session object. Reactivity is lost. Useful mainly for its functions (e.g. `fetch()`)
 */
session: typeof window !== 'undefined' ? new Session() : undefined, // no Session at server-side

Note that you can also serialize the state manually.

First enable the manualStoreSerialization option in the quasar.config.js file:

ssr: {
  manualStoreSerialization: true
},

Then create a Quasar boot file:

// src/boot/serialize-state.ts

import { boot } from 'quasar/wrappers'
import { stringify } from 'flatted'; // this package is used to serialize state, it handles circular object,
// You will need to add it to  your app dependencies

// "async" is optional;
// more info on params: https://v2.quasar.dev/quasar-cli/boot-files
export default boot(async ({ ssrContext }) => {
  if(!ssrContext) {
    return;
  }

  ssrContext.onRendered(() => {
    // at that time the store state is available in ssrContext.state
    // the lines below add a <script> to the pre-rendered markup that injects the serialized state into window.__INITIAL_STATE__
    // window.__INITIAL_STATE__ is used at client-side to prime the store

    const autoRemove = 'document.currentScript.remove()'

    ssrContext._meta.headTags = `<script>window.__INITIAL_STATE__=${stringify(ssrContext.state)};${autoRemove}</script>`+ ssrContext._meta.headTags;
  })
})

And only use it server-side:

// quasar.config.js

boot: [{
  client: false,
  path: 'serialize-state'
}],

from quasar-app-extension-ssg.

renyuneyun avatar renyuneyun commented on June 3, 2024

Thanks for the explanation a lot. However, after applying the first patch, another (or a related?) Pinia issue is still there:

TypeError: pinia is undefined
    useStore pinia.mjs:1705
    setup IndexPage.vue:15
    callWithErrorHandling runtime-core.esm-bundler.js:158
    setupStatefulComponent runtime-core.esm-bundler.js:7331
    setupComponent runtime-core.esm-bundler.js:7292
    mountComponent runtime-core.esm-bundler.js:5687
    hydrateNode runtime-core.esm-bundler.js:4691
    hydrateSubTree runtime-core.esm-bundler.js:5763
    componentUpdateFn runtime-core.esm-bundler.js:5783
    run reactivity.esm-bundler.js:178
    update runtime-core.esm-bundler.js:5902
    setupRenderEffect runtime-core.esm-bundler.js:5910
    mountComponent runtime-core.esm-bundler.js:5700
    hydrateNode runtime-core.esm-bundler.js:4691
    hydrateChildren runtime-core.esm-bundler.js:4853
    hydrateElement runtime-core.esm-bundler.js:4809
    hydrateNode runtime-core.esm-bundler.js:4672
    hydrateSubTree runtime-core.esm-bundler.js:5763
    componentUpdateFn runtime-core.esm-bundler.js:5783
    run reactivity.esm-bundler.js:178
    update runtime-core.esm-bundler.js:5902
    setupRenderEffect runtime-core.esm-bundler.js:5910
    mountComponent runtime-core.esm-bundler.js:5700
    hydrateNode runtime-core.esm-bundler.js:4691
    hydrateChildren runtime-core.esm-bundler.js:4853
    hydrateElement runtime-core.esm-bundler.js:4809
    hydrateNode runtime-core.esm-bundler.js:4672
    hydrateSubTree runtime-core.esm-bundler.js:5763
    componentUpdateFn runtime-core.esm-bundler.js:5783
    run reactivity.esm-bundler.js:178
    update runtime-core.esm-bundler.js:5902
    setupRenderEffect runtime-core.esm-bundler.js:5910
    mountComponent runtime-core.esm-bundler.js:5700
    hydrateNode runtime-core.esm-bundler.js:4691
    hydrateSubTree runtime-core.esm-bundler.js:5763
    componentUpdateFn runtime-core.esm-bundler.js:5783
    run reactivity.esm-bundler.js:178
    update runtime-core.esm-bundler.js:5902
    setupRenderEffect runtime-core.esm-bundler.js:5910
    mountComponent runtime-core.esm-bundler.js:5700
    hydrateNode runtime-core.esm-bundler.js:4691
    hydrateSubTree runtime-core.esm-bundler.js:5763
    componentUpdateFn runtime-core.esm-bundler.js:5783
    run reactivity.esm-bundler.js:178
    update runtime-core.esm-bundler.js:5902
    setupRenderEffect runtime-core.esm-bundler.js:5910
    mountComponent runtime-core.esm-bundler.js:5700
    hydrateNode runtime-core.esm-bundler.js:4691
    hydrateSubTree runtime-core.esm-bundler.js:5763
    componentUpdateFn runtime-core.esm-bundler.js:5783
    run reactivity.esm-bundler.js:178
    update runtime-core.esm-bundler.js:5902
    setupRenderEffect runtime-core.esm-bundler.js:5910
    mountComponent runtime-core.esm-bundler.js:5700
    hydrateNode runtime-core.esm-bundler.js:4691
    hydrateSubTree runtime-core.esm-bundler.js:5763
    componentUpdateFn runtime-core.esm-bundler.js:5783
    run reactivity.esm-bundler.js:178
    update runtime-core.esm-bundler.js:5902
    setupRenderEffect runtime-core.esm-bundler.js:5910
    mountComponent runtime-core.esm-bundler.js:5700
    hydrateNode runtime-core.esm-bundler.js:4691
    hydrate runtime-core.esm-bundler.js:4555
    mount runtime-core.esm-bundler.js:3853
    mount runtime-dom.esm-bundler.js:1486
    start client-entry.js:72
    promise callback*start client-entry.js:70
    promise callback* client-entry.js:79

[runtime-core.esm-bundler.js:226:12](http://127.0.0.1:4000/@vue/runtime-core/dist/runtime-core.esm-bundler.js)
Hydration completed but contains mismatches.

This can be reproduced regardless of which variant used in the other repo.
After clicking the line of code (i.e. the link with useStore pinia.mjs:1705), it jumps to a pinia source file under the helper library (solid-helper-vue/node_modules/pinia/), rather than a pinia source file under the main/application project. I can confirm that Pinia is installed in the main/application project, and a separate pinia source file exists in node_modules/pinia/.
(I also tried to remove the node_modules directory in my filesystem under solid-helper-vue, which seems to be irrelevant.)

Presumably this is caused because that separate pinia source results in a separate "instance" of pinia which is not properly initialized?
It seems somehow the dependency resolution / reproduction in the SSR/SSG is problematic? Or maybe I misconfigured somewhere, which made pinia not fully externalized or not recognized?

from quasar-app-extension-ssg.

freddy38510 avatar freddy38510 commented on June 3, 2024

The vue and pinia packages should not be direct dependencies of your library. You should add them as peerDependencies. It is the responsibility of the consumer of your library to install them. In your case, the consumer is your Quasar application.

For the @inrupt/solid-client-authn-browser package, you can add it as a direct dependency of your library, because your library seems to using it internally to provide authentication via actions and exposes the Session via its store state.
It means you should also remove this package from your Quasar app.

You should also add vue and pinia to the rollup external option. The @inrupt/solid-client-authn-browser package should be added to the rollup external option, only for ESM output format, because it will be handled by the consumer via a bundler (vite, webpack, etc...). The only case this package should be bundled in your library (not added to the rollup external option) is for the UMD output format.

Your issue about pinia occurs because the dep is loaded from your library instead of your Quasar app. This is because the dep is resolved locally ../../solid-helpers-vue where Node.js find a node_modules folder containing the pinia package. To solve this, I would recommend you to use yalc for development purposes.

To use your library correctly for SSR, don't forget to change this line:

session: typeof window !== 'undefined' ? new Session() : null

It should be set to null and not undefined for SSR, otherwise, the session property will not be defined when the store state will be primed with the server-initialized state at client-side, therefore it cannot be modified later.

To actually create a new Session instance at client-side, I would recommend you these lines of code:

import { onMounted } from 'vue';
import { useSessionStore } from 'solid-helper-vue';

const sessionStore = useSessionStore();

onMounted(() => {
  if (sessionStore.session === null) {
    sessionStore.$reset() // reset the state only at client-side when the component is mounted to avoid hydration mismatches
  }
})

from quasar-app-extension-ssg.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.