Categories
Vue

Using Firebase in a Vue App with Vuexfire — Add Document and Current Timestamp

The Vuefire library lets us add Firebase database manipulation capabilities right from our Vue app.

In this article, we’ll look at how to use Vuefire and Vuexfire to add support for Cloud Firestore database manipulation into our Vue app.

Adding Documents to a Collection

We can add a document to a collection with the add method.

For example, we can write:

db.js

import firebase from "firebase/app";
import "firebase/firestore";
export const db = firebase
  .initializeApp({ projectId: "project-id" })
  .firestore();
const { Timestamp, GeoPoint } = firebase.firestore;
export { Timestamp, GeoPoint };

main.js

import Vue from "vue";
import App from "./App.vue";
import { firestorePlugin } from "vuefire";
import { vuexfireMutations, firestoreAction } from "vuexfire";
import Vuex from "vuex";
import { db } from "./db";
Vue.use(Vuex);
Vue.use(firestorePlugin);
Vue.config.productionTip = false;
const store = new Vuex.Store({
  state: {
    books: []
  },
  mutations: {
    ...vuexfireMutations
  },
  actions: {
    bindBooksRef: firestoreAction((context) => {
      return context.bindFirestoreRef(
        "books",
        db.collection("books").orderBy("title", "desc")
      );
    }),
    addBook: firestoreAction(async ({ state }, book) => {
      await db.collection("books").add(book);
      console.log("book added");
    })
  },
  getters: {
    books: (state) => {
      return state.books;
    }
  }
});
new Vue({
  store,
  render: (h) => h(App)
}).$mount("#app");

App.vue

<template>
  <div>
    <button @click="addBook">add book</button>
    <div>{{books}}</div>
  </div>
</template>
<script>
import { mapGetters, mapActions } from "vuex";
export default {
  data() {
    return {};
  },
  methods: {
    ...mapActions(["bindBooksRef"]),
    addBook() {
      this.$store.dispatch("addBook", { title: "qux" });
    }
  },
  computed: {
    ...mapGetters(["books"])
  },
  mounted() {
    this.bindBooksRef();
  }
};
</script>

We have the bindBookRef action to sync the Firebase books collection with the books state.

Also, we have the addBook action which calls add to add our book object into the books collection.

Then in App.vue , we call this.$store.dispatch method to dispatch the addBook action with the object we want to add.

The button runs the addBook method when we click it.

So when we click it, then the entry is added.

Current Timestamp

We can add the current timestamp at creation or update.

To do that, we can use the firebase.firestore.FieldValue.serverTimestamp method.

For example, we can write:

App.vue

<template>
  <div>
    <button @click="addBook">add book</button>
    <div>{{books}}</div>
  </div>
</template>
<script>
import { mapGetters, mapActions } from "vuex";
import firebase from "firebase/app";

export default {
  data() {
    return {};
  },
  methods: {
    ...mapActions(["bindBooksRef"]),
    addBook() {
      this.$store.dispatch("addBook", {
        title: "qux",
        createdAt: firebase.firestore.FieldValue.serverTimestamp()
      });
    }
  },
  computed: {
    ...mapGetters(["books"])
  },
  mounted() {
    this.bindBooksRef();
  }
};
</script>

We just use it anywhere we want to add a timestamp.

Then we get something like:

{ "createdAt": { "seconds": 1598895154, "nanoseconds": 675000000 }, "title": "qux" }

added to the books collection.

Conclusion

Vuexfire provides us with methods to add documents and current timestamps with our Vue app and Firebase.

Categories
Vue

Adding Authentication to a Vue App with Firebase

Firebase provides us with built-in authentication capabilities.

We can manage users and authenticate them easily with it.

In this article, we’ll look at how to use Firebase’s auth capabilities in a Vue app.

Create Password-Based Accounts

We can create password-based accounts with a few lines of code.

To do this, we can write:

App.vue

<template>
  <div>
    <form @submit.prevent="createUser">
      <input type="text" v-model="email" placeholder="email">
      <input type="password" v-model="password" placeholder="password">
      <input type="submit" value="create user">
    </form>
  </div>
</template>
<script>
import firebase from "firebase/app";
import "firebase/auth";
const firebaseConfig = {
  apiKey: "api-key",
  authDomain: "project-id.firebaseapp.com",
  databaseURL: "https://project-id.firebaseio.com",
  projectId: "project-id",
  storageBucket: "project-id.appspot.com",
  appId: "app-id"
};

export default {
  data() {
    return {
      email: "",
      password: ""
    };
  },
  beforeMount() {
    firebase.initializeApp(firebaseConfig);
  },
  methods: {
    createUser() {
      const { email, password } = this;
      firebase
        .auth()
        .createUserWithEmailAndPassword(email, password)
        .then(() => alert("user creeated"))
        .catch(function(error) {
          console.log(error);
        });
    }
  }
};
</script>

