<?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: Christian Montero</title>
    <description>The latest articles on DEV Community by Christian Montero (@christianmontero).</description>
    <link>https://dev.to/christianmontero</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%2F402997%2Fb85a29c3-4a57-4d30-bfdc-d7a72c2f122f.jpg</url>
      <title>DEV Community: Christian Montero</title>
      <link>https://dev.to/christianmontero</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/christianmontero"/>
    <language>en</language>
    <item>
      <title>What to/not to test when building an App with MERN stack? 👨🏻‍💻</title>
      <dc:creator>Christian Montero</dc:creator>
      <pubDate>Sat, 26 Sep 2020 21:10:54 +0000</pubDate>
      <link>https://dev.to/christianmontero/what-to-not-to-test-when-building-an-app-with-mern-stack-n7k</link>
      <guid>https://dev.to/christianmontero/what-to-not-to-test-when-building-an-app-with-mern-stack-n7k</guid>
      <description>&lt;p&gt;Hi guys, I'm trying to keep learning testing, but I'm not sure what to test and what not to test, I been reading posts, seeing tutorials and everybody agree that you should avoid testing implementation details...&lt;/p&gt;

&lt;p&gt;but if you guys have some more experience, what should I focus on when it comes to testing either in the backend and the frontend, and what libraries/frameworks do you recommend?&lt;/p&gt;

&lt;p&gt;Also if you want to recommend any book, articles, video-tutorial or any other source that you consider useful, go ahead  , if not, it's ok, I'll look into the docs and search for examples and articles by myself.&lt;/p&gt;

&lt;p&gt;thank you guys! enjoy your weekend 👍&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>webdev</category>
      <category>node</category>
      <category>react</category>
    </item>
    <item>
      <title>React Router</title>
      <dc:creator>Christian Montero</dc:creator>
      <pubDate>Tue, 01 Sep 2020 02:55:04 +0000</pubDate>
      <link>https://dev.to/christianmontero/react-router-9eh</link>
      <guid>https://dev.to/christianmontero/react-router-9eh</guid>
      <description>&lt;h1&gt;
  
  
  react-router 🔀
&lt;/h1&gt;

&lt;p&gt;Hi, how are you guys? hope you are doing good, today we'll be talking about React Router.&lt;/p&gt;

&lt;p&gt;react-router is a library that allows us to handle routes in our Web application. &lt;/p&gt;

&lt;h2&gt;
  
  
  Why do we need routes? 🤷‍♂️
&lt;/h2&gt;

&lt;p&gt;You might be wondering why do we need routes, if we are developing SPA, it's very likely that you have been using conditional rendering based on the state to change the components that you want show, and it works, but... what happens when our application becomes bigger and more complex?&lt;/p&gt;

&lt;p&gt;this conditional rendering might become difficult to understand, manage and maintain.&lt;/p&gt;

&lt;h3&gt;
  
  
  From the documentation:
&lt;/h3&gt;

&lt;p&gt;Components are the heart of React's powerful, declarative programming model. React Router is a collection of navigational components that compose declaratively with your application.&lt;/p&gt;

&lt;p&gt;With react-router, we'll be able to:&lt;/p&gt;

&lt;p&gt;1.- Define which component/components to render based on a path.&lt;br&gt;
2.- Use the back and forward buttons of our browser.&lt;/p&gt;
&lt;h2&gt;
  
  
  Main components of react-router
&lt;/h2&gt;

&lt;p&gt;1.- BrowserRouter: This component is used for applications which have a dynamic server that knows how to handle any type of url. This means that our server has to be configured correctly. Specifically, our web server needs to serve the same page at all URLs that are managed client-side by react-router.&lt;/p&gt;
&lt;h3&gt;
  
  
  History 📍
&lt;/h3&gt;

&lt;p&gt;Something important that we need to know is that our router will create a history object which is used to keep track of the current location.&lt;/p&gt;

&lt;p&gt;2.- Route: This is a key piece of react-router, it's main responsibility is to render something when a location matches the route's path. the route expects this 3 arguments:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Argument&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;exact&lt;/td&gt;
&lt;td&gt;Is a boolean property, it means that the specified path must be exactly, for render the specified component&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;path&lt;/td&gt;
&lt;td&gt;Is a string that’s equal to the path of the current place where we are&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;component*&lt;/td&gt;
&lt;td&gt;The component that we want to render&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;*There are other ways to specify what do we want to render if the route's path matches, but we'll talk about it later.&lt;/p&gt;

&lt;p&gt;3.- Link: Provides declarative, accessible, navigation around our Application.&lt;/p&gt;

&lt;p&gt;Link takes 2 attributes, to and replace.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Argument&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;To&lt;/td&gt;
&lt;td&gt;Can be a string, object or function which tells the app which path to redirect to&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Replace&lt;/td&gt;
&lt;td&gt;Is an optional boolean, is it's true will replace the current entry in the history stack instead of adding a new one&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;4.- Redirect: Rendering a  will navigate to a new location. The new location will override the current location in the history stack, we can use this for example, when a user is already logged in and he try to navigate to the Login Page, there' s no point on doing that, so if he try to do it, we can redirect him to the Home Page.&lt;/p&gt;

&lt;p&gt;5.- Switch: We can use the  component to wrap our routes/redirects and it will render/redirect the first child that matches the location.&lt;/p&gt;

&lt;p&gt;How's different than just using a bunch of routes?&lt;/p&gt;

&lt;p&gt; is unique in that renders a route exclusively.&lt;/p&gt;
&lt;h2&gt;
  
  
  Installation 🔧
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install --save react-router
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Setup ⚙️
&lt;/h2&gt;

&lt;p&gt;Lets start coding, first lets create a couple of components to start playing with our Router, lets create a components folder and inside 3 components, Login, Home and Dashboard:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1rkuGzJV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/dkbrn9bhe/image/upload/v1598843525/Screenshot_1_fxg4f3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1rkuGzJV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/dkbrn9bhe/image/upload/v1598843525/Screenshot_1_fxg4f3.png" alt="Project structure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the last picture you can see the components folder and inside a folder for each component, right now I haven't created files for the styles, we'll do it later, and I like to name my component files as .component.jsx but you can name them however you like.&lt;/p&gt;

&lt;p&gt;The components will be very simple, we just want to render the name of the component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';

const Login = () =&amp;gt; {
  return(
    &amp;lt;div&amp;gt;This is Login Page&amp;lt;/div&amp;gt;
  )
}

export default Login;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now lets go to our App.js where we'll import our components and our router components. First lets wrap everything with our BrowserRouter and first we will create a couple of links to navigate through our components, then lets specify our routes and lets test it, here is the code of our App.js.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import { 
  BrowserRouter as Router,
  Route,
  Link
} from 'react-router-dom'
import './App.css';

import Login from './components/login/login.component';
import Home from './components/home/home.component';
import Dashboard from './components/dashboard/dashboard.component';

