SSR: Question about CSS and "flickering" + another question



  • Hello everyone

    Starting a SSR app, I have two difficulties.

    • First question: When I use CSS in the <style scoped> section of a component and when the page is loading, the text is “flickering” (for instance the text color or size of the font), meaning that the CSS is not applied before the PWA takes over the server-side rendering. Is it a normal behavior? Using inline CSS works, but it is quickly become ugly especially because I have a dynamic theming system, and so I end up doing things like that:
    <h1 :style="'color: '+getSite.color5">{{ getArticle.title }}</h1>
    

    While I expected to be able to do something like that:

    <style lang="scss" scoped>
    h1 {
      font-size: 2rem;
      color: var(--q-color-color5) !important;
    }
    </style>
    

    But if I do that, the H1 appears first as the standard one, and then the font is changed, which is ugly.

    • Second question: I have an q-list embeded in an q-infinite-scroll. The q-infinite-scroll is loading items through an Axios request to the backend. Problem: this is not very good for SEO as the list will just be empty for a search engine. Is there a mean to Prefetch the first items, and then use the callback of q-infinite-scroll to get additional elements?

    I tried something like that but without success:

    <q-infinite-scroll ref="infiniteScroll" @load="onLoad" intial-index="1" :offset="250">
    

    and in onLoad:

    onLoad (index, done) {
          if (index === 1) {
               done()
          }
          if (this.more_pages) {
            Loading.show()
            this.$store.dispatch('main/getArticles', { page: index, category: this.currentTab }).then((data) => {
             // new items are added in the vuex Store
             
              if (data.meta.current_page >= data.meta.last_page) {
                this.more_pages = false
              }
              Loading.hide()
    
              done()
            })
          } else {
            done(true)
          }
        },
    

    With a Prefetch function to collect the first 10 elements and to put them in the Store. But this is not working - onLoad is called with index = 2 immediately on page load.

    Many thanks!



  • @ju11 For the css, I can’t say for sure as I just use global css in my SSR app and it works fine, but you’d lose the scoped behavior doing that.

    For the list, how are you calling your prefetch? If using quasar’s prefetch, you wouldn’t have access to this.currentTab, which would cause an issue. And also it only works on route components which I’m not sure your component is.

    Maybe try putting it in the created hook?

    created() {
      if(process.env.SERVER) {
        // call your ajax, and put results into store
      }
    }
    


  • Many thanks @beets!

    I finally had the solution for Problem 1, and for Problem 2 I need to test more by prefetching some items for the infinite scroll.

    Solution for Problem 1

    • Scoped styles work for SSR (I had a doubt so I prefer to mention it for others)
    • The background problem was with my custom colors, which led me in the wrong direction.
    • Initially I called colors.setBrand() in beforeMount() of App.vue. This not the good way to customize the theme for SSR as it produces a flickering effect. Quite logicial: beforeMount() is only executed client-side.

    Solution provided on Discord by @Tobias-Mesquita (thanks!): defining a custom setBrand() function modifying body styles in the SSR Context:

    import { colors } from 'quasar'
    function setBrand(color, value, ssrContext) {
      if (ssrContext) {
        ssrContext.MY_BODY_STYLES = (ssrContext.MY_BODY_STYLES || '') + `--q-color-${color}: ${value};`
      } else {
        colors.setBrand(color, value)
      }
    }
    
    export default async function ({ app, ssrContext }) {
      const { data = theme } = await app.axios.get('...')
      setBrand('primary', theme.color1, ssrContext )
      setBrand('color1', theme.color1, ssrContext )
    }
    

    It can be a boot file (I guess) but I directly used the custom setBrand() function in my Prefetch function of App.vue.

    Then, in index.template.html:

    <body style="{{{ MY_BODY_STYLES }}}">
      <!-- DO NOT touch the following DIV -->
      <div id="q-app"></div>
    </body>
    

    By doing this, the custom colors are integrated server-side and not client-side, which solves the issue.


Log in to reply