We initialize Firebase with an object to configure it.

The apiKey has the API key.

authDomain is the URL of the Firebase app.

dataBaseURL has the URL to the database.

projectId has the Firebase project ID.

storageBucket is the URL of the storage bucket.

appId is the app’s ID.

In the template, we have the form that accepts an email and password.

And we have the createUser method to create the user.

The createUserWithEmailAndPassword method accepts an email and password string to create the user with the email and password.

The then callback is called when user creation is successful.

catch callback is called when user creation failed.

error has the code and message properties to get the source of the error.

Sign in a User with an Email Address and Password

We can sign in with a username and password with the signInWithEmailAndPassword method.

For example, we can write:

<template>
  <div>
    <form @submit.prevent="signIn">
      <input type="text" v-model="email" placeholder="email">
      <input type="password" v-model="password" placeholder="password">
      <input type="submit" value="sign in">
    </form>
  </div>
</template>
<script>
import firebase from "firebase/app";
import "firebase/auth";
const firebaseConfig = {
  apiKey: "api-key",
  authDomain: "project-id.firebaseapp.com",
  databaseURL: "https://project-id.firebaseio.com",
  projectId: "project-id",
  storageBucket: "project-id.appspot.com",
  appId: "app-id"
};

export default {
  data() {
    return {
      email: "",
      password: ""
    };
  },
  beforeMount() {
    firebase.initializeApp(firebaseConfig);
  },
  methods: {
    signIn() {
      const { email, password } = this;
      firebase
        .auth()
        .signInWithEmailAndPassword(email, password)
        .then(() => alert("sign in successful"))
        .catch(error => {
          console.log(error);
        });
    }
  }
};
</script>

We added the signIn method which is mostly the same as the createUser method.

Sign in with Google

We can add sign in with Google.

First, we go to the Authentication section of our app.

Then we go to the Sign-in method section to add the domain that our app is hosted into the list of authorized domains.

Now we can add the authentication.

For example, we can write:

<template>
  <div>
    <button @click="signIn">sign in with google</button>
  </div>
</template>
<script>
import firebase from "firebase/app";
import "firebase/auth";
const provider = new firebase.auth.GoogleAuthProvider();
const firebaseConfig = {
  apiKey: "api-key",
  authDomain: "project-id.firebaseapp.com",
  databaseURL: "https://project-id.firebaseio.com",
  projectId: "project-id",
  storageBucket: "project-id.appspot.com",
  appId: "app-id"
};

export default {
  data() {
    return {};
  },
  beforeMount() {
    firebase.initializeApp(firebaseConfig);
  },
  methods: {
    signIn() {
      firebase
        .auth()
        .signInWithPopup(provider)
        .then(result => {
          const token = result.credential.accessToken;
          const user = result.user;
          console.log(token, user);
        })
        .catch(error => {
          console.log(error);
          // ...
        });
    }
  }
};
</script>

We create the Google auth provider with the firebase.auth.GoogleAuthProvider constructor.

We added the signIn method which calls the signInWithPopup method with our auth provider object to add the sign-in functionality.

Then the then callback is called to get the user and token .

user has the user data.

token has the auth token.

The catch callback is called when there’s an error and it provides us with info about the error including the email, code, and message.

Conclusion

We can add authentication to our app easily with Firebase into a Vue app.

Categories
Vue Vuetify

Create a Desktop App with Vue, Vuetify, and Electron

Electron is an app framework to let us build desktop apps that are based on web apps.

Vuetify lets us build a web app with Material Design.

We can use the vue-cli-plugin-electron-builder generator to build an Electron app based on Vue.js.

In this article, we’ll look at how to build a simple Electron Vue app with Vuetify and Electron.

Getting Started

We can create our Vue project by running:

npx vue create .

after going into our project folder.

We follow the instructions to create the Vue project.

Then in the project folder, we run:

vue add electron-builder

Once we did that, we add Vuetify to our Vue app by running:

vue add vuetify

Now all the boilerplate code has been added for us.

We then run:

npm run electron:serve

or

yarn electron:serve

to preview our app.

Writing the Code

Now can create our app with Vuetify.

We can create a simple app by adding the following to App.vue :

