Nuxt.js (v1), Firestore & SSR 🔥

Pascal Luther
Sep 8, 2018 · 6 min read

This article will help you integrate Firebase Firestore into a Nuxt.js project while keeping the server-side rendering capabilities that come with the amazing Universal SSR mode of Nuxt.js.

And all of this without the need for any additional libraries other than Google’s own Firebase SDK.

❗️️ NEWER ARTICLE! This article is based on Nuxt.js Version 1.x. If you are working with the newer Nuxt 2.0, check out this article:
https://medium.com/@pascalluther/nuxt-js-v2-firestore-ssr-938d8fb7d2b0

1) Install Nuxt.js

skip to section 2 if you already have a Nuxt.js project running

First, install the vue-cli if you haven’t already:

npm install -g @vue/cli @vue/cli-init

Then, for the sake of simplicity, install the Nuxt.js starter template with the following command:

vue init nuxt-community/starter-template <project-name>

❗️️ Make sure to replace “<project-name>” with your project-name!

After following the installation instruction you should be able to run your project and see the following:

2) Install the Firebase SDK

skip to section 3 if you already have the Firebase SDK installed

Now let’s install the Firebase SDK. Do this with the following command:

npm install firebase --save

This is all the dependencies you will need. In your packages.json file you should see the below:

"dependencies": {
"firebase": "^5.4.2",
"nuxt": "^1.0.0"
},

The starter template comes with Nuxt v.1.0.0. Change that to ^1.4.2 or higher and then run npm install to update to a more recent version, just for the sake of not using a rather old version.

❗️️️️ but don’t update to Nuxt 2+since this article doesn’t cover that

This article was written with the following two versions:

"dependencies": {
"firebase": "^5.4.2",
"nuxt": "^1.4.2"
},

3) Initiate the Firebase SDK

Now let’s finally write some code. 🎉

We want to make sure that the Firebase SDK is initiated on the server, so the server can get data from Firestore and render it before it gets sent to the client.

In your /plugins folder, create a file called firebase.js and add the following code:

import firebase from 'firebase/app'
import 'firebase/firestore'

if (!firebase.apps.length) {

const config = {
apiKey: '<replace this>',
authDomain: '<replace this>',
databaseURL: '<replace this>',
projectId: '<replace this>',
storageBucket: '<replace this>',
messagingSenderId: '<replace this>'
}

firebase.initializeApp(config)
firebase.firestore().settings({timestampsInSnapshots: true})
}

const fireDb = firebase.firestore()

export {fireDb}

❗️️ Make sure to replace “<replace this>” with your Firebase credentials. I will refrain from explaining how to setup a Firebase project and getting the credentials, since this is well documented in the Firebase docs here.

Now we add the plugin to our nuxt.config.js like so:

plugins: [
'~/plugins/firebase.js'
],

4) Write to Firestore

Now we can already write something to Firestore! 🤩

Delete all content in your pages/index.vue file and replace it with the following:

<template>
<section class="container">
<div>
<h2>
Write to Firestore.
</h2>
<div>
<button @click="writeToFirestore" :disabled="writeSuccessful">
<span v-if="!writeSuccessful">Write now</span>
<span v-else>Successful!</span>
</button>
</div>
</div>
</section>
</template>

<script>
import {fireDb} from '~/plugins/firebase.js'

export default {
data() {
return {
writeSuccessful: false
}
},
methods: {
async writeToFirestore() {
const ref = fireDb.collection("test").doc("test")
const document = {
text: "This is a test message."
}

try {
await ref.set(document)
} catch (e) {
// TODO: error handling
console.error(e)
}
this.writeSuccessful = true
}
}
}
</script>

<style>
.container {
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
}
</style>

Your app should now look like this:

When clicking on “Write now”, the button should change to “Successful!” and there should be a collection “test” with a document named “test” in your Firestore database:

A document named “test” should now exist within a collection called “test”.

❗️️ If this did not work, make sure your project and Firestore is set up properly. You might have to setup an instance of Firestore first. Also, make sure that your security rules are defined as public (but change that later on!).

5) Read from Firestore

Now let’s read what we wrote to the Firestore!

Add a second <div> below the “Write to Firestore”-Div like so:

<div>
<h2>
Read from Firestore.
</h2>
<div>
<button @click="readFromFirestore" :disabled="readSuccessful">
<span v-if="!readSuccessful">Read now</span>
<span v-else>Successful!</span>
</button>
<p>{{text}}</p>
</div>
</div>

Add the attributes readSuccessful and text to your data, so it looks like this:

data() {
return {
writeSuccessful: false,
readSuccessful: false,
text: ""
}
},

And finally add a method to read the data from Firestore like below:

async readFromFirestore() {
const ref = fireDb.collection("test").doc("test")

let snap
try {
snap = await ref.get()
} catch (e) {
// TODO: error handling
console.error(e)
}
this.text = snap.data().text
this.readSuccessful = true
}

Now try it out!

After clicking both buttons, your app should look like this:

Below the “Read” button, the text written to Firestore should appear.

That’s it. You can now already read and write to Firebase Firestore with Nuxt.js!

But wait… that is a client side request to Firestore. 😱 That has nothing to do with SSR.

Well, read on.

6) Server-side Rendering (SSR)

If you want your page to render the data from Firestore already on server-side, simply do it as you are used to with Nuxt.js —by adding an asyncData function (more Infos here):

async asyncData({app, params, error}) {
const ref = fireDb.collection("test").doc("test")

let snap
try {
snap = await ref.get()
} catch (e) {
// TODO: error handling
console.error(e)
}
return {
text: snap.data().text
}
},

That’s already it! We successfully implemented Nuxt.js with Firebase Firestore! 🎉🎉

Additional Content

Entire index.vue:

<template>
<section class="container">

<div>
<h2>
Write to Firestore.
</h2>
<div>
<button @click="writeToFirestore" :disabled="writeSuccessful">
<span v-if="!writeSuccessful">Write now</span>
<span v-else>Successful!</span>
</button>
</div>
</div>

<div>
<h2>
Read from Firestore.
</h2>
<div>
<button @click="readFromFirestore" :disabled="readSuccessful">
<span v-if="!readSuccessful">Read now</span>
<span v-else>Successful!</span>
</button>
<p>{{text}}</p>
</div>
</div>

</section>
</template>

<script>
import {fireDb} from '~/plugins/firebase.js'

export default {
data() {
return {
writeSuccessful: false,
readSuccessful: false,
text: ""
}
},
async asyncData({app, params, error}) {
const ref = fireDb.collection("test").doc("test")

let snap
try {
snap = await ref.get()
} catch (e) {
// TODO: error handling
console.error(e)
}
return {
text: snap.data().text
}
},
methods: {
async writeToFirestore() {
const ref = fireDb.collection("test").doc("test")
const document = {
text: "This is a test message."
}

try {
await ref.set(document)
} catch (e) {
// TODO: error handling
console.error(e)
}
this.writeSuccessful = true
},
async readFromFirestore() {
const ref = fireDb.collection("test").doc("test")

let snap
try {
snap = await ref.get()
} catch (e) {
// TODO: error handling
console.error(e)
}
this.text = snap.data().text
this.readSuccessful = true
}
}
}
</script>

<style>
.container {
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
}
</style>

Links:

Thanks & Credits to:

Pascal Luther

Written by

Business Analyst for zuehlke.com by day, recreational hobby-coder by night. Currently a big fan of Vue & Nuxt.js and of going serverless with Google Firebase.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade