Developer Insights
Join millions of viewers! Our engineers craft human-written articles solving real-world problems weekly. Enjoy fresh technical content and numerous interviews featuring modern web advancements with industry leaders and open-source authors.
Nuxt.js for Complete Beginners
The Vuejs Amsterdam online conference was held at the end of February in 2021. It brought together Vue.js enthusiasts and community members from around the world. Many interesting topics were presented and covered. The focus, of course, was on Vue.js 3. In addition, the creators of Nuxt.js had the opportunity to showcase it from the current standpoint in development, to their intentions for it down the track. They even demonstrated a pre-alpha version of Nuxt.js 3, that’s based on Vue.js 3. This article will start by briefly covering general Nuxt.js concepts, creating a new Nuxt.js app using the create-nuxt-app CLI, and finally, going through the different files and folders that Nuxt.js auto-generates for us. Let’s start! Nuxt.js Concepts Nuxt.js is a web development framework that builds on top of the Vue.js framework. It allows you to use your Vue.js skills to build a more confident, structured, SEO friendly website purely in Vue.js. Remember when you had to mess with the Vue.js SSR module and the Vue Meta module to build a SEO friendly website? On top of that, you had to install and use Vuex and Vue Router too! Well, Nuxt.js takes care of that! No more chaotic setup and scaffolding to start a new Vue.js app. With the help of the create-nuxt-app CLI, you can scaffold a Nuxt.js app in no time. What’s remarkable about Nuxt.js is its capacity to enforce convention over configuration. This means, you write less configuration files by sticking to a specific directory structure that makes Nuxt.js happy and saves you a ton of time! Apps supported by Nuxt.js Nuxt.js supports building a variety of web apps, including the following: Server-Side Rendering (SSR) SSR apps are also known as Universal Apps. The app gets rendered on the server-side before it is sent to the client-side, and is displayed in the browser. This is the best option when working on an SEO friendly website written in Vue.js. You can read the full documentation for the SSR apps here: SSR Apps Single Page Apps (SPA) This is what you’ve been doing so far with Vue.js. The app is compiled into a few JS and CSS files. When the user requests the app, the files are downloaded to the client-side, and the Vue.js engine takes over rendering and displaying the app. Static Site Generation (SSG) Nuxt.js can pre-render your app at build time. This means the entire app will be converted to simple static HTML files that can be hosted and served over a Content Delivery Network (CDN). The SSG option makes an app a legal JAMStack app. You can read the full documentation for the Static Site Generation here: Static Site Generation. File System Routing Nuxt.js automatically generates all the Vue.js Routes in your app based on the folder structure inside the *pages* folder. For example, consider having this folder structure: ` Nuxt.js automatically generates the following route configuration: ` You can read about *File System Routing* here: File System Routing. Data Fetching Inside a Nuxt.js app, you can still use the old techniques you kmow when developing Vue.js apps. However, we have a new player here! Server-side rendering. Nuxt.js provides a new set of data-hooks that you can implement so that Nuxt.js can prefetch data when generating the app at the server-side. Here are two data-hooks offered by Nuxt.js: fetch() hook This hook was introduced with Nuxt.js 2.12+ release. It can be used inside Vue.js components stored in the *pages* folder and *components* folder. asyncData() hook This hook has been around for a while now, and can be used only inside the Vue.js components stored in the *pages* folder. You can read more about *Data Fetching* hooks here: Data Fetching. Meta Tags and SEO Nuxt.js makes it so intuitive to add SEO support to your SSR app. You can add Metadata to your app at two different levels: - Globally using the *nuxt.config.js* file - Locally inside a Nuxt.js Page You can read about *Meta Tags and SEO* hooks here: Meta Tags and SEO. Create our first Nuxt.js app Let’s use the create-nuxt-app CLI, and create our first Nuxt.js app! Before you start, you want to make sure you have all the perquisites required before you can install and run the CLI. For this article, I am going to use npx. However, you can also use npm, or feel free to use yarn. Step 0 Start by running the following command: ` This command uses the create-nuxt-app tool, and specifies the name of the project- in this case *my-first-nuxt-app*. The CLI will ask you a few questions that are important to scaffold the new Nuxt.js app based on your own preferences and decisions. Here’s what to expect. Step 1 First, let’s confirm the project name as shown in the Figure 1. Give the app a name and hit Enter. _Figure 1: Specify project name_ Step 2 You’ve got to choose whether you want to develop your app with TypeScript or JavaScript. I will select *JavaScript* as shown in Figure 2. _Figure 2: Programming language_ Step 3 Next, you need to choose between Npm or Yarn. I will select *Npm* as shown in Figure 3. _Figure 3: Package manager_ Step 4 In this step, you’ve got to select the UI framework you are going to use in the app. I will select *Tailwind CSS* as shown in Figure 4. Even if you skip this step, you can add any UI framework you want later. _Figure 4: UI framework_ Step 5 Nuxt.js offers a set of modules that you can use right away in your apps. For this app, I will pick the *Axios* module. Figure 5 shows the selection. _Figure 5: Nuxt.js modules_ Step 6 The CLI makes it super intuitive to integrate linters in your app. I will pick up both *ESLint* and *Prettier*. Figure 6 shows the selection. _Figure 6: Linting tools_ Step 7 Now it’s time to select a testing framework. For the sake of this article, I will select *None*. Feel free to add any. Figure 7 shows the selection. _Figure 7: Testing framework_ Step 8 By default, Nuxt.js supports two rendering modes. SSR/SSG and SPA. I will pick *SSR/SSG* to take advantage of the Server-side rendering. Figure 8 shows the selection. _Figure 8: Rendering mode_ Step 9 The deployment target depends on our selection in Step 8. In this case, we have two options to select from. Server (using a Node.js server hosting) or Static (CDN/JAMStack hosting). I will select the *Server* deployment target as shown in Figure 9. _Figure 9: Deployment target_ Step 10 For the development tools, I will keep it simple and select the *jsconfig.json* option as shown in Figure 10. _Figure 10: Development tools_ Step 11 I won’t be using any continuous integration for this app. I will simply select *None* as shown in Figure 11. _Figure 11: Continuous integration_ Step 12 Finally, the CLI asks whether you want to use any version control system. A version control system is always recommended when doing any kind of development. I will select *Git* as shown in Figure 12. _Figure 12: Version control system_ These twelve questions are enough for the CLI to start scaffolding and generating your app based on your preferences. It takes a few seconds to have everything ready for you. If all goes well, you should see the following as in Figure 13. _Figure 13: create-nuxt-app new app instructions_ The CLI gives you instructions on how to run and build the app. Step 13 Let’s run the app by following the steps highlighted in Figure 13. Run the following commands: ` The CLI compiles both the client and server parts of the app and starts the Node.js server on port 3000 as shown in Figure 14. _Figure 14: App is running_ Step 14 Open a browser instance and navigate to the URL *http://localhost:3000/* and you should see the default Nuxt.js app rendering. Figure 15 shows the app running in a browser. _Figure 15: App rendering in a browser_ That’s all you need to get started on your first Nuxt.js app. Enjoy! Nuxt.js Directory Structure Let’s quickly go through the different folders the CLI generated for us. I will start by opening the new app inside Visual Studio Code. Figure 16 shows the app open inside the editor. _Figure 16: App folders and files_ Let’s go through each folder, and explain their roles briefly. .nuxt The *.nuxt* folder is (re-)generated by the CLI every time you run or build the app. It has all the automatically generated files that Nuxt.js uses to run your app. You can read more about the *.nuxt* folder here: .nuxt. assets The *assets* folder contains all of your uncompiled files such as Sass files, images, or font files. Nuxt.js makes use of Webpack to load all the files inside this folder. You can read more about the *assets* folder here: assets. components This folder holds all of your Vue.js components. Nuxt.js components are not different from any other Vue.js component. Read more about the *components* folder here: components. layouts This folder contains all of your layout components. These are Vue.js components with placeholders for content. At run time, the component and the layout it uses get merged together into a single component. Layouts in Nuxt.js allows you to define fixed UI sections in your app instead of having to repeat things over and over. You can read more about the *layouts* folder here: layouts. pages This folder also holds Vue.js components. It is unique because Nuxt.js converts this folder structure (components with sub-folders) into actual Vue.js Routes. You can read about the *pages* folder here: pages. plugins This folder contains global JavaScript functions that you want to run before Nuxt.js instantiates the root Vue.js app. These functions are called *Plugins*. They can take multiple forms. For instance, you create a Nuxt.js Plugin to load a Vue.js Plugin to your app. You can also install, and make use of a third-party Nuxt.js Plugin. You can read more about the *plugins* folder here: plugins. static The name of this folder says it all! This folder is directly mapped to the server root. You can place any file in this folder that you do not want Webpack to process. For example, you can place a favicon file, any CSS files, and many other such files. You can read more about the *static* folder here: static. store The *store* folder holds all the Vuex store files. Nuxt.js comes with the Vuex module installed, but keeps it disabled. In order to enable the Vue store in your Nuxt.js app, create an *index.js* file inside this folder, and Nuxt.js will automatically enable it for you. You can read more about *store* folder here: store. nuxt.config.js As I mentioned, Nuxt.js prefers convention over configuration. However, at some times you may need to tweak the configuration a little. Nuxt.js provides the *nuxt.config.js* file to allow for custom configuration settings on the app level. Read more about *nuxt.config* file here: nuxt.config. That’s just a quick overview of what folders are generated by the Nuxt.js CLI. There are more you can read up on. You can find all the information you need on Nuxt.js Documentation website. Conclusion In this article, you were introduced to Nuxt.js and took a few baby steps towards creating your first Nuxt.js app. In the coming articles, we will immerse ourselves in the Nuxt.js world, and explore this fresh and promising web development framework together. You can follow me on Twitter to see more of my work....
Mar 22, 2021
12 mins
Making sense of Multiple v-model Bindings in Vue 3
This article is one of a series of articles on what’s new in Vue 3. If you haven’t checked that series yet, you can do so by visiting the links below: - Take your App to the Next Level with Vue 3 - Async Components in Vue 3 - Teleporting in Vue 3 - Your first Vue 3 app using TypeScript - Vue 3 Composition API, do you really need it? In this installment, I will introduce the new v-model in Vue 3 and go through a new feature that allows you to use multiple v-model on the same component! By design, the v-model directive allows us to bind an input value to the state of an app. We use it to create a two-way data binding on the form input, textarea, and select elements. It handles updates in two opposite directions: When the input value changes, it reflects the value onto the state inside the Component. When the Component state changes, it reflects the changes onto the form input elements. The core concept of v-model remains the same in Vue 3 with more enhancements and features. Let’s dig in! Vue 2: v-model Vue 2 supports a single v-model on any given Component. In Vue 2, to build a complex Component that supports two-way data binding, it utilizes a single v-model with one full-blown payload. The Component handles the state internally for all the input elements. It generates a single payload object representing the state of the Component. Finally, it emits an event to the parent Component with the payload attached. This method had several pitfalls, especially for creating Vue UI Libraries. Of these pitfalls is the vagueness of the payload interface. It’s unclear what’s being included in the payload. A developer had to loop through the payload object in order to uncover what properties were there. Another is the need to write the logic inside the Component to handle the internal state and the generation of the payload object. Shortly, we will uncover what has been improved in this regard with Vue 3. However, before this, let’s review some basics on how Vue 2 handles implementing two-way data binding in Components. Vue 2: Two-way Data Binding As mentioned, Vue 2 uses the v-model directive to support two-way data binding on Components. Internally, it follows certain steps and rules in order to support the v-model directive. By default, the v-model directive uses different properties and emits different events for different input elements: Text and Textarea elements use the value property and the input event Checkboxes and Radio buttons use the checked property and the change event Select fields use the input property and the change event. Building a Component with a single input element will internally use something similar to the snippet below: ` The custom Component above defines a single prop named value as follows: ` Then, in the parent Component, you use the new custom Component as follows: ` The v-model directive assumes that the CustomComponent defines an internal property named value and emits a single event named input. What if the CustomComponent has to handle multiple inputs? How do we accomplish that in Vue 2? Well, there is no official solution. However, there are two methods that you can use: The CustomComponent defines a single property named value of type Object. Internally, it parses the object into data fields and does the mapping manually on the template. On every change of any of the fields, it prepares a payload for all the fields and emits a single input event, and attaches the payload. That’s a lot of code to write for such a custom component. The other option is to skip using the v-model directive and instead utilize individual input/event pairs. I will illustrate this in a moment. Assuming you have a custom Component to handle the user’s first name and last name, you would employ something similar: ` As for the properties, the Component defines the following: ` Finally, the parent Component uses the new component as follows: ` We are not using the v-model anymore and providing multiple two-way data bindings on the new component. Further your understanding by reading the official docs on Using v-model on Components Vue 3: v-model In Vue 3, the v-model directive has had an overhaul to give developers more power and flexibility when building custom components that support two-way data binding. The v-model directive now supports new defaults. The default v-model property is renamed to modelValue instead of the old name of value. The default v-model event is renamed to update:modelValue instead of the old name of input. You might be thinking that's more typing when using the new v-model directive. The Vue team are one step ahead and have given you a shorthand to use instead. Let’s rebuild the custom component using it. ` The custom component defines a single prop named modelValue as follows: ` Then, in the parent component, use the new custom component as follows: ` The new v-model directive offers the new shorthand that is used like this: ` The v-model directive assumes that the CustomComponent defines an internal property named modelValue and emits a single event named update:ModelValue. In case you don’t want to use the default naming convention, feel free to use another name. Just remember to be consistent when naming properties. Here’s an example of using a custom name for the modelValue property. ` The custom component above defines a single prop named modelValue as follows: ` Then, in the parent component, you use the new custom component like so: ` Notice the use of the property fullName instead of the default property name. Vue 3: Multiple v-model directive bindings I hope the Vue 3 shorthand form of the v-model directive has given you a "hand up". With this, the v-model gives the flexibility to use multiple v-model directives on a single component instance. The modelValue can be renamed to whatever you want, allowing you to do this! This great new feature eliminates the previous two solutions I offered up on handling complex custom components for Vue 2. Let's jump in and go through an example demonstration! Demo - Multiple v-model directive bindings Let’s build a custom Address component that can be embedded in any form to collect a user’s address. > You can play with the example live on: vue3-multiple-v-model. > You can check the source code for the example on: vue3-multiple-v-model. Figure 1 below shows the final app in action. Let’s start by building the HTML template of the new component. Figure 1 shows that all the fields used are of type input elements. Except for the last one which is a checkbox element. Therefore, it’s suffice to focus on a single input field that will eventually be replicated for the rest of fields. ` The address-line input field binds the :value directive and the @input event as per the new v-model directive specifications in Vue 3. The component defines the following property: ` The other fields follow the same structure and naming convention. Let’s look at the checkbox field and see how it’s defined: ` In the case of a checkbox field element, we bind to the :checked directive instead of the :value directive. Also, we use the @change event instead of the @input event as in the case of input field elements. The event name follows the same standard way of emitting events in the new v-model directive. The component defines the following property: ` Let’s now embed the new custom Address component into the App component: ` For each and every property on the custom component, we bind using the v-model:{property-name} format. The modelValue was replaced with the specific property names we have in hand. When there was a single input binding, the shorthand format was so much easier. However, when there are multiple input elements, the modelValue is in a league of its own! Now, let’s define the properties inside the App component using the new Composition API setup() function: ` You create a new reactive property with an object payload. Finally, you return the reactive property to the component and use it to set bindings on the custom Address component as follows: ` That’s it! Conclusion Vue 3 has many new features and improvements. Today, we saw how we use multiple v-model directives on a single component instance. There is so much more to learn and uncover in Vue 3. The coming installments of this series will continue to look at different features to help you move from Vue 2 to Vue 3. Happy Vueing!...
Nov 6, 2020
6 mins
Take your App to the Next Level with Vue 3
Vue 3 has now officially launched and you are probably wondering how you are going to start migrating your existing Vue 2 apps to Vue 3. I will be honest with you: a framework migration is always the most tedious and painstaking task you will ever encounter. The good news is that migrating from Vue 2 to Vue 3 is not that difficult and complicated. As you may know, Vue 3 source code has been written from scratch. However, the maintainers of the framework made sure not to change the API too much. In other words, we will benefit from all the goodies Vue 3 brings, with minimal change. How awesome is that?! Vue 3 Official Migration Guide The Vue documentation website has been refreshed to reflect the latest changes. The Vue community has maintained the best documentation to help us learn and use Vue. The Vue documentation dedicates a section on Vue 3 Migration making mention of the new features, the breaking changes for Vue 2 apps, the supporting libraries like Vue CLI, Vuex, Vue Router and others. The website explicitly states that the team is still working on a dedicated migration guide from Vue 2 to Vue 3. Meanwhile, until an official migration guide is released, let’s get a little insight on what could possibly be involved if you were to tackle this for yourself. What to consider before upgrading to Vue 3? As Vue 3 is still new, there will be some things to keep in mind. There are thousands of applications and third-party libraries created for Vue 2 and even Vue 1.5. It’s going to be a lengthy and time consuming effort to migrate all those libraries to support Vue 3. Before you attempt any migration process, make sure all the libraries you use are supported by Vue 3. For instance, Vuetify isn't. You can read more about this here. In addition, if you use any of the third-party libraries, they need to be checked or you might find they have upgraded already. Moreover, the Vue 3 reactivity system has been rewritten to utilize the new language features in ES2015. Vue 3 uses proxies for its reactivity system instead of the Object.defineProperty() function. JavaScript proxies are supported by most modern browsers. Unfortunately, Proxies cannot be polyfilled for older browsers; therefore, Vue 3 offers two implementations of it’s reactivity system. One implementation will use proxies for the most recent and modern browsers. The other one will fall back to the Vue 2 way of implementing reactivity to support the older browsers. Step by Step Migration - Demo In this section, we'll go through migrating the This Dot - Vue Meetup website. The existing website is built with Vue 2. It’s essential to follow the steps below as is. Of course, depending on the features you’ve used, you will adjust this workflow to fit your needs and migrate more features in your apps. Let's start! Step 1: Create a new Git branch It’s important to start off with a brand new branch to play around with the migration. This way your main branches, like master or dev, will remain intact without disrupting any live code. Let’s assume we are branching from the master branch. Run the following command to create a new branch: ` Step 2: Install the latest Vue CLI version Currently, as of the time of writing this article, the latest version of the Vue CLI is 4.5.6. To install the latest version, run the following command: ` Verify the installation by running the following command and making sure it reads as @vue/cli 4.5.6: ` Upgrading the Vue CLI not only helps in upgrading the existing application, but it also gives you the chance to scaffold a new Vue 3 app in the future. Step 3: Upgrade the Vue libraries The next step is to upgrade the Vue NPM packages and all other packages used inside the package.json file. To start with, open the package.json file and make sure to amend the Vue libraries with the following versions: ` Now, let’s upgrade the rest of the libraries using the Vue CLI. Run the following command to start upgrading the libraries: ` The command goes through all the libraries you are using inside the package.json file and tries to upgrade them to the latest compatible version. For example, when I run this command, the Vue CLI detects the Vue libraries that need to be upgraded and prompts for confirmation: Type Y to continue with the upgrade. In summary, the upgrade reported the following packages changes, additions, and removal. While the CLI is upgrading the @vue/cli-plugin-eslint it will also upgrade the current ESLint version installed on your computer. The latest Vue CLI supports ESLint v6. Once again, the Vue CLI prompts for confirmation before upgrading ESLint. Type Y to continue with the upgrade. ` The numbers will definitely be different for you and depending on the app. It’s now time to run the app and make sure you don’t have missing libraries or other problems. In my case, I ran the app and got a few ESLint issues. Luckily, the Vue CLI comes packaged with a command to auto fix ESLint issues. In this case, you run the npm run lint and the Vue CLI handles the rest for you! Step 4: Add the @vue/compiler-sfc NPM package The @vue/compiler-sfc package contains lower level utilities that you can use if you are writing a plugin / transform for a bundler or module system that compiles Vue single file components into JavaScript. It is used in the vue-loader. This is an essential component if you are using Single File Components which is the case in most of the Vue apps. Let’s install this package by running the following command: ` Let’s move on and start upgrading the source code to use the latest APIs offered by Vue 3. Step 5: Upgrade the main.js file Vue 3 changes the way an application is created by introducing the createApp() function. Back in Vue 2 and earlier versions, we used to create a global Vue instance. This approach had several disadvantages. The main one had third-party libraries to making changes to our Vue single App instance. By introducing createApp(), you can instantiate multiple Vue apps side by side. It creates a context or boundary for your app instance where you do all the registration as you will see shortly. Typically, a Vue app is started inside the main.js file. Let’s visit this file and make the necessary changes to upgrade to Vue 3. ` This is a slimmed down version of the original main.js file in the app. Let’s dissect the file one line at a time and upgrade accordingly. ` Replace the line above with: ` Let’s replace the code that’s creating the app using the Vue 3 createApp() function. ` Replace with: ` The app variable now holds a new Vue app instance for us. The router instance will be registered separately. Let’s update the Vue component registration. ` Replace with: ` With Vue 3, you register components at the app instance level and not globally. Let’s update the Vue mixin registration. ` Replace with: ` Now register the router on the app instance as follows: ` Now let’s register the vue-analytics plugin on the app instance. ` Replace with: ` The plugin is now installed on the app instance rather than the global Vue instance. This is also valid for any other plugin out there. Make sure to remove the line below as it’s not needed anymore in Vue 3 apps: ` Finally, let’s mount the app instance by using the following: ` The final version of the upgrade main.js file looks like this: ` That’s it! Step 6: Upgrade the router.js file The Vue Router has undergone changes and it’s now under v4.0. Let’s review what the current router.js file looks like: ` Replace the import statements with the following line: ` Instead of creating a new instance of the Router object, we will be using the new function provided by Vue Router which is createRouter(). ` The router.js file now exports an instance of the Router object using the createRoute() function. This function expects an input parameter of type object. The routes and history properties are the minimum accepted to pass into this object. The routes array is still the same as in Vue 2. It’s an array of routes, nothing has changed here. The createWebHashHistory() function is now used to specify a Hash History mode in the Vue Router. As a side note, depending on what you are using in your app, there is also the createWebHistory() function that sets the mode to HTML 5. You can read more about History Modes. Next, we will update the scrollBehavior() function as it has undergone some major changes. Replace the existing function with the following: ` You can read more about Scroll Behavior in the Vue Router 4.0. Now, let’s run the app and see if everything works as expected. When I run the app, I get the following warning in the Dev Tools: ` This warning has to do with Vue Router and the Transition component. You can read more about the Transitions in Vue Router. Let’s navigate to the App.vue component and check what the current source code is: ` In Vue Router v4.0, you can no longer nest a component inside a component. The fix is simple and provided to you in the documentation. Replace the above with the following: ` These were all the steps needed to upgrade the Vue Meetup app. Others I’d like to draw your attention to a few more things when upgrading your apps to Vue 3. One of the components in the app had a single slot; that is, the default slot. The way it was used in the Vue 2 app was: ` When I ran the app, the component was showing nothing, an empty screen! It seems Vue 2 was more tolerant by not forcing me to specify the name of the slot, even though this is the default slot. The quick fix in Vue 3 is as follows: ` Something else I didn’t mention is the Vuex v4.0. The same steps that we followed to upgrade the Vue Router can be followed here. The approach is similar. You can read more about the Vuex v4.0 Breaking Changes. Conclusion I am pretty sure we will all face more issues and encounter different hiccups while upgrading our apps. It will all depend on the features of your Vue 2. Remember, everything has a solution! While we wait for the Vue team to share an official migration guide, start trying to upgrade and see how you go. If you get stuck, feel free to drop me a message on twitter using my Twitter handle @bhaidar....
Sep 30, 2020
9 mins
Introducing the release of Vue 3
Back in October 2018, Evan You announced plans to start building the third version of VueJS. Featuring 30+ RFCs, over 2,600 commits, 628 pull request from 99 contributors, Vue 3's release reflects tireless ingenuity, passion, and hard work. Its release, no doubt, is a cause for celebration for all of the Vue community members who have been eagerly awaiting it. I, for one, am thrilled to share some resources that I believe will help developers migrate to Vue 3: - Vue 2 -> Vue 3 Migration Guide - Vue Router 3.0 -> Vue Router 4.0 Migration Guide - Vuex 4 - Chrome Vue JS DevTools - FireFox DevTools Here at This Dot, we have tracked Vue 3's development from the onset. We have written blog posts, published a book, hosted Vue Meetups, debuted JavaScript Marathon, shared Modern Web Podcasts, and more! Today, we’ll take a guided tour through all the material we have shared on Vue 2 and Vue 3. Blog Posts Here are our latest blog posts on Vue 3: - How to Set Up Storybook in Vue 3 - Async Components in Vue 3 - Your first Vue 3 app using TypeScript - Teleporting in Vue 3 - Content Distribution in Vue 3 - Custom Directives in Vue 3 - Vue 3 Composition API, do you really need it? You may access the remaining blog posts at This Dot Labs Blog. A Complete Guide to VueJS In April 2020, This Dot released A Complete Guide to VueJS by Bilal Haidar. This book is a precise, and detailed resource for learning VueJS, and highlights some top courses for Vue and JavaScript. Most importantly, it gives a brief introduction to almost all the new features in Vue 3. Grab your own copy for free! Vue Meetups We have hosted more than 10+ Vue Meetups in the past year with dozens of speakers, including Evan You, other Vue Core team members, and Vue developers interested in the future of the framework. To watch past meetup recordings, follow this link to get access to all the meetups on one page. JavaScript Marathon This Dot's team delivered six free live Vue JS tutorials during the JavaScript Marathon. Here’s a list of all the VueJS live sessions recordings: - 1 Hour to Learn Vue - Master State Management in Vue with VueX - Master PWA in Vue - Learning Unit Testing in Vue - Pro Tips on Using AWS with Vue - Debugging Vue: Quick Tips and Tricks Modern Web Podcasts This Dot's team delivered more than 40+ podcasts in the last two years. Here’s a link to the Vue JS Podcasts: - S07E1 Modern Web Podcast - Introducing Vite - Evan You’s new project + Vue 3 Updates - S06E12 Modern Web Podcast - Vue 3, Code Education, & the Vue Community - S06E4 Modern Web Podcast - Vue Updates with Chris Fitz, Jake Dohm, and Rob Ocel The Future of Vue The team at This Dot is hardly finished tracking Vue's progress, as well as the progress of many other web based technologies. To join us on our technical exploration journey, be sure to follow This Dot Media on Twitter! If you have specific questions about how to begin your Vue 3 migration, or have general questions about Vue 3, don't hesitate to reach out to us at hi@thisdot.co....
Sep 18, 2020
4 mins
Async Components in Vue 3
Explore the revamped Async Components API in Vue 3, by focusing on their utility in medium to large applications by efficiently loading components asynchronously, and provides examples demonstrating both simple and options-based usage of the API....
Sep 4, 2020
5 mins
Your first Vue 3 app using TypeScript
Vue 3 has been rebuilt from the ground up using TypeScript. Since Vue2, Vue has supported TypeScript and still does. However, these days, I sense a certain hype and interest to develop Vue 3 apps using TypeScript. Without any doubt, developing JavaScript apps using TypeScript is a life saver. TypeScript, in addition to the many goodies it brings, provides type safety. You will be happy, your IDE will be happy, and of course, it makes writing JavaScript more interesting and robust. This article will take you on a step-by-step guide to creating a Vue 2 app, adding TypeScript support, upgrading the app to Vue 3 RC 5, compiling the app, fixing some common compile time errors, and finally make sure the app runs in the browser. > If you’re new to TypeScript, I suggest you watch this free course Learn TypeScript from Scratch by the distinguished [Maximilian Schwarzmüller](https://academind.com/). > If, on the other hand, you want the source code accompanying this article, feel free to access it at this GitHub Repo. _Disclaimer - This article applies to existing Vue 2 apps that you want to upgrade to Vue 3 and add TypeScript to the mix, and to any new app._ Demo Let’s start by creating a Vue 2 app, and going through the necessary steps. Create a New App As the sub heading suggests, we will be creating a Vue 2 app using the Vue CLI. Step 1: Install @vue/cli NPM package Open a terminal window and run the command: ` Step 2: Create a new Vue 2 app ` Select the default preset when prompted. The CLI scaffolds the files for you, and also initializes a Git repository for the app. Step 3: Run the app Run the app to make sure it’s working properly: ` You should have a running app now! Add TypeScript Support Let's run the following command to add TypeScript support to our app. ` The command above downloads and installs the @vue/cli-plugin-typescript plugin to bring TypeScript support to our app. Once installed, you are asked a few questions that are shown in Figure 1. | Installation Questions | | ---------- | | Use class-style component syntax? Yes | | Use Babel alongside TypeScript? Yes | | Convert all .js files to .ts? Yes | | Allow .js files to be compiled? Yes | | Skip type checking of all declaration files? Yes | Among the many things the plugin adds to the app, I’d like to point out the tsconfig.json file at the root of the app folder. TypeScript uses this file to customize the compilation process, and gives you a chance to do so, to suit your needs. The settings below are recommended by the Vue team. However, feel free to add or change things as you see fit. > For a complete list of all the options available for you to use in this file, follow this link tsconfig.json. ` Finally, make sure to commit your changes to Git before moving on any further. Upgrade App to Vue 3 Now that the app supports writing Vue Components in TypeScript syntax, let's move on, and upgrade the app to Vue 3. Step 1: Add the Vue-Next Plugin Open a terminal window and navigate to the root folder of our app. Then, run the following command: ` The command downloads and installs the vue-cli-plugin-vue-next plugin to upgrade the app to Vue 3. Figure 2 shows all the steps the CLI has taken to perform the upgrade. Open the /package.json file, and make sure the dependencies and dev-dependencies sections are similar to the one below: ` The vue-next plugin automatically goes through your app files, and converts them to be compatible with Vue 3 syntax. Step 2: Fix Warnings & Errors At this point, if you compile the app, you will see some warnings and errors. These are mostly related to using TypeScript in Vue 3. Let's tackle these one by one. Run the following command to compile and start the app in the browser: ` The output is shown below: Warnings ` Errors ` The warnings and errors show that TypeScript is not able to digest the HelloWorld Component that's written in the old TypeScript syntax for Vue 2. Let's refactor this component to use the latest TypeScript syntax in Vue 3. Currently, the /components/HelloWorld.vue component's script block is defined as follows: ` First of all, notice the use of a lang="ts" attribute on the element. This defines a TypeScript code block instead of a JavaScript code block. Let's replace this code with: ` The code makes use of the new defineComponent global method. This method lets TypeScript properly infer types inside of the Vue Component options. The defineComponent method accepts an input parameter object. It can be an Options API object or a Composition API object. > You can read more about Options API and Composition API by checking my article on Vue 3 Composition API, do you really need it? Now that the HelloWorld component is refactored. Let’s move on, and refactor the App.vue component to use the new TypeScript syntax in Vue 3: ` Let's run the app by issuing the following command: ` Wow! More errors and warnings! ` Importing Vue Components The error above is generated for Line #2 in the main.ts file: ` Typescript, like ES 6, supports modules by using the keywords import and export. As long as you are writing your modules in TypeScript, that is, module files ending with .ts then you are covered. The error above signals that TypeScript is not able to import the App component, as if the App.vue module returned is not understood by TypeScript. The solution? Define a shim or declation file at the root folder of the app. This file has the extension of .d.ts. It basically makes it easier for the tooling to know how to handle *.vue files, also known as Single File Components (SFC). Locate the shim-vue.d.ts file at the root folder of your app and replace its content with the following: ` The code declares a TypeScript module for every file ending with *.vue (SFC). TypeScript will digest such a module as having the following: - An import statement for the defineComponent global method - Declaration of a component variable of type defineComponent - Finally, a default export of the component variable Having the shim file above allows TypeScript to consider any Vue Component to be a well-defined module. Run the app Now you can safely run the app knowing that it will run successfully inside the browser. Run the following command to start the app: ` Navigate to the URL http://localhost:8080 inside your browser and you should be able to see the default home page of a newly created Vue 3 app using TypeScript, as shown in Figure 3 below. Use Composition API with TypeScript Now that the application is TypeScript-aware, let me show you how you can make use of the Composition API and type safety to define a function with typed parameters. Replace the content of the HelloWorld component script with the following: ` Notice how the code defines a new function using the Composition API with a typed parameter. The parameter is named msg and has a data type of string. Conclusion Whether you are upgrading your existing Vue 2 app, or starting a new one, the article provides a step-by-step approach to adding TypeScript to the app, upgrading to Vue 3, fixing all warnings and errors, and finally running the app successfully in the browser. This is a stepping stone in your way to build Vue 3 apps with TypeScript. The next step is to familiarize yourself more with TypeScript. Happy Vueing!...
Aug 17, 2020
6 mins
Teleporting in Vue 3
An introduction to Teleporting feature in Vue 3...
Aug 14, 2020
7 mins
Content Distribution in Vue JS
Vue implements a content distribution API inspired by the Web Components spec draft, using the element to serve as distribution outlets for content. It promotes building composable and reusable components. Many folks have been writing about, or discussing, best practices, how to build components, how they communicate with each other, and how they should be structured in an app. In this article, we'll dive head-first into Vue.js Slots, and Scoped Slots concepts, and go through code samples. Slots A Slot is a placeholder that allows content projection from a parent component to a child component. The Vue engine, at runtime, processes the parent template, pulls the dynamic content, and injects it inside the Slot placeholder in the child component. In general, the child component hosts the element, and the parent component specifies the content to go inside it. Figure 1 shows the interaction between a parent and child component. | Figure 1: Parent and child component| | - | Basically, Slots are used for building Layout components (also known as Master Pages), base components (Button, Hyperlink and the like) or any other type of composable components to provide flexibility for component consumers to inject dynamic content at runtime. Let’s create a Button component with a element. ` The Button component is basic and contains a single element. The button wraps a component with a default fallback text. This means, if the parent component didn’t provide any content for the Slot, it will be replaced at runtime with the default fallback text Click Me. Let's embed this Button component inside a parent component. ` The child component Button is embedded into the parent component like any other normal component in Vue.js. Notice that in the code snippet above, the parent component is not injecting any content. When you run the app, you will see an HTML element with the default fallback text. Figure 2 shows the app running. | | |-| |Figure 2: Slot with default content| Let's inject some other text instead of the default fallback text, and run the app again. You have multiple choices when it comes to injecting content. Without element ` With element ` Personally, I prefer the option using element. The template content will be rendered in place of the element. The element has a special attribute called name. This allows you to embed multiple Slots in your component, each designated with a different Slot name. A element without a name attribute is considered the default Slot. To provide content for a element, you would use the v-slot directive, and then specify the name of the Slot. In this code snippet, we could have removed the v-slot:default as this is the only element in the component. But, as a best practice, and in case you add more Slots in the future, I’d recommend you stick to this naming convention by using the v-slot:default. You can play with this example on codesandbox.io. Let's assume the Button component has another slot: ` Inside the parent component: ` There are two elements, each for a specific slot.To add content to the default element, you add the v-slot:default directive by specifying the name of the slot. For the footer Slot, you provide the v-slot:footer directive to target the footer element. Now, it makes more sense to use the v-slot directive on both Slots to differentiate them, and make your code readable. You can play with this example on codesandbox.io. Slots and Props Thus far, we have seen how to use elements, and inject content to them. In some other cases, you might need to pass data to Slots. Slots are generally compiled under the parent’s component context. This means whatever content you project inside a element is aware of the parent’s context only. For instance, if you have an interpolation or binding projected inside the element, these will be compiled with respect to the parent component, and not the child component. A code snippet is worth a thousand words. ` The {{ text }} interpolation is referencing a local data variable defined on the component named text. The Vue.js engine compiles the projected content inside the parent component scope, and embeds the results into the child component. You can play with this example on codesandbox.io. A element can also render default fallback text passed from the parent component to the child component. How? Nothing special really. It's similar to how you pass data to Vue components via props. Let's introduce a new text property on the Button component: ` In the parent component: ` You make use of Vue.js binding convention to bind the text prop on Button component to a local variable also named text. That’s all! You can play with this example on codesandbox.io. You can even go wild and accept a prop of type Function on the child component! The child component can share its context with the parent component. The parent component can then manipulate the child component context and return whatever content back to the child component. The child component accepts a prop of type Function: ` The default fallback content inside the child component calls the prop Function passing some random text. The parent component defines the prop Function as follows: ` The function textFunc() executes under the parent component context. In this case, the function returns the text received from the child component, and appends it to a message that’s local to the parent component. The end result is shown in Figure 3. || |-| |Figure 3: Function prop| You can play with this example on codesandbox.io. The takeaway, in using functions as props, is the ability to share the child component’s context with the parent component. Scoped Slots Passing functions as props to a child component is one way of sharing context between child and parent components. However, this method is limited to text only. The function defined on the parent component can only return text. What if you want the parent component to pass HTML content to the child component’s slot(s) and also make use of the child component context? This is where Scoped Slots play their part. Pretty complicated right? Well, not as complicated as you might think. Let’s check it out together! Let's build a List component that owns an array of objects with a title and description properties. ` The component uses a element to loop over the items in the array. An element is used to represent a single item. The code places a element inside each and every element. The slot is bound to the single item object. In addition, the element defines a default fallback content. Let’s switch to the parent component: ` The component binds the items array property to the List component property items. It uses the default fallback content coming from the child component. Figure 4 shows the app running: || |-| |Figure 4: List component with default fallback content| Let’s see how we can make use of the Slot binding. As a refresher, the child component defines the following: ` The element binds the item object on the Slot. It also provides a default fallback content. What if the parent component wants to replace this default content with a new content? That's easy! Let's change the parent component as follows: ` The code snippet provides a with a v-slot:default directive. The value given to the v-slot:default directive is actually the directive value representing the object passed in by the element defined inside the child component. > As a side note, I am writing another article, to be published very soon, exploring custom directives in Vue.js. Stay tuned! Going back to the code snippet, the parent component now has access to the child component represented by the v-slot:default directive value. The element replaces the default fallback content by rendering just the title field and making it bold. Figure 5 shows the app running: || |-| |Figure 5: List component with custom content| Scoped Slots is a powerful tool in Vue.js to allow you to build composable and reusable components. Slots in Vue 3 The content on Slots and Scoped Slots in this article applies to both Vue 2 and Vue 3. I am not aware of any change up until this moment. Things might change with the final release of Vue 3, but we’ll have to wait and see together! Conclusion Vue Slots feature gives developers the flexibility needed to build reusable and composable components in their applications....
Jul 23, 2020
7 mins
Custom Directives in Vue JS
Vue JS promotes the use of components as the primary form of code reuse and abstraction. However, there are some instances when you want to manipulate the low-level DOM from within Vue JS components. In these instances, directives come to the rescue! If you have already been developing apps with Vue JS you must surely be familiar with some of the core directives offered by the Vue JS core team. Here are a few worth mentioning: v-model, v-if, v-for’, etc. In this article, I will cover everything you need to know to start building your own custom directives in Vue JS. Dissect a Custom Directive Custom directives enrich HTML with new reactive functionality that's fully managed by Vue JS. Let's start with a full dissection of a basic custom directive written for Vue JS. Consider the following directive: ` This example registers a new global custom directive into the main Vue instance. Later I will discuss the different ways available for registering directives. For now, let’s focus on the directive itself. A custom directive is defined by a JavaScript literal object implementing a set of functions. These functions are called hooks by Vue JS and are standard to any custom directive. More on hook functions in the coming section. The inserted() hook function accepts the el input parameter. This parameter represents the HTML element where this custom directive is applied. Inside the function, the focus() function is called on the element itself. In summary, when the element with the custom directive is added to its parent node, this function runs and makes the element in the focus state. How do you apply this custom directive inside a component? Every custom directive should be prefixed by the letter v-. In this case, assuming we are adding this custom directive to an input control, then it follows like this: ` Hook Functions All hook functions provided by Vue Js for building custom directives are optional. Hook functions are there to help you customize and provide the needed functionality for the directive at certain stages of the directive life cycle. There are five available: - bind - inserted - update - componentUpdate - unbind bind This function is called once when the directive is bound to the underlying element. Think of it as a one-time setup hook. inserted This is called when the underlying element is inserted into the parent node. This doesn’t mean the element is inserted into the live DOM but rather its context is now known and part of a well-defined tree of nodes. You can read more about VNodes to understand how Vue JS works with them. update This function is called after the containing component's VNode has updated, but possibly before its children have updated. componentUpdate This is called after the containing component's VNode and the VNodes of its children have updated. unbind This function is called only once when the directive is unbound from the element. Vue JS engine passes the same set of input parameters to all hook functions. Let's look at these parameters. Binding Function Parameters Each and every hook function receives the same set of input parameters defined as follows. el This parameter represents the element that this custom directive is applied to. It can be any valid HTML element. binding This input parameter is an object containing the following properties: name: The name of the directive without the v- prefix. For instance, using a custom directive as v-focus yields a name of focus. value: The value passed to the directive. For instance, using the v-slot=”prop” directive yields a value of prop. oldValue: This field is only available inside update() and componentUpdate() hook functions. It contains the previous value of the directive, before the update. expression: This field represents the expression of the binding as a string literal. For instance, using the custom directive v-add="1+1" yields an expression of "1+1". arg: This field represents the argument (if any) that's passed to the directive. There can be only one argument passed. For instance, using the v-slot:default directive yields an argument of default. modifiers: This field is an object containing modifiers that could change and control the behavior of the directive if they are set. Think of modifiers as flags you set on the directive. If a modifier is set, it will have a value of true, if not set, it won’t even be visible to the directive. For example, using the directive v-on:click.prevent yields a modifier of { prevent: true } object. vnode The virtual node produced by Vue's compiler. See the VNode API for full details. oldVnode The previous virtual node, only available in the update() and componentUpdated() hooks. Now that you know all about hooks and the details about their input parameters, let's see how you register a custom directive in your Vue JS app. Globally Registered Directives There are two ways to define and register a custom directive. In this section, we will look at how to register a custom directive globally in your app. To do this, navigate to the main.js file located at the root folder of your application and add the following to register the focus custom directive. ` The Vue.directive() function accepts as a first parameter the name of the custom directive (without the v- prefix). The second parameter is the custom directive object. In this case, the object contains the inserted() hook function only. That's it! Now you can use the custom directive anywhere inside your components. Locally Registered Directives The second way of registering custom directives is local to the component. You can define and register a custom directive to be used inside a single component. In case you want to use the same custom directive somewhere else in your app, you have to redefine it again inside the other component. This method of registering custom directives is definitely limited and might not be used often, if not at all! I strongly recommend registering your custom directives as global directives for better performance and easier access across your app. To register a custom directive locally, navigate to the component where you want to use the custom directive, and add the method below as part of the Vue Options API: ` That’s it! Demo: List Custom Directive Now that you understand custom directives in Vue JS, let's build a custom directive. The custom directive I am going to build in this section is the v-list directive. Using this custom directive as such: ` Yields the following HTML being generated inside the DOM: ` Given a variable named items defined as an array of strings, yields the app showing in Figure 1: || |-| |Figure 1: The List custom directive in action| Figure 2 below shows the details of using this custom directive: || |-| |Figure 2: Using the custom directive| The diagram above is self-explanatory! Let's sift through the code and define this custom directive. > You can play with the custom directive on codesandbox.io. Add a new \directives\List.directive.js file and add the following code: ` This code snippet defines an object called directive. Then, this object is exported as the default export of this code file. The custom directive at hand makes use of the bind() hook function to implement the functionality of this directive. First of all, it checks if the binding.value is bound to an array variable. If not, it returns and nothing happens. The next step is to validate the argument and modifiers. This is done in a separate local utility function called validate. We will get into this very shortly. The validate() function not only validates the different parts of the custom directive but also sets some default values in order to appease the rendering process. Finally, it's time to render the list, whether a ul or ol list. Let's have a look at the validate() method. ` The method prepares a well-defined result object containing the following properties: - items: This property represents the binding.value of the directive. Whatever array variable you bind to the directive, it is being captured inside the items property. - listType: This property represents the type of list to render. Whether it is a ul element or ol element. It represents the binding.arg property defined on the custom directive. - listStyleType: This property represents the list-style-type CSS property defined on an ul or ol element. It represents one of the modifiers that this custom directive accepts. The code validates this modifier based on a known list of values that the list-style-type property accepts. - listStylePosition: This property represents the list-style-position CSS property defined on a ul or ol element. It represents one of the modifiers that this custom directive accepts. The code validates this modifier based on a known list of values that the list-style-position property accepts. The properties above are defined with a default value representing the real default value behind list-style-type and list-style-position respectively. If these modifiers are incorrect, the default values take precedence. Let's have a look at the render() method: ` This method starts by clearing the parent container, the el element. It then creates a new HTML element, whether a new ul or ol element. It appends the list into the parent container el element. After that, it sets the listStyleType and listStylePosition properties on the newly created list element. It then iterates over the items stored inside the binding.value array. For each array item, it creates a new li element, appends it to the list element created above, and sets it's textContent property to the value of the array item. To use this custom directive, switch back to the \main.js file and register this directive globally as follows: ` That's all! Navigate to App.vue file and add the directive as follows: ` Attach the directive to a element. Then set the items variable to an array of strings. Running the app yields the same app shown above in Figure 1. This custom directive can be made much more complicated. However, I opted for a simplified implementation to illustrate the ideas behind building a custom directive in Vue JS. > You can play with the custom directive on codesandbox.io. Conclusion Despite the fact that Vue JS pushes for coding components rather than custom directives, there are some instances when you need to manipulate the DOM reactively using custom directives....
Jul 13, 2020
8 mins
Going Serverless with Vue.js and Firebase Cloud Functions
Welcome to a new episode of the Fire the base of Vue.js! series. In this episode, I will integrate our Vue.js Notes Writer App with a serverless backend- specifically, the Firebase Cloud Functions. If you haven’t read the other parts of this series, I highly recommend you do so before starting here. Vue the Mirage from this angle! Storing your notes in the Cloud Firestore with Vue.js Firebase for user authentication in Vue.js To follow up on the demo part of this article, you can use this GitHub source code repo as a starting point. Firebase Cloud Functions, the concept Cloud Functions are part of the Google Cloud Platform. You use them to write and deploy code that can respond to events coming from Google Cloud Services, including, but not limited to, the Firebase family of products. With Cloud Functions, you piece together your application using different products. For instance, a user creates a new Document inside Firestore via the Web app. Consequently, a Cloud Function triggers, and responds to the event of Document Creation. The logic of a Cloud Function depends solely on the business scenario you are implementing. Not only do they let you connect Google Cloud Services together, but they also allow you to create your own set of REST APIs to consume inside your Web or Mobile app. The Cloud Functions project is a wrapper on top of the Google Cloud project. However, it was made easier for developers to configure and use. The two major benefits Cloud Functions offer: Centralize your code in a safe way on Google Cloud Servers. Firebase Cloud Functions run on Google Servers. All of your apps, whether they be Web, Mobile or Desktop, can access and use them. Code security. It is better to save the access codes and keys for Firebase Services on the backend (on the Google Servers) rather than exposing them inside the client-side app code. Cloud Functions are best used to: Trigger code in response to events coming from Firebase products. Perform writes to the Realtime Database and Firestore Upload to your Cloud Storage buckets. Respond to new accounts created in Firebase Authentication. Handle incoming HTTPs Request. Firebase supports two flavors of Cloud Functions: HTTPs triggered Functions Background triggered Functions Unlike Google Cloud Functions, Firebase Cloud Functions support only JavaScript/TypeScript with Node.js. The team is working on including more programming languages. Until then, let’s enjoy JavaScript! HTTPs Triggered Cloud Functions Let’s explore the anatomy of Cloud Functions for HTTPs triggers. Start by ensuring Node.js version >= 8.13.0 is installed on your machine. Next, install the Firebase CLI globally on your computer by running the following command: ` Create a Firebase project by running the commands: ` The next step is to log into Firebase services to connect the new project. Issue this: ` That command opens up a new tab in your default browser to ask for some permissions needed by the Firebase account. Let’s initialize the Firebase project by running the following command: ` This command guides you through a command-line wizard to choose the Firebase features you want to add to the project. For our case, let’s pick the following: Which Firebase CLI features do you want to set up for this folder? *Functions* What language would you like to use to write Cloud Functions? *JavaScript* Do you want to use ESLint to catch probable bugs and enforce style? *Yes* Do you want to install dependencies with npm now? *Yes* That’s all! Let the Firebase CLI do the project scaffolding, and get the project files ready. The command scaffolds a Node.js project, and stores the Cloud Function related code inside the /functions folder. The /functions.package.json lists all the dependencies needed by the Cloud Function. The most important dependencies are: ` Let’s make sure we have the latest bits of these packages by running the following command: ` The /functions/index.js file contains the Cloud Function code. ` The index.js file is a typical Node.js module file that exports a single Cloud Function named helloWorld. You can export more functions as needed. The module starts by requiring the firebase-functions library. This library allows you to create Cloud Functions for HTTPs triggers. It exposes the onRequest() function. This function expects two parameters, the Request and Response objects. The callback function is required to return a Promise by issuing a call for response.send() function. The popular Express.js module for Node.js is behind a Cloud Function for HTTPs trigger. When you deploy a Cloud Function on Firebase, it creates an Express.js app behind the scenes. This app will listen to any HTTPs request for /helloWorld, prepare a Request and Response object, and will call through your Cloud Function, passing it to the two objects. You can include any code inside the onRequest() callback function like you do when writing Express.js apps. > I highly recommend reading this great article on dissecting the Express.js module, and learning how it’s made under the hood. Understanding how Express.js Works Let’s run this Cloud Function locally by issuing the following command: ` The command starts the Firebase Cloud Functions emulator to allow you to run the function locally, without the need to deploy it to Firebase servers. ` Copy & Paste the Function URL into your browser, and you will see a plain text response of Hello from Firebase!. To deploy the Cloud Function to Firebase platform, run the following command: ` > Cloud Functions for HTTPs triggers can only be run under HTTPS and not HTTP. Inside a Cloud Function for HTTPs trigger, you can call any other third party service. You can query the Firestore database, and return data from it, for instance. > You can always refer to the amazing Firebase Cloud Functions documentation to study the full range of capabilities supported by them. Background Triggered Cloud Functions The Background Triggered functions is the other type of functions offered and supported by Firebase. Each and every product in the Firebase family exposes a set of events that are triggered upon a certain action. For example, when a new Document is created inside Firestore, the OnCreate event is triggered. Another example is when a new User is created in the Firebase Authentication module, the onCreate event is triggered. ` The functions object gives access to all supported types of Cloud Functions. This includes both the HTTPs, and Background triggered ones. The example above gives you access to the user that was created. Then, you might decide to send the user an email, or push down a notification to the app. The sky's the limit!! The Firebase Cloud Functions supports all Firebase products, and gives the developer the chance to handle many of the events triggered by them. > For a full list of all the supported background triggered functions, have a look at Trigger background functions The Firebase Cloud Functions documentation is complete, and is extremely helpful to learning all the ins and outs. Therefore, without any further ado, let’s jump into our Notes App Writer, and add a new background triggered Cloud Function. Demo Clone the Notes App Writer at the add-auth branch. This is the branch we worked on in the previous article while authenticating users in the app. Clone the app Run the following command to clone the branch: ` Make sure to install all NPM packages by running this command: ` Add support for Firebase Cloud Functions If you haven’t logged into Firebase before, it’s time to do it by running this command: ` Once you log in, let’s initialize the Firebase services once again to include Functions this time. ` Follow the same steps mentioned in the HTTPs Triggered Cloud Functions section. You will notice a new folder created under the root folder of the project named functions. This folder, as you know by now, holds all the source code for the Cloud Functions in your project. It’s always important, whenever you add support for Cloud Functions in your project, to update the Firebase NPM packages by running the following command: ` Use Environment Variables to store configuration settings Let’s revisit the /firebaseConfig.js file. This file holds the Firebase connection settings as provided by Firebase Console. I will make use of a hidden gem in Vue.js CLI v3, which allows you to use Environment Variables in your application to store such configuration settings. In fact, this is the recommended way of storing configuration settings in a Vue.js app rather than putting them in plain JSON or JavaScript files. The CLI documentation referenced above gives you all the details about the Environment Variable files to use in your app. For now, create a new .env file at the root of the project, and paste the following keys: ` Grab the actual keys from the Firebase Console and place them after they == sign on each and every line. For instance, ` Going back to the firebaseConfig.js file, replace its content with the following: ` Implement the Cloud Function Let’s visit the functions/index.js file, and start implementing our function logic. The purpose of this function is to listen to any new Note Document created inside Firestore, grab its details, and send them in an email. Replace the contents of the index.js file with the following: ` The JavaScript module imports the Firebase Functions Admin SDK libraries. > The Firebase Admin SDK lets you interact with Firebase from privileged environments to perform several actions. The module exposes a single Cloud Function named onNewNoteCreated. This function subscribes to the OnCreate() event handler to run once a new Firestore Document is created. The onCreate() event handler accepts as callback function having two parameters: DocumentSnapshot. EventContext. The former parameter lets you access the content of the Document created, while the latter lets you access the context in which the event has occurred. The next line extracts the body property of the Notes Document. Then, the code extracts the notesId from the EventContext parameter. The variables are then logged to the Cloud Functions Logs database. From my experience, the Cloud Functions Logs is the best tool to debug and test your functions! Finally, the function returns a resolved Promise. I will further discuss the concept of returning Promises from Cloud Functions in the next section of this article. Let’s run the Cloud Function locally first by using the Firebase Functions Shell. Run the following command: `bash onNewNoteCreated({ body: "Hello Firebase Functions!" }, { params: { notesId: "note-#001" }}) `bash 'Successfully invoked function.' firebase > > { eventId: 'c6f8eec2-e7e0-463e-9966-c8c8b0a25505', > timestamp: '2020-02-15T08:12:02.088Z', > eventType: 'google.firestore.document.create', > resource: > { service: 'firestore.googleapis.com', > name: > 'projects/notes-writer-f1s85/databases/(default)/documents/notes/note-#001' }, > params: { notesId: 'note-#001' } } > Hello Firebase Functions! > note-#001 `bash npm install nodemailer `javascript const functions = require('firebase-functions') const admin = require('firebase-admin') const nodemailer = require('nodemailer') admin.initializeApp() var transporter = nodemailer.createTransport({ host: 'smtp.gmail.com', port: 465, secure: true, auth: { user: '', pass: '' } }) exports.onNewNoteCreated = functions.firestore.document('notes/{notesId}').onCreate((snap, context) => { const { body } = snap.data() const { params: { notesId } } = context console.log(body) console.log(notesId) const mailOptions = { from: '', to: '', subject: 'A new note is created', html: ` New Note A new note is created with the following details: Note Id: ${notesId} Note Body: ${body} ` } return transporter.sendMail(mailOptions) .then(() => console.log('Email Sent!')) .catch(error => console.error(error)) }) `bash firebase deploy --only functions `javascript return transporter.sendMail(mailOptions) .then(() => console.log('Email Sent!')) .catch(error => console.error(error)) }) ` The sendMail() function sends an email, and returns a Promise. In our case, we are sending an Email Sent! message to the logs when the Promise is fulfilled. Also, we are logging any errors when the Promise is rejected. At the same time, we are returning the sendMail() Promise to let the Cloud Functions Runner use that Promise to clean up the resources for this function. This only works because JavaScript Promises are chainnable! Conclusion For now, this will be the last episode on Fire the base of Vue.js! series. Firebase is such a big topic, and requires many articles to cover it all. The team at Firebase did a great job at providing decent documentation. Still, I believe, working with the Firebase SDKs will give you experience and knowledge that theory cannot. In the future, I might add episodes to this series. However, in the coming two weeks, I will start a new series on Vue.js development. Stay tuned! Happy Vueing!...
Mar 11, 2020
10 mins
Vue 3 Composition API, do you really need it?
Oh What a New Vue! The Vue team has announced that version 3 of the Vue framework will be released during Q1 2020. The new framework is expected to bring a number of advancements, most of which target the framework core itself, while maintaining the standard syntax for building Vue apps to which we have become accustomed. Essentially,the codebase is rewritten, and the framework is changed. With new features in JavaScript, the opportunity to rewrite was seized. Additionally, they incorporated developer feedback and ideas to the framework, and it shows. The result is a much more performant framework. Developers will notice an improvement in the framework performance without having to dig into the source code to adjust it. Thank them later when you discover just how much heartache this saves you! Below is a brief summary of the things that will change in Vue 3: - Virtual DOM rewrite for better performance, and improved TypeScript support. - Exposed Reactivity API. - Time Slicing Support. - Static Tree Hoisting. - Optimized Slots Generations. - Monomorphic Calls. We will focus on the new Vue 3 Composition API. This API is fully optional, however, you can easily integrate it, and benefit from it in your app. To stay in the loop on the Vue 3 roadmap, I highly recommend you keep checking this website Vue 3 – A roundup of infos about the new version of Vue.js Vue Components / Ways to build them The new Composition API is Vue’s approach to building Components in Vue 3. Using the Component Options API has been the traditional way of building components adopted in Vue 2. A component has several options that a developer can use to implement a certain feature inside the component. With several options, a developer can use, and implement a certain feature inside the component. Component Options API / Traditional method For instance, your app has a feature to display a list of products and allow the user to execute Create Read Update Delete (CRUD) operations on them. One of the possible ways to implement this feature in a Vue 2 component is to define the following script code: ` The Component Options API refers to the artifacts that a Vue 2 component offers to help you implementing a certain feature in your app. The data option is used to define an array of product items to display, and a single product object to track selected or new products. The methods option is used to define any custom function or method you need to use in the component. There are other options too like computed, watch, etc. This has been the traditional way of building components in Vue 2. This approach works well for small or even medium apps. The problems emerge when the app grows to a few thousand components. Typically, your entire app won’t be built with a few components only. The best approach has been to compose your app out of smaller components. This has many benefits in terms of testing, readability, and code maintenance. In other words, with more features implemented, the components become convoluted and difficult to track. Moreover, the Options API has limits on code reuse and sharing. Shared functionalities have to be repeated over and over again throughout your components. The Component Options API itself introduces confusion to developers. Think of it this way; if you want to build a single feature, you have to scatter it among the different options (props, data, watch to name a few). As components are growing in size as well as function, the features are scattered across the options inside a component. A hot mess! Component Options API and Mixins The Component Options API doesn’t promote code reuse or share. This adds to its complexity when using it. One solution to mitigate around the complexity is to build components with the help of mixins. We still have to deal with the fact that features' implementations are spread over several options. However, now with mixins, you can enhance your components by employing more code reuse and sharing common functionalities inside mixins. Vue mixins allow you to refactor your common code inside a mixin file. Then, you can import this mixin to any component that needs to use this common code. This is a step in the right direction, to solving the problem of code reuse in Vue 2 apps, but it’s not the end all and be all. Why? A mixin follows the same standards of the Composition Options API. Let’s refactor the component shown before making use of mixins: ` Almost all of the code in the component has been stripped out. A ProductsMixin is now imported into the component. To let the component know and use this mixin, you add the mixin into the mixins option array. The ProductsMixin looks like this: ` The mixin exports a default ES6 object that uses the Component Options API to layout its code. Looking at a mixin file reminds me of a Vue component. The same structure and organization! I’ve removed the data and methods options from inside the component, and placed them inside the mixin. At runtime, the Vue framework will merge the component code, and the mixin code, to produce a single component with options coming from the two sources. You can import this mixin to other components in your app where they need to offer Products CRUD operations. Using a mixin comes at a cost: - Naming conflicts. - The complexity of the Component Options API is inherited. - Complexity in tooling. With mixins, you always have to open the mixin file and check the names of methods or data properties before using them. The auto-merging happens behind the scenes at runtime. Therefore, there is no way to have intelligence inside the components for mixins fields. Things to keep in mind when using Vue mixins: - Life cycle hooks run first for mixins then for components. - Options from both components and mixins will be merged at runtime. - The components options will take priority when there are conflicting keys in these objects (methods, data, etc.) Using the Composition API The Composition API introduces a new approach to building components, and implementing features in them. Let’s see how the aforementioned component with the mixin example can be converted to the Composition API approach. First, let’s look at the Products component: ` The most remarkable section of the component is the setup() function. It is added by the new Vue 3 Composition API. Vue is aware of it, and will run it before even creating the component object itself. Hence, this explains why the object this, that refers to the component itself, is not available inside the function. Inside this function, you define the data properties, computed methods, watch methods, normal methods and any other utility methods needed for your code. It should expose and return an object containing all the public methods and data properties. By public, we mean anything you want shared and used by the Vue component itself. In our case, the function returns an object by spreading the useProducts() function. In the Vue 3 Composition API terminology, useProducts() is a Composition Function, and returns an object. The setup() function returns an object containing all data properties and methods returned by useProducts() function. The useProducts() function is defined inside the file /src/cmp-functions/Products.js as follows: ` Start by importing ref function from the @vue/composition-api package. It wraps any value or object, and makes it reactive so that if its value changes, Vue is aware of its presence, and it will update the UI accordingly. The useProducts() function is a normal JavaScript function (arrow function in our case). It returns an object. Inside the function, we define the products reactive data property with an initial value of an empty array. > Without the use of ref([]), Vue won’t be able to detect changes to the array, and the UI can’t be updated. The rest of the functions createProduct(), updateProduct(), and deleteProduct() are just JavaScript functions to handle the CRUD operations on Products. Notice the use of products.value when interacting with reactive data properties. This syntax is only required inside the composition function. When using the data properties inside a Vue component, whether for data set or get, you refer to the name of the data property without the need to use the .value syntax. This syntax is only used inside the composition function. Finally, the useProducts() functions return an object with the list of data properties and methods to expose and are available to the Vue Component. > A composition function returns a whitelisted list of data properties and methods to the Vue component. It can define as much as it needs to form private data properties and methods, without exposing them to the Vue component. You expose whatever is needed to run the feature you are building. > You can move the code from inside the useProducts() function to the body of the setup() function inside the component. This is absolutely legit. However, from the code reuse perspective, it’s recommended to move out a single composition function into its own JavaScript file. Now back to the Vue component, the setup() function returns the same list of data properties and methods returned by the composition function. The Vue component treats those properties and methods as if they were defined on the component itself. Inside the component template you can bind to the data properties and methods defined inside the setup() function. One cannot help but notice the many advantages the Composition API brings on such as: A composition function or setup() function doesn’t follow the Component Options API. Hence, a feature can be implemented as a single composition function, or even as one block inside the setup() function. There’s no need to spread a feature implementation anymore among the component options. You can put together data properties, private methods, public methods, computed properties, watch methods and others. To any vanilla JavaScript developer, a composition function looks very familiar. Nothing is special about it. Just a usual JavaScript function. The tooling experience has been improved. Now you specify exactly what you are returning from any composition function. This is compared to the auto-magic that was happening at runtime when mixins options were merged with the component options. Better and clear code reuse and sharing. Each and every feature is now implemented in its own composition function or JavaScript file. Demo Now that you have the theory down on the new Vue Composition API, let's look at how to develop a basic Vue 2 app that contains two views: The first is the Download Image view that allows the user to view and download an image file. The second is the Download Pdf view that allows the user to view and download a PDF file. I will first build this app following the traditional Vue Component Options API method. Then, I will enhance this method to make use of Mixins for code reuse. Finally, I will convert this app to make use of the new Vue Composition API. Start by cloning the app source code from the following GitHub repo git@github.com:bhaidar/vue3-composition-api.git. Once done, switch to the *dev** branch, and run the following commands in order to start the app. ` The app navigation bar allows you to switch between the two available views. Traditional Vue Components / Options API > the complete solution with duplicated components code can be found at feat/repeated-inside-components branch To build the download file feature, I am going to implement this feature in both Views separately. The implementation will be similar in both components, hence, I will show you only one of the implementations. Replace the content of the DownloadPdf.vue file with the following: ` The component defines some data options to track the download process, and display feedback accordingly. The downloadPdf() method makes use of axios HTTP Client to request the PDF file from the server. Once the file content is available, it creates a Hyperlink element with a URL pointing to a blob Url of the file downloaded, and simulates a click event on the link so that the file is forced to download inside the browser. > In a real-life example, you would most probably have a backend API that will handle downloading files. The same code is repeated inside the DownloadImage.vue view. The same code is repeated without any code reuse or sharing. Let’s see how we can improve on this code by introducing mixins. Using Mixins in Components > the complete solution with mixins can be found at feat/using-mixins branch I will now refactor the repeated code inside the views into a single mixin file. Add a new mixin under the path /src/mixins/DownloadFile.mixin.js. Place the following content inside this new file: ` The code is now more modularized, and split into smaller and readable functions. The same data properties have been defined inside this mixin. In addition, a new generic method, the downloadFile() is defined to cater for any file download. Switch back to the DownloadPDF.vue view, and update the component by pasting: ` The component is now more concise. It imports the DownloadFile.mixin.js file, and injects it into the mixins option of the Vue component. A message is now shown to signal the starting, success and failure stages of the file download. The mixin exposes a single method, the downloadFile(). The component calls this method to download the PDF file. Finally, let’s improve on the code and introduce the Vue Composition API. Using Composition API > the complete solution with mixins can be found at feat/composition-api branch To start using the Vue 3 Composition API you don’t have to wait until Vue 3 is released. The Vue team made available the Composition API for any Vue 2 app. Add the Composition API to your app by installing the following NPM package: ` Once the library is installed, go to the main.js file inside your app folder, and add the code to tell Vue to use this library or plugin. ` That’s all! Now you can start using the Composition API in your app. Let’s add a new composition function under the path /src/cmp-functions/download-file.js. Replace its content with the following: ` The code should be familiar to you by now. The only new thing you see is the definition of some computed properties. You define a new computed property inside the Composition API by using the computed() function. This function accepts a callback function that should return a value. This is the value of the computed property. It, as you know from Vue 2, it will track any change to the underlying data properties, and will run accordingly. The useDownloadFile() composition function makes use of several private functions. It only exposes what’s needed by the Vue component and not by exposing all the implementation. That’s it for the composition function. Let’s go back to the DownloadPdf.vue view to import this function and make use of it. Replace the content of the view with the following: ` The component imports the useDownloadFile() composition function. It extracts the computed properties and the downloadFile() method from the composition function and returns them from inside the setup() function. To download a file, the component calls on the downloadFile(‘dummy.pdf’, ‘application/pdf’) method, passing over the name of the PDF file to download and the file’s content type. To show download progress, the component binds the UI to the computed properties, defined by the composition function. Conclusion The Vue 3 Composition API is optional! I am pretty sure you can see the value and benefit when using the new Vue 3 Composition API. The most remarkable enhancement, in my opinion, is building a single feature in a single composition function without the need to spread the implementation among the Vue options (Options API). In addition, the new tooling experience and intellisense make it easier to see what you are importing from the composition function, and also what you are exposing to your Vue component. This brings an incredible experience while coding. Whether you start using the new Composition API in your apps will depend on what you want to achieve. I definitely recommend using the new API in much larger apps with many components where code reuse and sharing is necessary! Similarly, if you are fed up with the Component Options API and the notion of building a feature by spreading it over the different available options, it’s time to start using this new API! Happy vueing!...
Mar 4, 2020
12 mins
Firebase for user authentication in Vue.js
And the Firebase goes on! In the first installment of this series, I covered how fast you can kick off your dev life cycle by using the Mirage.js library as a local, and client-side, backend with a REST API in-memory service for your app. In my second, and most recent, [installment] (https://dev.to/thisdotmedia/vue-the-mirage-from-this-angle-352p), I replaced Mirage.js with Cloud Firestore, a serverless database service offered by Firebase. This, of course, makes our app function in a more realistic manner, giving us an overview of it. In this article, I will introduce Firebase User Authentication module to authenticate and authorize users accessing the Notes Writer app. Since my last article, I’ve done a complete face-lift for the Notes Writer app in preparation for user authentication. The app is now more responsive and mobile friendly. Here is a quick preview of the completed app after the addition of the User Authentication Module. The login page, needless to say, is self explanatory. The home page lists the existing notes, allows deleting or editing those notes and the ability to create new ones. This page introduces the Logout button as well. The app is shown on a mobile. You review your existing notes by clicking the burger button located on the left side of the app header bar. The source code of this article can be cloned from this GitHub repo: Notes Writer. Firebase Authentication Firebase Authentication Engine utilizes several methods to authenticate a user on your app via means such as Email with a Password, Phone, Facebook, Twitter, Apple ID, and many other options as shown here. For this article, I will be using the Email/Password provider to authenticate users on the Notes Writer app. > You can always consult with the amazing Firebase Authentication docs here. The Firebase Authentication module is also capable of doing user authorization by allowing administrators to define rules on how users can read, write, delete and edit data stored in the Cloud Firestore. You can read more about securing data in the Cloud Firestore here. Let’s move on, and start coding user authentication in our app! Demo We will be adding the authentication feature on top of the new UI branch of the Notes Writer app. Therefore, start by cloning the Git branch by running this command: git clone --branch new-ui git@github.com:bhaidar/notes-writer.git The command clones the remote new-ui branch by creating a local copy of the branch on your computer. Install Vue Router Start by installing the Vue Router NPM package by running this command: npm install vue-router This command adds the Vue Router library into the app to allow navigation from one route to another. Locate the /src/views folder, and add a new file named Login.vue. Initialize an empty Vue component by pasting the following content into the new file: ` Save the file and switch back to the router/index.js file. Configure Vue Router and routes Now that the Vue Router is installed, and the Login view is created, let’s configure the Vue Router in the app, and define the different routes available for the Notes Writer app. Inside the router/index.js file, start by adding the following imports: ` The firebaseConfig.js file is imported into this file, and is needed later on to check whether the current user is signed-in already. Configure the Vue object to use the Vue Router plugin by adding this line of code: ` This step is required by the Vue engine to install the Vue Router plugin, and make its functionality available to the rest of the app. Next, we need to create a new instance of the VuewRouter object, and define our routes as follows: ` The VueRouter instance defines a catch-all route to redirect users to the Home view. The Home route defines a meta object with a single property of requiresAuth. This boolean value is used later to decide whether the route requires the user to be signed-in before accessing it. Finally, the Login route is defined to load the Login view component. > If you are new to Vue Router plugin I suggest you visit their docs website The Vue Router defines navigation guards and hooks. These guard and hooks are extension points you can implement to change the default behavior of the Vue Router engine when handling a specific route. In our case, we want to implement the beforeEach navigation guard to decide whether the user can access the route he/she intends to visit. The decision is based solely on whether the route at hand requires the user to be authenticated, and that the user is indeed authenticated, and signed-in to the app. ` This hook or navigation guard accepts a single callback function that defines three main input parameters: - to: The route you are navigating to. - from: The route you are coming from. - next: Is a function that is used to move forward to the next hook in the pipeline, to redirect to a new route, to throw an error, and to terminate the current navigation. The callback function above started by checking whether the route the user is navigating to requires authentication. It then uses the Firebase Auth API to get a hand on the currently signed-in user. > You can read more about managing users in Firebase Auth API here. If the route requires authentication, and the user is not signed-in, then redirect the user to the Login view to enter their credentials, and sign-in to the app before visiting the route. If the route doesn’t require authentication, and the user is currently signed-in, then redirect the user to the Home view. If the route doesn’t require authentication, and the user is not signed-in, then let the user continue with the current navigation. For instance, this applies to a user visiting the Login view, or Register view. Finally, if none of the above applies, the user is allowed to route to the desired route. This applies to the Home view. This route requires authentication, and if the user is currently signed-in, then the user is automatically redirected to the Home view. To try this navigation guard, run the app by issuing the following command, and try to navigate to the root page /: ` You are instantly redirected to the login page to sign-in, and access the app. The final step is to tell the Vue about the routes that we defined above. Locate, and open the main.js file, and make sure to pass over the routes object to the root Vue instance as follows: ` Also notice that I’ve moved the initialization of the Vue root app inside the Firebase onAuthStateChanged event handler. This event is usually fired when a change occurs on the currently signed-in user. The user has signed-in, or the user has signed-out. This way, the app won’t initialize before Firebase is fully initialized. Implement Login view Naturally, the next step is to implement the Login view so that users can start accessing the app. Paste the following inside the Login.vue view component: ` The component defines a basic Login form with two fields: Email and Password. Upon clicking the Log In button, the event handler fires: ` The login() function makes use of the Firebase Auth API to sign-in the user using the signInWithEmailAndPassword() function. This function accepts as input both the user’s email and password. If the request is successful, this function returns the currently signed-in user. The code then calls a Vuex Store mutation to store the current signed-in user. In addition, the user is redirected to the home page to start managing the notes. In the case of an error, the code catches it, and informs the user that their sign in attempt failed. The above introduces a new piece of state that we need to manage inside the Vuex Store instance: the currentUser. Let’s build it. Navigate to the store/index.js file, and add the following to the state object: ` Also, add the mutation function as: ` Now the store is ready! Before you can sign-in using the above Login view, we need to set the Firebase sign-in provider on this app. Navigate to the Firebase Console. 1. Click on your app. 2. Click the Authentication menu item. 3. Select the Sign-in method tab. 4. Hover over the first row labeled Email/Password and click the pencil icon to enable this option. Once you enable this provider, make sure to hit the Save button. Next, you need to create a new user on the Firebase Console to test the app with. 1. Select the Users tab. 2. Click the Add user button. Enter a valid email, a strong password and hit the Add user button to save the new user credentials. Now that the backend Firebase is ready, let’s run the app, and test the work that has been done so far! To run the app, issue the following command: ` You enter your newly created user credentials and the app should sign you in to start managing your notes. Add Author ID on Note model Now that you can sign-in to the app, it’s time to introduce the field Author ID onto the Note model object. Every time you create a new Note, the app will grab the ID of the currently signed-in user and attach it on the Note model object to be stored in the Database. Every Note should have an author or owner! This change is minor and affects only the saveNo0te() action inside the Vuex Store instance. Navigate to the /store/index.js file and amend the saveNote() action as follows: ` When creating a new Note record, the code retrieves the currently signed-in User ID and stores this value inside a local variable named authorId. This variable is then passed over to the notesCollection.add() function when creating a new Note record as I’ve just shown in the source code. That’s all! Now every Note created in the system has an owner or author. You will see shortly how we are going to use this feature to query for customized and owned Notes only. Integrate Authentication into the Vuex Store The Vuex Store instance should be updated whenever the status of the currently signed-in user changes. To cater for that, we will refactor the code inside the store object as follows: ` Now the store watches real-time changes on the notesCollection inside the onAuthStatechanged event handler callback. If there is a valid user passed over, the store is updated accordingly. Then the store starts watching any changes on the notesCollection object. Query for User’s own Notes only So far the Vuex Store instance is watching the entire notesCollection object. However, what’s needed is to query only the notes that belong to the currently signed-in user. To achieve this goal, navigate to the store/index.js file, and replace the following line of code: ` With the following line of code: ` The code now fetches Note records that belong to the currently signed-in user! Configure Authorization rules on Firebase Previously in this series, I created the Database and opted for the Start in test mode. This mode allows anyone to read and write to the database for 30 days. Now that we have authentication in place, let’s reassess the Cloud Firestore rules and allow only authenticated users to read, update, create and delete. Follow the steps below to setup authorization on your Cloud Firestore: 1. Visit the Firebase console and login to your account. 2. Locate and click the Database menu item.. 3. Click the Rules tab. Replace the content there with: ` This rule targets any document in the current database and allows any requests that hold an auth object with an uid that’s not null. Only requests sent by an authenticated user, will carry a valid auth object. That’s it! Pretty easy. Now we can be sure that anonymous requests won’t find their way into our database. Add Logout button Finally, let’s add support for a Logout button for the user. Navigate to the components/Navbar.vue component, and insert the following inside the links section: ` Let’s implement the logout() function as follows: ` The code calls the signOut() function on the Firebase Auth API to sign-out the user, and clear any local cookies or data related to the currently signed-in user. In addition, it clears the data stored about the currently signed-in user inside the Vuex Store instance. Finally, it redirects the user to the Login page. Let’s add the clearData() action onto the Vuex Store instance. Navigate to the store/index.js file, and add the following action: ` The action clears out the signed-in user, all loaded Notes records, and the current Note object. Conclusion We’re done! We’ve implemented user authentication in the Notes Writer app using Firebase Authentication API. The Firebase Authentication is rich in features, and offers more functionalities than we could possibly cover in this article. My suggestion: always refer to the Firebase Authentication docs website to learn more about the different options available. In the next installment, we’ll make use of Firebase Cloud Functions to both extend the features of the Notes Writer app, and demonstrate the capabilities of the Cloud Functions. Stay tuned!...
Feb 5, 2020
11 mins
Let's innovate together!
We're ready to be your trusted technical partners in your digital innovation journey.
Whether it's modernization or custom software solutions, our team of experts can guide you through best practices and how to build scalable, performant software that lasts.