function App() {
  return (
    &amp;lt;Router&amp;gt;
      &amp;lt;div&amp;gt;
      &amp;lt;Link to="/login"&amp;gt;Login&amp;lt;/Link&amp;gt;&amp;lt;br/&amp;gt;
      &amp;lt;Link to="/home"&amp;gt;Home&amp;lt;/Link&amp;gt;&amp;lt;br/&amp;gt;
      &amp;lt;Link to="/dashboard"&amp;gt;Dashboard&amp;lt;/Link&amp;gt;&amp;lt;br/&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;Route exact path='/login' component={Login}/&amp;gt;
      &amp;lt;Route exact path='/home' component={Home}/&amp;gt;
      &amp;lt;Route exact path='/dashboard' component={Dashboard}/&amp;gt;
    &amp;lt;/Router&amp;gt;
  );
}

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, after saving our changes, we will see in the browser our links to navigate through our components, but nothing else, notice  that when we click in the login link our URL will change as well as the content in the page, under our links we will see our Login component.&lt;/p&gt;

&lt;p&gt;We expect the same behavior when we click in the rest of our links, the URL will change as well as the component being rendered.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CrdKQHs2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/dkbrn9bhe/image/upload/v1598847040/Screenshot_2_bjnago.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CrdKQHs2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/dkbrn9bhe/image/upload/v1598847040/Screenshot_2_bjnago.png" alt="Testing our router"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Great our router is working as we expect, lets see how the exact argument of the route works, first lets change the path of the route for our Home component, also lets change the Link for our Home component and lets remove the exact argument from our Routes, this is the new code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function App() {
  return (
    &amp;lt;Router&amp;gt;
      &amp;lt;div&amp;gt;
        &amp;lt;Link to="/"&amp;gt;Home&amp;lt;/Link&amp;gt;&amp;lt;br/&amp;gt;
        &amp;lt;Link to="/login"&amp;gt;Login&amp;lt;/Link&amp;gt;&amp;lt;br/&amp;gt;
        &amp;lt;Link to="/dashboard"&amp;gt;Dashboard&amp;lt;/Link&amp;gt;&amp;lt;br/&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;Route exact path='/' component={Home}/&amp;gt;
      &amp;lt;Route exact path='/login' component={Login}/&amp;gt;
      &amp;lt;Route exact path='/dashboard' component={Dashboard}/&amp;gt;
    &amp;lt;/Router&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---s2lpi0N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/dkbrn9bhe/image/upload/v1598849305/Screenshot_3_xut6zo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---s2lpi0N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/dkbrn9bhe/image/upload/v1598849305/Screenshot_3_xut6zo.png" alt="Testing our router"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As we can see now, our Home component is always visible and the reason of this is because it's path ('/') matches with the URL in the browser in all scenarios. &lt;/p&gt;

&lt;h2&gt;
  
  
  Arguments passed to the rendered component.
&lt;/h2&gt;

&lt;p&gt;Something important is that any component that gets rendered by a  route get passed 3 arguments, History, location and Match.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PL3iPJiA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/dkbrn9bhe/image/upload/v1598850236/Screenshot_4_klndrb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PL3iPJiA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/dkbrn9bhe/image/upload/v1598850236/Screenshot_4_klndrb.png" alt="Arguments passed to rendered compoennts"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is a description of the most used properties of our arguments.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Argument&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;match&lt;/td&gt;
&lt;td&gt;⬇️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;url&lt;/td&gt;
&lt;td&gt;is the url until our component matches, so if the path  associated to our component is ‘/’ but we navigate to &lt;a href="http://localhost:3000/"&gt;http://localhost:3000/&lt;/a&gt; or to &lt;a href="http://localhost:3000/topics/details/something"&gt;http://localhost:3000/topics/details/something&lt;/a&gt; our url inside the match object will be ‘/’ because is the url until it match.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;path&lt;/td&gt;
&lt;td&gt;Is the pattern that our route is looking to match, it means, the path that we specify in our route.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;isExact&lt;/td&gt;
&lt;td&gt;Becomes true if the entire url match the pattern to match&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;params&lt;/td&gt;
&lt;td&gt;Is an object of url parameters. Lets say that we have a route with this path ='/topics/:topicId' notice that after ‘/topics/’ we have “:topicId” this means that after this point we can dynamically change our url. And we can use those params for fetch data from a database or if it’s a title for some item, we can use it to display that title in the Component.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;history&lt;/td&gt;
&lt;td&gt;⬇️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;push&lt;/td&gt;
&lt;td&gt;There are 2 ways to navigate with react-router the first one is using the Link component, where we can specify a parameter called to and we specify the route where when want it to takes us to. For example: to='/topics'. Just remember that React is SPA, so what we are actually doing is hijacking the url and determine with Javascript what component to replace, there’s no navigation at all (we are not re-rendering the whole application). The other way to do this is: props.history.push('/topics')&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;location&lt;/td&gt;
&lt;td&gt;⬇️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pathname&lt;/td&gt;
&lt;td&gt;It tells us where we are in the application. So if we navigate to: &lt;a href="http://localhost:3000/topics/15/something/props"&gt;http://localhost:3000/topics/15/something/props&lt;/a&gt; that url is exactly what pathname will return. And this is useful because our component is aware what the full url looks like.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Nested Routing
&lt;/h2&gt;

&lt;p&gt;Lets create an quickly example of nested routing, Lets add a TopicsList component a Topic component to our project.&lt;/p&gt;

&lt;p&gt;This is the code of our TopicsList component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import { Link } from 'react-router-dom'

const TopicsList = (props) =&amp;gt; {

  React.useEffect(() =&amp;gt; {
    console.log(props.match.url);
  }, []);

  return(
    &amp;lt;div&amp;gt;
      &amp;lt;h1&amp;gt;Topics List Page&amp;lt;/h1&amp;gt;
      &amp;lt;Link to={`${props.match.url}/A`} &amp;gt;To topic A&amp;lt;/Link&amp;gt;&amp;lt;br/&amp;gt;
      &amp;lt;Link to={`${props.match.url}/B`} &amp;gt;To topic B&amp;lt;/Link&amp;gt;&amp;lt;br/&amp;gt;
      &amp;lt;Link to={`${props.match.url}/C`} &amp;gt;To topic C&amp;lt;/Link&amp;gt;&amp;lt;br/&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}

export default TopicsList;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see we are using Links inside our TopicsList component. and the "to" argument is being created with a string template so we can use our props.match.url + the topic we want to see. The props.match.url at this point is '/topics' because that is the path specified to render the TopicsList component, we can see that if we console.log that value.&lt;/p&gt;

&lt;p&gt;And after that we specify which Topic we want to see&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KFmYs846--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/dkbrn9bhe/image/upload/v1598855335/Screenshot_5_ifvhx9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KFmYs846--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/dkbrn9bhe/image/upload/v1598855335/Screenshot_5_ifvhx9.png" alt="props.match.url"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the code of our Topic component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';

const Topic = (props) =&amp;gt; {

  React.useEffect(() =&amp;gt; {
    console.log(props);
  }, []);

  return(
    &amp;lt;div&amp;gt;
      &amp;lt;h1&amp;gt;Topic {props.match.params.topicId}&amp;lt;/h1&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}

export default Topic;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside our topic component we are using the props.match.params.topicId because we want to know which Topic we need to render, we are using the same component to render all the topics, we just need to change the content and we get it from the params:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dOgWFkEU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/dkbrn9bhe/image/upload/v1598855512/Screenshot_6_xoosmu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dOgWFkEU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/dkbrn9bhe/image/upload/v1598855512/Screenshot_6_xoosmu.png" alt="Using props.match.params"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we just need to update our App.js with this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import { 
  BrowserRouter as Router,
  Route,
  Link
} from 'react-router-dom'
import './App.css';

import Home from './components/home/home.component';
import TopicsList from './components/topicsList/topicsList.component';
import Topic from './components/topic/topic.component';

function App() {
  return (
    &amp;lt;Router&amp;gt;
      &amp;lt;div&amp;gt;
        &amp;lt;Link to="/"&amp;gt;Home&amp;lt;/Link&amp;gt;&amp;lt;br/&amp;gt;
        &amp;lt;Link to="/topics"&amp;gt;TopicsList&amp;lt;/Link&amp;gt;&amp;lt;br/&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;Route exact path='/' component={Home}/&amp;gt;
      &amp;lt;Route exact path='/topics' component={TopicsList}/&amp;gt;
      &amp;lt;Route exact path='/topics/:topicId' component={Topic}/&amp;gt;
    &amp;lt;/Router&amp;gt;
  );
}

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice our Route for the Topic Component, we are using a new syntax:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;Route exact path='/topics/:topicId' component={Topic}/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After /topics/ we use :topicId as we said before in our table,  this means that after this point we can dynamically change our url, and it will be passed as a parameter.&lt;/p&gt;

&lt;p&gt;Lets save our changes and test our App.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SjDzeBVr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/dkbrn9bhe/image/upload/v1598856032/Screenshot_7_ackvmt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SjDzeBVr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/dkbrn9bhe/image/upload/v1598856032/Screenshot_7_ackvmt.png" alt="Testing our nested Router"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see everything is working as expected, now you know how everything works together, how we can used the props that are being passed to the components rendered by the Route and by the Link components.&lt;/p&gt;

&lt;p&gt;I hope you enjoyed this post and found it useful, if you like it, feel free to share, also if you have any thoughts about this post, feel free to comment here or contact me, any feedback would be appreciated.&lt;/p&gt;

&lt;p&gt;Have a nice day! ✌️&lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>beginners</category>
    </item>
    <item>
      <title>GitLab CI/CD example with a dockerized ReactJS App 🚀</title>
      <dc:creator>Christian Montero</dc:creator>
      <pubDate>Wed, 26 Aug 2020 05:11:22 +0000</pubDate>
      <link>https://dev.to/christianmontero/gitlab-ci-cd-example-with-a-dockerized-reactjs-app-1cda</link>
      <guid>https://dev.to/christianmontero/gitlab-ci-cd-example-with-a-dockerized-reactjs-app-1cda</guid>
      <description>&lt;p&gt;Good afternoon!&lt;br&gt;
Today we'll be creating a CI/CD pipeline using GitLab to automate a dockerized ReactJS deployment 🚀&lt;/p&gt;

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

&lt;p&gt;So today We're going to use Create-react-app in order to generate a simple ReactJS project, then we are going to dockerized that project in our local environment just to test it, Then we are going to upload our code to a GitLab repository in order to use it's CI/CD pipeline functionality and then deploy our dockerized app into a Digital Ocean droplet.&lt;/p&gt;

&lt;p&gt;So, to follow this tutorial you should have:&lt;/p&gt;

&lt;p&gt;1.- create-react-app installed ⚛️&lt;br&gt;
2.- docker installed 🐳&lt;br&gt;
3.- Good understanding about docker 🐳&lt;br&gt;
4.- Good understanding about nginx 🆖&lt;br&gt;
5.- GitLab account 🦊&lt;br&gt;
6.- Digital Ocean account 🌊&lt;/p&gt;

&lt;p&gt;Let's get started 💪&lt;/p&gt;

&lt;h2&gt;
  
  
  1.- Let's generate a react project using create-react-app
&lt;/h2&gt;

&lt;p&gt;I'm gonna create a project called Budgefy 🐖 (an old project that I never finished), we just need to type:&lt;/p&gt;

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

npx create-react-app budgefy


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

&lt;/div&gt;

&lt;p&gt;and we'll see something like this:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598059591%2FScreenshot_1_fvfsyz.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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598059591%2FScreenshot_1_fvfsyz.png" alt="console output"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After the project was successfully created, let' s verify that we can start the project typing this:&lt;/p&gt;

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

cd budgefy
npm start


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

&lt;/div&gt;

&lt;p&gt;And it will open a new tab in our browser with the project running, you'll see 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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598059997%2FScreenshot_2_bbkb2y.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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598059997%2FScreenshot_2_bbkb2y.png" alt="console output"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's  check if the tests are passing as well, by typing this:&lt;br&gt;
(first ctrl + c to stop the project)&lt;/p&gt;

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

npm test


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

&lt;/div&gt;

&lt;p&gt;and it will prompt this in the console:&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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598060252%2FScreenshot_3_feor4p.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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598060252%2FScreenshot_3_feor4p.png" alt="Test Menu"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and then just type 'a'  to run all tests, and we expect this 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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598060252%2FScreenshot_4_fdjf2x.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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598060252%2FScreenshot_4_fdjf2x.png" alt="Test output"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2.- Let's dockerize our application
&lt;/h2&gt;

&lt;p&gt;This is not an article about docker, so I'm assuming that you have a good understanding of docker, I'm planning to write an article about docker in a couple of days or maybe weeks, I'll do it as soon as possible. Anyways this is our docker file (this file will be in the root folder of our project):&lt;/p&gt;

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

# Set the base image to node:12-alpine
FROM node:12-alpine as build

# Specify where our app will live in the container
WORKDIR /app

# Copy the React App to the container
COPY . /app/

# Prepare the container for building React
RUN npm install
RUN npm install react-scripts@3.0.1 -g
# We want the production version
RUN npm run build

# Prepare nginx
FROM nginx:1.16.0-alpine
COPY --from=build /app/build /usr/share/nginx/html
RUN rm /etc/nginx/conf.d/default.conf
COPY nginx/nginx.conf /etc/nginx/conf.d

# Fire up nginx
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]


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

&lt;/div&gt;

&lt;p&gt;We need to create a .dockerignore file (this file will be in the root folder of our project) to ignore the node_modules folder in our dockerized app, so, the content of our .dockerignore is this:&lt;/p&gt;

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

node_modules


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

&lt;/div&gt;

&lt;p&gt;Also, since we will be using nginx (I will write about nginx in another article) we need to create the nginx folder in the root folder of our application, and inside we need to create the nginx.conf file with this content:&lt;/p&gt;

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

server {

  listen 80;

  location / {
    root   /usr/share/nginx/html;
    index  index.html index.htm;
    try_files $uri $uri/ /index.html;
  }

  error_page 500 502 503 504 /50x.html;

  location = /50x.html {
      root /usr/share/nginx/html;
  }

}



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

&lt;/div&gt;

&lt;p&gt;Now that we have our files in place, make sure that in your terminal you are in the same folder where the Dockerfile is and let's run this command to create our image:&lt;/p&gt;

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

docker build --tag budgefy:1.0 .


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

&lt;/div&gt;

&lt;p&gt;docker will log a lot of messages during the build process and at the end we can verify that our image was created by typing docker images and we should see our budgefy image, 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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598071462%2FScreenshot_6_f3zfrf.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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598071462%2FScreenshot_6_f3zfrf.png" alt="Docker images"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and now we can run our image with this command:&lt;/p&gt;

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

docker run -p 4250:80 -d --name bugefycontainer budgefy:1.0


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

&lt;/div&gt;

&lt;p&gt;After running our image, we will see an output like this one, where we'll see that we have a container running with our application&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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598072128%2FScreenshot_7_pht0q1.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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598072128%2FScreenshot_7_pht0q1.png" alt="Docker images"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;so now, if you are using ubuntu, you can go to localhost:4250 and you will see our dockerized app running, in my case since I' m using Docker in windows, I have to access to the app through an IP that docker provides me, and this is our result:&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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598072135%2FScreenshot_8_sgrzje.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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598072135%2FScreenshot_8_sgrzje.png" alt="Dockerized app running"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Great everything is working!!!😎💪&lt;/p&gt;

&lt;p&gt;What's next? Let's upload our code to GitLab!&lt;/p&gt;

&lt;h2&gt;
  
  
  3.- Creating a project on GitLab 🦊
&lt;/h2&gt;

&lt;p&gt;To create a Project on GitLab it's super easy, just login into your account and click on the "New Project" Button:&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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598073138%2FScreenshot_9_qw3usq.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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598073138%2FScreenshot_9_qw3usq.png" alt="Create New Project"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;then just fill the name field, let's leave it as a private repository and click on "Create Project":&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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598073138%2FScreenshot_10_clyokv.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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598073138%2FScreenshot_10_clyokv.png" alt="Create new Project on GitLab"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Great! we have our project, let's upload our code, in our GitLab we'll see the instructions, in my case I need to follow this instructions:&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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598073430%2FScreenshot_11_tddo69.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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598073430%2FScreenshot_11_tddo69.png" alt="Upload our code to GitLab"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And after following those instructions we will see our code in our GitLab repository as you can see in this image:&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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598073614%2FScreenshot_12_rye3bh.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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598073614%2FScreenshot_12_rye3bh.png" alt="Updated repository"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4.- Let's create our Pipeline
&lt;/h2&gt;

&lt;p&gt;In order to create our pipeline we need to add a new file in the root folder of our project whit the name: .gitlab-ci.yml&lt;/p&gt;

&lt;p&gt;Once we added the .gitlab-ci.yml file and push it to our GitLab repository, GitLab will detect this file and a GitLab runner will go through the file and run all the jobs that we specify there. By default GitLab provides us with "shared runners" that will run the pipeline automatically unless we specify something else in our file. We can also use "specific runner" which basically means to install the GitLab runner service on a machine that allows you to customize your runner as you need, but for this scenario, we will use the shared runners. &lt;/p&gt;

&lt;p&gt;In this file we can define the scripts that we want to run, we can run commands in sequence or in parallel, we can define where we want to deploy our app and specify whether we want to run the scripts automatically or trigger any of them manually.&lt;/p&gt;

&lt;p&gt;We need to organize our scripts in a sequence that suits our application and in accordance with the test we want to perform&lt;/p&gt;

&lt;p&gt;Let's see the next example:&lt;/p&gt;

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

stages:
  - build
  - test

build:
  stage: build
  image: node
  script: 
    - echo "Start building App"
    - npm install
    - npm build
    - echo "Build successfully!"

test:
  stage: test
  image: node
  script:
    - echo "Testing App"
    - npm install
    - CI=true npm test
    - echo "Test successfully!"



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

&lt;/div&gt;

&lt;p&gt;let's include this code in our .gitlab-ci.yml file and commit those changes to our repo.&lt;/p&gt;

&lt;p&gt;If we go to our repo we will see that our pipeline is running, let's take a look to our pipeline, we need to go to CI/CD and then to pipelines in our sidebar:&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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598211177%2FScreenshot_13_w6zw1h.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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598211177%2FScreenshot_13_w6zw1h.png" alt="Sidebar menu"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and then click in our status button:&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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598211177%2FScreenshot_14_pdbc0c.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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598211177%2FScreenshot_14_pdbc0c.png" alt="Pipeline"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;then we will see the progress/status of our jobs as you can see here:&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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598211819%2FScreenshot_15_iry5pz.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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598211819%2FScreenshot_15_iry5pz.png" alt="Jobs status"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And since we test our App locally, everything should work as expected, and eventually we will see the successful message.&lt;/p&gt;

&lt;p&gt;So, this was a very simple example to see how the pipeline works, we have two stages, and in the first one we just build the application and in the second one we run our tests. You might be asking you why are we running "npm install" 2 times, surely there's a better way to do it.&lt;/p&gt;

&lt;p&gt;This is because each job runs in a new empty instance and we don't have any data from previous jobs, in order to share data we need to use artifacts or cache, what's the difference?&lt;/p&gt;

&lt;h3&gt;
  
  
  Artifacts:
&lt;/h3&gt;

&lt;p&gt;1.- I usually the output of a build tool.&lt;br&gt;
2.- In GitLab CI, are designed to save some compiled/generated paths of the build.&lt;br&gt;
3.- Artifacts can be used to pass data between stages/jobs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cache:
&lt;/h3&gt;

&lt;p&gt;1.- Caches are not to be used to store build results&lt;br&gt;
2.- Cache should only be used as a temporary storage for project dependencies.&lt;/p&gt;

&lt;p&gt;So, let's improve our pipeline:&lt;/p&gt;

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

stages:
  - build
  - test

build:
  stage: build
  image: node
  script: 
    - echo "Start building App"
    - npm install
    - npm build
    - echo "Build successfully!"
    artifacts:
      expire_in: 1 hour
      paths:
        - build
        - node_modules/

test:
  stage: test
  image: node
  script:
    - echo "Testing App"
    - CI=true npm test
    - echo "Test successfully!"


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

&lt;/div&gt;

&lt;p&gt;Let's commit our code, and we'll see that everything it's still working, thats good! 🌟&lt;/p&gt;

&lt;h2&gt;
  
  
  5.- Let's build our image in the Pipeline
&lt;/h2&gt;

&lt;p&gt;Now let's create another stage to dockerize our App. Take a look in our "docker-build" stage, our file will look like this:&lt;/p&gt;

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

stages:
  - build
  - test
  - docker-build

build:
  stage: build
  image: node
  script: 
    - echo "Start building App"
    - npm install
    - npm build
    - echo "Build successfully!"
  artifacts:
    expire_in: 1 hour
    paths:
      - build
      - node_modules/

test:
  stage: test
  image: node
  script:
    - echo "Testing App"
    - CI=true npm test
    - echo "Test successfully!"

docker-build:
  stage: docker-build
  image: docker:latest
  services: 
    - name: docker:19.03.8-dind
  before_script:
    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
  script:
    - docker build --pull -t "$CI_REGISTRY_IMAGE" .
    - docker push "$CI_REGISTRY_IMAGE"




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

&lt;/div&gt;

&lt;p&gt;After committing and pushing our code, it will take a few minutes for the pipeline to finish the jobs, and if everything goes well, you'll see that all jobs passed, 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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598245394%2FScreenshot_16_lz3gt0.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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598245394%2FScreenshot_16_lz3gt0.png" alt="All Jobs passed"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also if you go to our sidebar in the GitLab dashboard, to "Packages and Registries" then to "Container Registry"&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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598246161%2FScreenshot_17_aa8oh7.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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598246161%2FScreenshot_17_aa8oh7.png" alt="Packages and Registries"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will see the image that we just built 😎&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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598246167%2FScreenshot_18_qfx3fs.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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598246167%2FScreenshot_18_qfx3fs.png" alt="docker image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Amazing job! 👌&lt;/p&gt;

&lt;p&gt;So, what is happening in our "docker-build" stage? 🐳&lt;br&gt;
Basically the same that we did in our local environment to build our docker image, we are using a docker image for this because we will need to run some docker commands, also we need to use the docker-dind service, in this case I'm using this specific version (docker:19.03.8-dind) because I had a couple of problems with other versions, and after that we are just login in to our GitLab account and build and push the image to the GitLab registry.&lt;/p&gt;

&lt;p&gt;Also we are using some predefined GitLab variables, what is that?&lt;/p&gt;

&lt;h3&gt;
  
  
  Predefined Environment Variables:
&lt;/h3&gt;

&lt;p&gt;GitLab offers a set of predefined variables that we can see and use if some of them are useful for our particular needs, you can see the full list here (&lt;a href="https://docs.gitlab.com/ee/ci/variables/predefined_variables.html" rel="noopener noreferrer"&gt;https://docs.gitlab.com/ee/ci/variables/predefined_variables.html&lt;/a&gt;) In our particular case we are using this ones:&lt;/p&gt;

&lt;p&gt;1.- CI_REGISTRY_USER: The username to use to push containers to the GitLab Container Registry, for the current project. 🤵&lt;/p&gt;

&lt;p&gt;2.- CI_REGISTRY_PASSWORD: The password to use to push containers to the GitLab Container Registry, for the current project. 🙈&lt;/p&gt;

&lt;p&gt;3.- CI_REGISTRY: If the Container Registry is enabled it returns the address of GitLab’s Container Registry. This variable includes a :port value if one has been specified in the registry configuration. 🔗&lt;/p&gt;

&lt;p&gt;4.- CI_REGISTRY_IMAGE: If the Container Registry is enabled for the project it returns the address of the registry tied to the specific project 🔗&lt;/p&gt;

&lt;p&gt;So, what's next? We need to deploy our App to our server!!! so first, let's&lt;/p&gt;

&lt;h2&gt;
  
  
  6.- Adding the Deploy stage 🔨
&lt;/h2&gt;

&lt;p&gt;Again we need to do what we did in our local environment, we need to pull our image from the GitLab registry and then we need to run it, and that's it! our App will be available in our server. So first let's add some commands to our .gitlab-ci.yml file, our last version of this file will be this one:&lt;/p&gt;

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

stages:
  - build
  - test
  - docker-build
  - deploy

build:
  stage: build
  image: node
  script: 
    - echo "Start building App"
    - npm install
    - npm build
    - echo "Build successfully!"
  artifacts:
    expire_in: 1 hour
    paths:
      - build
      - node_modules/

test:
  stage: test
  image: node
  script:
    - echo "Testing App"
    - CI=true npm test
    - echo "Test successfully!"

docker-build:
  stage: docker-build
  image: docker:latest
  services: 
    - name: docker:19.03.8-dind
  before_script:
    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
  script:
    - docker build --pull -t "$CI_REGISTRY_IMAGE" .
    - docker push "$CI_REGISTRY_IMAGE"
    - echo "Registry image:" $CI_REGISTRY_IMAGE

deploy:
  stage: deploy
  image: kroniak/ssh-client
  before_script:
    - echo "deploying app"
  script:
    - chmod 400 $SSH_PRIVATE_KEY
    - ssh -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY root@$PROD_SERVER_IP "docker pull registry.gitlab.com/alfredomartinezzz/budgefy"
    - ssh -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY root@$PROD_SERVER_IP "docker stop budgefycontainer || true &amp;amp;&amp;amp; docker rm budgefycontainer || true"
    - ssh -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY root@$PROD_SERVER_IP "docker run -p 3001:80 -d --name budgefycontainer registry.gitlab.com/alfredomartinezzz/budgefy"



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

&lt;/div&gt;

&lt;p&gt;What are we doing?&lt;/p&gt;

&lt;p&gt;In order to make this happens, we need to establish a ssh connection between our pipeline and our server, to do that we will need to store the IP of our server as a environment variable and also our private key.&lt;/p&gt;

&lt;p&gt;So, for this stage we will use an image with a ssh client (kroniak/ssh-client) and we will run our commands 1 by 1 like this:&lt;/p&gt;

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

ssh -o StrictHostKeyChecking=no -i &amp;lt;private_key&amp;gt; &amp;lt;user_in_server&amp;gt;@&amp;lt;server_ip&amp;gt; "&amp;lt;command&amp;gt;"


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

&lt;/div&gt;

&lt;p&gt;But if we want to test our last stage, we need to let our server ready!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Do not commit/push this changes (it will throw an error) we'll do it later&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  6.- Creating our server in Digital Ocean 🌊
&lt;/h2&gt;

&lt;p&gt;You don't need to use Digital Ocean but I think that it's a very fast and easy option to get our server up an running! you just need to create an account, most of the time they give 100 dlls  that you can use in the next 60 days, the server that we'll be using costs 5 dlls per month, so I found digital ocean very useful to practice and learn.&lt;/p&gt;

&lt;p&gt;So just go ahead and create your account it will ask you for a payment method, you need to introduce your credit card but it won't charge you a cent.&lt;/p&gt;

&lt;p&gt;Once you have your account, go to your dashboard and create a Droplet&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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598248765%2FScreenshot_19_rqoomw.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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598248765%2FScreenshot_19_rqoomw.png" alt="Creating a Droplet"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then you need to choose your droplet requirements, we need a very basic one, choose the one of 5 dlls per month as you can see in this image:&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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598248765%2FScreenshot_20_voubub.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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598248765%2FScreenshot_20_voubub.png" alt="Choosing our requirements"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can leave the rest of the options as they are, just need to type a password and give your server a cool name 😎&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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598248765%2FScreenshot_21_fpbk5w.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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598248765%2FScreenshot_21_fpbk5w.png" alt="Creating our Droplet"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And that's it, then it will take around 55 seconds to get your server up and running, pretty simple isn't? 👌&lt;/p&gt;

&lt;p&gt;Now you can see your server and it's IP!&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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598249180%2FScreenshot_22_laltk4.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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598249180%2FScreenshot_22_laltk4.png" alt="Our server"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So now, let's get inside of our server via SSH from our local environment, let's go to our terminal (I'm using the cmder terminal for windows, if you are using the regular one, maybe you need to download putty or probably you can establish a ssh connection from the powershell, if you are on Mac or Linux you can do it from the regular terminal), so we just need to type:&lt;/p&gt;

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

ssh root@&amp;lt;server_ip&amp;gt;


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

&lt;/div&gt;

&lt;p&gt;it will prompt you a message if you want to establish the connection:&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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598249562%2FScreenshot_23_l5ahta.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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598249562%2FScreenshot_23_l5ahta.png" alt="Accessing to our server"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and then it will ask you for the password that you established when you created your droplet, just type it in and then you'll be in!&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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598249562%2FScreenshot_24_ke2npc.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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598249562%2FScreenshot_24_ke2npc.png" alt="You are in!"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So now that we are in, we have a clean ubuntu server, we need to install docker, and let's login to our GitLab account, pull our project image and run it.&lt;/p&gt;

&lt;p&gt;Here's a very simple guide to install docker in our ubuntu server: &lt;a href="https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-20-04" rel="noopener noreferrer"&gt;https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-20-04&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can verify that docker was successfully installed by typing docker -v or/and docker ps to list our containers:&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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598250356%2FScreenshot_25_jmpowv.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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598250356%2FScreenshot_25_jmpowv.png" alt="Verifying docker installation "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;so, lets go to our Container Registry in GitLab, we will find a blue button that says "CLI commands": &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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598250617%2FScreenshot_26_fmwxue.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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598250617%2FScreenshot_26_fmwxue.png" alt="CLI commands"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We'll need the login into our GitLab account, and then we need to  pull and run the image manually in our server, so let's do it.&lt;/p&gt;

&lt;p&gt;Let's login:&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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598250932%2FScreenshot_27_rauz1h.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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598250932%2FScreenshot_27_rauz1h.png" alt="login"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Then let's pull our image:&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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598250932%2FScreenshot_28_gqia9h.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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598250932%2FScreenshot_28_gqia9h.png" alt="Pulling our image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And then let's run it with this command, make sure that you change your image name if it's different and if you want to use another port, just change it, in my case I'll run it with this command:&lt;/p&gt;

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

docker run -p 3005:80 -d --name budgefycontainer registry.gitlab.com/alfredomartinezzz/budgefy


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

&lt;/div&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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598250932%2FScreenshot_29_chc7py.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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598250932%2FScreenshot_29_chc7py.png" alt="running our image from the server"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can run the docker ps command to see our containers:&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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598251120%2FScreenshot_30_beancs.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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598251120%2FScreenshot_30_beancs.png" alt="Listing our containers"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And then let's go to our browser and go to our SERVER_IP:PORT&lt;/p&gt;

&lt;p&gt;In my case I will access to the app on port 3005 and the IP of my server is: 138.68.254.184&lt;/p&gt;

&lt;p&gt;And now we can see our App up and running in our server! as simple as that! 👍&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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598251239%2FScreenshot_31_gmgbnn.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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598251239%2FScreenshot_31_gmgbnn.png" alt="App running on server"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, now that we verify that our server is running perfectly and we can run our app there, we need to store our server's private key as an environment variable in our GitLab Project and also we need to store the IP address, so let's do it.&lt;/p&gt;

&lt;p&gt;Let's go to our sidebar in our GitLab dashboard, and let's click on settings and then CI/CD we will see a lot of options, let's expand the variables section:&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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598292653%2FScreenshot_32_niesf7.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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598292653%2FScreenshot_32_niesf7.png" alt="Settings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then click on the "Add variable" button and a modal will pop up, our variable key will be "PROD_SERVER_IP" and the value will be our server IP, leave the rest of the options as they are and click on "Add variable".&lt;/p&gt;

&lt;p&gt;Now we need to add our private key, but first let's create one in our server. Go to your server, open the terminal and type this:&lt;/p&gt;

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

ssh-keygen -m PEM -t rsa -b 4096 -C "your_email@example.com"


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

&lt;/div&gt;

&lt;p&gt;it will ask you for a file to save the key, just type enter to use the default one, then it will ask you for a passphrase, for this example let's leave it empty and press enter a couple of times, and then you will see a successful message, then we need to copy our private key add it to our project on GitLab, we can run this command to see the our private key:&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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598294446%2FScreenshot_33_sxkmci.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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598294446%2FScreenshot_33_sxkmci.png" alt="ssh key generation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;then let's copy our private key &lt;/p&gt;

&lt;p&gt;let's type cat ~/.ssh/id_rsa and copy the output, create a new variable, the key will be SSH_PRIVATE_KEY and the value will be our private key:&lt;/p&gt;

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

cat ~/.ssh/id_rsa


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

&lt;/div&gt;

&lt;p&gt;so, let's copy the content and paste it.&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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598316490%2FScreenshot_35_ugb45y.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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598316490%2FScreenshot_35_ugb45y.png" alt="Adding our ptivate key"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then we need to go to our server and run this command:&lt;/p&gt;

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

cat ~/.ssh/id_rsa.pub &amp;gt;&amp;gt; ~/.ssh/authorized_keys


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

&lt;/div&gt;

&lt;p&gt;Now that everything is ready, let's commit and push our code to see the result.&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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598417610%2FScreenshot_38_xyfmk1.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%2Fres.cloudinary.com%2Fdkbrn9bhe%2Fimage%2Fupload%2Fv1598417610%2FScreenshot_38_xyfmk1.png" alt="Final result"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's all, now every time that we push our code into our repo, our pipeline will build our app, then it will run our tests, it will dockerize our app and push it into the GitLab Registry and finally it will deploy our App into our server!&lt;/p&gt;

&lt;p&gt;I hope you enjoyed this post and found it useful, if you like it, feel free to share, also if you have any thoughts about this post, feel free to comment here or contact me, any feedback would be appreciated.&lt;/p&gt;

&lt;p&gt;Have a nice day! ✌️&lt;/p&gt;

</description>
      <category>react</category>
      <category>devops</category>
      <category>gitlab</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Create React App</title>
      <dc:creator>Christian Montero</dc:creator>
      <pubDate>Wed, 19 Aug 2020 05:08:08 +0000</pubDate>
      <link>https://dev.to/christianmontero/create-react-app-1de8</link>
      <guid>https://dev.to/christianmontero/create-react-app-1de8</guid>
      <description>&lt;h2&gt;
  
  
  What is create-react-app and Why are we going to use it?
&lt;/h2&gt;

&lt;p&gt;From its website, they define create-react-app as a comfortable environment for learning React, and is the best way to start building a new single-page application in React.&lt;/p&gt;

&lt;p&gt;It sets up our development environment so we can use the latest JavaScript features, provides a nice developer experience, and optimizes our App for production. We'll need to have node &amp;gt;= 8.10 and npm &amp;gt;= 5.6 in our machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does it includes?
&lt;/h2&gt;

&lt;p&gt;1.- Webpack: A static module bundler for modern JavaScript applications.&lt;br&gt;
2.- Webpack Dev Server: To run a local environment.&lt;br&gt;
3.- Babel: For transpiling our files to work on the targets we choose.&lt;br&gt;
4.- ESLint: For error checking and help you to format code.&lt;br&gt;
5.- Jest: A testing library!&lt;/p&gt;

&lt;h2&gt;
  
  
  How to create a Project?
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx create-react-app my-app
cd my-app
npm start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Folder Stucture
&lt;/h2&gt;

&lt;p&gt;So as a result, create-react-app will create a project with the next structure:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vfB60Lrd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/dkbrn9bhe/image/upload/v1597726791/Screenshot_from_2020-08-17_21-59-18_fjkivi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vfB60Lrd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/dkbrn9bhe/image/upload/v1597726791/Screenshot_from_2020-08-17_21-59-18_fjkivi.png" alt="create-react-app project"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;1.- node_modules: This is the folder in which all the dependencies are installed, it's generated when we run the create-react-app or the npm install command.&lt;br&gt;
2.- public: contains 3 files, usually we would only make a few changes in the index.html file&lt;br&gt;
3.- src: The folder in which we will be working, the starting point of our react application is the index.js where we specify the root component which is App.js.&lt;br&gt;
4.- .gitignore: a list of folders/files that don't want to include in our repo when we push our code.&lt;br&gt;
5.- package-lock.json: ensure consistent installation in our dependencies.&lt;br&gt;
6.- package.json: Contains the dependencies and scripts requried for the project.&lt;br&gt;
7.- README.md: We include information related to the project, sometimes the steps to run it, test it, etc.&lt;/p&gt;

&lt;p&gt;That was a pretty short introduction to our structure, we will come back to them in next lessons. &lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>beginners</category>
    </item>
    <item>
      <title>JS fundamentals: const vs var vs let?</title>
      <dc:creator>Christian Montero</dc:creator>
      <pubDate>Tue, 04 Aug 2020 05:55:16 +0000</pubDate>
      <link>https://dev.to/christianmontero/js-fundamentals-const-vs-var-vs-let-3nbj</link>
      <guid>https://dev.to/christianmontero/js-fundamentals-const-vs-var-vs-let-3nbj</guid>
      <description>&lt;p&gt;A lot of features came out with ES6 (ECMAScript 6. ES2015, Harmony, ESNext), many of these features are already supported by the newest features.&lt;/p&gt;

&lt;p&gt;One of these features is the incorporation of new ways to declare variables, but you might be wondering what's the difference? what makes them better than our friendly var?&lt;/p&gt;

&lt;p&gt;In the next posts we are going to be discussing the Javascript fundamental concepts so we can switch to the latest syntax if we haven't yet. In this post we will discuss about the differences between var, let and const in relation to their use, &lt;strong&gt;&lt;em&gt;hoisting&lt;/em&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;em&gt;scope&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Terminology 📕
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Scope:&lt;/strong&gt; In Javascript the scope refers to the current context of code that determines the accessibility (visibility) of a variable. There are 2 types of scope:&lt;/p&gt;

&lt;p&gt;-Global Scope: Variables declared outside of a block.&lt;br&gt;
-Local Scope: Variables declared inside of a block.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Hoisting:&lt;/strong&gt; Is a Javascript mechanism that moves the declaration of variables and functions to the top of their scope before code execution.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;We will talk more about this concepts later on this post.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Const ❗️
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Const doesn't mean "constant" it means one time assignment&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;Const cannot be updated or re-declared&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;Const keyword is a litttle tricky especially if you have used them in other languages. A constant is a variable with an inmutable reference. When we declare a primitive type as const we cannot change its value, if we try, we will see an error in the console, as you can see here:&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;PI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;3.1415926535&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;PI&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;PI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;3.1416&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;PI&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iwMX9nsg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/drvosvqt0/image/upload/v1596432261/Screenshot_3_o6fsfc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iwMX9nsg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/drvosvqt0/image/upload/v1596432261/Screenshot_3_o6fsfc.png" alt="Console Error"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;The same way if we try to re-declare a const variable we will see this error:&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;PI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;3.1415926535&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;PI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;3.1416&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QTZIriO1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/drvosvqt0/image/upload/v1596432156/Screenshot_2_hhdlzy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QTZIriO1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/drvosvqt0/image/upload/v1596432156/Screenshot_2_hhdlzy.png" alt="Console Error"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;This means that when we want to declare a variable using the const keyword, we must initialize them at the time of the declaration or we will see another error message:&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;PI&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;PI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;3.1415926535&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zuhbwS_a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/drvosvqt0/image/upload/v1596432632/Screenshot_4_panaml.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zuhbwS_a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/drvosvqt0/image/upload/v1596432632/Screenshot_4_panaml.png" alt="Console Error"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;However this behavior changes when it comes to non-primitive types (objects, arrays, etc) as const. The way the const keyword works with objects is this:&lt;/p&gt;

&lt;p&gt;We cannot re-declare the object but we can update the value of its properties and we can add more properties without returning errors.&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;user&lt;/span&gt; &lt;span class="o"&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;Obi-Wan&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;age&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="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;user&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;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Luke&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;lastname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Skywalker&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;age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;25&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;user&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;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YiTznIWf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/drvosvqt0/image/upload/v1596435299/Screenshot_6_lcpusa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YiTznIWf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/drvosvqt0/image/upload/v1596435299/Screenshot_6_lcpusa.png" alt="Console Output"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;Const is block scoped&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;Before ES6 we had &lt;em&gt;local/function scope&lt;/em&gt;  and &lt;em&gt;global scope&lt;/em&gt;.&lt;br&gt;
&lt;em&gt;function-scoped variables&lt;/em&gt; were only available inside the function where they were declared. Now with ES6 and with the addition of the let and const keywords, we have the &lt;strong&gt;block scope&lt;/strong&gt; where block code means the code bounded by {}, anything within curly braces is a block. We will this explain in the next example:&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;PI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;3.1415926535&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;cirleArea&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;radius&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;PI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;3.1416&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;PI inside circleArea function: &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PI&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;radius&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;radius&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;PI&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PI outside circleArea function: &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PI&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;area&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cirleArea&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="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="s2"&gt;The area is: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;area&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9uTLy0N2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/drvosvqt0/image/upload/v1596433774/Screenshot_5_ma6wcq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9uTLy0N2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/drvosvqt0/image/upload/v1596433774/Screenshot_5_ma6wcq.png" alt="Console output"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, we define a PI constant outside our circleArea function, and we define another constant with the same name inside our function, since they have different scope, we won't run into a re-declaration error, also if we console log both of this variables in their respective scope, we will see the different values. &lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;em&gt;Hoisting of const&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;const delcarations are hoisted to the top but is not initialized. so if we try to use a const variable before its declarations, we'll get a Reference error.&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;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="s2"&gt;The value of PI is: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PI&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;PI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;3.1415926535&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uXG0LB1y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/drvosvqt0/image/upload/v1596435876/Screenshot_7_it7ifh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uXG0LB1y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/drvosvqt0/image/upload/v1596435876/Screenshot_7_it7ifh.png" alt="Console Error"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Let ✅
&lt;/h2&gt;

&lt;p&gt;Javascript now has lexical variable scoping, we create code blocks with curly backets. With functions, these curly brackets block off the scope of variables, but if we think about if-else statements, we might assume that these blocks would also block variable scope, before the addition of the let keywork this wasn't the case as we can see in the next example:&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;var&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Peter Griffin&lt;/span&gt;&lt;span class="dl"&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="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Homer Simpson&lt;/span&gt;&lt;span class="dl"&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;name&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;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IpQdh4F7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/drvosvqt0/image/upload/v1596472134/Screenshot_8_uxy88k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IpQdh4F7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/drvosvqt0/image/upload/v1596472134/Screenshot_8_uxy88k.png" alt="Console Output"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The name variable inside the if block resets the value of the global name variable.&lt;/p&gt;

&lt;p&gt;Fortunately with the let keyword, we can scope a variable to any code block. Using let protects the value of the global variable and that's why let is now the preferred for variable declaration.&lt;br&gt;
We can see the same example here:&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;var&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Peter Griffin&lt;/span&gt;&lt;span class="dl"&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="kc"&gt;true&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;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Homer Simpson&lt;/span&gt;&lt;span class="dl"&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;name&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;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--epsxSX33--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/drvosvqt0/image/upload/v1596473053/Screenshot_9_qvltzy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--epsxSX33--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/drvosvqt0/image/upload/v1596473053/Screenshot_9_qvltzy.png" alt="Console Output"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;Unlike const, let can be updated but not re-declared&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;Any variable declared with the let keyword can be updated, but if we try to re-declare it, we will get an error as we can see in the next example:&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;let&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Peter Griffin&lt;/span&gt;&lt;span class="dl"&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;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Homer Simpson&lt;/span&gt;&lt;span class="dl"&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;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OgqddzHN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/drvosvqt0/image/upload/v1596475990/Screenshot_11_thqnc3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OgqddzHN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/drvosvqt0/image/upload/v1596475990/Screenshot_11_thqnc3.png" alt="Console Output"&gt;&lt;/a&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;let&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Peter Griffin&lt;/span&gt;&lt;span class="dl"&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;name&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;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Bart Simpson&lt;/span&gt;&lt;span class="dl"&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;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FNPkbOmq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/drvosvqt0/image/upload/v1596476032/Screenshot_12_khewhq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FNPkbOmq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/drvosvqt0/image/upload/v1596476032/Screenshot_12_khewhq.png" alt="Console Error"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;Let is block scoped&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;A variabled declared in a code block using the let keyword will be only available within that block.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;Hoisting of let&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;The same way that const, let delcarations are hoisted to the top but they are not initialized, so if we try to use a const variable before its declarations, we'll get a Reference error.&lt;/p&gt;

&lt;h2&gt;
  
  
  What about our old friend var? 👨‍🦳
&lt;/h2&gt;

&lt;p&gt;Most of the time we can replace let with var and vice-versa and expect things to work, but there are some important points that we have to know.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;var has no block scope&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;When we declare a variable using the var keyword they are either function-wide or global. They are visible through blocks:&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="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
   &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Peter Griffin&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;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;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RGB26P8k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/drvosvqt0/image/upload/v1596517508/Screenshot_12_qfthsd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RGB26P8k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/drvosvqt0/image/upload/v1596517508/Screenshot_12_qfthsd.png" alt="Console Output"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;As we can see, even when we declare the variable inside the if block, the variable lives outside. We will see the same behavior with for loops blocks. The only different scenario is if the code block is inside a function, in that case the variable becomes a function-level variable.&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="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
   &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Peter Griffin&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;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;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1XIh-H5C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/drvosvqt0/image/upload/v1596517935/Screenshot_13_u52ceq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1XIh-H5C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/drvosvqt0/image/upload/v1596517935/Screenshot_13_u52ceq.png" alt="Console Error"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;em&gt;var can be re-declared&lt;/em&gt;
&lt;/h3&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;var can be declare below their use (This is possible because declarations are hoisted, but assignments are not)&lt;/em&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&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;b&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
  &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;b&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;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nx"&gt;add&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Zm1JmvIg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/drvosvqt0/image/upload/v1596518264/Screenshot_14_m8tq0p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Zm1JmvIg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/drvosvqt0/image/upload/v1596518264/Screenshot_14_m8tq0p.png" alt="Console Output"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  💡 Summary 💡
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Scope means the code context where variables are available for use. 👀&lt;/li&gt;
&lt;li&gt;Hoisting is a Javascript mechanism that moves the declaration of variables and functions to the top of their scope before code execution. 🔺&lt;/li&gt;
&lt;li&gt;Const doesn't necessarily means that holds an immutable value, it means that holds an immutable reference and it behaves different depending the type of variable that we assign to. But even though our code can be more meaningful if we use the const keyword. 👍&lt;/li&gt;
&lt;li&gt;Let is similar to var, but let is block scoped. 💪
5.- Reading across many articles I found that many authors recommend to avoid the use of var, there's no need to use it anymore. 👎&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I believe that there's always something to learn from everyone, hopefully this post will be useful for somebody, I'm still learning, so any feedback would be appreciated. Have a nice day! ✌️&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>beginners</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
