<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: crisarji</title>
    <description>The latest articles on DEV Community by crisarji (@crisarji).</description>
    <link>https://dev.to/crisarji</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F66229%2F7594ba29-f615-4118-a568-1b71f75ff0d7.jpg</url>
      <title>DEV Community: crisarji</title>
      <link>https://dev.to/crisarji</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/crisarji"/>
    <language>en</language>
    <item>
      <title>5 tips for interviewing peer-ple in technology</title>
      <dc:creator>crisarji</dc:creator>
      <pubDate>Thu, 21 Apr 2022 01:25:13 +0000</pubDate>
      <link>https://dev.to/crisarji/5-tips-for-interviewing-peer-ple-in-technology-ph6</link>
      <guid>https://dev.to/crisarji/5-tips-for-interviewing-peer-ple-in-technology-ph6</guid>
      <description>&lt;h2&gt;
  
  
  5 tips for interviewing peer-ple in technology
&lt;/h2&gt;

&lt;p&gt;Hello developer pal!, glad to see you here.&lt;/p&gt;

&lt;p&gt;Interviewing people is always a challenge, you never know who is joining in person or in a call with you, it is a lottery!&lt;/p&gt;

&lt;p&gt;Perhaps you are interviewing the next Steve J, the next Mark Z, or the next... You!&lt;/p&gt;

&lt;p&gt;Some time(or long time) ago, someone gave you the opportunity to start working as an intern, as a fix term, as a freelancer, whatever the job was, you had the chance to start a career because someone wanted to!; maybe this person saw something in you that outstand from others?, perhaps you used the right words or coded the right challenge?, anyway you had this chance and I'm pretty sure you were happy when you received the news that you were selected!&lt;/p&gt;

&lt;p&gt;After all this epilogue, do you remember how it was?, what were the steps the person from technology followed for that interview?, you were prepared for sure, but how about the interviewer?, well in case you don't recall, and if you are in this situation where you will evaluate candidates, maybe this tips could fit you!&lt;/p&gt;

&lt;h2&gt;
  
  
  Show Me The Topics
&lt;/h2&gt;

&lt;p&gt;The topics to be focused on are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Introduction&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Set the Rules&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Ice Breakers&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Interview&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Closing Time&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;Disclaimer&lt;/em&gt;: This post comes from my own experience interviewing candidates for different roles, not saying this is the best way to go, nor the worst, any contribution is more than welcome in the threads below!&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;What's the very first thing you should do when driving an interview?, either way in person or virtually: it could sound too obvious, but you do need to &lt;code&gt;introduce yourself&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Aside being polite, you would be evaluating a peer, a person who has(at least in paper before the interview) the same skills, maybe more maybe less, than you.&lt;/p&gt;

&lt;p&gt;For properly introduce yourself, let the candidate to know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Your Name&lt;/code&gt;: this is a most!, the candidate needs to know your name, when some questions arise it could be awkward to hear them say &lt;code&gt;hey dude&lt;/code&gt;, &lt;code&gt;hey you&lt;/code&gt; or something like that just because we forgot to give it a the very beginning.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Role that you have&lt;/code&gt;: you can be flexible with this!, which of the two scenarios below could sound better when you are interviewing, for instance, a Junior?:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Hi, my name is Shanks, I am a &lt;code&gt;Senior Full-Stack Cloud Architect Scrum Master&lt;/code&gt; pleased to meet you!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Unless you are interviewing another &lt;code&gt;Senior Full-Stack Cloud Architect Scrum Master&lt;/code&gt;, you can expect this reaction:&lt;/p&gt;



&lt;p&gt;
  &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2F2022-04-interviewing-peerple%2Fassets%2Fthe-what.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2F2022-04-interviewing-peerple%2Fassets%2Fthe-what.png"&gt;&lt;/a&gt;
&lt;/p&gt;