<template>
  <v-app>
    <v-app-bar app color="primary" dark>
      <div class="d-flex align-center">
        <v-img
          alt="Vuetify Logo"
          class="shrink mr-2"
          contain
          src="https://cdn.vuetifyjs.com/images/logos/vuetify-logo-dark.png"
          transition="scale-transition"
          width="40"
        />

    <span class="mr-2">App</span>
      </div>
    </v-app-bar>

    <v-main>
      <v-form v-model="valid" @submit.prevent="add">
        <v-container>
          <v-row>
            <v-col cols="12" md="6">
              <v-text-field v-model="title" :rules="rule" label="book title" required></v-text-field>
            </v-col>

            <v-col cols="12" md="6">
              <v-text-field v-model="author" :rules="rule" label="book author" required></v-text-field>
            </v-col>
          </v-row>
          <v-row>
            <v-col cols="12">
              <v-btn text type="submit" color="primary">add</v-btn>
            </v-col>
          </v-row>
        </v-container>
      </v-form>

      <v-simple-table>
        <template v-slot:default>
          <thead>
            <tr>
              <th class="text-left">title</th>
              <th class="text-left">author</th>
              <th></th>
            </tr>
          </thead>
          <tbody>
            <tr v-for="(b, i) in books" :key="b.id">
              <td>{{ b.title }}</td>
              <td>{{ b.author }}</td>
              <td>
                <v-btn text color="primary" @click="remove(i)">remove</v-btn>
              </td>
            </tr>
          </tbody>
        </template>
      </v-simple-table>
    </v-main>
  </v-app>
</template>

<script>
import { v4 as uuidv4 } from "uuid";

export default {
  name: "App",
  data: () => ({
    title: "",
    author: "",
    rule: [(v) => !!v || "required"],
    valid: false,
    books: [],
  }),
  methods: {
    add() {
      if (!this.valid) {
        return;
      }
      const { title, author } = this;
      this.books.push({
        id: uuidv4(),
        title,
        author,
      });
    },
    remove(index) {
      this.books.splice(index, 1);
    },
  },
};
</script>

We created a book app with a form and a table.

v-app-bar is the top app bar.

v-main has the main content of the app.

v-form creates the form.

The v-model attribute on the form has the form validation state.

The @submit.prevent directive listens for the submit event to be emitted.

prevent calls preventDefault implicitly.

Inside the form, we have the v-text-field to add the text field.

v-model binds to the model states.

The rules prop has the form validation rules.

The rules are defined with an array of functions with the inputted value as the parameter.

The table is created with the v-simple-table component.

And we populate the default slot with the regular table elements.

In the methods object, we have the add method to let us add entries to this.books .

We check for form data validity with the this.valid property.

A unique ID is generated for each entry with the uuid package.

We need a unique ID for the key prop in the table so the items are rendered correctly.

We install that by running:

npm i uuid

Also, we have the remove method to remove items by its index.

Now we should be able to add and remove items as we wish.

Build Our App

To build our app into an executable file, we run:

yarn electron:build

with Yarn or:

npm run electron:build

with NPM.

Conclusion

We can create our a good looking Vue desktop app with Vuetify, Vue, and the vue-cli-plugin-electron-builder code generator.

Categories
Vue

Create a Desktop App with Vue and Electron

Electron is an app framework to let us build desktop apps that are based on web apps.

The apps are cross-platform and are rendered with the Chromium browser engine.

We can use the vue-cli-plugin-electron-builder code generator to build an Electron app based on Vue.js.

In this article, we’ll look at how to build a simple Electron Vue app.

Getting Started

We can get started by creating a Vue.js project.

To do that, we create an empty project folder, go into it, and run:

npx vue create .

Then we follow the instructions to add the items we want.

Next, we run the Vue CLI Plugin Electron Builder generator to add the Electron files to our Vue app.

We run:

vue add electron-builder

to add all the files and settings automatically.

Then to start the dev server, we run:

yarn electron:serve

or

npm run electron:serve

We should see a Window for our app displayed.

The dev console should also be shown.

Now we just have to write our Vue app.

Writing the Code

We write the code like any other Vue app.

In App.vue , we write:

<template>
  <div id="app">
    <form @submit.prevent="add">
      <input type="text" v-model="todo" />
      <input type="submit" value="add" />
    </form>
    <div v-for="(t, i) of todos" :key="t.id">
      {{t.todo}}
      <button @click="remove(i)">remove</button>
    </div>
  </div>
</template>

<script>
import { v4 as uuidv4 } from "uuid";

export default {
  name: "App",
  data() {
    return {
      todo: "",
      todos: [],
    };
  },
  methods: {
    add() {
      this.todos.push({ id: uuidv4(), todo: this.todo });
      this.todo = "";
    },
    remove(index) {
      this.todos.splice(index, 1);
    },
  },
};
</script>

to add a todo list into our app.

We have a form to add the todo list.

Then we have the add method to add an entry to this.todos .

We create unique IDs for each entry with the uuid NPM package, which we install by running:

npm i uuid

And we have the remove to remove the this.todos entry with the given index.

In the form with listen to the submit event with the @submit.prevent directive to also call preventDefault to prevent default submission behavior.

Now we should see our todo app displaying in the window.

Build Our App

To build our app into an executable file, we run:

