@aleksejdix

<div id="app"></div>

 Aleksej Dix

 Front End Developer

@aleksejdix

aleksej.dix@oddeven.ch

https://oddeven.ch

nuxt.js

Sébastien & Alexandre
Chopin

GraphQL

Why SSR

@aleksejdix

  • BETTER FOR SEO
  • FASTER WEBSITES
  • BETTER UX
  • CAN BE COMPLICATED

CONS:

PROS:

@aleksejdix

CONS: CAN BE COMPLICATED

SSR?

REQUEST

RESPONSE

SERVER

CLIENT

1. HTTP

REQUEST

HTTP

RESPONSE

SERVER

CLIENT

GRAPHQL API

GraphQL

Query

GraphQL

RESPONSE

GQL REQ

GQL RES

@aleksejdix

  • public
  • SEO
  • behind auth
  • internal

no

yes

WHEN TO SSR?

@aleksejdix

  • NO `window` OBJECT
  • NO Browser API's
  • NO Reactive Data
  • Some libraries won't work
  • Vue directives need SSR fallback
 

LIMITS:

  • EVERY Request creates fresh Vue.js instance
     
  • Axios, node-fetch or Apollo client are required for data fetching

!!! WARNING !!!

npx create-nuxt-app <project-name>

create an app

yarn create nuxt-app <project-name>
<template>
  <h1>
    Hello, Konstanz!
  </h1>
</template>

<script>
  export default {

  }
</script>

<style scoped>

</style>

pages/index.vue

import Vue from 'vue'
import Router from 'vue-router'

const _94b0fd58 = () => import('../pages/index.vue')

Vue.use(Router)

export function createRouter() {
  return new Router({
    mode: 'history',
    routes: [{
      path: "/",
      component: _94b0fd58,
      name: "index"
    }]
  })
}

automatic router

Hello, Konstanz!
<body data-n-head="">
  <div data-server-rendered="true" id="__nuxt">
    <h1>Hello, Konstanz!</h1>
  </div>
</body>

client/browser


<script>
import speakersQuery from './graphql/query/speakers'

export default {
  data() {
    return {
      speakers: []
    }
  },
  mounted() {
    axios.$post('', speakersQuery).then(speakers => {
      this.speakers = speakers
    }) 
  }
}
</script>

async?

view page source

<div id="app"></div>

🤔

export default {
 
  asyncData(context) {}

  fetch(context) {} 

  nuxtServerInit(store, context) {}

}

no `this`, but `context`

NEW HOOKS

 🤩

context

  • query
  • params
  • res
  • req
  • redirect
  • route
export default {
 
  asyncData() {
    return axios.$post('', speakers)
      .then(speakers => ({ speakers }) 
  }

}

asyncData

<script>
  window.__NUXT__=(function(a){
    return {	
      layout: "default",
      data: [{
        speakers: [{
          id:"cjnirn6wim84h0932hrvvrc82", 
          name: "Jesse Martin"
        }]
      }],
      error: null,
      serverRendered:true 
    }
  }(400));
</script>

__NUXT__

view page source

<div id="app">
 <h1>Jesse Martin</h1>
</div>

 🤩

SSR works!

<template>
  <form @submit.prevent="askServer">
    <input type="search" v-model="search"/>
    <button>search<button>
  </form>
</template>

goodbye GET

?search=GETPARAMS

 

💀⚰️

URL is your friend

REQUEST

RESPONSE

SERVER

domain.com/speakers?sort=DESC

will resolve GraphQL Query and send sorted data back to the client

make your

URL PARAMETER reactive

export default {
  data() {
    return {
      page: ''
    } 
  },
  watch: {
    '$route.query.page'(page) {
      this.page = page
      this.submit()
    }
  }
}

watch

vuex
redux
apollo

URL

VS

recreate the state on every request

 

Dynamic Pages

domain.com/speaker/{id}

 
  async asyncData(context) {
    const { id } = context.route.params
    const speakerQuery = {
      query: `query speaker ($id: ID!) {
        speaker (
          where: {
            id: $id
          }
        ) {
          ${speakersFields}
        }
      }
      `,
      variables: { id }
    }
    const { data : {speaker}} = await context.$axios
    	.$post('', speakerQuery)
    
    return { speaker }
  }

const defaultData = {
  talks: [],
  perPage: 10,
  page: 1,
  talksCount: 0,
}

export default {
  components: { Talk, Pagination },
  computed: {
    skip () {
      return this.page * this.perPage - this.perPage;
    }
  },
  data() {
    return defaultData
  },
  watch: {
    '$route.query.page': {
      handler (newPage = 1) {
        this.page = +newPage
      },
      immediate: true
    }
  },
  apollo: {
    talks: {
      query: QueryTalks,
      variables () {
        return {
          skip: this.skip,
          first: this.perPage,
        };
      },
    },
    talksCount: {
      query: QueryTalksCount,
      update: ({ talksConnection }) => talksConnection.aggregate.count
    }
  }
}
</script>

<script>
export default {
  apollo: {
    speaker: {
      query: QuerySpeaker,
      variables () {
        return {
          id: this.$route.params.id
        };
      }
    }
  },
  data() {
    return {
      speaker: ""
    }
  }
}
</script>

VUE META

export default {
  head () {
    return {
      title: 'Aleksej Dix - webzueri.ch',
      meta: [
        { 
          hid: 'description', 
          name: 'description', 
          content: 'Front-end Developer and webzurich organizer' 
        }
      ]
    }
  }
}

ApOLLO

export default {
  apollo: {
    speakers: {
      query: QuerySpeakers,
      variables () {
        return {
          skip: this.skip,
          first: this.perPage,
        };
      },
    },
    speakersCount: {
      query: QuerySpeakersCount,
      update: ({ speakersConnection }) => speakersConnection.aggregate.count
    }
  }
}

THANKS!

 Aleksej Dix

 Front End Developer

@aleksejdix

aleksej.dix@oddeven.ch

https://oddeven.ch