&lt;p&gt;The other scenario instead:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Hi, my name is Shanks, I am a &lt;code&gt;Senior&lt;/code&gt; dev in here, pleased to meet you!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;See the difference?, the first one could sound a bit intimidating for most of the people, and so far it is very possible that &lt;em&gt;only 5 seconds have passed&lt;/em&gt;(Jojo's pun intended)!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;The time frame for the interview&lt;/code&gt;: time is precious, for you, for me, for everybody, so let the candidate know the time frame you could be using for the interview(by the way, thanks for taking some of your time for reading this!)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Set the Rules
&lt;/h2&gt;

&lt;p&gt;As an interviewer, you should be in control of the interview, this include the times for questions, comments, suggestions, so let the candidate know about this since the very beginning.&lt;/p&gt;

&lt;p&gt;If you determine that it could be a heavy interview, let the candidate know when there could be a break, for how long is gonna be that break, and in what part of the interview you would place the time for questions.&lt;/p&gt;

&lt;p&gt;This is useful and allows you to hurry or slow down the main points you want to evaluate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ice Breakers
&lt;/h2&gt;

&lt;p&gt;Well, so far you have only done 2 things introduce yourself and set the rules, now it is time to listen the person in front of you!&lt;/p&gt;

&lt;p&gt;You have two options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Go straightforward to the interview topics; start with all the questions right away, and evaluate in an atomic way: answer correct?: Yes/No.&lt;/p&gt;

&lt;p&gt;Let's add up:&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;➕ No introduction

➕ No idea where the interview is going

➕ No sure whether questions are allowed or no
&lt;/code&gt;&lt;/pre&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    Recipe for disaster ✅
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Start in a nicer way, and let the candidate to feel comfortable.&lt;br&gt;
A technique that I apply is the use of ice breakers, in particular:&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;🧊 How do you define yourself?

❄️ What are you doing right now in your current project?

♨️ Could you give me a brief introduction about yourself?

🔥 What's your favorite tech stack?
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;-&lt;em&gt;Note&lt;/em&gt;: try to emphasize that it is a brief introduction, from 3 to 5min of the interview should be more than enough.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interview
&lt;/h2&gt;

&lt;p&gt;Now it comes the showtime!&lt;/p&gt;

&lt;p&gt;By the time being, the candidate hopefully should feel more comfortable, you had the chance to talk, the candidate had the chance to talk, 5min is not enough for feeling familiar with someone, but 5 is greater than absolute Zero.&lt;/p&gt;

&lt;p&gt;In this sections there are no restrictions, every interview is different for a thousand reasons, so follow the documents, templates, situations, or whatever resource you have for leading the interview in the way you feel it more natural.&lt;/p&gt;

&lt;p&gt;As suggestions, try to keep a casual conversation with the candidate, you already set the mood, try to keep it simple, you are in front of a peer, cover all the areas you need to without applying extra pressure(for sure the candidate already has a lot of it).&lt;/p&gt;

&lt;p&gt;Try to start with the easy topics and let the interview flows, according to the performance of the person, you would have an idea whether you would need to shrink or stretch the times, and cover or not some extra topics.&lt;/p&gt;

&lt;h3&gt;
  
  
  Closing Time
&lt;/h3&gt;

&lt;p&gt;Last but not least, the Closing Time section, where Q/A can happen.&lt;/p&gt;

&lt;p&gt;Perhaps the candidate did not have any questions at the very beginning, or in the middle(if you set some time in the middle for it), so you could give it a last try.&lt;/p&gt;

&lt;p&gt;It is also a good opportunity for you to ask for comments or suggestions that the person could have for you, maybe you have some improvements areas that you don't even know yet and having the insight of different persons for free could worth a lot!&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;When you interview peers you most be prepared for the best interview in your life or the worst!; maybe you could have another thoughts, let's discuss in a thread below!&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>interview</category>
      <category>screening</category>
      <category>technology</category>
      <category>peers</category>
    </item>
    <item>
      <title>5 tips for dealing with tough conversations in agile teams</title>
      <dc:creator>crisarji</dc:creator>
      <pubDate>Mon, 17 Jan 2022 14:50:44 +0000</pubDate>
      <link>https://dev.to/crisarji/5-tips-for-dealing-with-tough-conversations-in-agile-teams-11l8</link>
      <guid>https://dev.to/crisarji/5-tips-for-dealing-with-tough-conversations-in-agile-teams-11l8</guid>
      <description>&lt;h2&gt;
  
  
  5 tips for dealing with tough conversations in agile
&lt;/h2&gt;

&lt;p&gt;Hello developer pal!, glad to see you here.&lt;/p&gt;

&lt;p&gt;Have you ever been working in a team, and suddenly a tough conversation with your team mate(s) is around the corner?, if you have, welcome to the team!, if you have not, be patient!, it is waiting for you!&lt;/p&gt;

&lt;p&gt;One of these days, I was listening to a podcast, and I bumped into this topic, &lt;code&gt;Dealing with tough conversations&lt;/code&gt;; I heard it and it caught my attention the fact that most of the items mentioned by the speaker match in agile teams, therefore I wanted to shared the episode, some principles and the similarities that came to my mind.&lt;/p&gt;

&lt;h2&gt;
  
  
  Show Me The Topics
&lt;/h2&gt;

&lt;p&gt;The topics to be focused on are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Podcast Episode&lt;/li&gt;
&lt;li&gt;Principles&lt;/li&gt;
&lt;li&gt;Similarities&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Disclaimer&lt;/em&gt;: In this post, I share my thoughts and make a summary down to 5 main points, not looking for a transcription from the episode, instead I unified some of the bullets which I think should be together for agile teams purposes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Podcast Episode
&lt;/h2&gt;

&lt;p&gt;You can find a direct link clicking in the link below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://open.spotify.com/episode/2siRWLri2NZzCTbW3XOvEa"&gt;Spotify: John C. Maxwell&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://open.spotify.com/episode/2siRWLri2NZzCTbW3XOvEa"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EizVaoF8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://spotify-api-py.vercel.app/api/spotify%3Fpodcast_id%3D5Tx9Zr4AImvrdHuJ1lswUw" alt="Spotify" width="480" height="133"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note: Not sponsoring this podcast, just wanted to share the episode in case you want to hear it before reading along.&lt;/p&gt;

&lt;h2&gt;
  
  
  Principles
&lt;/h2&gt;

&lt;p&gt;Whether you heard the episode aforementioned or not, let me summarize it in 2 words: &lt;code&gt;Care&lt;/code&gt; and &lt;code&gt;Candor&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In agile teams, the relation with your teammates could be established with these 2 principles in mind&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Care&lt;/em&gt;: values the person; he/she is not only a team member, is a valuable person, someone you could end up interacting with on a daily basis even more than you do with your family and friends, and guess what?, it goes also the other way around, so let's value our teammates in the same way we want them to value us.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Candor&lt;/em&gt;: values the persons potential; aside of value your teammates for what they currently are, let's value them for what they could become, as a team, we all have a big responsibility, to reach our clients expectations, and after reaching them, go beyond!, alone we are not enough, but as a team we are, we can grow, learn more, expand hard/soft skills.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Similarities
&lt;/h2&gt;

&lt;p&gt;I found these next 5 points as the more important ones when working on agile teams:&lt;/p&gt;

&lt;h3&gt;
  
  
  Meet privately...NOW!
&lt;/h3&gt;

&lt;p&gt;In agile teams time is everything!, time for plannings, time for understand the business expectations, time for developing, time for testing, etc. When having a disagreement, discrepancy, misunderstanding, the best time to aboard it is &lt;em&gt;NOW&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The golden rule is to reach the other person(s) out ASAP in &lt;em&gt;private&lt;/em&gt;, doing so, the scope of the conversation will be open for discussion between the parts of interest and close for outsiders.&lt;/p&gt;

&lt;h3&gt;
  
  
  Assume Good Motives
&lt;/h3&gt;

&lt;p&gt;Giving the benefit of doubt is a &lt;em&gt;MUST&lt;/em&gt;, when you are reached by a teammate, have a good attitude, it is good to remember that your teammates are a very important part of your life now, sometimes you interact with them even more than with your own family!, so it is better off to think that there are good reasons behind a meeting, a call, a chat message.&lt;/p&gt;

&lt;h3&gt;
  
  
  Offer-Receive specific and tangible observations explaining the consequences of certain things for the team
&lt;/h3&gt;

&lt;p&gt;This is a tricky one, when you are the one reaching, keep in mind what is it that you have observed that could impact the team, and the negative impact of keeping that along; for instance, you schedule planning sessions, though you notice that your teammates are not participating, what could it be an approach?:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Observations&lt;/em&gt; =&amp;gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lack of participation of a key member(s) during the planning session&lt;/li&gt;
&lt;li&gt;Lack of opinions in topics related to certain critical functionality&lt;/li&gt;
&lt;li&gt;Committing to a delivery with some gaps not discussed&lt;/li&gt;
&lt;li&gt;Business thinking everything is "crystal clear"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Negative impact&lt;/em&gt; =&amp;gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Blurry requirements when starting the design/dev/qa phase&lt;/li&gt;
&lt;li&gt;Misunderstandings since the creation of &lt;em&gt;User Stories&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Unplanned calls/meetings for clarifying requirements&lt;/li&gt;
&lt;li&gt;Pressure on all areas right before end of sprint&lt;/li&gt;
&lt;li&gt;Client upset for not reaching the commitments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This could be the hardest part of the conversation, some people or even you could not like that much to me questioned about your work, just keep in mind that feedback is an improvement opportunity, good or bad, no harsh feelings!&lt;/p&gt;

&lt;h3&gt;
  
  
  Look for common ground
&lt;/h3&gt;

&lt;p&gt;I really like this sentence, &lt;code&gt;look for common ground&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It seems like just words, but think about it, &lt;code&gt;look for&lt;/code&gt; something, for what?, &lt;code&gt;common ground&lt;/code&gt;, it means, let's look where we are more equals and less different, lets look for a &lt;code&gt;common goal&lt;/code&gt;, for something &lt;em&gt;beneficial&lt;/em&gt; for both or all of us.&lt;/p&gt;

&lt;p&gt;Think it this way, we are a team, we are on a boat, as long as this boat keeps floating, we all keep floating, when it sinks, we all sink!, so let's &lt;code&gt;leave aside our differences&lt;/code&gt;, let's wear each others shoes, be emphatic, and now let's look together for a target, a way to not repeat the same behavior and grow up as professionals.&lt;/p&gt;

&lt;h3&gt;
  
  
  Let's size us up and give our help accordingly
&lt;/h3&gt;

&lt;p&gt;The more worth I see in you, the more help I express, and vice versa.&lt;/p&gt;

&lt;p&gt;This is tricky, but see that the previous steps are a &lt;code&gt;block-chain&lt;/code&gt;(pun intended) for end up in here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;if we talk as soon as a difference arise, it is because we care&lt;/li&gt;
&lt;li&gt;if we assume good motives from each other, is because we care&lt;/li&gt;
&lt;li&gt;if we flag each others points of improvement, is because we care&lt;/li&gt;
&lt;li&gt;if we look for common ground instead of looking for who is right and who is wrong, it is because we care&lt;/li&gt;
&lt;li&gt;then we can say we value the teammates(&lt;code&gt;Care&lt;/code&gt;) and what they can become(&lt;code&gt;Candor&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;When treating another teammates as we expect to be treated, the tough conversation is less tough and more a conversation; maybe you could have another thoughts, let's discuss in a thread below!&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>agile</category>
      <category>leadership</category>
      <category>synergy</category>
    </item>
    <item>
      <title>Lessons Learned of Connect Tech 2021</title>
      <dc:creator>crisarji</dc:creator>
      <pubDate>Sun, 28 Nov 2021 22:24:15 +0000</pubDate>
      <link>https://dev.to/crisarji/lessons-learned-of-connect-tech-2021-469m</link>
      <guid>https://dev.to/crisarji/lessons-learned-of-connect-tech-2021-469m</guid>
      <description>&lt;h2&gt;
  
  
  Lessons Learned: Connect Tech 2021
&lt;/h2&gt;

&lt;p&gt;Hello developer pal!, glad to see you here.&lt;/p&gt;

&lt;p&gt;In this post, I'll share my lessons learned after &lt;a href="https://twitter.com/connect_js"&gt;Connect.Tech&lt;/a&gt; version &lt;code&gt;2021&lt;/code&gt;, and the best of all: it was &lt;em&gt;BACK IN PERSON!&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclaimer&lt;/em&gt;: This post comes from my own experience after evaluating the most important aspects of the conference, there were remarkable talks about &lt;a href="https://reactjs.org/"&gt;React&lt;/a&gt;, &lt;a href="https://angular.io/"&gt;Angular&lt;/a&gt;, &lt;a href="https://vuejs.org/"&gt;Vue&lt;/a&gt; and others, this includes no code at all, I'd rather mention some other aspects, more soft-skills-driven instead, though any contribution is more than welcome in the threads below!&lt;/p&gt;

&lt;h2&gt;
  
  
  Hook the Audience
&lt;/h2&gt;

&lt;p&gt;Something I noticed in this conference, is the way that the speakers kept the audience hooked since the very beginning of the talk.&lt;/p&gt;

&lt;p&gt;One speaker asked to everybody to stand up and start stretching!, another one asked to stay sit and warm up from there!, another one played the the trailer of an upcoming movie, I wont say what it was, maybe just a &lt;a href="https://www.youtube.com/watch?v=G_ua10EMbSg&amp;amp;ab_channel=Ghostbusters"&gt;hint&lt;/a&gt; but gave all the people goosebumps and received an immediate reaction!&lt;/p&gt;

&lt;p&gt;This seems to be something silly, but definitely it is not; having most of the people paying attention to you before start speaking is something hard to accomplish; there are a looot of distractions, top-1: the electronic devices, so it was interesting to see the different nets displayed to fish in the see of "skeptical".&lt;/p&gt;

&lt;h2&gt;
  
  
  Be Reactive with the Audience
&lt;/h2&gt;

&lt;p&gt;Imagine you planned your talk for weeks; you did your research, found a topic, polished your weak spots, mounted a presentation, hooked the audience, and at the very beginning of you talk a cellphone's ringtone goes off!, what would you do?&lt;/p&gt;

&lt;p&gt;Well, according to the physics:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For every action, there is an equal and opposite reaction...&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Source: Third Law of Motion, Sir Isaac Newton&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;The natural behavior would be to be mad at the person, before starting the talk the speakers always ask for turning off the devices, or at least set them on vibrating mode, how is it that someone could not follow such a simple request?, well that happens, and a lot!&lt;/p&gt;

&lt;p&gt;I saw that during one of the talks, but the speaker instead of yelling or being mad, had a very different reaction, he just stared at the person and said: "Hey, put the speaker on, so everybody can say hello!", everybody laugh about it, it was so natural that nobody got mad, right after that, the talk resumed and everything just went as expected.&lt;/p&gt;

&lt;h2&gt;
  
  
  Accessibility in the Presentations
&lt;/h2&gt;

&lt;p&gt;We give for granted some stuff, and we forget that not everybody feels, sees or perceives the world in the same way we do.&lt;/p&gt;

&lt;p&gt;In one of the talks, it caught my attention the fact that the presentation, which included some live coding, had a light background!, I couldn't help but to ask the speaker the reason why.&lt;/p&gt;

&lt;p&gt;Well, he kindly gave an answer: it turned out that having a dark background(what is so normal to me) in a presentation could affect some people, not only in their eyes but their comprehension!&lt;/p&gt;

&lt;p&gt;I read a little about it to understand and it makes sense, you can find a brief in this post&lt;a href="https://www.skillset.co.nz/blog/michael-brown-blog/132-powerpoint-tip-7-should-the-background-be-dark-or-light"&gt;post&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Color scheme, font size, animations, etc, among the key points for making the presentation remarkable, some other bullets can be found in this &lt;a href="https://www.sigaccess.org/welcome-to-sigaccess/resources/accessible-presentation-guide/"&gt;article&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Make the Talk Interactive: Complete/Incomplete Source Code
&lt;/h2&gt;

&lt;p&gt;It is said that time is money, in this case time is knowledge(which can be turned into money later, anyway).&lt;/p&gt;

&lt;p&gt;When dealing with dozens of persons at the same time, ensure that all are working along with you is virtually impossible; some people has the tools, but not the knowledge, or have the knowledge but not the tools, they need to catch up their envs with everybody else's, but some have Linux, some other Windows, some other Mac, this could be a mess. A nice workaround I saw and I have always agreed to is having 2 versions of the code you are working:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Incomplete: allows the participants to feel like they are getting their hands dirt, the feeling of ownership of the code, and the satisfaction to move along during the session.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Complete: sometimes sh*t happens, so allowing the participant to have a final version of an executable code could let them keep the attention during the rest of the session.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In some of the talks this aforementioned approach was the one to follow, you can later double check or triple check the source code, and compare the pushed commits with your own notes, that could make it easier to understand.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources Links
&lt;/h2&gt;

&lt;p&gt;It is said also that &lt;code&gt;Sharing is Caring&lt;/code&gt;, agree!, even more when talking about code resources.&lt;/p&gt;

&lt;p&gt;There are so many websites you can visit, posts, video tutorials, platform's courses; you don't even know where to start from.&lt;/p&gt;

&lt;p&gt;When you assist to a conference like &lt;a href="https://twitter.com/connect_js"&gt;Connect.Tech&lt;/a&gt;, you notice that the speakers did their work; they do research, they create the exercises, they care about their presentation, and they share where to find this and other resources used.&lt;/p&gt;

&lt;p&gt;There was this workshop where the speaker even created a channel with all of us, a whole bunch of strangers, and shared relevant info related to the topics.&lt;/p&gt;

&lt;h2&gt;
  
  
  Be Ready for Anything
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;It's better to be a warrior in a garden than a gardener in war...&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Source: Japanese saying&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nice saying!, and so true.&lt;/p&gt;

&lt;p&gt;During the conference, there was this session where the speaker was doing his best even when his machine kept failing and failing, till the point where he just quit using his machine and he resume &lt;code&gt;a capella&lt;/code&gt;. It is better to be prepare for anything that could happen, than thinking that everything will go smoothly, also remember &lt;a href="https://en.wikipedia.org/wiki/Murphy%27s_law"&gt;Murphy's Law&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Networking
&lt;/h2&gt;

&lt;p&gt;My favorite bullet for sure, after all this time in the pandemic, we have been put through several restrictions, enclosed for several months and a bit afraid to interact with others face to face.&lt;/p&gt;

&lt;p&gt;Of course there are plenty of web platforms for making this sort of events virtually; audio, video, recordings, side notes, and all of that is awesome!, but there is a human factor involved with the networking.&lt;/p&gt;

&lt;p&gt;During the conference, we were able to interact with people from different places of the world, leading in all kind of companies, some of them world wide known, some others domestics; what all they shared was the importance they have in their own field.&lt;/p&gt;

&lt;p&gt;It is something easy to accomplish in person; you can go for a drink or a snack, start a conversation with some other people, exchange points of view in technologies, approaches, platforms, finish your snack and move along to the next talk, maybe you can talk with the same persons later and learn a little more from each other!, but, how do we do it virtually?&lt;/p&gt;

&lt;p&gt;It could be a little harder to interact with people other than the speaker when you joined a call; it is not like you can just ping someone out of the blue and ask him/her to join you in a private room, do you see my point?&lt;/p&gt;

&lt;h2&gt;
  
  
  Moving along with the New Normal
&lt;/h2&gt;

&lt;p&gt;Till two years ago, having conferences was the rule every single year, right now it is the exception.&lt;/p&gt;

&lt;p&gt;The changes during the pandemic are HUGE, passing from hundreds of attenders to ZERO to a few dozens in conferences, after almost 2 years, we are having a break therefore it is possible to plan and attend to an event like this, the sanitary protocols, the response of the people, and the commitment of everybody to make the things right are remarkable, not a single problem in 3 days in a row, we can still have hope to see more conferences in the upcoming year.&lt;/p&gt;

&lt;p&gt;The face-to-face interaction is in the human nature, and it is nice to know that little by little is possible to do it again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;After seeing that the event was a success, some other conferences could try the same approach, follow the same directives and get the same success, thus I can foresight new conferences and in-person web tech events in the horizon!; maybe you have second thoughts, or you even attended and have a different point of view, let's discuss in a thread below!&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>vue</category>
      <category>angular</category>
    </item>
    <item>
      <title>Spooky Dev Stories</title>
      <dc:creator>crisarji</dc:creator>
      <pubDate>Sun, 31 Oct 2021 13:38:49 +0000</pubDate>
      <link>https://dev.to/crisarji/spooky-dev-stories-5345</link>
      <guid>https://dev.to/crisarji/spooky-dev-stories-5345</guid>
      <description>&lt;p&gt;Hello developer pal!, glad to see you here.&lt;/p&gt;

&lt;p&gt;What about sharing one spooky story from your life as dev?, me first!&lt;/p&gt;

&lt;p&gt;When I started to work, it was as a Jr BE dev, using &lt;code&gt;C#&lt;/code&gt; and &lt;code&gt;Visual Source Safe&lt;/code&gt;, there was this delivery we needed to accomplish in one week, so I started coding on Monday, Tuesday, I made a couple initial commits, the CI/CD we had that time took the changes, created an artifact minimized and optimized, deployed it to QA and that was all, everything was running smoothly.&lt;/p&gt;

&lt;p&gt;Next 3 days, I was so focused in my work that I completely forgot to commit, 3 days in a row without committing, on Friday afternoon, I finally did, and guess what?, the panic.&lt;/p&gt;

&lt;p&gt;Something happened that I lost all my changes, I tried to recover it in any possible way, unsuccessfully. After spending a couple hours, I went to my boss, sure that I was gonna get fired, explained the whole situation, and instead of asking me for a card box, he sat at my desk, helped me to track down the latest deploy(from 3 days ago), disassembled some minimized files(function names as &lt;code&gt;i&lt;/code&gt;, return values as &lt;code&gt;x&lt;/code&gt;, etc), stand up from my desk and just said &lt;code&gt;Good luck during the weekend&lt;/code&gt;, then left.&lt;/p&gt;

&lt;p&gt;After spending the whole weekend decoding and remembering what a function with signature &lt;code&gt;(a,b,c)&lt;/code&gt; with a return &lt;code&gt;z&lt;/code&gt; could be, and not sleeping at all, I was able to deliver by Monday.&lt;/p&gt;

&lt;p&gt;Moral: always commit!&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>halloween</category>
      <category>spooky</category>
    </item>
    <item>
      <title>The Whats &amp; Whys in a FE Senior position</title>
      <dc:creator>crisarji</dc:creator>
      <pubDate>Mon, 30 Aug 2021 04:34:25 +0000</pubDate>
      <link>https://dev.to/crisarji/the-whats-whys-in-a-fe-senior-position-1kp7</link>
      <guid>https://dev.to/crisarji/the-whats-whys-in-a-fe-senior-position-1kp7</guid>
      <description>&lt;h2&gt;
  
  
  Tech Skills: The Whats &amp;amp; Whys in a FE Senior position
&lt;/h2&gt;

&lt;p&gt;Hello developer pal!, glad to see you here.&lt;/p&gt;

&lt;p&gt;Most of the time, we heard that some knowledge is &lt;span&gt;required&lt;/span&gt; for certain position, usually we heard &lt;code&gt;What&lt;/code&gt; is required, but what about the &lt;code&gt;Why&lt;/code&gt; is it required?.&lt;br&gt;
In this post, I'll share my thoughts in the reasons why some tech skills are mandatory when being/opting-in for a &lt;em&gt;Frontend Senior position&lt;/em&gt;, I'll leave aside the must of &lt;code&gt;HTML&lt;/code&gt;, &lt;code&gt;CSS&lt;/code&gt;, &lt;code&gt;GIT&lt;/code&gt;(or some other version control tools).&lt;/p&gt;
&lt;h2&gt;
  
  
  Show Me The Topics
&lt;/h2&gt;

&lt;p&gt;The topics to be focused on are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Programming Languages &amp;amp; Web Frameworks&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CSS Frameworks &amp;amp; Preprocessors&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Design Systems&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Testing/Debugging&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DevOps/Automation&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;State Managers&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SPA/SSR/SSG&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Rest/Graphql&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Build Process: under the hood&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;Disclaimer&lt;/em&gt;: This post comes from my own experience and what I have seen so far in the area, not saying this is the best way to go, nor the worst, any contribution is more than welcome in the threads below!&lt;/p&gt;
&lt;h2&gt;
  
  
  Programming Languages &amp;amp; Web Frameworks
&lt;/h2&gt;

&lt;p&gt;Want to know &lt;code&gt;What&lt;/code&gt; to learn in this 2021?, take a look:&lt;/p&gt;



&lt;p&gt;
  &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Fsr-techskills-what-why-2021%2Fassets%2Fmost-demanded-programming-languages-2021.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Fsr-techskills-what-why-2021%2Fassets%2Fmost-demanded-programming-languages-2021.png"&gt;&lt;/a&gt;
&lt;/p&gt;



&lt;blockquote&gt;
&lt;p&gt;Source: &lt;a href="https://cdn.ucberkeleybootcamp.com/wp-content/uploads/sites/106/2020/12/most-demand-programming-languages-2021.jpg" rel="noopener noreferrer"&gt;Most Popular Languages 2021&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As a FE dev, having &lt;a href="https://www.javascript.com/" rel="noopener noreferrer"&gt;Javascript&lt;/a&gt; or &lt;a href="https://www.python.org/" rel="noopener noreferrer"&gt;Python&lt;/a&gt; is a must, the most used languages worldwide now.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Why&lt;/code&gt; should you learn either or both of them? because they are the core for the main Web Frameworks out there, for sure you have heard about these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Angular&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Django&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;React&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Flask&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Vue&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The list of web frameworks aforementioned is built on top of either, &lt;code&gt;Javascript&lt;/code&gt; or &lt;code&gt;Python&lt;/code&gt;. Having a robust base will help you to understand how to tackle an obstacle, or at least will give you a hunch, also will allow you to move from one framework to another easier.&lt;/p&gt;

&lt;h2&gt;
  
  
  CSS Frameworks &amp;amp; Preprocessors
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;What&lt;/code&gt; can I find when starting in a new project?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CSS Frameworks:

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://getbootstrap.com/" rel="noopener noreferrer"&gt;Bootstrap&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tailwindcss.com/" rel="noopener noreferrer"&gt;Tailwind&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://materializecss.com/" rel="noopener noreferrer"&gt;Materialize&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;CSS Preprocessors:

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://sass-lang.com/" rel="noopener noreferrer"&gt;Sass&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://lesscss.org/" rel="noopener noreferrer"&gt;Less&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Nice!, all the heavy lifting related to the styling ready to be used!&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Why&lt;/code&gt; should I care when it is only plug &amp;amp; play?&lt;/p&gt;

&lt;p&gt;Well, because you do need to know the small hacks that could spare some precious time for you and your team!; for instance how to declare a &lt;em&gt;variable&lt;/em&gt;, a &lt;em&gt;mixin&lt;/em&gt;, the corresponding &lt;em&gt;breakpoints&lt;/em&gt;, even adding a &lt;em&gt;media query&lt;/em&gt; changes a little depending on the framework. Also, you need to know your preprocessor for avoiding duplication of &lt;em&gt;classes&lt;/em&gt;, how to apply &lt;em&gt;specificity&lt;/em&gt;(in the right way), writing less and getting more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design Systems
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;What&lt;/code&gt; is a design system?, well as I exposed in a &lt;a href="https://dev.to/crisarji/my-vue-experience-after-3-projects-in-18-months-456c"&gt;previous post&lt;/a&gt;, this is a converging point for different areas, which has 3 fundamental goals:&lt;/p&gt;

&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt; &lt;code&gt;UI/UX&lt;/code&gt; does not repeat itself&lt;/li&gt;
&lt;li&gt; &lt;code&gt;WebDev&lt;/code&gt; has one-and-only-one source of truth&lt;/li&gt;
&lt;li&gt; &lt;code&gt;QA&lt;/code&gt; can evacuate questions on its own&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Source: &lt;a href="https://dev.to/crisarji/my-vue-experience-after-3-projects-in-18-months-456c"&gt;My Vue Experience after 3 projects in 1.5 years&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;Why&lt;/code&gt; should I remotely care about other areas such as &lt;code&gt;UI/UX&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;Because nothing last forever, you could be so comfortable in your current project, with a design system already defined that you just use, and tomorrow you loose the client, the account is abruptly finished, you had a discussion with a stakeholder and you are expelled, then you move to another project, and you are asked to start working from scratch.&lt;/p&gt;

&lt;p&gt;Wouldn't it be better to start fresh with some knowledge than with no knowledge at all?, well you should care about this point since it is easier to talk with the &lt;code&gt;UI/UX&lt;/code&gt; person in charge of defining the Design System when both understand what's going on, the pros and cons, the different approaches, the changes, discussions, and agreements are easier when both areas are on the same page.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;TIP&lt;/em&gt;: Among the best tools for accomplishing this sync up is &lt;a href="https://storybook.js.org/" rel="noopener noreferrer"&gt;Storybook&lt;/a&gt;, if you are not familiar yet, you could give it a try, thanks me later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing/Debugging
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;What&lt;/code&gt; are the unit testing tools you are more familiar with?, let me guess:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Mocha&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Chai&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Jest&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Karma&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Jasmine&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;Why&lt;/code&gt; all his hype with the unit testing when you know you did it in the right way?&lt;/p&gt;

&lt;p&gt;Easy!, it is our responsibility to ensure that new components, services, changes on the state of the application does not break higher environments, and does not break other pieces of the application added by other people.&lt;/p&gt;

&lt;p&gt;A well performed unit testing is a relief, and can help to have a high coverage, also help the next dev to understand faster and better, even you can understand better the code when writing the unit tests.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;TIP&lt;/em&gt;: Maybe you would like to take a look at &lt;a href="https://www.npmjs.com/package/husky" rel="noopener noreferrer"&gt;Husky&lt;/a&gt;, this little fellow has some awesome features, for instance, you can set the rules for writing the commits your historical will have, also you can run all the tests before committing, when all tests success it allows the addition, otherwise it does not commit.&lt;/p&gt;

&lt;h2&gt;
  
  
  DevOps/Automation
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;What&lt;/code&gt; are some of the responsibilities &lt;em&gt;DevOps&lt;/em&gt; and &lt;em&gt;Automation&lt;/em&gt; people have in your project?:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Responsible of CI/CD&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Create environments&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Check Pipes and Jobs statuses&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Run the automation alongside the Jobs&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Create, check, correct and fix test suites&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;Why&lt;/code&gt; is it important to know about these processes when there is a person in charge of it?&lt;/p&gt;

&lt;p&gt;Because sometimes the DevOps, Automation and Dev are the same, it is a bad practice(from my perspective), but how could you be sure this is not gonna happen to you sooner or later?, if so you better rise the flag, but some other times you could be unblocking your own team, let me elaborate.&lt;/p&gt;

&lt;p&gt;DevOps and Automation Testers are human beings too, these persons can have PTOs, sick days, appointments, capacitations, for any number of reasons can be out of work, in case of issues, what would it happen?, is your team ok with the fact to wait from 1 to several days before a fix is done in pipes or releases?, knowing about devops and automation processes can help to unblock not only your team, also others(in case you do have granted permissions, otherwise, you'll have some free time to read a book or take a couple courses)&lt;/p&gt;

&lt;p&gt;&lt;em&gt;TIP&lt;/em&gt;: there are plenty of platforms for working and understanding &lt;code&gt;CI/CD&lt;/code&gt;, you can check for instance &lt;a href="https://github.com/features/actions" rel="noopener noreferrer"&gt;GitHubActions&lt;/a&gt;, &lt;a href="https://travis-ci.org/" rel="noopener noreferrer"&gt;TravisCI&lt;/a&gt;, &lt;a href="https://circleci.com/" rel="noopener noreferrer"&gt;CircleCI&lt;/a&gt; before jumping to &lt;a href="https://docs.microsoft.com/en-us/azure/devops-project/azure-devops-project-github" rel="noopener noreferrer"&gt;Azure&lt;/a&gt;, &lt;a href="https://aws.amazon.com/es/getting-started/projects/set-up-ci-cd-pipeline/" rel="noopener noreferrer"&gt;AWS&lt;/a&gt; or &lt;a href="https://www.cloudbees.com/jenkins/what-is-jenkins" rel="noopener noreferrer"&gt;Jenkins&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  State Managers
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;What&lt;/code&gt; are those libs, patterns or packages you have heard of?:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Redux&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RxJS&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;React/Redux&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NgRx&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Vuex&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;Why&lt;/code&gt; should I know any of those when http, services and local storage are available?&lt;/p&gt;

&lt;p&gt;Well, because sometimes you will not be handling small apps/sites, when starting a client project, or even one on your own, keep in mind always the scalability of the project; local storage and its derivatives are an option, but a state manager for a SPA could be a better option. Adding new features involves add new setters, getters, actions, services interacting to each other, the final goal is to keep up to date the state for as long as the user has a session, hit the DB as few as possible and display required info in the fastest way.&lt;/p&gt;

&lt;h2&gt;
  
  
  SPA, SSR, SSG
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Why&lt;/code&gt; should I know something other than SPA?, &lt;code&gt;What&lt;/code&gt; could they aport to my experience?&lt;/p&gt;

&lt;p&gt;Maybe you are used to write a &lt;em&gt;SPA&lt;/em&gt; for every single scenario, but what if I told you that there are some other valid approaches for fulfilling a client expectations?&lt;/p&gt;

&lt;p&gt;Not everyone needs a &lt;em&gt;SPA&lt;/em&gt;, maybe the client needs a particular feature for holding a blog post, or a wiki, which changes every once in a while, or barely changes at all, would not it be better a &lt;em&gt;Static Site&lt;/em&gt;?, maybe a &lt;em&gt;Server Side Generator&lt;/em&gt; does the job with a better performance, &lt;code&gt;Gastby&lt;/code&gt;?, &lt;code&gt;VuePress&lt;/code&gt;? those are valid options!&lt;/p&gt;

&lt;p&gt;Or even better, the users need to interact with the page, and needs a better &lt;em&gt;SEO&lt;/em&gt; positioning, what about a &lt;em&gt;Server Side Rendering&lt;/em&gt;?, &lt;code&gt;Nuxt&lt;/code&gt; or &lt;code&gt;Next&lt;/code&gt; could be a better approach(yes, we'll always have &lt;code&gt;WordPress&lt;/code&gt;, up to you)!&lt;/p&gt;

&lt;p&gt;Perhaps you cant decide the right approach because you dont know the difference between them, well for being/opting to a Senior position you should, this is part of the tech conversations you could be holding with a stakeholder, a Product Owner, or some other peers when deciding what's the best for business. You can read a bit more bout the differences &lt;a href="https://graphcms.com/blog/difference-spa-ssg-ssr" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Rest, Graphql
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Why&lt;/code&gt; is Rest always on the table?, &lt;code&gt;What&lt;/code&gt; is this trend for Graphql when I already master Rest?&lt;/p&gt;

&lt;p&gt;The only constant is the change, even more in technology; some years ago, there was something called &lt;a href="https://en.wikipedia.org/wiki/SOAP" rel="noopener noreferrer"&gt;SOAP&lt;/a&gt;, the most used way to interact with http request/responses in &lt;code&gt;xml&lt;/code&gt; format; later we had(and still have) &lt;a href="https://en.wikipedia.org/wiki/Representational_state_transfer" rel="noopener noreferrer"&gt;Rest&lt;/a&gt; has been hanging around for a while, the days of interacting with &lt;code&gt;XMLs&lt;/code&gt; are over(for most of the devs out there), plenty of services rely on Rest now; &lt;a href="https://graphql.org/" rel="noopener noreferrer"&gt;Graphql&lt;/a&gt; is the new member of the family, even though it is not a protocal, instead a query language, makes the API interaction cleaner, it is easy to learn and use, and has a lot of support, so better start learning now!&lt;/p&gt;

&lt;h2&gt;
  
  
  Build Process: Under the hood
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Why&lt;/code&gt; should you know what happens in the backstage?, is not enough knowing &lt;code&gt;What&lt;/code&gt; are the steps to follow?&lt;/p&gt;

&lt;p&gt;Errors during the building phase of an application are not odd, in fact, several times they are expected, knowing about the process under the hood can give some guidance related to the issues and how to fix them; also what if the client complaints about a lot of console errors, the performance of the page is too low, the build takes a lot of time to get deployed, all of these could be part of a lack of knowledge in the process of building and deploying.&lt;br&gt;
Required flags, changing the build environment, optimize the build, tree shaking the build, handling alerts on the build size, all of this needs to be covered; learning about &lt;a href="https://webpack.js.org/" rel="noopener noreferrer"&gt;Webpack&lt;/a&gt; and &lt;a href="https://rollupjs.org/guide/en/" rel="noopener noreferrer"&gt;Rollup&lt;/a&gt; could have a big impact in your next deploy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;As shown above, there is a sort of gap between the &lt;code&gt;what&lt;/code&gt; is required for being/opting-in for a Senior position and &lt;code&gt;why&lt;/code&gt; it is required; it is not the fact to be an expert in all the areas, but reading and practicing a bit will help you to sharp the skills and when the time comes it gets easier to fit in in a project!&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webframeworks</category>
      <category>techskills</category>
      <category>senior</category>
    </item>
    <item>
      <title>How I met your...Scraper? </title>
      <dc:creator>crisarji</dc:creator>
      <pubDate>Mon, 19 Jul 2021 04:57:26 +0000</pubDate>
      <link>https://dev.to/crisarji/how-i-met-your-scraper-4n6o</link>
      <guid>https://dev.to/crisarji/how-i-met-your-scraper-4n6o</guid>
      <description>&lt;p&gt;&lt;strong&gt;How I met your... Scraper?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Hello developer pal!, glad to see you here.&lt;/p&gt;

&lt;p&gt;In this post, I'll share my experience after running into a topic I had not met before... web scraping!.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Show Me The Topics&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The topics to be focused on are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Problem to solve: Booking a weekly service&lt;/li&gt;
&lt;li&gt;Project dependencies&lt;/li&gt;
&lt;li&gt;NodeJS folders structure&lt;/li&gt;
&lt;li&gt;
Express, Routing and Services

&lt;ul&gt;
&lt;li&gt;Services Visualization&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Puppeteer(Booking Service)&lt;/li&gt;
&lt;li&gt;Nodemailer(Email Service)&lt;/li&gt;
&lt;li&gt;Local use and remote Deploy&lt;/li&gt;
&lt;li&gt;Bonus: Dealing with Captcha&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Disclaimer&lt;/em&gt;: This post comes from a particular scenario I've been struggling with, I'm not preaching this is the best approach to follow for web scraping, nor the worst, any contribution is more than welcome in the threads below!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: There is available also a template project on &lt;a href="https://github.com/crisarji/scraper-template"&gt;GitHub&lt;/a&gt; in case it could be useful and save you some time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem to solve: Booking a weekly service
&lt;/h2&gt;

&lt;p&gt;A couple weeks ago, I got subscribed to a weekly delivery service, I am pretty happy with the service!, it is fast, efficient, always on time!, since day 1 the service has had no issues, not even delays, what's the only fallback I have found so far?, the booking process!&lt;/p&gt;

&lt;p&gt;This could be a little picky from my end, I know, but see the steps I need to do every-single-day:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open a website(only works on &lt;em&gt;Chrome&lt;/em&gt;, no other browser)&lt;/li&gt;
&lt;li&gt;Fill in my &lt;em&gt;user/password&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Move to &lt;em&gt;Members&lt;/em&gt; path&lt;/li&gt;
&lt;li&gt;Check my information and select the delivery address(displayed in a dropdown)&lt;/li&gt;
&lt;li&gt;Move to the Next Step&lt;/li&gt;
&lt;li&gt;Select the day of the week I want to book me the service(come on!, it is a week from today, as usual)&lt;/li&gt;
&lt;li&gt;Move to the Next Step&lt;/li&gt;
&lt;li&gt;Select the time of the day I want to book me the service on(it is the same time as every single day, dammit)&lt;/li&gt;
&lt;li&gt;Finish the process&lt;/li&gt;
&lt;li&gt;A "Thank you page is displayed"(without the result of the process I just did)&lt;/li&gt;
&lt;li&gt;Move to &lt;em&gt;Members&lt;/em&gt; path(again) and look for my upcoming bookings table result&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These steps needs to be done every-single-day, and it is a pain in the back, cause if for some reason I forget to do it, my preferred time could have been taken, and I need to look for a different time, then I need to be aware of the delivery time(it would be different a week from today than the rest of the days); am I clear why this is a pain?, I hope so...&lt;/p&gt;

&lt;p&gt;After a few days of missing the booking, I decided to automate the process with the help of some tools, I was not sure about how to start, so I research and gladly met web scrapping(don't get me wrong, I had heard about it, but there is a slightly difference between hearing and researching with a purpose, at least form my end 🤷).&lt;/p&gt;

&lt;p&gt;So, what's the web scraping?, there are plenty of definitions out there on the Internet, the one that is more accurate for this post purposes is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Web scraping is the process of using bots to extract content and data from a website.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Source: &lt;a href="https://www.imperva.com/learn/application-security/web-scraping-attack/"&gt;What is web scraping?&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is exactly what this post is about, create a sort of robot that will fill in information on my behalf in a site and later it will extract a result for me, and put it on my inbox.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project dependencies
&lt;/h2&gt;

&lt;p&gt;The tools used for accomplishing this enterprise are:&lt;/p&gt;

&lt;p&gt;Main Dependencies&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nodejs.org/"&gt;NodeJS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://expressjs.com/"&gt;Express&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pptr.dev/"&gt;Puppeteer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nodemailer.com/about/"&gt;Nodemailer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Dev Dependencies&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nodemon.io/"&gt;Nodemon&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;package.json&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"dependencies": {
    "express": "^4.17.1",
    "nodemailer": "^6.6.2",
    "puppeteer": "^10.1.0"
  },
  "devDependencies": {
    "eslint-config-prettier": "^8.3.0",
    "eslint-plugin-prettier": "^3.4.0",
    "nodemon": "^2.0.9",
    "prettier": "^2.3.2"
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Prettier&lt;/code&gt; and &lt;code&gt;Nodemon&lt;/code&gt; come handy for having a nice experience, not mandatory though, fell free to use any other tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  NodeJS folders structure
&lt;/h2&gt;

&lt;p&gt;For this project, the structure is simple and set as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;scraper-template/
    ├── index.js
    ├── package.json
    └── routes/
      ├── booking.js
    └── screenshots/
      ├── home-page.png
    └── services/
      ├── bookingHandler.js
      ├── emailSender.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is one route for express to serve, two services for booking and emailing the results and a folder for &lt;em&gt;screenshots&lt;/em&gt;, which only steps in development environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Express, Routing and Services
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;index.js&lt;/code&gt; is a simple file with a 20 lines extension:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;booking&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./routes/booking&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ok&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/booking&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;booking&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="cm"&gt;/* Error handler middleware */&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;statusCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statusCode&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0.0.0.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Scrapper app listening at http://localhost:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;routes/booking.js&lt;/code&gt; includes the &lt;code&gt;expressjs&lt;/code&gt;, &lt;code&gt;services&lt;/code&gt; and &lt;code&gt;config&lt;/code&gt; references, let's decompose it!:&lt;/p&gt;

&lt;p&gt;express.js&lt;/p&gt;

&lt;p&gt;The references to the packages used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;services.js&lt;/p&gt;

&lt;p&gt;The references to the defined services for handling the bookings and sending emails, a preview can be found below on Services Visualization&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;emailSender&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../services/emailSender&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bookingHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../services/bookingHandler&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;config.js&lt;/p&gt;

&lt;p&gt;All the vales in here are &lt;code&gt;process.env&lt;/code&gt; vars, these includes keys for login(&lt;code&gt;webSiteUser&lt;/code&gt;, &lt;code&gt;webSitePassword&lt;/code&gt;), email impersonation(&lt;code&gt;authUser&lt;/code&gt;, &lt;code&gt;appPassword&lt;/code&gt;) and email receivers(&lt;code&gt;emailFrom&lt;/code&gt;, &lt;code&gt;emailTo&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;webSiteUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;webSitePassword&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;authUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;appPassword&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;emailFrom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;emailTo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;preferTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;book-me endpoint&lt;/p&gt;

&lt;p&gt;This route does the booking process for a user with a preferred time(if any):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/book-me&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bookMeResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;bookingHandler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bookMe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;webSiteUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;webSitePassword&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;preferTime&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`The result of the booking was::&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;bookMeResult&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Error while booking me for next week`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;book-me endpoint&lt;/p&gt;

&lt;p&gt;This route gets the bookings the user has set for the upcoming week:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/my-bookings&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bookingResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;bookingHandler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;myBookings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;webSiteUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;webSitePassword&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;emailSender&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sendEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bookingResult&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;authUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;appPassword&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;emailFrom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;emailTo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;format&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bookingResult&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Error while getting the booking for this week`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Services Visualization
&lt;/h3&gt;

&lt;p&gt;Service &lt;code&gt;emailSender&lt;/code&gt;:&lt;/p&gt;



&lt;p&gt;
  &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DpDD7MbF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/crisarji/blogs-dev.to/master/blog-posts/scraping-template/assets/email-service.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DpDD7MbF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/crisarji/blogs-dev.to/master/blog-posts/scraping-template/assets/email-service.png"&gt;&lt;/a&gt;
&lt;/p&gt;



&lt;p&gt;Service &lt;code&gt;bookingHandler&lt;/code&gt;:&lt;/p&gt;



&lt;p&gt;
  &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gLnWXFOh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/crisarji/blogs-dev.to/master/blog-posts/scraping-template/assets/booking-service.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gLnWXFOh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/crisarji/blogs-dev.to/master/blog-posts/scraping-template/assets/booking-service.png"&gt;&lt;/a&gt;
&lt;/p&gt;



&lt;h2&gt;
  
  
  Puppeteer(Booking Service)
&lt;/h2&gt;

&lt;p&gt;Here is where the magic begins!, only one reference for rule the whole process:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;puppeteer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;puppeteer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After this import, &lt;code&gt;puppeteer&lt;/code&gt; is ready to roll!; there are plenty of examples on the internet, most of them apply all the concepts for web scraping in one single file, this is not the case.&lt;/p&gt;

&lt;p&gt;This project applies some separations that, from my perspective, makes it easier to understand what's going on every step throughout the whole process, so let's dive into the sections:&lt;/p&gt;

&lt;p&gt;-- Start the Browser --&lt;/p&gt;

&lt;p&gt;The first interaction is starting the Browser. &lt;code&gt;Puppeteer&lt;/code&gt; works perfectly with &lt;a href="https://www.chromium.org/"&gt;Chronium&lt;/a&gt; and &lt;a href="https://www.mozilla.org/en-US/firefox/92.0a1/releasenotes/"&gt;Nightly&lt;/a&gt;, for this project the reference used is the default one, with &lt;code&gt;Chrome&lt;/code&gt;(the web site to scrap only opens on &lt;code&gt;Chrome&lt;/code&gt;), but if &lt;code&gt;Firefox&lt;/code&gt; preferred, take a look at this thread on &lt;a href="https://stackoverflow.com/a/65045737/2299787"&gt;StackOverflow&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the piece of code below, there is a var initialized for &lt;code&gt;isProduction&lt;/code&gt;, this var is ready for being used when deployed on a web platform(&lt;a href="https://www.heroku.com/"&gt;Heroku&lt;/a&gt; we'll talk about it later), and another for &lt;code&gt;isDev&lt;/code&gt;, I repeat, this is for explanation purposes, it is not required to have 2 when one of them can be denied and cause the same result.&lt;/p&gt;

&lt;p&gt;When &lt;code&gt;isProduction&lt;/code&gt; the launch is done &lt;code&gt;headless&lt;/code&gt; by default, it means that the process is done in the background without any UI, also some &lt;code&gt;args&lt;/code&gt; are included for a better performance, refer to the list of &lt;code&gt;Chromium&lt;/code&gt; flags &lt;a href="https://peter.sh/experiments/chromium-command-line-switches/"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When &lt;code&gt;isDev&lt;/code&gt;, the &lt;code&gt;headless&lt;/code&gt; is false, and &lt;code&gt;args&lt;/code&gt; also include one for opening te dev tools after loading the browser.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isProduction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODE_ENV&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isDev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isProduction&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;authenticationError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Failed the authentication process&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bookingError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Failed the booking process&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;startBrowser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isProduction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;browser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;puppeteer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--no-sandbox&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--disable-setuid-sandbox&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--disable-dev-shm-usage&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;newPage&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;browser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;puppeteer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;headless&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;defaultViewport&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;slowMo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;75&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--auto-open-devtools-for-tabs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--disable-web-security&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--disable-features=IsolateOrigins,site-per-process&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--flag-switches-begin --disable-site-isolation-trials --flag-switches-end&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nx"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createIncognitoBrowserContext&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;newPage&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As seen above, the site is loaaded in Incognito, but can be opened in a regular tab.&lt;/p&gt;

&lt;p&gt;-- Do Login --&lt;/p&gt;

&lt;p&gt;For doing the login, some &lt;code&gt;puppeteer&lt;/code&gt; features come in play:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;goto&lt;/code&gt;: allows the navigation to a web site&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;type&lt;/code&gt;: types a value in an input field&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;click&lt;/code&gt;: allows clicking on buttons, table cells, submits&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;waitForSelector&lt;/code&gt;: recommended for allowing the page to recognize a particular selector before moving along&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;screenshot&lt;/code&gt;: takes a screenshot on demand, and store it in the app(it is possible to redirect the screenshots to remote services, in dev just place them in a root folder)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;doLogIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;webSiteUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;webSitePassword&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;constants&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;baseUrl&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;constants&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loginEndpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;constants&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timeOut&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;waitUntil&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;load&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;isDev&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Navigation to Landing Page Succeeded!!!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#loginform-email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;webSiteUser&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#loginform-password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;webSitePassword&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button[type="submit"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;isDev&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Login submitted&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;waitForSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#sidebar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;isDev&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;screenshot&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;screenshots/home-page.png&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;findLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;constants&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scheduleEndpoint&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Something to remark in the code above is that when dealing on development environment, the screenshots are taken, in production those are skipped(on purpose for the sake of the example)&lt;/p&gt;

&lt;p&gt;-- Find a link --&lt;/p&gt;

&lt;p&gt;This can change from page to page, but for this project, there is a link that was tracked down to the point that only &lt;code&gt;loggedin&lt;/code&gt; members are able to see, for finding this or any other, a function is available, which receives as parameters the &lt;code&gt;page&lt;/code&gt; instance and the &lt;code&gt;endpoint&lt;/code&gt; to look for as an &lt;em&gt;href&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;findLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pageLinks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a[href]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;href&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;pageLinks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;-- Close the Browser --&lt;/p&gt;

&lt;p&gt;Just pass the &lt;code&gt;browser&lt;/code&gt; instance as parameter and &lt;code&gt;close&lt;/code&gt; it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;closeBrowser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: not going to elaborate on the details of the booking process, just take into account:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It is a wizard&lt;/li&gt;
&lt;li&gt;The wizard has 3 steps, the final one is a submit&lt;/li&gt;
&lt;li&gt;The name of the elements in the query selectors are tied to the site I'm scraping on, feel free to change them as much as you need&lt;/li&gt;
&lt;li&gt;The idea is to share how to find elements, how to use query selectors, how to get the outerHtml on elements, wait for them to be available, all of this using &lt;code&gt;Puppeteer&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Nodemailer(Email Service)
&lt;/h2&gt;

&lt;p&gt;Email service is contained in 30 lines of code, it is a define structure required by the import of &lt;code&gt;nodemailer&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: When using &lt;code&gt;Gmail&lt;/code&gt;, it is mandatory to enable &lt;a href="https://myaccount.google.com/lesssecureapps"&gt;less secure apps&lt;/a&gt;, this will create a new password for just the particular application you are trying to link to, can read more here in &lt;a href="https://nodemailer.com/usage/using-gmail/"&gt;nodemailer&lt;/a&gt; or in &lt;a href="https://support.google.com/accounts/answer/6010255?hl=en"&gt;Google Support&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nodemailer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;nodemailer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;sendEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;weekBookings&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;authUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;appPassword&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;emailFrom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;emailTo&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nodemailer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createTransport&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gmail&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;authUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;pass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;appPassword&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mailOptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;emailFrom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;emailTo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Your bookings for this week&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;weekBookings&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="nx"&gt;mail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sendMail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mailOptions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;info&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Email sent: &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;sendEmail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is not too much complication in here, pass the &lt;code&gt;authUser&lt;/code&gt;, &lt;code&gt;appPassword&lt;/code&gt;, email &lt;code&gt;from/to&lt;/code&gt; and the &lt;code&gt;html&lt;/code&gt; to be send as email.&lt;/p&gt;

&lt;h2&gt;
  
  
  Local use and remote Deploy
&lt;/h2&gt;

&lt;p&gt;How to be sure that everything is working as expected?, well two options:&lt;/p&gt;

&lt;p&gt;-- Locally --&lt;/p&gt;

&lt;p&gt;For running this locally &lt;a href="https://www.postman.com/"&gt;Postman&lt;/a&gt; is the tool(don't judge me too much, I am used to it... used to Postman I meant, anyway)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  WEB_SITE_USER=YOUR_USER@YOUR_EMAIL_DOMAIN.com WEB_SITE_PASSWORD=YOUR_PASSWORD
  GMAIL_AUTH_USER=YOUR_USER@gmail.com GMAIL_APP_PASSWORD=YOUR_APP_PASSWORD
  GMAIL_EMAIL_FROM=YOUR_USER@gmail.com GMAIL_EMAIL_TO=YOUR_USER@gmail.com
  BOOKING_PREFER_TIME=06:55:00 npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will start the local server using &lt;code&gt;nodemon&lt;/code&gt; setting all the expected &lt;code&gt;process.env&lt;/code&gt; variables in port 3000 by default, so just use &lt;code&gt;Postman&lt;/code&gt; for hitting &lt;code&gt;http://localhost:3000/booking/book-me&lt;/code&gt; or &lt;code&gt;http://localhost:3000/booking/my-bookings&lt;/code&gt; and a result will be retrieved.&lt;/p&gt;

&lt;p&gt;-- Remote --&lt;/p&gt;

&lt;p&gt;For deploying remotely the platform used id &lt;a href="https://www.heroku.com/"&gt;Heroku&lt;/a&gt;, not getting in details but found this helpful &lt;a href="https://blog.logrocket.com/free-services-deploy-node-js-app/"&gt;post&lt;/a&gt; in case you decide to follow that path(read carefully the &lt;code&gt;Heroku's&lt;/code&gt; sections, and highly suggested to use &lt;a href="https://kaffeine.herokuapp.com/"&gt;Kaffeine&lt;/a&gt;).&lt;br&gt;
All the &lt;code&gt;process.env&lt;/code&gt; passed to the terminal when running locally are set as &lt;code&gt;Heroku's&lt;/code&gt; environment variables, then the deploy is transparent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus: Dealing with Captcha
&lt;/h2&gt;

&lt;p&gt;Sometimes the sites you try to scrap are sort of "protected" by &lt;code&gt;Captcha&lt;/code&gt;, I say "sort of" cause there are ways to skip it, even some companies pay to regular users to help them to recognize &lt;code&gt;captchas&lt;/code&gt;, you can read more over &lt;a href="https://2captcha.com/"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The page scraped for this post behaves "interesting", sometimes the &lt;code&gt;reCaptcha&lt;/code&gt; is ignored, some others appear right after submitting the login, so randomly fails; I opened an issue in &lt;code&gt;puppeteer-extra&lt;/code&gt;, an npm lib extension for &lt;code&gt;puppeteer&lt;/code&gt; which works hand-to-hand with &lt;a href="https://2captcha.com/"&gt;2captcha&lt;/a&gt;, I'm watching the &lt;a href="https://github.com/berstend/puppeteer-extra/issues/526"&gt;issue&lt;/a&gt; closely, in case of getting a fix for the random issue I'll edit the post.&lt;/p&gt;

&lt;p&gt;In case you were wondering, the hit of the endpoints after deployed to &lt;code&gt;Heroku&lt;/code&gt; are done by a &lt;a href="https://cron-job.org/en/"&gt;Cron-Job&lt;/a&gt;, it is fast and easy, and I received a custom email when the process randomly fails(the idea is to make it work permanently!).&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;As shown above, the web scraping is a great technique for making life easier, some hiccups could appear along the way(Captcha, Deploy servers restrictions or conditions) though some how it is possible to make it through!; maybe you could have a better way to do it, let's discuss in a thread below!&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>node</category>
      <category>express</category>
      <category>puppeteer</category>
      <category>nodemailer</category>
    </item>
    <item>
      <title>My Vue Experience after 3 projects in 18 months </title>
      <dc:creator>crisarji</dc:creator>
      <pubDate>Sun, 13 Jun 2021 23:52:08 +0000</pubDate>
      <link>https://dev.to/crisarji/my-vue-experience-after-3-projects-in-18-months-456c</link>
      <guid>https://dev.to/crisarji/my-vue-experience-after-3-projects-in-18-months-456c</guid>
      <description>&lt;h2&gt;
  
  
  My Vue Experience after 3 projects in 18 months
&lt;/h2&gt;

&lt;p&gt;Hello developer pal!, glad to see you here.&lt;/p&gt;

&lt;p&gt;In this post, I'll share my experience after 3 projects written/maintained in Vue 2.* during the last 18 months.&lt;/p&gt;

&lt;h2&gt;
  
  
  Show Me The Topics
&lt;/h2&gt;

&lt;p&gt;The topics to be focused on are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Agile Methodology and frameworks used&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Design Systems&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Infrastructure&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Backend&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;State Management&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Frontend&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;Disclaimer&lt;/em&gt;: This post comes from my own experience during this lapse, not saying this is the best way to go, nor the worst, any contribution is more than welcome in the threads below!&lt;/p&gt;

&lt;h2&gt;
  
  
  Agile Methodology and Frameworks used
&lt;/h2&gt;

&lt;p&gt;Are you familiar with &lt;a href="https://www.agilealliance.org/agile-essentials/"&gt;Agile Software Development&lt;/a&gt;?, cause I really am right now!, I really like this simple sentence as a summary:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Agile is the ability to create and respond to change. It is a way of dealing with, and ultimately succeeding in, an uncertain and turbulent environment.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Source: &lt;a href="https://www.agilealliance.org/agile101/"&gt;What is Agile?&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nice, simple, straight to the point, isn't it?, during the last year and a half my teams passed over 3 different of its frameworks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.agilealliance.org/glossary/scrum"&gt;Scrum&lt;/a&gt;: from my perspective, the most interesting, this framework allowed our &lt;a href="https://www.visual-paradigm.com/scrum/what-is-cross-functional-team-in-agile/"&gt;cross functional team&lt;/a&gt; to interact as a whole, splitting the work up in 2-weeks sprints, and constantly adjusting the business requirements, it is a quite nice experience!, highly recommended.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.agilealliance.org/glossary/kanban"&gt;Kanban&lt;/a&gt;: my second favorite from top to bottom, a good option when the work to be done does not follow the same path, for instance working on different repos at the same time(MonoRepos, MFEs, Legacy Systems)l; when this happens perhaps &lt;em&gt;Scrum&lt;/em&gt; is not enough cause the time-frames.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.agilealliance.org/glossary/xp"&gt;Extreme Programming (XP)&lt;/a&gt;: required for an MVP one of my teams had, from my experience, the most risky one since you dynamically change requirements and some heavy lifting could magically appear/disappear down the road, highly not-recommended unless it is "Extreme"-ly necessary(pun intended), and please be "Extreme"-ly cautious(pun intended X2).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In case you want to read about the &lt;code&gt;Agile Manifesto&lt;/code&gt;(the corner stone of the methodology) you can do it right &lt;a href="http://agilemanifesto.org/principles.html"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design System
&lt;/h2&gt;

&lt;p&gt;I learned that after defining the Methodology, it is good to have a robust &lt;code&gt;Design System&lt;/code&gt;, you have 2 options: reuse an existing one or create one custom from scratch, either way the benefits are amazing!, when present it covers up 3 different areas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;code&gt;UI/UX&lt;/code&gt; does not repeat itself&lt;/li&gt;
&lt;li&gt; &lt;code&gt;WebDev&lt;/code&gt; has one-and-only-one source of truth&lt;/li&gt;
&lt;li&gt; &lt;code&gt;QA&lt;/code&gt; can evacuate questions on its own&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In case you want to have some existing guide lines, &lt;a href="https://designerup.co/blog/10-best-design-systems-and-how-to-learn-and-steal-from-them/"&gt;here&lt;/a&gt; you can find a list of available resources on the wild.&lt;/p&gt;

&lt;p&gt;In the teams I was working on, those where custom, a recipe for success was:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://vuejs.org/"&gt;VueJS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://storybook.js.org/"&gt;StoryBook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tailwindcss.com/"&gt;Tailwind&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A great strategy that we found was to create &lt;code&gt;Vue&lt;/code&gt; components using &lt;code&gt;Tailwind&lt;/code&gt; and creating its respectives stories on &lt;code&gt;Storybook&lt;/code&gt;; I can say this is a great approach cause you can define your &lt;code&gt;Design System&lt;/code&gt; in &lt;code&gt;Storybook&lt;/code&gt; itself, and publish this to an accessible page for all your team members(under a VPN is even more secure), so it is available for everybody, they can see the components running in an isolated scope before even implementing it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Infrastructure
&lt;/h2&gt;

&lt;p&gt;Oh right, we had the Methodology and the Design System then what?&lt;/p&gt;

&lt;p&gt;I learned that here it comes the &lt;code&gt;Infrastructure&lt;/code&gt;, well the approaches we had the opportunity to work with where &lt;a href="https://www.jenkins.io/"&gt;Jenkins&lt;/a&gt;, &lt;a href="https://travis-ci.org/"&gt;TravisCI&lt;/a&gt; and &lt;a href="https://github.com/features/actions"&gt;GitHub Actions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For experience, in big projects, &lt;code&gt;Jenkins&lt;/code&gt; is a great way to go, among all its pros, you can set it up for running on your behalf the &lt;em&gt;unit testing&lt;/em&gt; and &lt;em&gt;end-to-end&lt;/em&gt; testing before deploying!, in case of failure you are notified and a fix can be included.&lt;/p&gt;

&lt;p&gt;In small projects, or side projects, you can use the &lt;a href="https://travis-ci.org/"&gt;TravisCI&lt;/a&gt; + &lt;a href="https://github.com/features/actions"&gt;GitHub Actions&lt;/a&gt; approach; &lt;code&gt;GitHub&lt;/code&gt; already has some built-in options for setting up &lt;code&gt;ymls&lt;/code&gt; and help you with &lt;em&gt;Merge Requests&lt;/em&gt; and &lt;em&gt;Deployments&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: &lt;a href="https://travis-ci.org/"&gt;TravisCI&lt;/a&gt; gives you 10,000 builds for free with your sign up, for small projects, proof of concepts or side projects it is a great deal!.&lt;/p&gt;

&lt;h2&gt;
  
  
  Backend
&lt;/h2&gt;

&lt;p&gt;Also I learned for these projects, that a &lt;code&gt;Backend&lt;/code&gt; on &lt;a href="https://nodejs.org/en/docs/"&gt;NodeJS&lt;/a&gt; and &lt;a href="https://firebase.google.com/docs"&gt;Firebase&lt;/a&gt; is easily handle.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://nodejs.org/en/docs/"&gt;NodeJS&lt;/a&gt; + &lt;a href="https://expressjs.com/"&gt;Express&lt;/a&gt; give you the chance to handle the routing for &lt;em&gt;CRUD&lt;/em&gt; operations, it is easy to handle the &lt;em&gt;request/responses&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://firebase.google.com/docs"&gt;Firebase&lt;/a&gt; is ready to go as soon as you import it in your &lt;a href="https://vuejs.org/"&gt;Vue&lt;/a&gt; project; with a few lines of code you are able to do a lot!; Authentication, Storage, Realtime DB, a whole bunch of options are available for you.&lt;/p&gt;

&lt;p&gt;I wrote non-canonical series related to some Firebase features if you want to check them.&lt;/p&gt;

&lt;h2&gt;
  
  
  State Management
&lt;/h2&gt;

&lt;p&gt;I learned about &lt;a href="https://vuejs.org/"&gt;VueJS&lt;/a&gt; + &lt;a href="https://vuex.vuejs.org/"&gt;Vuex&lt;/a&gt;. I'm used to Rxjs, NgRx but Vuex is from my experience the easiest; with a little of knowledge you are able to start creating on your own, the separation of concerns through modules, and the way to reference then is crystal clear:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;store/
   ├── index.js
   └── modules/
       ├── module1.store.js
       ├── module2.store.js
       ├── module3.store.js
       ├── module4.store.js
       └── module5.store.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Referencing the modules in the &lt;code&gt;index.js&lt;/code&gt; make them importable through out your project, this includes &lt;code&gt;State&lt;/code&gt;, &lt;code&gt;Getters&lt;/code&gt;, &lt;code&gt;Mutations&lt;/code&gt;, &lt;code&gt;Actions&lt;/code&gt;; a new module is just the addition of a new entry in the &lt;code&gt;index.js&lt;/code&gt;, a deprecated module is the removal of that entry(conditions may apply).&lt;/p&gt;

&lt;p&gt;I also learned that you can &lt;code&gt;namespace&lt;/code&gt; the modules!, then you can differentiate the elements by module instead of having dozens of lines with no context(trust me, with several modules this is amazing for debugging purposes, scalability and visual sake).&lt;/p&gt;

&lt;p&gt;A clear example can be found below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;mapState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mapGetters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mapActions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mapMutations&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vuex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Accessing root properties&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;mapState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my_module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;property&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
    &lt;span class="c1"&gt;// Accessing getters&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;mapGetters&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my_module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;property&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
    &lt;span class="c1"&gt;// Accessing non-root properties&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;mapState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my_module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;property&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nested&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;

  &lt;span class="na"&gt;methods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Accessing actions&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;mapActions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my_module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;myAction&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
    &lt;span class="c1"&gt;// Accessing mutations&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;mapMutations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my_module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;myMutation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It doesn't matter how small or how big is your project, it will be ready to scale, you can read here a bit more about &lt;a href="https://vuex.vuejs.org/"&gt;Vuex&lt;/a&gt; and &lt;a href="https://www.telerik.com/blogs/10-good-practices-building-maintaining-large-vuejs-projects"&gt;Namespaces&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frontend
&lt;/h2&gt;

&lt;p&gt;I learned that &lt;code&gt;Vue&lt;/code&gt; has a smaller learning curve than &lt;code&gt;Angular&lt;/code&gt;, and it is very similar to &lt;code&gt;React&lt;/code&gt;(&lt;em&gt;Note&lt;/em&gt;: assuming you have a strong base of Javascript, otherwise the curve is high on either of them).&lt;/p&gt;

&lt;p&gt;As a dev who was mostly involved in &lt;code&gt;Angular&lt;/code&gt; projects, understanding the core concepts and starting to be productive was easier than expected; I really think that the other way around must be harder, cause &lt;code&gt;Angular&lt;/code&gt; has its own world.&lt;/p&gt;

&lt;p&gt;Also learned about some core concepts that made my development faster and easier:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://vuedose.tips/how-to-structure-a-vue-js-app-using-atomic-design-and-tailwindcss/"&gt;Atomic Design Pattern&lt;/a&gt;: structure your folders as =&amp;gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Atoms&lt;/em&gt;: these are basic components, dummy ones; could be buttons, inputs, dropdowns, any imagiable component small enough to be functional and testable&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Molecules&lt;/em&gt;: a group of &lt;em&gt;Atoms&lt;/em&gt;, at this level just a little logic included, it should not include communication with you state(if possible)&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Organisms&lt;/em&gt;: mixture!, can have &lt;em&gt;Atoms&lt;/em&gt; and &lt;em&gt;Molecules&lt;/em&gt;, at this tier communication with you &lt;em&gt;State&lt;/em&gt; can be allowed; Mappers, Getters, here are accepted&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Templates&lt;/em&gt;: here you add together the aforementioned structures&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Pages&lt;/em&gt;: every page you add is an instance that can be accessed from your routing strategy
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://router.vuejs.org/guide/advanced/lazy-loading.html"&gt;Vue Lazy Routing&lt;/a&gt;: it is trivially easy to lazy load the route components; after defining your &lt;em&gt;routerOptions&lt;/em&gt; in 5 lines of code it is set and done.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Vue&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Router&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vue-router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;routerOptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Home&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/home&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Home&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/auth&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Auth&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Auth&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;routes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;routerOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cm"&gt;/* webpackChunkName: "{{route.component}}" */&lt;/span&gt; &lt;span class="s2"&gt;`../views/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.vue`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://vue-test-utils.vuejs.org/"&gt;Vue Test Utils&lt;/a&gt;: &lt;code&gt;Vue&lt;/code&gt; has its own utils for testing purposes, and it is quite easy to understand and use, let me show the most simple sample I found:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;modal&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;modal&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;aria&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;modal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;modal-content&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;slot&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/slot&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/template&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;chai&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;shallowMount&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@vue/test-utils&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;BaseModal&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/components/atoms/BaseModal.vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;BaseModal&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Template&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;existence of the element&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;should exist 'modal' element&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wrapper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;shallowMount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;BaseModal&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;[data-test='modal']&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://vuejs.org/v2/guide/components-registration.html"&gt;Global Registration of Components&lt;/a&gt;: There are components widely used, these are candidates to be registered globally so they can be referenced without importing them.
An easy way to accomplished this is creating a &lt;code&gt;_globals.js&lt;/code&gt; file and fill it in with:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Globally register all base components for convenience, because they&lt;/span&gt;
&lt;span class="c1"&gt;// will be used very frequently. Components are registered using the&lt;/span&gt;
&lt;span class="c1"&gt;// PascalCased version of their file name.&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Vue&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// https://webpack.js.org/guides/dependency-management/#require-context&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;requireComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="c1"&gt;// Look for files in the current directory&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./atoms&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// Do not look in subdirectories&lt;/span&gt;
  &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// Only include .vue files&lt;/span&gt;
  &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[\w&lt;/span&gt;&lt;span class="sr"&gt;-&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="sr"&gt;vue$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// For each matching file name...&lt;/span&gt;
&lt;span class="nx"&gt;requireComponent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fileName&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Get the component config&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;componentConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;requireComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// Get the PascalCase version of the component name&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;componentName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fileName&lt;/span&gt;
    &lt;span class="c1"&gt;// Remove the "./" from the beginning&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="se"&gt;\.\/&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;// Remove the file extension from the end&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\.\w&lt;/span&gt;&lt;span class="sr"&gt;+$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;componentName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;componentConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;componentConfig&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, just import that file in &lt;em&gt;main.js&lt;/em&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/components/_globals&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Some other good practices can be found:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://learnvue.co/2020/01/12-vuejs-best-practices-for-pro-developers/"&gt;Syntax and Logic&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.telerik.com/blogs/10-good-practices-building-maintaining-large-vuejs-projects"&gt;Slots use&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.bitsrc.io/4-best-practices-for-large-scale-vue-js-projects-9a533450bdb2"&gt;Large Scale Vue.js Projects&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;As shown above, I had a long way during the last 18 months, I'm giving my two cents in here in the way I understood the concepts, and what I think were the best practices applied; maybe you could have a better way to do it, let's discuss in a thread below!&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>vue</category>
      <category>github</category>
    </item>
    <item>
      <title>Vue Slots and Reusable components </title>
      <dc:creator>crisarji</dc:creator>
      <pubDate>Sat, 08 May 2021 01:00:55 +0000</pubDate>
      <link>https://dev.to/crisarji/vue-slots-and-reusable-components-5g3p</link>
      <guid>https://dev.to/crisarji/vue-slots-and-reusable-components-5g3p</guid>
      <description>&lt;h2&gt;
  
  
  Vue Slots and Reusable components
&lt;/h2&gt;

&lt;p&gt;Hello developer pal!, glad to see you here.&lt;/p&gt;

&lt;p&gt;In this post, we will take a look at the way a simple feature as it is &lt;code&gt;slot&lt;/code&gt; in &lt;em&gt;vue&lt;/em&gt; could spare a lot of time and effort when having the same components displaying different data.&lt;/p&gt;

&lt;p&gt;Sometimes, we need to replicate the same task with different data, for instance, you have a design system which determines that every single list element throughout the site needs to be consistent, this means having the same height, width, font, etc. Sounds fair!&lt;/p&gt;

&lt;p&gt;For accomplishing this, there are 2 options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Copy + Paste&lt;/code&gt; the same listing component in multiple places; the fallback of this approach comes when, for example, the &lt;em&gt;font&lt;/em&gt; of the list item needs to be updated; if you, by chance, have in the project 1, 2 or 3 list items, you can manually make the change, all good!, but what happens when your project has a whole bunch of listing components?, it would be required go one by one and make the change; the effort on dev, qa, and the risk of letting one scenario out of the scope is high.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a &lt;code&gt;Reusable Component&lt;/code&gt;, this will allow it to make the change in one only place and affect all of them at once!, here the &lt;code&gt;slot&lt;/code&gt; concept comes handy, when using a &lt;code&gt;slot&lt;/code&gt;, you can have the same look and feel, behavior, properties and others available for all the listing components.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Show Me The Code
&lt;/h2&gt;

&lt;p&gt;The steps to be focused on are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Having 1 reusable listing component&lt;/li&gt;
&lt;li&gt;Having different view components, injected with different data&lt;/li&gt;
&lt;li&gt;Having different view components, displaying different elements&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let me share to you the GitHub code &lt;a href="https://github.com/crisarji/vuejs-slots" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Having 1 reusable listing component
&lt;/h2&gt;

&lt;p&gt;How would it look a &lt;code&gt;slot&lt;/code&gt; for the example purposes?:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;v-for=&lt;/span&gt;&lt;span class="s"&gt;"(element, index) in elements"&lt;/span&gt; &lt;span class="na"&gt;:key=&lt;/span&gt;&lt;span class="s"&gt;"element.id"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;slot&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"element"&lt;/span&gt; &lt;span class="na"&gt;v-bind:element=&lt;/span&gt;&lt;span class="s"&gt;"element"&lt;/span&gt; &lt;span class="na"&gt;v-bind:index=&lt;/span&gt;&lt;span class="s"&gt;"index"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/slot&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the snippet above, there is a &lt;code&gt;v-for&lt;/code&gt; directive which loops over the array in a property named &lt;code&gt;elements&lt;/code&gt;; what it is happening is that every single element, and its index, are available to be part of the template, the &lt;code&gt;slot&lt;/code&gt; has the option for &lt;em&gt;binding&lt;/em&gt; values, these are available as soon as the &lt;code&gt;slot&lt;/code&gt; is invoked.&lt;/p&gt;

&lt;p&gt;This simple is to have a reusable component with &lt;code&gt;slots&lt;/code&gt;!, the html elements can be modified as required: add css, new attributes, new binding props, everything will be ready to be used when invoked the component(check the &lt;a href="https://github.com/crisarji/vuejs-slots" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; repo for a nicer experience including &lt;code&gt;Tailwind&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Having different view components, injected with different data
&lt;/h2&gt;

&lt;p&gt;For the sake of the exercise, 3 different arrays are present for feeding the view components:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;agents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;07531267-D&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Remedios Carmona&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;calls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;deals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;91958619&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Dalal Heidema&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;calls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;deals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;NNaN31539321&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Julien Legrand&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;calls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;deals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;17&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1NNaN60472038&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Karina da Cunha&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;calls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;33&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;deals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;060469-1435&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Evelyn Scheerer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;calls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;deals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;35&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;supervisors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;75687&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Idelso Gonçalves&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;agents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;teams&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;gender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;male&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2NNaN64983816&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Cassandra Leroy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;agents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;teams&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;gender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;female&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;N901057Z&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Arron Johnston&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;agents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;teams&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;gender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;male&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;18066349671&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Siham Reitan&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;agents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;teams&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;gender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;female&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;48926083&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Mariam Linde&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;agents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;teams&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;gender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;female&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;managers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;NaNNA831undefined&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Niilo Keranen&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;department&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;IT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;gender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;male&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2NNaN40789264&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Leana Deschamps&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;department&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Operations&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;gender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;female&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;283707860&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Irma Boyd&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;department&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;HHRR&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;gender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;female&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;290471&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Nicole Oehme&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;department&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ACC&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;gender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;female&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1NNaN44873525&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Antonin Rey&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;department&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Facilities&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;gender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;male&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can notice, the &lt;code&gt;views&lt;/code&gt; will be &lt;code&gt;Agents&lt;/code&gt;, &lt;code&gt;Supervisors&lt;/code&gt; and &lt;code&gt;Managers&lt;/code&gt;; as aforementioned, this items must be listed up following a design system specifications(width, height, font, typo) for keeping the consistency.&lt;/p&gt;

&lt;p&gt;Let's suppose that the design system ask for something like these:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Agents&lt;/code&gt; view:&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;p&gt;
  &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Fvue-slots%2Fassets%2Fagent-list.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Fvue-slots%2Fassets%2Fagent-list.png"&gt;&lt;/a&gt;
&lt;/p&gt;



&lt;p&gt;&lt;code&gt;Supervisors&lt;/code&gt; view:&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;p&gt;
  &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Fvue-slots%2Fassets%2Fsupervisor-list.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Fvue-slots%2Fassets%2Fsupervisor-list.png"&gt;&lt;/a&gt;
&lt;/p&gt;



&lt;p&gt;&lt;code&gt;Managers&lt;/code&gt; view:&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;p&gt;
  &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Fvue-slots%2Fassets%2Fmanager-list.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Fvue-slots%2Fassets%2Fmanager-list.png"&gt;&lt;/a&gt;
&lt;/p&gt;



&lt;p&gt;After taking a look at the mocking data and the requirements, what is changing are the fields to display, the order, and the background, since the &lt;code&gt;Copy+Paste&lt;/code&gt; approach is discarded, the other possible way to go is the &lt;em&gt;Reusable Components&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Having different view components, displaying different elements
&lt;/h2&gt;

&lt;p&gt;Let's dig a bit into the implementation of the &lt;em&gt;Reusable Component&lt;/em&gt; and &lt;em&gt;slots&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The very first view is the one for &lt;code&gt;Agents&lt;/code&gt;, we need to import the &lt;em&gt;reusable component&lt;/em&gt;, register it, add an input property for feeding the list of elements and render it out(skipped steps in here, you can check the source code for more info), let focus in the &lt;code&gt;template&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Agents&lt;/code&gt; view:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;custom-list&lt;/span&gt; &lt;span class="na"&gt;:listElements=&lt;/span&gt;&lt;span class="s"&gt;"listElements"&lt;/span&gt; &lt;span class="na"&gt;itemStyling=&lt;/span&gt;&lt;span class="s"&gt;"justify-between bg-gray-300"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;v-slot:element=&lt;/span&gt;&lt;span class="s"&gt;"{ element }"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex w-1/5"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex w-2/5"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex w-2/5"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/custom-list&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A couple of interesting things from above snippet:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;custom-list&lt;/code&gt;(our reusable component) is expecting for the list of elements and an item styling, also, it is accessing the &lt;code&gt;element&lt;/code&gt; binding, so the data to be display is dynamic.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What about the second view?&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Supervisors&lt;/code&gt; view:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;custom-list&lt;/span&gt; &lt;span class="na"&gt;:listElements=&lt;/span&gt;&lt;span class="s"&gt;"listElements"&lt;/span&gt; &lt;span class="na"&gt;itemStyling=&lt;/span&gt;&lt;span class="s"&gt;"justify-between bg-blue-300"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;v-slot:element=&lt;/span&gt;&lt;span class="s"&gt;"{ element }"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex w-2/5"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex w-1/5"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex justify-end w-2/5"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/custom-list&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is pretty similar to the previous one, the biggest difference is that a different color is send to affect the background(in case you are not familiar with Tailwind, it is this &lt;code&gt;bg-blue-300&lt;/code&gt;), and the order of the divs(the avatar from the mocks will be placed at the center)&lt;/p&gt;

&lt;p&gt;Last but not least:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Managers&lt;/code&gt; view:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;custom-list&lt;/span&gt; &lt;span class="na"&gt;:listElements=&lt;/span&gt;&lt;span class="s"&gt;"listElements"&lt;/span&gt; &lt;span class="na"&gt;itemStyling=&lt;/span&gt;&lt;span class="s"&gt;"justify-between bg-green-300"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;v-slot:element=&lt;/span&gt;&lt;span class="s"&gt;"{ element, index }"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex w-2/5"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex justify-center w-2/5"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex w-1/5"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/custom-list&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also similar to the other 2(that's the idea), but changing the background color again, the order of the elements to be displayed(avatar at the end) and also including the other binding property declared in the &lt;em&gt;reusable component&lt;/em&gt;, the &lt;code&gt;index&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;After all the steps above, this is the output:&lt;/p&gt;



&lt;p&gt;
  &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Fvue-slots%2Fassets%2Fvue-slots-switching.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Fvue-slots%2Fassets%2Fvue-slots-switching.gif"&gt;&lt;/a&gt;
&lt;/p&gt;



&lt;p&gt;&lt;em&gt;Notes&lt;/em&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You can find the repo for &lt;a href="https://github.com/crisarji/vuejs-slots" rel="noopener noreferrer"&gt;Vue2&lt;/a&gt; and &lt;a href="https://github.com/crisarji/vue3-slots" rel="noopener noreferrer"&gt;Vue3&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Feel free to fork it and/or import it in an online code editor(I tried but there seems to be a known &lt;a href="https://stackoverflow.com/questions/66112768/how-to-fix-vue-is-not-defined-in-vue-3-vue-router-4" rel="noopener noreferrer"&gt;error&lt;/a&gt; )&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;Challenge&lt;/em&gt;: The &lt;code&gt;CustomList&lt;/code&gt; component could be register globally, in case you want to stop importing it throughout the site&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;As shown above, the &lt;code&gt;slots&lt;/code&gt; could spare some precious development time, help with the scalability and be customized as required; maybe you could have a better way to do it, let's discuss in a thread below!&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>vue</category>
      <category>github</category>
    </item>
    <item>
      <title>3 steps for handling GitHub Workflow Secrets</title>
      <dc:creator>crisarji</dc:creator>
      <pubDate>Tue, 06 Apr 2021 23:57:23 +0000</pubDate>
      <link>https://dev.to/crisarji/3-steps-for-handling-github-workflow-secrets-26om</link>
      <guid>https://dev.to/crisarji/3-steps-for-handling-github-workflow-secrets-26om</guid>
      <description>&lt;h2&gt;
  
  
  What's the matter with Secrets?
&lt;/h2&gt;

&lt;p&gt;Hello developer pal!, glad to see you here.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Secrets&lt;/code&gt;(aka &lt;code&gt;environment vars&lt;/code&gt; in other contexts out of GitHub) can be used in different ways, basically they are a &lt;code&gt;key/value&lt;/code&gt; pairs which allow the interaction with your app, site, blog, etc.&lt;/p&gt;

&lt;p&gt;For a &lt;code&gt;Secret&lt;/code&gt; to work, you will always have visibility for the &lt;code&gt;Key&lt;/code&gt; but the &lt;code&gt;Value&lt;/code&gt; will remain hidden till the end of time(or till you update it manually, up to you)!&lt;/p&gt;

&lt;p&gt;For this post, in 3 steps we gonna set up a &lt;code&gt;GitHub Workflow&lt;/code&gt;(&lt;em&gt;PullRequest&lt;/em&gt; and &lt;em&gt;Merge&lt;/em&gt;) for accessing &lt;code&gt;GitHub Secrets&lt;/code&gt;, and allowing the deploy of a site.&lt;/p&gt;

&lt;h2&gt;
  
  
  Show Me The Code
&lt;/h2&gt;

&lt;p&gt;The steps to be focus on are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Creating the Secrets on GitHub&lt;/li&gt;
&lt;li&gt; Connecting the GitHub Secrets to local repo for testing&lt;/li&gt;
&lt;li&gt; Connecting the GitHub Secrets to remote repo for GitHub Workflow to kick in&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  1. Creating the Secrets on GitHub
&lt;/h2&gt;

&lt;p&gt;Maybe the "hardest" of the steps; you just need to navigate to the repo where you want to add the data, go to &lt;code&gt;Settings&lt;/code&gt;, and look for the option &lt;code&gt;Secrets&lt;/code&gt;&lt;/p&gt;



&lt;p&gt;
  &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ViCs3TGP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/crisarji/blogs-dev.to/master/blog-posts/github-workflow-secrets/assets/repo-new-secret.png" class="article-body-image-wrapper"&gt;&lt;img width="90%" src="https://res.cloudinary.com/practicaldev/image/fetch/s--ViCs3TGP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/crisarji/blogs-dev.to/master/blog-posts/github-workflow-secrets/assets/repo-new-secret.png"&gt;&lt;/a&gt;
&lt;/p&gt;



&lt;p&gt;&lt;em&gt;Tip&lt;/em&gt;: Though you can add whatever &lt;em&gt;Name&lt;/em&gt; and &lt;em&gt;Value&lt;/em&gt; you want to, it is better to add a relevant &lt;em&gt;Name&lt;/em&gt;, since this is the &lt;code&gt;Key&lt;/code&gt;, something meaningful is crucial.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: Remember that the &lt;em&gt;Value&lt;/em&gt; is hidden right after you save the &lt;code&gt;Secret&lt;/code&gt; and wont be accessible again!, you can edit but wont see it again, be careful.&lt;/p&gt;

&lt;p&gt;For this post purposes, let's take a &lt;a href="https://vuejs.org/"&gt;Vue&lt;/a&gt; app + &lt;a href="https://firebase.google.com/"&gt;Firebase&lt;/a&gt; project, these &lt;code&gt;Secrets&lt;/code&gt; would look something like this:&lt;/p&gt;



&lt;p&gt;
  &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AfE4lZYM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/crisarji/blogs-dev.to/master/blog-posts/github-workflow-secrets/assets/repo-secrets-vue-app.png" class="article-body-image-wrapper"&gt;&lt;img width="90%" src="https://res.cloudinary.com/practicaldev/image/fetch/s--AfE4lZYM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/crisarji/blogs-dev.to/master/blog-posts/github-workflow-secrets/assets/repo-secrets-vue-app.png"&gt;&lt;/a&gt;
&lt;/p&gt;



&lt;h2&gt;
  
  
  2. Connecting the GitHub Secrets to local repo for testing
&lt;/h2&gt;

&lt;p&gt;When looking for a consistent project, it is required to be sure that the values of the &lt;code&gt;Secrets&lt;/code&gt; stored on &lt;code&gt;GitHub&lt;/code&gt; are working in your app.&lt;/p&gt;

&lt;p&gt;Look below that the &lt;code&gt;Keys&lt;/code&gt; are exactly the same present in the step above, taking &lt;a href="https://firebase.google.com/"&gt;Firebase&lt;/a&gt; as an example here since it gives a set of values for identify the required project and it is easy to run and test, but the same logic should apply with keys of any other platform&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="o"&gt;----------------------------------------------------------&lt;/span&gt;
&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;
&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="o"&gt;----------------------------------------------------------&lt;/span&gt;
&lt;span class="nx"&gt;VUE_APP_FIREBASE_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;not-set-yet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="nx"&gt;VUE_APP_FIREBASE_APP_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;not-set-yet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="nx"&gt;VUE_APP_FIREBASE_AUTH_DOMAIN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;not-set-yet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="nx"&gt;VUE_APP_FIREBASE_DATABASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;not-set-yet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="nx"&gt;VUE_APP_FIREBASE_MESSAGING_SENDER_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;not-set-yet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="nx"&gt;VUE_APP_FIREBASE_PROJECT_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;not-set-yet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="nx"&gt;VUE_APP_FIREBASE_STORAGE_BUCKET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;not-set-yet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="o"&gt;----------------------------------------------------------&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running this project locally should work for you as expected, if so, you can be sure that the &lt;code&gt;Secrets&lt;/code&gt; remotely are synced up with the local ones.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: If you are not familiar with the .env modes, maybe this &lt;a href="https://cli.vuejs.org/guide/mode-and-env.html#environment-variables"&gt;reference&lt;/a&gt; could be helpful!&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Connecting the GitHub Secrets to remote repo for GitHub Workflow to kick in
&lt;/h2&gt;

&lt;p&gt;Now you could we wondering, &lt;code&gt;how can I use those Secrets in my GitHub Workflow?&lt;/code&gt;, well it is quite easy to accomplish using GitHub Action; if you are not familiar with it, maybe you can take a look at this &lt;a href="https://docs.github.com/en/actions/reference/events-that-trigger-workflows"&gt;documentation&lt;/a&gt;, long story short, you just need to include a &lt;code&gt;yaml&lt;/code&gt; to a &lt;code&gt;.github/workflows&lt;/code&gt; folder in your root repo, and add the commands you want to affect the behavior of your app, for instance when pushing a new &lt;code&gt;Pull Request&lt;/code&gt; or &lt;code&gt;Merging&lt;/code&gt; to a specific branch.&lt;/p&gt;

&lt;p&gt;For this post purposes, an action for a new &lt;code&gt;Pull Request&lt;/code&gt; is triggered mimicking a Firebase hosted project, keep focus on &lt;code&gt;env&lt;/code&gt; entry:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# This file was auto-generated by the Firebase CLI&lt;/span&gt;
&lt;span class="c1"&gt;# https://github.com/firebase/firebase-tools&lt;/span&gt;

&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to Firebase Hosting on PR&lt;/span&gt;
&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;on'&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pull_request&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build_and_preview&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;VUE_APP_FIREBASE_API_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.VUE_APP_FIREBASE_API_KEY }}&lt;/span&gt;
      &lt;span class="na"&gt;VUE_APP_FIREBASE_AUTH_DOMAIN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.VUE_APP_FIREBASE_AUTH_DOMAIN }}&lt;/span&gt;
      &lt;span class="na"&gt;VUE_APP_FIREBASE_DATABASE_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.VUE_APP_FIREBASE_DATABASE_URL }}&lt;/span&gt;
      &lt;span class="na"&gt;VUE_APP_FIREBASE_PROJECT_ID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.VUE_APP_FIREBASE_PROJECT_ID }}&lt;/span&gt;
      &lt;span class="na"&gt;VUE_APP_FIREBASE_STORAGE_BUCKET&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.VUE_APP_FIREBASE_STORAGE_BUCKET }}&lt;/span&gt;
      &lt;span class="na"&gt;VUE_APP_FIREBASE_MESSAGING_SENDER_ID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.VUE_APP_FIREBASE_MESSAGING_SENDER_ID }}&lt;/span&gt;
      &lt;span class="na"&gt;VUE_APP_FIREBASE_APP_ID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.VUE_APP_FIREBASE_APP_ID }}&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci &amp;amp;&amp;amp; npm run build&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;FirebaseExtended/action-hosting-deploy@v0&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;repoToken&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;secrets.GITHUB_TOKEN&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;
          &lt;span class="na"&gt;firebaseServiceAccount&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;secrets.FIREBASE_SERVICE_ACCOUNT&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;
          &lt;span class="na"&gt;projectId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;secret-project-test&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;FIREBASE_CLI_PREVIEWS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hostingchannels&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As shown above, before running the checkout/deploy steps, the &lt;code&gt;env&lt;/code&gt; entry takes the wheel; what happens here is that the GitHub Workflow will declare and initialize on its scope the &lt;code&gt;secrets&lt;/code&gt; already defined in the GitHub repo!, so everything is kept together through 3 different places!:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;Secrets&lt;/code&gt; you define on GitHub&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;Key/Values&lt;/code&gt; you use locally(.env file recommended)&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;GitHub Workflow&lt;/code&gt; used for the GH Action(&lt;code&gt;PR&lt;/code&gt;, &lt;code&gt;Merge&lt;/code&gt;, etc)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A change in the &lt;code&gt;Secrets&lt;/code&gt; wont mess with the whole logic, editing a value, as long as it is a valid one, will run seamlessly for your devs and users, saving time and avoiding some headaches.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: you can find more info about the used steps actions here &lt;a href="https://github.com/actions/checkout"&gt;actions/checkout@v2&lt;/a&gt; and here &lt;a href="https://github.com/FirebaseExtended/action-hosting-deploy"&gt;FirebaseExtended/action-hosting-deploy@v0&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;As shown above, keeping &lt;code&gt;Secrets&lt;/code&gt;, or &lt;code&gt;env variables&lt;/code&gt; is not so difficult when following the integration steps; maybe you could have a better way to do it, let's discuss in a thread below!&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>github</category>
      <category>firebase</category>
      <category>secrets</category>
    </item>
    <item>
      <title>Firebase: Firestore-Rules</title>
      <dc:creator>crisarji</dc:creator>
      <pubDate>Mon, 22 Mar 2021 15:15:11 +0000</pubDate>
      <link>https://dev.to/crisarji/firebase-firestore-rules-3mpc</link>
      <guid>https://dev.to/crisarji/firebase-firestore-rules-3mpc</guid>
      <description>&lt;h2&gt;
  
  
  What's Firebase Firestore Rules?
&lt;/h2&gt;

&lt;p&gt;Hello developer pal!, glad to see you here.&lt;/p&gt;

&lt;p&gt;Rules, rules and rules, we always hear about rules to follow for interacting with databases, endpoints, programming languages, and well, &lt;code&gt;Firebase Firestore&lt;/code&gt; is not the exception to the...&lt;code&gt;Rule&lt;/code&gt;(dammit once again!).&lt;/p&gt;

&lt;p&gt;Anyway, when you work with Firebase you see the features related to store some kind of information have their own &lt;code&gt;Rules&lt;/code&gt; tab, this is the way you can declare for allowing/denying the access to certain resources based on the user who is trying the request.&lt;/p&gt;

&lt;p&gt;A bad practice is to keep the resources open for everybody throughout the web, if so, anyone could perform &lt;code&gt;CRUD&lt;/code&gt; operations on your &lt;em&gt;site/app&lt;/em&gt;, modify &lt;em&gt;assets&lt;/em&gt;, or even remove &lt;em&gt;collections&lt;/em&gt;(and I am pretty sure you don't want that, do you?), you can read more information right &lt;a href="https://firebase.google.com/docs/firestore/security/get-started" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Show Me The Code
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Disclaimer&lt;/em&gt;: For this post, a shallow explanation will be given related to &lt;code&gt;Firestore ans Security Rules version 2&lt;/code&gt;, released on May 2019&lt;/p&gt;

&lt;p&gt;The 3 main pieces to be focus on are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Default versions for test and prod&lt;/li&gt;
&lt;li&gt; Writing rules straight in console vs versioned file&lt;/li&gt;
&lt;li&gt; Allow/Deny access according to auth states and functions&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Default versions for test and prod
&lt;/h2&gt;

&lt;p&gt;Whenever you start a new Firebase project, in the section &lt;code&gt;Firestore/Rules&lt;/code&gt;, creating a new db project will present 2 options, you can opt any of those in, let's see the difference:&lt;/p&gt;

&lt;h3&gt;
  
  
  Mode Production
&lt;/h3&gt;

&lt;p&gt;Under this mode, any access is explicitly &lt;em&gt;denied&lt;/em&gt;, this forces the developer to add some logic for explicitly allowing users to access the resources.&lt;/p&gt;



&lt;p&gt;
  &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Ffirebase-firestore-rules%2Fassets%2Ffirestore-opted-mode-prod.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Ffirebase-firestore-rules%2Fassets%2Ffirestore-opted-mode-prod.png"&gt;&lt;/a&gt;
&lt;/p&gt;



&lt;p&gt;The default schema for &lt;code&gt;production mode&lt;/code&gt; looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="nx"&gt;rules_version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;service&lt;/span&gt; &lt;span class="nx"&gt;cloud&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firestore&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;match&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;databases&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="sr"&gt;/documents &lt;/span&gt;&lt;span class="err"&gt;{
&lt;/span&gt;      &lt;span class="nx"&gt;match&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="o"&gt;=**&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;allow&lt;/span&gt; &lt;span class="nx"&gt;read&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;write&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Something to remark is the fact that the rules keep the track on a historical, this means that is possible to activate a previous rule schema, compare a former version against the most recent one, and even delete unused schemas; this also helps to easily find bugs when adding new docs or collections.&lt;/p&gt;



&lt;p&gt;
  &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Ffirebase-firestore-rules%2Fassets%2Ffirestore-rules-edition-historical.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Ffirebase-firestore-rules%2Fassets%2Ffirestore-rules-edition-historical.png"&gt;&lt;/a&gt;
&lt;/p&gt;



&lt;h3&gt;
  
  
  Mode Test
&lt;/h3&gt;

&lt;p&gt;Under this mode, any access is explicitly &lt;em&gt;allowed&lt;/em&gt; to any user for the next whole month(by default through a timestamp). This will allow the developer to start the work right away, though, the idea is set the schema as soon as possible for allowing only expected users to consume resources.&lt;/p&gt;



&lt;p&gt;
  &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Ffirebase-firestore-rules%2Fassets%2Ffirestore-opted-mode-test.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Ffirebase-firestore-rules%2Fassets%2Ffirestore-opted-mode-test.png"&gt;&lt;/a&gt;
&lt;/p&gt;



&lt;p&gt;The default schema for &lt;code&gt;test mode&lt;/code&gt; looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="nx"&gt;rules_version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;service&lt;/span&gt; &lt;span class="nx"&gt;cloud&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firestore&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;match&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;databases&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="sr"&gt;/documents &lt;/span&gt;&lt;span class="err"&gt;{
&lt;/span&gt;      &lt;span class="nx"&gt;match&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="o"&gt;=**&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;allow&lt;/span&gt; &lt;span class="nx"&gt;read&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;write&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt;
            &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2021&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just like in production mode, the rules keep the track on a historical, also, a few days before due date, the main email registered will start receiving notifications about the expiring access to the database collections and docs unless a new rule schema is applied.&lt;/p&gt;

&lt;h2&gt;
  
  
  Writing rules straight in console vs versioned file
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Straight in Console
&lt;/h3&gt;

&lt;p&gt;Writing straight to &lt;code&gt;Firebase Console&lt;/code&gt; is an option, it is easy and fast.&lt;/p&gt;



&lt;p&gt;
  &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Ffirebase-firestore-rules%2Fassets%2Fschema-in-console.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Ffirebase-firestore-rules%2Fassets%2Fschema-in-console.png"&gt;&lt;/a&gt;
&lt;/p&gt;



&lt;p&gt;One more feature with this approach, is the integration with an sort of built-in linter, it determines some syntax issues before publishing, in fact, it throws an error, and the changes wont be published till the issue is fixed.&lt;/p&gt;



&lt;p&gt;
  &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Ffirebase-firestore-rules%2Fassets%2Fschema-in-console-error.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Ffirebase-firestore-rules%2Fassets%2Fschema-in-console-error.png"&gt;&lt;/a&gt;
&lt;/p&gt;



&lt;h3&gt;
  
  
  Versioned File
&lt;/h3&gt;

&lt;p&gt;A cleaner way to have the rules is through a versioned file, in your &lt;em&gt;firebase.json&lt;/em&gt; file, you can add an entry for &lt;code&gt;firestore/rules&lt;/code&gt;(and even &lt;code&gt;indexes&lt;/code&gt;!).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"hosting"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"firestore"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"rules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"firestore.rules"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"indexes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"firestore.indexes.json"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"functions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"emulators"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then you can add the &lt;code&gt;firestore.rules&lt;/code&gt; file and keep the versions in git or any other version handler&lt;/p&gt;



&lt;p&gt;
  &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Ffirebase-firestore-rules%2Fassets%2Ffirestore-versioned-file.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Ffirebase-firestore-rules%2Fassets%2Ffirestore-versioned-file.png"&gt;&lt;/a&gt;
&lt;/p&gt;



&lt;p&gt;The flow goes as shown below, if more info required, take a look at the documentation right &lt;a href="https://firebase.google.com/docs/firestore/security/get-started?authuser=0" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  // Set up Firestore &lt;span class="k"&gt;in &lt;/span&gt;your project directory, creates a .rules file
  firebase init firestore

  // Edit the generated .rules file to your desired security rules
  // ...

  // Deploy your .rules file
  firebase deploy &lt;span class="nt"&gt;--only&lt;/span&gt; firestore:rules
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Allow/Deny access according to auth states and functions
&lt;/h2&gt;

&lt;p&gt;Either way the writing of rules goes, the critical part is the access to docs and collections. It is possible to create js functions for avoid duplicating conditionals for every element, I wrote a post related to &lt;a href="https://dev.to/crisarji/adding-roles-to-the-authentication-with-vue-x-firebase-2o62"&gt;Adding roles to the authentication with Vue(x)+Firebase&lt;/a&gt; in case you want to check the use of claims and token additions.&lt;/p&gt;

&lt;p&gt;So, for example, you could add a function for determining whether a request comes from an &lt;code&gt;Admin&lt;/code&gt; or a &lt;code&gt;Regular&lt;/code&gt; user profile, according to the resolution(handle by &lt;em&gt;Firebase&lt;/em&gt; itself), the access to different resources is granted or not.&lt;/p&gt;

&lt;p&gt;Take a look at the example below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="nx"&gt;rules_version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;service&lt;/span&gt; &lt;span class="nx"&gt;cloud&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firestore&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;match&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;databases&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="sr"&gt;/documents &lt;/span&gt;&lt;span class="err"&gt;{
&lt;/span&gt;      &lt;span class="c1"&gt;// true if the user is signed in and the claim is admin&lt;/span&gt;
      &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isAdmin&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uid&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;admin&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="c1"&gt;// true if the user is signed in and the claim is regular&lt;/span&gt;
      &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isRegular&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uid&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;regular&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="c1"&gt;// Shared collections&lt;/span&gt;
      &lt;span class="nx"&gt;match&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;settings&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;allow&lt;/span&gt; &lt;span class="na"&gt;read&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isAdmin&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nf"&gt;isRegular&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nx"&gt;allow&lt;/span&gt; &lt;span class="na"&gt;write&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isAdmin&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="p"&gt;...&lt;/span&gt;
      &lt;span class="p"&gt;...&lt;/span&gt;
      &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What happened in the code above?:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The functions created always ask whether the request incoming is related to a user authenticated, otherwise, the access is invalid and the request is denied&lt;/li&gt;
&lt;li&gt;The function &lt;code&gt;isAdmin()&lt;/code&gt;, when is invoked by an authenticated user, it looks for a particular &lt;code&gt;token&lt;/code&gt;, in this case, the &lt;em&gt;admin&lt;/em&gt; token, if presented, the request is validated&lt;/li&gt;
&lt;li&gt;The function &lt;code&gt;isRegular()&lt;/code&gt;,just like &lt;code&gt;isAdmin()&lt;/code&gt; looks for a particular &lt;code&gt;token&lt;/code&gt;, in this case, the &lt;em&gt;regular&lt;/em&gt; token, if presented, the request is validated&lt;/li&gt;
&lt;li&gt;There is a collection of &lt;code&gt;settings&lt;/code&gt;, when a request for &lt;code&gt;reading&lt;/code&gt; comes, the fetching is available only for authenticated &lt;code&gt;users&lt;/code&gt; with a role of &lt;code&gt;admin&lt;/code&gt; or &lt;code&gt;regular&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;In the same collection of &lt;code&gt;settings&lt;/code&gt;, when a request for &lt;code&gt;writing&lt;/code&gt; comes, the upsert is available only for authenticated &lt;code&gt;users&lt;/code&gt; with a role of &lt;code&gt;admin&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is useful since even when the APIkey of your app/site is available for third-parties, the requests wont do any operations to your data without an &lt;em&gt;authenticated-and-roled&lt;/em&gt; user.&lt;/p&gt;

&lt;p&gt;Sometimes &lt;code&gt;read&lt;/code&gt; and &lt;code&gt;write&lt;/code&gt; could be to macro, you can granulate them a bit more:&lt;br&gt;
_&lt;code&gt;read&lt;/code&gt; rule can be broken into &lt;code&gt;get&lt;/code&gt; and &lt;code&gt;list&lt;/code&gt;&lt;br&gt;
_&lt;code&gt;write&lt;/code&gt; rule can be broken into &lt;code&gt;create&lt;/code&gt;, &lt;code&gt;update&lt;/code&gt;, and &lt;code&gt;delete&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;More info about this topic can be found right &lt;a href="https://firebase.google.com/docs/firestore/security/rules-structure?authuser=0" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;As shown above, Firebase Firestore rules are quite powerful, allowing even write some functions in the declared schema for avoid repeating the code over and over again; maybe you could have a better way to do it, let's discuss in a thread below!&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>firebase</category>
      <category>firestore</category>
      <category>rules</category>
    </item>
    <item>
      <title>Tailwind Feature: animate-pulse</title>
      <dc:creator>crisarji</dc:creator>
      <pubDate>Tue, 02 Feb 2021 13:12:35 +0000</pubDate>
      <link>https://dev.to/crisarji/tailwind-feature-animate-pulse-3nbn</link>
      <guid>https://dev.to/crisarji/tailwind-feature-animate-pulse-3nbn</guid>
      <description>&lt;h2&gt;
  
  
  What's animate-pulse in Tailwind?
&lt;/h2&gt;

&lt;p&gt;Hello developer pal!, glad to see you here, have you ever been wandering on your social networks and suddenly you find a post which caught your attention, you want to see the comments, click in the link, and have the impression that a whole bunch of comments are coming cause you see a sort of template which fades in and out, and after a few milliseconds, it loads 1 comment, or sometimes 0!? it is a a mix of feelings, you are half happy/ half disappointed; well today we will be talking about this really cool feature, then you can pull the leg to your own users!.&lt;/p&gt;

&lt;p&gt;For this endeavor, it is this reaaaally cool feature included in TailwindCss, the &lt;code&gt;animate-pulse&lt;/code&gt; you can read more information right &lt;a href="https://tailwindcss.com/docs/animation#pulse"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Show Me The Code
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Disclaimer&lt;/em&gt;: For this post, want to show 1 possible approach used in some other projects, maybe not the best way to do it, maybe not the worst, please feel free to start a thread in the comments section below in case of question, suggestions, improvements.&lt;/p&gt;

&lt;p&gt;The 3 main pieces to be focus on are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; The use of Tailwind.&lt;/li&gt;
&lt;li&gt; A practical example using VueJS.&lt;/li&gt;
&lt;li&gt; The code posted in Stackblitz(so you can play around)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let me share to you the Stackblitz code &lt;a href="https://stackblitz.com/edit/tailwindcss-animate-pulse"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Want some explanation? chop-chop!
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;animate-pulse&lt;/code&gt; causes this fade in/out effect, it is a nice way for letting the user know that something is happening under the hood and keep them hooked!, let see step by step how to accomplish something like this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Set a list of elements
&lt;/h3&gt;

&lt;p&gt;For example purposes, a &lt;code&gt;employees.js&lt;/code&gt; file is being consumed, it has the elements to be used for loading the component; notice that this can be changed for an API response or any other resource invocation for feeding the component up.&lt;/p&gt;

&lt;p&gt;Every element has a shared structure that will be important for the pulse effect a bit further.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;employees&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Emp-001&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Yusha Beil&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;avatar&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://i.pinimg.com/736x/3f/94/70/3f9470b34a8e3f526dbdb022f9f19cf7.jpg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;isActive&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Emp-002&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Fearne Greene&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;avatar&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://i.pinimg.com/736x/3f/94/70/3f9470b34a8e3f526dbdb022f9f19cf7.jpg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;isActive&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Emp-003&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Keegan Cortes&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;avatar&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://i.pinimg.com/736x/3f/94/70/3f9470b34a8e3f526dbdb022f9f19cf7.jpg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;isActive&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Emp-004&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Anton Chaney&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;avatar&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://i.pinimg.com/736x/3f/94/70/3f9470b34a8e3f526dbdb022f9f19cf7.jpg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;isActive&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Emp-005&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Ruari Mellor&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;avatar&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://i.pinimg.com/736x/3f/94/70/3f9470b34a8e3f526dbdb022f9f19cf7.jpg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;isActive&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;employees&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Have some props ready to be filled
&lt;/h3&gt;

&lt;p&gt;There are 2 important properties required when following this approach: 1 the &lt;code&gt;listElements&lt;/code&gt; and 2 &lt;code&gt;isLoading&lt;/code&gt;(or any other named flag for noticing when an operation still pending).&lt;/p&gt;

&lt;p&gt;It is important to remark that as the &lt;code&gt;listElements&lt;/code&gt; is faking an API call, the &lt;code&gt;isLoading&lt;/code&gt; is mocking a state flag, this could be a flag shared in &lt;code&gt;Vuex&lt;/code&gt; state manager for keeping the interaction up to date at any time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;listElements&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;employees&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;//Note: this employees comes from the imported file, in a real scenario the default would be `[]` and the prop will be feeded externally&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: For testing purposes, the &lt;code&gt;isLoading&lt;/code&gt; flag is set after a &lt;code&gt;setTimeout&lt;/code&gt; in the &lt;code&gt;mounted&lt;/code&gt; hook, thus mimicking the state manager behavior as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="nx"&gt;mounted&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;//Note: When interacting with a state manager(e.g. Vuex), remove this hook and let the flag to be filled from a state getter.&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Have a data prop ready with a list of fake elements to be loop through
&lt;/h3&gt;

&lt;p&gt;Here is where the tweaks start on!, handling this list of fake elements will allow the component to iterate over a ready-to-use list at any time&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Example List!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;fakeElements&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can add as many fake elements as you want; for not overwhelming the example only 5 are added here, it matches the number of entries to be added after flipping the flag &lt;code&gt;isLoading&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Let a computed property to determine which list to render
&lt;/h3&gt;

&lt;p&gt;Another small tweak for switching between the fake list(always ready) and the real list of elements.&lt;/p&gt;

&lt;p&gt;This way it is for sure that the html will have a list of elements at any time, the trick is just to flip between the real deal and the fake stuff, as easy as that!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="nx"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;renderList&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fakeElements&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listElements&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The component html
&lt;/h3&gt;

&lt;p&gt;Vuejs allows to set classes to the html elements as expressions, that's the final piece of code, add the &lt;code&gt;animate-pulse&lt;/code&gt; for the more relevant elements depending on the flag value &lt;code&gt;isLoading&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Since the fake list is always ready to be looped, and it is composed of barely valid elements, none of the properties are shown, therefore the effect can be used as long as the flag does not change in all the desired elements.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;{{name}}&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"w-screen bg-transparent flex items-center justify-around"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ul&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"w-full max-w-md overflow-auto"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt;
        &lt;span class="na"&gt;v-for=&lt;/span&gt;&lt;span class="s"&gt;"element in renderList"&lt;/span&gt;
        &lt;span class="na"&gt;:key=&lt;/span&gt;&lt;span class="s"&gt;"element.id"&lt;/span&gt;
        &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"p-4 mb-3 flex items-center justify-between bg-white shadow rounded-lg cursor-move"&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex items-center"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt;
              &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"w-10 h-10 rounded-full"&lt;/span&gt;
              &lt;span class="na"&gt;:src=&lt;/span&gt;&lt;span class="s"&gt;"element.avatar"&lt;/span&gt;
              &lt;span class="na"&gt;:alt=&lt;/span&gt;&lt;span class="s"&gt;"element.name"&lt;/span&gt;
              &lt;span class="na"&gt;:class=&lt;/span&gt;&lt;span class="s"&gt;"{'animate-pulse bg-gray-400' : isLoading}"&lt;/span&gt;
            &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt;
              &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"ml-2 text-gray-700 font-semibold font-sans tracking-wide break-all md:break-words"&lt;/span&gt;
              &lt;span class="na"&gt;:class=&lt;/span&gt;&lt;span class="s"&gt;"{'animate-pulse bg-gray-400 w-48 h-6' : isLoading}"&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
              {{element.name}}
            &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex items-center"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt;
              &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn mx-4 px-4 rounded"&lt;/span&gt;
              &lt;span class="na"&gt;:class=&lt;/span&gt;&lt;span class="s"&gt;"[{'animate-pulse w-12 h-6' : isLoading}, element.isActive ? 'bg-green-400' : 'bg-red-400']"&lt;/span&gt;
              &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;click=&lt;/span&gt;&lt;span class="s"&gt;"editItem(element)"&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"capitalize text-white"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{isLoading ? '' : 'Edit'}}&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code above, notice a few thing, for example, when loading the values, the &lt;code&gt;animate-pulse&lt;/code&gt; is applied from 1 to N elements, this means that it is possible to include the animation on any html element depending on your own requirements, thus it is possible to match the styles even with no data available.&lt;/p&gt;

&lt;p&gt;A good example is the &lt;em&gt;button&lt;/em&gt; element, the width and height is given by the text content rendered on it; when loading, we don't want to show the label to be used, so there is no way to calculate that value, the easiest way to get rid off this issue is to assign a width and height as long as the real data is not available, and that's exactly what happens on&lt;br&gt;
&lt;code&gt;{'animate-pulse w-12 h-6' : isLoading}&lt;/code&gt;, the effect is active with a Tailwind height and width whilst processing the real data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;AS shown above, this Tailwind feature is pretty cool and can be integrated with api calls results and loading flags in the state manager to make the user feel more comfortable when interacting with your site/app; maybe you could have a better way to do it, let's discuss in a thread below!&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>vue</category>
      <category>tailwindcss</category>
    </item>
    <item>
      <title>Adding roles to the authentication with Vue(x)+Firebase</title>
      <dc:creator>crisarji</dc:creator>
      <pubDate>Sat, 05 Dec 2020 23:20:46 +0000</pubDate>
      <link>https://dev.to/crisarji/adding-roles-to-the-authentication-with-vue-x-firebase-2o62</link>
      <guid>https://dev.to/crisarji/adding-roles-to-the-authentication-with-vue-x-firebase-2o62</guid>
      <description>&lt;h2&gt;
  
  
  Greetings and Recap
&lt;/h2&gt;

&lt;p&gt;Hello again developer pal!, if you have come across this repo on purpose great! thanks for reading, otherwise, maybe you want to take a look at its predecesor &lt;a href="https://dev.to/crisarji/authentication-with-vue-x-firebase-31dc"&gt;login-vuex-firebase&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Anyway, let me tell you that this repo is the next step to the &lt;em&gt;authentication&lt;/em&gt; using &lt;em&gt;Vuex&lt;/em&gt; and &lt;em&gt;Firebase&lt;/em&gt;, yes, this is for the &lt;em&gt;authorization&lt;/em&gt;; it is a simple one, using an assigned role for some users by email. I can bet that there are several ways to do it, I wont go too deep because:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; These are my first posts so I am taking it easy.&lt;/li&gt;
&lt;li&gt; Want to give you a sample, you are allowed to fork and reimplement as much as you want/require.&lt;/li&gt;
&lt;li&gt; Any feedback is more than welcome as a PR or thread in this post.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you checked my aforementioned code and post, you remember we ended up having a functional authentication like this:&lt;/p&gt;



&lt;p&gt;
  &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Froles-vuex-firebase%2Fassets%2Flogin-vue-firebase.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Froles-vuex-firebase%2Fassets%2Flogin-vue-firebase.gif"&gt;&lt;/a&gt;
&lt;/p&gt;



&lt;p&gt;So far so good!, but what would happen if you want to limitate the access to the users?, depending whether dealing with an &lt;code&gt;admin&lt;/code&gt; or a &lt;code&gt;player&lt;/code&gt;(yeap these are the couple roles we could have for this case), we want to have a way to allow certain views to the &lt;code&gt;admin&lt;/code&gt; and some others to the &lt;code&gt;player&lt;/code&gt;, something like this:&lt;/p&gt;



&lt;h3&gt;Admin&lt;/h3&gt;

&lt;p&gt;Allow the access as an administrator to a &lt;strong&gt;dashboard&lt;/strong&gt; page, but forbid to access other users page&lt;/p&gt;

&lt;p&gt;
  &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Froles-vuex-firebase%2Fassets%2Flogin-admin.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Froles-vuex-firebase%2Fassets%2Flogin-admin.gif" alt="Login Admin"&gt;&lt;/a&gt;
&lt;/p&gt;





&lt;h3&gt;Player&lt;/h3&gt;

&lt;p&gt;Allow the access as a player to a &lt;strong&gt;landing&lt;/strong&gt; page, but forbid to access admin pages&lt;/p&gt;

&lt;p&gt;
  &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Froles-vuex-firebase%2Fassets%2Flogin-player.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Froles-vuex-firebase%2Fassets%2Flogin-player.gif" alt="Login Player"&gt;&lt;/a&gt;
&lt;/p&gt;



&lt;p&gt;Too much text and gifs, let see the code!&lt;/p&gt;

&lt;h2&gt;
  
  
  Show Me The Code
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Disclaimer&lt;/em&gt;: For the last post, I mentioned that there are plenty of posts related to &lt;code&gt;Firebase&lt;/code&gt; and how to set it up, and that you should have a basic knowledge of the platform, at least have 1 project and the API Keys available. In this ocassion I'll be a bit more picky, it is imperative to have some knowledge of &lt;code&gt;Firebase functions&lt;/code&gt;, in case you are not familiar you can read about it &lt;a href="https://firebase.google.com/docs/functions" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&gt;
Also, for running functions there are 2 main requirements: 1. node version when deploying must be 10 or above, 2. some interactions may require an upgrade from &lt;code&gt;Spark&lt;/code&gt; to &lt;code&gt;Blaze&lt;/code&gt; plan.&lt;/p&gt;

&lt;p&gt;Let me share to you the Github code &lt;a href="https://github.com/crisarji/roles-vuex-firebase" rel="noopener noreferrer"&gt;here&lt;/a&gt;, you can find the requirements for running the app locally, also a &lt;code&gt;functions&lt;/code&gt; folder which is required for the roles implementation; since it is still in an early stage, no live demo yet.&lt;/p&gt;
&lt;h2&gt;
  
  
  Want some explanation? sure thing! keep reading below
&lt;/h2&gt;

&lt;p&gt;As you already know, we are diving in a bay called &lt;code&gt;Firebase&lt;/code&gt;, we'll interact a bit more with one of its islands the &lt;code&gt;Firebase console&lt;/code&gt;, so please have an active project, that will make it easier for you to follow the explanations, I'll split them into steps for trying to make it easier to read.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 1
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Roles collection on Firebase
&lt;/h3&gt;

&lt;p&gt;Since the goal is give you an idea of what you can do with the platform &lt;code&gt;roles&lt;/code&gt; collection only requires 2 properties: one for the &lt;em&gt;email&lt;/em&gt; and one for the &lt;em&gt;isAdmin&lt;/em&gt;, remember that you can make it suit your requirements whatever other way you want or need.&lt;/p&gt;



&lt;p&gt;
  &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Froles-vuex-firebase%2Fassets%2Froles-entry.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Froles-vuex-firebase%2Fassets%2Froles-entry.png" alt="Login Player"&gt;&lt;/a&gt;
&lt;/p&gt;



&lt;p&gt;Now on, whenever a user with this email is created, &lt;code&gt;Firebase&lt;/code&gt; on its own will turn it into an &lt;code&gt;admin&lt;/code&gt; user, any other user will be treated as a &lt;code&gt;player&lt;/code&gt; role, keep reading to see the how!&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Firebase and Custom Claims
&lt;/h3&gt;

&lt;p&gt;First thing to know is the way the platform exposes the authorization interaction, this is through the use of &lt;em&gt;Custom Claims&lt;/em&gt; and &lt;em&gt;Security Rules&lt;/em&gt;; we are aboarding the first in here. According to the official documentation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The Firebase Admin SDK supports defining custom attributes on user accounts. This provides the ability to implement various access control strategies, including role-based access control, in Firebase apps. These custom attributes can give users different levels of access (roles), which are enforced in an application's security rules.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What does that mean?, well in summay it means that after creating a new user, we can append some new attributes to the &lt;code&gt;claims&lt;/code&gt; object present in the background, and we can take advantage of that behavior for handling &lt;em&gt;roles&lt;/em&gt;, not too hard to follow right?&lt;/p&gt;

&lt;p&gt;You can read much more about &lt;em&gt;Claims&lt;/em&gt; &lt;a href="https://firebase.google.com/docs/auth/admin/custom-claims" rel="noopener noreferrer"&gt;here&lt;/a&gt; in case you are not convinced with my shallow explanation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Setting Custom Claims
&lt;/h3&gt;

&lt;p&gt;For setting a custom claim is necessary to make a couple changes in the previous code we used for the login.&lt;/p&gt;

&lt;p&gt;First of all, a small tweak needs to be done on &lt;em&gt;signup&lt;/em&gt; action on &lt;code&gt;store/modules/authentication.js&lt;/code&gt;; just flip the &lt;em&gt;enable&lt;/em&gt; to &lt;code&gt;false&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;signup&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;commit&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;setLoading&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createUserWithEmailAndPassword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;firebaseData&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;fb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;usersCollection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;firebaseData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;nickname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nickname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;enable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;= this from true to false&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will force every single created user to be flipped to &lt;em&gt;enable = true&lt;/em&gt; manually or programatically.&lt;/p&gt;

&lt;p&gt;You could ask yourself &lt;em&gt;Why would I disable every new user?&lt;/em&gt;, well imagine that you have a selected group of users for your application, you dont want to control the signup but the signin, so you can filter who interacts with your before hand.&lt;/p&gt;

&lt;p&gt;Important: take into account that what we just did was to disconnect the user created in our custom &lt;code&gt;users&lt;/code&gt; collection, remember that this is an extension for the &lt;code&gt;authorization user&lt;/code&gt;, this last is the one which possesses the &lt;code&gt;claim&lt;/code&gt; that we need to modify for the role.&lt;/p&gt;

&lt;p&gt;So, how can we add the &lt;code&gt;claim&lt;/code&gt; for a brand new created user?, well with a predefined &lt;a href="https://firebase.google.com/docs/functions/firestore-events" rel="noopener noreferrer"&gt;trigger background function&lt;/a&gt; of course!&lt;/p&gt;

&lt;p&gt;Long story short =&amp;gt; &lt;code&gt;Firebase&lt;/code&gt; has some triggers to be used out of the box in cases of create, update, delete, etc a user; the trigger we do care in particular is &lt;code&gt;onCreate&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;After knowing this, in the &lt;em&gt;root&lt;/em&gt; folder of the project, there is new folder called &lt;code&gt;functions&lt;/code&gt;, it is a simple structure with an &lt;em&gt;index.js&lt;/em&gt;, a &lt;em&gt;package.json&lt;/em&gt;, and a few more required-but-simple files, take a look at the first:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;index.js&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firebase-functions&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firebase-admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initializeApp&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;processSignUp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;user&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;adminUsers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;firestore&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;adminUsers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;snapshot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;adminUsers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;==&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;customClaims&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;empty&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;player&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setCustomUserClaims&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;customClaims&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userUpdate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;firestore&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="nx"&gt;userUpdate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;nickname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;enable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;});&lt;/span&gt;
          &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`User with email &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; was added as admin and enabled!`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;metadataRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;database&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;metadata/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;metadataRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;refreshTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;getTime&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`There was an error whilst adding &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; as admin`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`There was no email supplied for user, no role added.`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Saw that?, in only 32 lines of code(it could be even less) resides all the logic for checking the role, add it if required, modify the extended user and report the execution status of the function, let's split it bit by bit.&lt;/p&gt;

&lt;p&gt;This code imports the required modules, initialize the app and registers the trigger for the &lt;code&gt;OnCreate&lt;/code&gt;; therefore whenever a new user is added, via &lt;code&gt;signUp&lt;/code&gt; or &lt;code&gt;manually&lt;/code&gt; it will pass through this function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firebase-functions&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firebase-admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initializeApp&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;processSignUp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;user&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, if no email is registered for any reason, the logger exposed by &lt;em&gt;firebase-functions&lt;/em&gt; writes in the web logs&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`There was no email supplied for user, no role added.`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In case a valid email is in place(this should be almost always), the function will look for the &lt;code&gt;roles&lt;/code&gt; collection, will execute a query &lt;em&gt;where&lt;/em&gt; looking up for the email, in case of match, the &lt;code&gt;snapshot&lt;/code&gt; will not be empty, thus the &lt;code&gt;customClaim&lt;/code&gt; is set as &lt;em&gt;admin&lt;/em&gt;, otherwise it will be dealing with a &lt;em&gt;player&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;processSignUp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;user&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;adminUsers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;firestore&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;adminUsers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;snapshot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;adminUsers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;==&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;customClaims&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;empty&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;player&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The final step is &lt;code&gt;setCustomUserClaims&lt;/code&gt; using the &lt;em&gt;uid&lt;/em&gt; identifying the user and the &lt;em&gt;customClaim&lt;/em&gt; which determines whether dealing with an &lt;em&gt;admin&lt;/em&gt; or a &lt;em&gt;player&lt;/em&gt;; also notice that in case the function is dealing with an &lt;em&gt;admin&lt;/em&gt; it will add a new record in the extended &lt;em&gt;users&lt;/em&gt; collection(pretty much what we do in the &lt;em&gt;signup&lt;/em&gt; action in our &lt;em&gt;authentication&lt;/em&gt; module).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;customClaims&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;empty&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;player&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setCustomUserClaims&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;customClaims&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userUpdate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;firestore&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;userUpdate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;nickname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;enable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`User with email &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; was added as admin and enabled!`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;metadataRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;database&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;metadata/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;metadataRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;refreshTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;getTime&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`There was an error whilst adding &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; as admin`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look the code above, among the props notice the &lt;em&gt;enable = true&lt;/em&gt;, this has a double purpose:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Enable the admin user immediately&lt;/li&gt;
&lt;li&gt;Allows the creation of admin users directly from &lt;code&gt;Firebase console&lt;/code&gt; instead of going through the whole signup process&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So, something like this is possible, easier and more viable than running the whole signup:&lt;/p&gt;



&lt;p&gt;
  &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Froles-vuex-firebase%2Fassets%2Fadding-admin-user.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Froles-vuex-firebase%2Fassets%2Fadding-admin-user.png" alt="Login Player"&gt;&lt;/a&gt;
&lt;/p&gt;



&lt;p&gt;In case you were wondering, yes, this user above is the same added in the Step 1.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Deploying the processSignUp function
&lt;/h3&gt;

&lt;p&gt;Hope you have followed the previous steps, may look a bit complicated, but after a couple more reads will be cristal clear!, so for the next step we need to deploy the &lt;code&gt;processSignUp&lt;/code&gt; function, let's take a look at &lt;code&gt;Firebase's&lt;/code&gt; console first:&lt;/p&gt;

&lt;p&gt;In console, in &lt;code&gt;Functions&lt;/code&gt; section, if no functions created a 2-steps wizard will appear&lt;/p&gt;

&lt;p&gt;Step 1&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;p&gt;
  &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Froles-vuex-firebase%2Fassets%2Fconfig-functions-step1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Froles-vuex-firebase%2Fassets%2Fconfig-functions-step1.png" alt="Config Functions Step1"&gt;&lt;/a&gt;
&lt;/p&gt;



&lt;p&gt;Step 2&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;p&gt;
  &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Froles-vuex-firebase%2Fassets%2Fconfig-functions-step2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Froles-vuex-firebase%2Fassets%2Fconfig-functions-step2.png" alt="Config Functions Step2"&gt;&lt;/a&gt;
&lt;/p&gt;



&lt;p&gt;Final Panel&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;p&gt;
  &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Froles-vuex-firebase%2Fassets%2Ffunctions-panel.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Froles-vuex-firebase%2Fassets%2Ffunctions-panel.png" alt="Functions Panel"&gt;&lt;/a&gt;
&lt;/p&gt;



&lt;p&gt;Now, how to deploy the function in Firebase?, it is an easy process(the followinf steps must be executed inside &lt;code&gt;functions&lt;/code&gt; folder):&lt;/p&gt;

&lt;p&gt;Connect your &lt;code&gt;functions&lt;/code&gt; with your &lt;code&gt;Firebase&lt;/code&gt; project executing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  firebase use &lt;span class="nt"&gt;--add&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pick the project and an alias(this works better when multiple projects exist under the same instance)&lt;/p&gt;



&lt;p&gt;
  &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Froles-vuex-firebase%2Fassets%2Ffirebase-use-add.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Froles-vuex-firebase%2Fassets%2Ffirebase-use-add.png" alt="Firebase Use Add"&gt;&lt;/a&gt;
&lt;/p&gt;



&lt;p&gt;Next, run the script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  npm run deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, the deploy should be completed and successful&lt;/p&gt;



&lt;p&gt;
  &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Froles-vuex-firebase%2Fassets%2Ffunction-deploy-successful.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Froles-vuex-firebase%2Fassets%2Ffunction-deploy-successful.png" alt="Firebase Use Add"&gt;&lt;/a&gt;
&lt;/p&gt;



&lt;p&gt;Now if you navigate to the &lt;code&gt;Firebase functions console&lt;/code&gt; again, there must be a new entry for the just created function&lt;/p&gt;



&lt;p&gt;
  &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Froles-vuex-firebase%2Fassets%2Fpanel-deployed-function.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Froles-vuex-firebase%2Fassets%2Fpanel-deployed-function.png" alt="Firebase Use Add"&gt;&lt;/a&gt;
&lt;/p&gt;



&lt;p&gt;And that's it! every time a matching-role user is added, an information message will be displayed in the records of the function&lt;/p&gt;



&lt;p&gt;
  &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Froles-vuex-firebase%2Fassets%2Ffunction-execution-successful.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrisarji%2Fblogs-dev.to%2Fmaster%2Fblog-posts%2Froles-vuex-firebase%2Fassets%2Ffunction-execution-successful.png" alt="Firebase Use Add"&gt;&lt;/a&gt;
&lt;/p&gt;



&lt;h2&gt;
  
  
  Step 5
&lt;/h2&gt;

&lt;h3&gt;
  
  
  New Routes to be validated
&lt;/h3&gt;

&lt;p&gt;The routes are pretty much the same, just add the new views, add a &lt;em&gt;meta&lt;/em&gt; attribute with the custom prop &lt;code&gt;requiresAuth&lt;/code&gt;, and register them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;routerOptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Landing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;requiresAuth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/auth&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Auth&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/landing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Landing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;requiresAuth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/dashboard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Dashboard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;requiresAuth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Auth&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;routes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;routerOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cm"&gt;/* webpackChunkName: "{{route.component}}" */&lt;/span&gt; &lt;span class="s2"&gt;`../views/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.vue`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember the method &lt;em&gt;beforeEach&lt;/em&gt;? now is more important than before, the &lt;code&gt;claims&lt;/code&gt; added in the &lt;code&gt;processSignUp&lt;/code&gt; are checked before navigating to every single view; when an &lt;code&gt;admin&lt;/code&gt; tries to navigate a &lt;code&gt;player&lt;/code&gt; page, is inmediately redirected to its scope of enabled view(s) and vice versa; this way the app is ready to &lt;code&gt;authenticate&lt;/code&gt; and &lt;code&gt;authorize&lt;/code&gt; users(in a simple way)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;history&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;routes&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onAuthStateChanged&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userAuth&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userAuth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getIdTokenResult&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt;&lt;span class="nx"&gt;claims&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;claims&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/dashboard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
              &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/dashboard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="p"&gt;});&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;claims&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;player&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/landing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
              &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/landing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="p"&gt;});&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;requiresAuth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;matched&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;record&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;requiresAuth&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isAuthenticated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requiresAuth&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isAuthenticated&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/auth&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Protect the app views is possible using &lt;code&gt;Firebase&lt;/code&gt; and &lt;code&gt;Vue&lt;/code&gt;, it is a bit trickier than the simple login but not impossible; maybe you could have a better way to do it, let's discuss in a thread below!&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>vue</category>
      <category>vuex</category>
      <category>firebase</category>
    </item>
  </channel>
</rss>