yarn electron:build

with Yarn or:

npm run electron:build

with NPM.

Native Modules

We can add native modules into our app within the vue.config.js file:

module.exports = {
  pluginOptions: {
    electronBuilder: {
      externals: ['my-native-dep'],
      nodeModulesPath: ['../../node_modules', './node_modules']
    }
  }
}

We can add the node_module paths for location the modules.

externals is for listing names of modules that don’t work with our app.

Web Workers

To add workers, we add them to the vue.config.js file by writing:

const WorkerPlugin = require('worker-plugin')

module.exports = {
  configureWebpack: {
    plugins: [new WorkerPlugin()]
  }
}

We install the worker-plugin package by running:

npm i worker-plugin

Now we can use worker files by writing:

src/worker.js

onmessage = (e) => {
  const { a, b } = e.data;
  const workerResult = +a + +b;
  postMessage(workerResult);
}

src/App.vue

<template>
  <div id="app">
    <form @submit.prevent="send">
      <input type="text" v-model="a" />
      <input type="text" v-model="b" />
      <input type="submit" value="add" />
    </form>
    <p>result: {{result}}</p>
  </div>
</template>

<script>
const worker = new Worker("./worker.js", { type: "module" });

export default {
  name: "App",
  data() {
    return {
      a: 0,
      b: 0,
      result: 0
    };
  },
  mounted() {
    worker.onmessage = this.onMessage;
  },
  methods: {
    send() {
      const { a, b } = this;
      worker.postMessage({ a, b });
    },
    onMessage({data}) {
      this.result = data;
    },
  },
};
</script>

We created a worker that listens to the message event.

The message event is emitted by the worker.postMessage method that we emit in the send method.

send gets the data from what we typed in.

Once the message event is emitted, then we get the data sent from e.data .

Then we compute the result and call postMessage to send the computed result back to App.vue .

App.vue gets the result from the onMessage method.

And we display the result from it.

Conclusion

We can create a desktop app with Vue.js with the vue-cli-plugin-electron-builder generator.

It has support for web workers.

Categories
Reviews

Why A2 Hosting is a Great Hosting Provider for Beginner?

A2 Hosting is a shared hosting provider that offers lots of values to their customers.

The benefits and pricing they offer are very suitable for beginners.

Fastest Shared Hosting Speed

A2 Hosting loads sites faster than any other hosting provider. They can load a site usually in less than half a second.

This shows how fast they can load a site.

Customer Support

A2 Hosting offers a live chat for customer support.

It’s also available 24/7 so we can get support from them at any time.

Their support staff also replies very quickly so you’ll be sure to be able to reach them.

HackScan

The HackScan feature keeps your site safe by checking for any malware in your site and traffic patterns that may indicate an attack is going 24/7.

This prevents any chance of a denial of service attack breaking out on your site.

Free Site Migrations

A2 Hosting also offers free site migration.

You can get 1 site migrated for free.

Content Management Systems, Website Builders, and Developer Tools

They offer many tools for web hosts to help webmasters.

There are one-click installers for various CMSes like WordPress, Drupal, Joomla, and more.

And they offer their own website builder called SiteBuilder.

With that, you get a WYSIWYG interface for building your own site so that you don’t have to know how to code.

A2 Hosting also has free CloudFlare integration for caching to keep your site fast.

Money-Back Guarantee

A2 Hosting offers more than the 30-day money-back guarantee that most hosts offer.

They offer a refund even after 30 days with the ‘anytime’ money-back guarantee.

You can get a refund as far as 120 days.

Uptime of 99.93%

They have a high uptime percentage of 99.93%.

This means that your site is very unlikely to go down if you host it with A2 Hosting.

The Startup Plan

A2 Hosting offers the entry-level Startup plan which is great because of the affordable price and features offered.

The Startup plan only allows one site to be hosting, but the rest can be used to host an unlimited number of sites.

The storage available for the Startup plan is 100GB, which is generous. The rest are unlimited.

Bandwidth, databases, email addresses, are all unlimited.

The Startup plan offers 0.7GB of RAM, which is more than adequate for small websites.

Plans other than Startup also offer 2 or more cores for processing.

Caching is available on the Turbo Boost and Turbo Max plans.

There’re many add-ons that we can buy separately like SSL certificates, spam filtering, and Cloudflare.

Also, it’s one of a few hosting providers that offer Windows hosting if we want Windows servers.

The Startup plan starts at $3.95 a month.

With these features, it’s more than enough to host small to medium sites.

cPanel

cPanel hosting is useful for managing sites.

It’s great for beginners since everything is done graphically.

Conclusion

A2 Hosting offers many benefits that not all web hosts can offer.

The pricing and benefits they offer are great for small businesses.

Click Here to Sign Up for A2 Hosting