<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Viviana Yanez - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Viviana Yanez - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Thu, 21 May 2026 16:10:31 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/author/vivianay/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ What Happens When You Visit a Website? How the Web Works Explained ]]>
                </title>
                <description>
                    <![CDATA[ In this article, I’ll guide you through an overview of what happens when you navigate to a website using your browser. Whether you’re new to web development or have some experience, this post will help you gain a better understanding of how the web a... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-happens-when-you-visit-a-website/</link>
                <guid isPermaLink="false">67378578138bc8b1c027a1e8</guid>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ internet ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Viviana Yanez ]]>
                </dc:creator>
                <pubDate>Fri, 15 Nov 2024 17:31:36 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1731682843488/32065460-190d-472f-9268-5b181430eef6.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this article, I’ll guide you through an overview of what happens when you navigate to a website using your browser.</p>
<p>Whether you’re new to web development or have some experience, this post will help you gain a better understanding of how the web and its core technologies work.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-finding-a-resource-urls">Finding a Resource: URLs</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-matching-ips-and-urls-dns-resolution">Matching IPs and URLs: DNS Resolution</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-the-dns-resolver">What is the DNS Resolver?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-the-root-dns-server">What is the Root DNS Server?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-the-top-level-domain-server">What is the Top Level Domain Server?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-authoritative-nameserver">Authoritative Nameserver</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-establishing-a-connection-tcpip-model">Establishing a Connection: TCP/IP Model</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-how-does-tcp-connection-work">How Does TCP Connection Work?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-tcp-three-way-handshake">TCP Three-way Handshake</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-starting-the-exchange-client-server-communication">Starting the Exchange: Client-Server Communication</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-the-http-protocol">What is the HTTP Protocol?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-http-requestresponse">HTTP Request/Response</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-https">HTTPS</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-time-to-first-byte">Time to First Byte</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-from-data-to-pixels-the-critical-rendering-path">From Data to Pixels: The Critical Rendering Path</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-building-the-dom-tree">Building the DOM tree</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-building-the-cssom-tree">Building the CSSOM Tree</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-javascript-compilation-and-execution">Javascript Compilation and Execution</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-building-the-accessibility-tree">Building the Accessibility Tree</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-render-tree">Render tree</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-layout">Layout</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-painting">Painting</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-a-note-about-javascript-hydration">A Note About JavaScript Hydration</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<p>Before going into the details of every step included in the process, let's review some of the basic concepts we’ll be covering.</p>
<p>The internet is a huge network of interconnected computers. The World Wide Web (aka web) is built on top of that technology, as well as other services such as email, chat systems or file sharing, and so on.</p>
<p>Computers connected to the internet are either:</p>
<ul>
<li><p><strong>Clients</strong>, the web user's devices and the software that those devices use to access the web.</p>
</li>
<li><p><strong>Servers</strong>, computers that store web pages, sites, or apps and the files they need to be displayed in the user's web browser or devices.</p>
</li>
</ul>
<h2 id="heading-finding-a-resource-urls">Finding a Resource: URLs</h2>
<p>Each resource stored in a server can be located by clients using its valid associated URL. The following is an example of a valid URL:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1731414821178/970907db-f349-421e-b410-45f4ee978e0b.jpeg" alt="Example of a valid URL, including its scheme, authority, path to resource, two parameters and an anchor." class="image--center mx-auto" width="1200" height="178" loading="lazy"></p>
<p>You may already know what a URL is, but let’s see in detail each one of its parts:</p>
<ul>
<li><p><strong>Scheme</strong>: The first part of an URL indicates the protocol that should be used to retrieve the resource. Websites use the HTTP and the HTTPS protocol, but we’ll see more details about this later. The <code>:</code> after the scheme is what separates it from the next part of the URL.</p>
</li>
<li><p><strong>Authority</strong>: this part is composed by the domain name and the port number separated by a colon. The port is only mandatory when the standard ports of the HTTP protocol (80 for HTTP and 443 for HTTPS) are not being used by the web server. The <code>//</code> before the domain name indicates the beginning of the authority.</p>
</li>
<li><p><strong>Path to resource</strong>: this is the abstract or physical path to the resource in the web server.</p>
</li>
<li><p><strong>Parameters</strong>: a set of key/value pairs that add extra options to apply to the returning the requested resource. They are separated by a <code>&amp;</code> and each web server has its own way to handle parameters. This section starts with <code>?</code>.</p>
</li>
<li><p><strong>Anchor</strong>: This section, if present, starts by a <code>#</code> and is handled by the browser to display a specific part of the returned document. For example, it can point to a specific section in a HTML document.</p>
</li>
</ul>
<p>There are a few things that happen when you type a URL into your browser’s address bar that allow you to navigate to a site and interact with its content. Let’s see each one in detail.</p>
<h2 id="heading-matching-ips-and-urls-dns-resolution">Matching IPs and URLs: DNS Resolution</h2>
<p>While, as humans, we prefer domain names composed of words, computers communicate with each other using IP addresses. IP addresses are composed by numbers and are harder to remember for our human minds. The <a target="_blank" href="https://en.wikipedia.org/wiki/Domain_Name_System">Domain Name System</a> (<strong>DNS</strong>) is what puts together domain names and IP addresses.</p>
<p>When you type a URL, the browser will first look into the local cache to see if the results for the DNS lookup are already stored. Then, it will equally check into the operating system cache.</p>
<p>If there are no results stored, then the browser will call the DNS Resolver to try to find the associated IP address for the domain name.</p>
<h3 id="heading-what-is-the-dns-resolver">What is the DNS Resolver?</h3>
<p>The resolver is typically defined by your internet provider’s DNS, even though that’s the default most people use, and it is possible to change it to Google’s or Cloudflare’s or anything else you want.</p>
<p>Again, the provider’s DNS might have the results for the domain name stored in its cache, if not, it will ask the Root DNS server.</p>
<h3 id="heading-what-is-the-root-dns-server">What is the Root DNS Server?</h3>
<p>The Root DNS server is a system that actually drives the entire internet. It is composed of thirteen servers distributed across the planet. It returns the query from the resolver with the relevant Top Level Domain server for the requested domain name.</p>
<p>At this moment, the DNS resolver will cache the IP of that Top Level Domain server so it doesn’t have to ask the Root DNS server again for it.</p>
<h3 id="heading-what-is-the-top-level-domain-server">What is the Top Level Domain Server?</h3>
<p>The <a target="_blank" href="https://en.wikipedia.org/wiki/Top-level_domain">Top Level Domain</a> (<strong>TLD</strong>) server stores the IP addresses of the authoritative name servers for the domain that the user is looking for.</p>
<p>In the URL, <code>www.exampleurl.com</code>, the top-level domain is <code>.com</code>. There are different types, such as generic top-level domains like <code>.com</code> or <code>.org</code>, country code top-level domains, usually represented by the two letters ISO country code, and more.</p>
<p>The TLD returns the authoritative name servers for the requested domain. One more time, the DNS resolver will cache the results so it doesn’t have to come back later for them.</p>
<h3 id="heading-authoritative-nameserver">Authoritative Nameserver</h3>
<p>This server contains the DNS records that maps domain names to IP addresses. There is more than one name server attached to any domain.</p>
<p>There is no caching involved at this point, because the authoritative nameserver is the highest authority and the latest piece in the DNS resolution chain.</p>
<p>If the IP address is available, the authoritative nameserver responds to the DNS resolver query with the domain name’s IP address. If not available it will respond with an error. Then, the DNS resolver stores the IP and sends it back to the client’s browser.</p>
<p>Once the DNS lookup is completed and the browser has the IP address, it can attempt to establish a connection with the server.</p>
<h2 id="heading-establishing-a-connection-tcpip-model">Establishing a Connection: TCP/IP Model</h2>
<p>The connection between client and server is established using the <a target="_blank" href="https://en.wikipedia.org/wiki/Transmission_Control_Protocol">Transmission Control Protocol</a> (<strong>TCP</strong>) and the <a target="_blank" href="https://en.wikipedia.org/wiki/Internet_Protocol">Internet Protocol</a> (<strong>IP</strong>). These protocols are the main ones behind the World Wide Web and other internet technologies, such as email, and determine how data travels across the network.</p>
<p>The <a target="_blank" href="https://en.wikipedia.org/wiki/Internet_protocol_suite">TCP/IP model</a> is a framework used to organize the different protocols involved in the internet and other network communications. The primary responsibility of TCP/IP is to divide the data into packets and send them to their final destination, ensuring the packets can be put back together on the other end of the communication.</p>
<p>This process follows a four-layer model, where data travels in one direction and then in the reverse direction when it reaches the destination:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1731414848576/178ce64e-2216-487a-b142-c88c2125dcde.jpeg" alt="The four-layer model includes the application layer, the transport layer, the internet layer, and the network layer. Data travels back and forth through these layers." class="image--center mx-auto" width="1062" height="555" loading="lazy"></p>
<p>The transport layer that ensures applications can exchange data by establishing data channels. It is also the layer that establishes the concept of network ports, a system of numbered data channels allocated for the specific communication channels that applications need.</p>
<p>The TCP/IP model’s transport layer includes two protocols that are most commonly used on the internet: the TCP and the <a target="_blank" href="https://en.wikipedia.org/wiki/User_Datagram_Protocol">User Datagram Protocol</a> (UDP).</p>
<p>TCP includes some capabilities that make it prevalent over most of the internet-based applications such as the web, so let’s focus on it.</p>
<h3 id="heading-how-does-tcp-connection-work">How Does TCP Connection Work?</h3>
<p>TCP allows data to be transferred reliably and in order to its destination. It is a connection-oriented protocol, that means that the sender and the receiver must agree on connection parameters before actually establishing the connection. This process is known as the handshake procedure.</p>
<h3 id="heading-tcp-three-way-handshake">TCP Three-way Handshake</h3>
<p>The handshake is a way for the client and the server to establish a secure connection and ensure that both parties are synchronized and ready to start exchanging messages.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1731414866173/6d66c360-2d2e-427b-8c8d-1555fdaa7197.jpeg" alt="The three steps of the TCP handshake." class="image--center mx-auto" width="904" height="604" loading="lazy"></p>
<p>The three steps of the TCP handshake include:</p>
<ol>
<li><p>The client informs the server that it wants to establish a connection by sending a SYN (synchronize) packet. This packet specifies a sequence number that subsequent segments will start with.</p>
</li>
<li><p>The server receives the SYN and responds with a SYN-ACK (synchronize-acknowledgment) segment. It includes the server’s sequence number and an acknowledgment of the client’s sequence number, incremented by one.</p>
</li>
<li><p>The client responds with an ACK message, acknowledging the server’s sequence number. At this point, the connection has been established.</p>
</li>
</ol>
<h2 id="heading-starting-the-exchange-client-server-communication">Starting the Exchange: Client-Server Communication</h2>
<p>Once the TCP connection is established, the client and server can start exchanging messages using the HTTP protocol.</p>
<h3 id="heading-what-is-the-http-protocol">What is the HTTP Protocol?</h3>
<p><a target="_blank" href="https://en.wikipedia.org/wiki/HTTP">Hypertext Transfer Protocol</a> (<strong>HTTP</strong>) is the most widely used application layer protocol in the TCP/IP suite, but it’s considered insecure, leading to a shift towards HTTPS, which uses TLS on top of TCP for data encryption. You see find more details about this later.</p>
<p>The browser will start by sending an HTTP request message to the server, asking for a copy of the site in the form of an HTML file. HTTP protocol can transfer files like HTML, CSS, JS, SVG, and so on.</p>
<h3 id="heading-http-requestresponse">HTTP Request/Response</h3>
<p>There are two types of HTTP messages:</p>
<ul>
<li><p><strong>Requests</strong>, sent by the client to the server to trigger an action.</p>
</li>
<li><p><strong>Responses</strong>, sent from the server to the client as an answer to the previous request.</p>
</li>
</ul>
<p>Messages are plain text documents, structured in a precise way determined by the communication protocol, in this case, HTTP.</p>
<p>The three parts included in a <strong>HTTP request</strong> are:</p>
<ol>
<li><p><strong>Request line</strong>: Includes the request method, which is a verb defining the action to perform. In the case we are covering in this blogpost, the browser will make a GET request to fetch a page from the server. The request line will also include the resource location, in this case an URL, and the protocol version being used.</p>
</li>
<li><p><strong>Request header</strong>: A set of key value pairs. Two of them are mandatory. <code>Host</code> indicates the domain name to target, and <code>Connection</code> which is always set to close unless it must be kept open. The request header always ends with a blank line.</p>
</li>
<li><p><strong>Request body</strong>: Is an optional field that allows sending data over the server.</p>
</li>
</ol>
<p>The server will reply to the request with an HTTP response. Responses include information about the request status and may include the requested resource or data.</p>
<p>HTTP responses are structured in the following parts:</p>
<ol>
<li><p><strong>Status line</strong>: Includes the used protocol version, a status code and a status text, with a human readable description of the status code.</p>
</li>
<li><p><strong>Headers</strong>: A set of key-value pairs that can either be general headers, applying to the whole message; response headers, giving additional information about the server status; or representation headers, describing the format and encoding for the message data if present.</p>
</li>
<li><p><strong>Body</strong>: Contains the requested data or resource. If no data or resource is expected by the client, the response usually won’t include a body.</p>
</li>
</ol>
<p>When the request for a web page is approved by the server, the response will include a <code>200 OK</code> message. Other existing HTTP response codes are:</p>
<ul>
<li><p>404 Not Found</p>
</li>
<li><p>403 Forbidden</p>
</li>
<li><p>301 Moved Permanently</p>
</li>
<li><p>500 Internal Server Error</p>
</li>
<li><p>304 Not Modified</p>
</li>
<li><p>401 Unauthorized</p>
</li>
</ul>
<p>The response will also contain a list of HTTP headers and the response body, including the corresponding HTML code for the requested page.</p>
<h3 id="heading-https">HTTPS</h3>
<p><a target="_blank" href="https://en.wikipedia.org/wiki/HTTPS">Hypertext Transfer Protocol Secure</a> (<strong>HTTPS</strong>) is not a different protocol, but an extension of the HTTP. It is usually referred to as HTTP over Transport Layer Security (<strong>TLS</strong>). Let’s see what it exactly means.</p>
<p>HTTP is the protocol used for most communications between browsers and servers, but it lacks security. Any data sent over HTTP can potentially be visible to anyone on the network. This is especially risky when sensitive data is involved in the connection, such as login credentials, financial information, health information, and so on.</p>
<p>The main motivation behind HTTPS is to ensure data privacy, integrity, and identification. This means ensuring that data is only accessible to whom it is supposed to be and cannot be intercepted or modified by anyone in between. Also, that both sender and receiver can be identified as who they claim to be by a legitimate authority.</p>
<p>In HTTPS the communications are encrypted using the TLS protocol, which relies on asymmetric public key infrastructure. It combines two keys: one public and one private. The server shares its public key so the client can use it to encrypt messages that can only be decrypted by the server’s private key.</p>
<p>To establish an encrypted communication, the client and the server have to initiate another handshake. During the handshake, they agree on the TLS version to use and on how they will encrypt data and authenticate each other during the connection, a set of rules known as the cipher suite.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1731414891509/541f6b6c-ad54-4301-834a-1056aea524c0.jpeg" alt="Steps in the SSL Handshake." class="image--center mx-auto" width="1171" height="1177" loading="lazy"></p>
<p>This handshake or TLS negotiation starts once a TCP connection has been established, and includes the following steps:</p>
<ul>
<li><p><strong>Client hello</strong>: The browser sends a hello message that includes all supported TLS versions and cipher suites.</p>
</li>
<li><p><strong>Server Hello</strong>: The server responds with the chosen cipher suite and TLS version, along with its SSL certificate containing the server's public key.</p>
</li>
<li><p><strong>Authentication and Pre-Master Key</strong>: The client verifies the server’s SSL certificate with the corresponding trusted authority, then creates a pre-master key using the server's public key (previously shared in the certificate) and shares this pre-master key with the server.</p>
</li>
<li><p><strong>Pre-master key decryption</strong>: The pre-mastered key can only be decrypted using the server’s private key. If the server is able to decrypt it, the client and server can then agree on a shared master secret to use for the session.</p>
</li>
<li><p><strong>Client ChangeCipherSpec</strong>: The client creates a session key using the shared master secret and sends the server all previously exchanged records, this time encrypted with the session key.</p>
</li>
<li><p><strong>Server ChangeCipherSpec</strong>: If the server generates the correct session key, it will be able to decrypt the message and verify the received record. The server then sends a record to confirm that the client also has the correct keys.</p>
</li>
<li><p><strong>Secured connection established</strong>: The handshake is complete.</p>
</li>
</ul>
<p>Once the handshake is completed, all the communication between the client and server is protected by symmetric encryption using the session key, and the browser can make the first HTTP GET request for the site.</p>
<h3 id="heading-time-to-first-byte">Time to First Byte</h3>
<p>Once the browser's request is approved, the server will send a 200 OK message along with the response headers and the contents requested. As it is a website, content is likely to be an HTML document.</p>
<p>Data travels between the client and server divided into a series of small data chunks, called data packets. This makes it easy to replace corrupted chunks of data if needed and also allows data to travel to and from different locations, enabling multiple users to access data faster and at the same time.</p>
<p>When the first request is made from the client, the first packet that arrives as response marks the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/Time_to_first_byte">Time to First Byte</a> (<strong>TTFB</strong>), which represents the time elapsed since the request was initiated and when the first chunk of data was received as a response. It will include the time taken for the DNS lookup, the TCP handshake to establish the connection, and the TLS handshake if the request is made over HTTPS.</p>
<h2 id="heading-from-data-to-pixels-the-critical-rendering-path">From Data to Pixels: The Critical Rendering Path</h2>
<p>The <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/Performance/Critical_rendering_path">Critical Rendering Path</a> (<strong>CRP</strong>) is a series of steps that the browser performs to transform the data received back from the server into pixels on the screen. It includes creating the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model">Document Object Model</a> (<strong>DOM</strong>) and <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/CSS_Object_Model">CSS Object Model</a> (<strong>CSSOM</strong>), the <strong>render tree</strong> and <strong>layout</strong>.</p>
<h3 id="heading-building-the-dom-tree">Building the DOM tree</h3>
<p>When the first chunk of data arrives, the browser starts parsing the HTML. Parsing means analyzing and converting a piece of input code into a syntax and representation that can be interpreted by a specific runtime. In this case, the browser assembles the data packets received and parses the HTML, building a representation of the document as a node tree known as the DOM tree.</p>
<p>Each HTML tag in the document is represented as a node in the DOM tree. Nodes are connected to the DOM tree according to their hierarchical position in the document, and each node's representation includes all relevant information about the tag.</p>
<p>For the following HTML code:</p>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>What Really Happens When You Navigate to a Website<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">main</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">header</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>What Really Happens When You Navigate to a Website<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">section</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Intro<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
                Before entering into the details of every step included in the process, let's review some of the basic concepts we will be discussing throughout the blog.
            <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
                The Internet is a huge network of interconnected computers. The World Wide Web (aka web) is built on top of that technology, as well as other services such as email, chat systems, or file sharing.
            <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Computers connected to the internet are either:<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Clients, the web user's devices and the software that those devices use to access the web.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Servers, computers that store web pages, sites, or apps and the files they need to be displayed in the user's web browser or devices.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">footer</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>© 2024<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">footer</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>The resulting DOM tree looks like following:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1731498370760/4267c646-145e-487c-83af-f97d6f8ce21d.jpeg" alt="The DOM tree includes all HTML elements, its content and its hierarchy relationships." class="image--center mx-auto" width="1171" height="897" loading="lazy"></p>
<p>While parsing the HTML, the browser makes additional requests for encountered resources. CSS files and images are non-blocking resources, meaning the parser will continue its task while awaiting the requested resources. But if a <code>&lt;script&gt;</code> tag is found, the HTML parsing will pause impacting the time to first rendering.</p>
<h3 id="heading-building-the-cssom-tree">Building the CSSOM Tree</h3>
<p>While the DOM contains all the information about the content of the page and its hierarchy, the CSSOM contains the information on how to style the page.</p>
<p>In the CSSOM, each HTML element is matched with its corresponding CSS styles. The result is a tree that doesn’t contain information about the content of the elements, but about how they should be displayed.</p>
<p>Given the following CSS code:</p>
<pre><code class="lang-css">* {
    <span class="hljs-attribute">box-sizing</span>: border-box;
}

<span class="hljs-selector-tag">body</span> {
    <span class="hljs-attribute">font-family</span>: Arial, sans-serif;
    <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#f4f4f9</span>;
    <span class="hljs-attribute">color</span>: <span class="hljs-number">#333</span>;
}

<span class="hljs-selector-tag">main</span> {
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">20px</span>;
    <span class="hljs-attribute">max-width</span>: <span class="hljs-number">800px</span>;
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span> auto;
}

<span class="hljs-selector-tag">header</span> {
    <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#005bbb</span>;
    <span class="hljs-attribute">color</span>: <span class="hljs-number">#ffffff</span>;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span>;
    <span class="hljs-attribute">text-align</span>: center;
}

<span class="hljs-selector-tag">h1</span> {
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">24px</span>;
}

<span class="hljs-selector-tag">section</span> {
    <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">20px</span>;
}

<span class="hljs-selector-tag">h2</span> {
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">20px</span>;
    <span class="hljs-attribute">color</span>: <span class="hljs-number">#005bbb</span>;
    <span class="hljs-attribute">display</span>: none;
}

<span class="hljs-selector-tag">p</span> {
    <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">10px</span>;
}

<span class="hljs-selector-tag">ul</span> {
    <span class="hljs-attribute">margin-left</span>: <span class="hljs-number">20px</span>;
    <span class="hljs-attribute">list-style-type</span>: disc;
}

<span class="hljs-selector-tag">footer</span> {
    <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">40px</span>;
    <span class="hljs-attribute">text-align</span>: center;
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">14px</span>;
    <span class="hljs-attribute">color</span>: <span class="hljs-number">#555</span>;
}
</code></pre>
<p>When the browser processes it, the resulting CSSOM will look like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1731496962735/f3cb0399-a9fb-48cc-8043-00608d1236db.jpeg" alt="The CSSOM tree includes each HTML element and their corresponding styles. " class="image--center mx-auto" width="596" height="918" loading="lazy"></p>
<p>Its creation is not incremental, meaning that the browser stops rendering the page until it processes all the CSS.</p>
<p>This works this way because, as its name suggests, Cascading Style Sheets (<strong>CSS</strong>) apply styles from top to bottom, meaning that classes defined later override those at the beginning of the document. A CSS document needs to be fully processed before rendering anything on the screen, as there are classes that may change.</p>
<h3 id="heading-javascript-compilation-and-execution">Javascript Compilation and Execution</h3>
<p>While the CSSOM is being created, rendering is blocked, but the browser continues downloading any JavaScript files it encounters.</p>
<p>JavaScript is also parsed, compiled, and interpreted by the browser, but as mentioned before, it is a parser-blocking resource by default. This means that when the browser encounters a <code>&lt;script&gt;</code> tag, it stops HTML parsing and executes the file before continuing. The async or defer attributes can be used to avoid this behavior, allowing parsing to continue while the resource is fetched.</p>
<p>Once the browser completes parsing and executes all JavaScript files that may modify the DOM and CSSOM, the next step is to build the render tree. However, before seeing this step in detail, let’s take a moment to focus on the accessibility tree.</p>
<h3 id="heading-building-the-accessibility-tree">Building the Accessibility Tree</h3>
<p>Based on the structure of the site created in the DOM tree, the browser also creates an accessibility tree.</p>
<p>The accessibility tree is another representation of the site’s content, specifically designed to allow navigation through the site using <a target="_blank" href="https://en.wikipedia.org/wiki/Web_accessibility#Assistive_technologies_used_for_web_browsing">assistive technologies</a>.</p>
<p>In the accessibility tree, each DOM element is represented as an accessible object, containing the following information:</p>
<ul>
<li><p><strong>Name</strong>: An identifier used to refer to the element.</p>
</li>
<li><p><strong>Description</strong>: Additional information about the element.</p>
</li>
<li><p><strong>Role</strong>: The type of element it is, related to its intended use.</p>
</li>
<li><p><strong>State</strong> and other properties: If the element is subject to change, it may include its current state. It can also include other properties specifying other functionality.</p>
</li>
</ul>
<p>In major web browsers, you can access the accessible objects and their information by selecting a node in the DOM tree viewer and the navigating to the “Accessibility” tab.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1731578933460/0a8c7a78-c19a-4d19-a96a-fabd19772156.png" alt="A unordered list selected and the accessibility tab in Chrome Dev Tools." class="image--center mx-auto" width="2400" height="864" loading="lazy"></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1731579023128/85aeb312-1632-49c3-80cb-0d5db8ec8502.png" alt="A unordered list selected and the accessibility tab in Firefox Dev Tools." class="image--center mx-auto" width="2478" height="980" loading="lazy"></p>
<p>Having a well-structured accessibility tree is key in determining whether a site will be navigable using assistive technology, making the difference between inclusion and exclusion.</p>
<h3 id="heading-render-tree">Render tree</h3>
<p>After building the DOM, CSSOM, and accessibility trees, the browser builds the render tree.</p>
<p>This tree is a combination of the DOM and CSSOM trees. The browser processes all nodes and keeps only the visible ones. Then, it combines them with their corresponding CSSOM rules. The result is a collection of all visible elements matched with their computed styles.</p>
<p>Non-visible nodes, such as <code>&lt;script&gt;</code> or <code>&lt;meta&gt;</code> tags, as well as elements hidden with the <code>display: none</code> CSS property, are not included in this tree.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1731501603172/d3467e9a-e75b-4217-875b-58684edfdbc0.jpeg" alt="The render tree is created from the DOM and CSSOM trees." class="image--center mx-auto" width="1332" height="1023" loading="lazy"></p>
<h3 id="heading-layout">Layout</h3>
<p>Once the render tree is computed, the browser runs the layout. In this process, the browser calculates the exact position and size each element will take into the page.</p>
<p>These calculations are based on the viewport size, the browser area that will actually display the site content. The size of the viewport varies based on the device screen size, the browser window size, system settings along other conditions.</p>
<p>The layout output is a box model that captures the size and position that correspond to each element and object present in the render tree. The browser starts processing the document usually from the <code>&lt;body&gt;</code> tag and going through all its descendants.</p>
<p>After the layout calculation, any changes in the size or position of one or more elements in the document will trigger new calculations. Those following calculations are called reflows.</p>
<h3 id="heading-painting">Painting</h3>
<p>Now, the final step is displaying the layout output on the user's screen. During the painting or rasterization phase, the browser converts each layout box element into corresponding pixels on the screen.</p>
<p>A visual representation of the entire page is initially rendered on the screen, and then only the areas affected by changes are re-rendered.</p>
<p>Many factors impact the time it takes for the browser to perform this step, and there are tools that help developers measure and optimize this time.</p>
<p>After painting, and before users can start interacting with the website, the browser may execute any JavaScript that has been deferred using the <code>defer</code> or <code>async</code> attributes to avoid blocking the initial HTML parsing.</p>
<h3 id="heading-a-note-about-javascript-hydration">A Note About JavaScript Hydration</h3>
<p>The steps we described above show the process of rendering all the website’s HTML, CSS, and JavaScript code in the browser. This is known as Client-Side Rendering (CSR). You may have also heard about Server-Side Rendering (SSR).</p>
<p>SSR consists of rendering a website’s content on each request and delivering it to the client as HTML ready to be displayed in the browser.</p>
<p>When a site is rendered using CSR, all the JavaScript is executed before the page is rendered. In SSR, the server-rendered HTML loads and displays quickly in the browser, but JavaScript still needs to be sent to the client to enable user interaction.</p>
<p>JavaScript Hydration is the process where JavaScript is added to a server-rendered HTML page to make it interactive. Once the initial HTML is served and displayed in the browser, JavaScript "hydrates" the static content, attaching event listeners and enabling interactive functionality.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Throughout this article, you enhanced your understanding of what happens from the moment you type a web address into your browser’s address bar until you access the content of the site you’re looking for.</p>
<p>You learned about URLs and the DNS lookup performed by the browser to find the site’s IP address. You also learned how connections are established between the browser and servers and how they communicate.</p>
<p>Finally, you explored what happens from the time the first chunk of data is received from the server until the site is displayed on your screen, along with key concepts such as the accessibility tree and the JavaScript hydration process.</p>
<p>I hope you enjoyed this guide and found it useful. Thanks for reading!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Set Up a CI/CD Pipeline with Husky and GitHub Actions ]]>
                </title>
                <description>
                    <![CDATA[ CI/CD is a core practice in the modern software development ecosystem. It helps agile teams deliver high-quality software in short release cycles. In this tutorial, you'll learn what CI/CD is, and I'll help you set up a CI/CD pipeline using Husky and... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-set-up-a-ci-cd-pipeline-with-husky-and-github-actions/</link>
                <guid isPermaLink="false">66bccaed4a4c0beb784641ce</guid>
                
                    <category>
                        <![CDATA[ continuous delivery ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Continuous Integration ]]>
                    </category>
                
                    <category>
                        <![CDATA[ GitHub Actions ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Viviana Yanez ]]>
                </dc:creator>
                <pubDate>Mon, 15 Jul 2024 17:46:34 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/07/how-to-set-a-cicd-pipeline-1.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>CI/CD is a core practice in the modern software development ecosystem. It helps agile teams deliver high-quality software in short release cycles.</p>
<p>In this tutorial, you'll learn what CI/CD is, and I'll help you set up a CI/CD pipeline using Husky and GitHub Actions in a Next.js application. </p>
<p>This tutorial assumes that you already have knowledge of React and Next.js or other modern JavaScript frameworks. You will need also a GitHub account, and basic knowledge of Git will be strongly beneficial. </p>
<p>If you already have a working web app that is not built with Next.js, you might still find this article useful. All the concepts and most of the configurations will work with little adaptation in apps created with other frameworks.</p>
<h2 id="heading-heres-what-well-cover">Here's What We'll Cover:</h2>
<ol>
<li><a class="post-section-overview" href="#heading-what-is-cicd">What is CI/CD?</a><br>– <a class="post-section-overview" href="#heading-what-is-ci">What is CI?</a><br>– <a class="post-section-overview" href="#heading-what-is-cd">What is CD?</a><br>– <a class="post-section-overview" href="#heading-what-is-a-cicd-pipeline-and-what-are-its-benefits">What is a CI/CD pipeline and what are its benefits?</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-a-cicd-pipeline">How to Set Up a CI/CD Pipeline</a><br>– <a class="post-section-overview" href="#heading-step-1-set-up-a-nextjs-app">Step 1: Set Up a Next.js App with Vitest</a><br>– <a class="post-section-overview" href="#heading-step-2-set-a-git-hook">Step 2: Set a Git Hook</a><br>– <a class="post-section-overview" href="#heading-step-3-create-a-github-actions-workflow">Step 3: Create a GitHub Actions Workflow</a><br>– <a class="post-section-overview" href="#heading-step-4-deploy-the-project">Step 4: Deploy the Project</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ol>
<h2 id="heading-what-is-cicd">What is CI/CD?</h2>
<p>Continuous Integration/Continuous Delivery or Continuous Deployment (CI/CD) is a practice that involves automating the process of building, testing, and deploying software.</p>
<p>Its main benefit is speeding up the entire development process. It also increases productivity by ensuring smooth code integration, standards, and security best practices adoption. It also helps produce a shorter feedback cycle with early issue detection, among other advantages explained below.</p>
<p>CI/CD is an essential tool in today’s software development practices, enabling teams to deliver high-quality software quickly, efficiently, and reliably.</p>
<p>Let’s learn more about it in detail.</p>
<h3 id="heading-what-is-ci">What is CI?</h3>
<p><strong>Continuous Integration</strong> is a software practice that means that developers in a team merge code changes into a central repository multiple times a day. </p>
<p>Instead of having independent dev environments and merging at a specific time, developers frequently integrate their changes to an application into a shared branch or “trunk”.</p>
<h3 id="heading-what-is-cd">What is CD?</h3>
<p>The CD in CI/CD usually refers to <strong>Continuous Delivery</strong>. It's a practice that, on top of CI, automates the software integration, testing, and release process. The automation stops just before deploying to production, where a human-controlled step is needed.</p>
<p>But CD can also refer to <strong>Continuous Deployment</strong>, which adds automation to the step of releasing software to a production environment.</p>
<p>Even though CD usually refers to Continuous Delivery, both terms are sometimes used interchangeably. The difference between them is the amount of automation implemented in a project.</p>
<h3 id="heading-what-is-a-cicd-pipeline-and-what-are-its-benefits">What is a CI/CD pipeline and what are its benefits?</h3>
<p>When put together, these two practices create a CI/CD pipeline. Adding CI/CD to your project brings the following benefits:</p>
<ul>
<li>Faster development: reduces the time required to deliver new features thanks to automating the build, test and deploy.</li>
<li>Enhanced Collaboration: encourages frequent code integrations and reduces integration conflicts.</li>
<li>Improved Code Quality: enforces the adoption of coding standards and best practices throughout the codebase.</li>
<li>Early Detection of Issues: makes the feedback cycle smaller, as issues can be caught in advance.</li>
<li>Increased Productivity: prevents developers from needing to work on repetitive tasks.</li>
</ul>
<p>These are some of the reasons why CI/CD is a core practice in modern software development and why it is such an important topic to learn about. The following steps will guide you through the process of setting up a CI/CD pipeline for your project.</p>
<h2 id="heading-how-to-set-up-a-cicd-pipeline">How to Set Up a CI/CD Pipeline</h2>
<h3 id="heading-step-1-set-up-a-nextjs-app">Step 1: Set Up a Next.js App</h3>
<p>If you already have a working web app, you can skip this and go directly to the first step.</p>
<p>Otherwise, let's set up a basic Next.js app with the default ESLint configuration and Vitest, and push it to a GitHub repo.</p>
<h4 id="heading-create-a-nextjs-app">Create a Next.js app</h4>
<p>Navigate into the directory where you want to create the new project folder, then run the following command in your terminal:</p>
<pre><code class="lang-bash">npx create-next-app@latest
</code></pre>
<p>When prompted with the installation options, make sure you choose to use ESLint in your project. This will ensure that ESLint is properly installed and a <code>lint</code> script is created in the package.json. </p>
<p>Wait for <code>create-next-app</code> to create the folder and install the project dependencies. Once it's done, navigate into the new folder and start the dev server:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> &lt;your-project-name&gt;
npm run dev
</code></pre>
<h4 id="heading-set-up-vitest">Set up Vitest</h4>
<p>Let's add Vitest to the project and add some automated tests to run in the CI/CD pipeline.</p>
<p>First, install <code>vitest</code> and the dev dependencies needed:</p>
<pre><code class="lang-bash">npm install -D vitest @vitejs/plugin-react jsdom @testing-library/react
</code></pre>
<p>Create a <code>vitest.config.js</code> file (or <code>vitest.config.ts</code> if using TypeScript) with the following content:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { defineConfig } <span class="hljs-keyword">from</span> <span class="hljs-string">'vitest/config'</span>
<span class="hljs-keyword">import</span> react <span class="hljs-keyword">from</span> <span class="hljs-string">'@vitejs/plugin-react'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> defineConfig({
  <span class="hljs-attr">plugins</span>: [react()],
  <span class="hljs-attr">test</span>: {
    <span class="hljs-attr">environment</span>: <span class="hljs-string">'jsdom'</span>,
  },
})
</code></pre>
<p>And finally, add the <code>test</code> script to the package.json:</p>
<pre><code> <span class="hljs-string">"test"</span>: <span class="hljs-string">"vitest --no-watch"</span>
</code></pre><p>Note that I added the no-watch option to the test script. This prevents Vitest from starting in the default watch mode in dev environment.</p>
<p>Now, you can add tests for your project. If you don't know how to start, you can check out <a target="_blank" href="https://nextjs.org/docs/app/building-your-application/testing/vitest#creating-your-first-vitest-unit-test">this guide</a> for some examples.</p>
<h4 id="heading-push-the-project-to-github">Push the project to GitHub</h4>
<p>Log in into your GitHub account and create new repository. Once your are done, you can connect the local repo with the one you just created, adding this repo as the remote. Then push the changes:</p>
<pre><code class="lang-bash">git add .
git commit -m <span class="hljs-string">"first commit"</span>
git remote add origin git@github.com:&lt;your-user-name&gt;/&lt;your-repo-name&gt;.git
git push origin main
</code></pre>
<p>You should be now ready to continue to the interesting part of this tutorial. :)</p>
<h3 id="heading-step-2-set-a-git-hook">Step 2: Set a Git Hook</h3>
<p>A Git hook is a script that allows you to run some event within the Git lifecycle. In this case we will be using Husky.</p>
<p><a target="_blank" href="https://typicode.github.io/husky/">Husky</a> is a pre-commit hook for Git that allows you maintain code quality by executing some task upon committing or pushing. You can run various checks before making a commit with new changes, such as linting the code and running automated tests.</p>
<p>By implementing these checks, you can avoid wasting time and resources by catching issues in advance before triggering the GitHub Actions workflow.  </p>
<p>Let’s start by adding Husky to the project with the following command:</p>
<pre><code class="lang-bash">npm install --save-dev husky
</code></pre>
<p>Next, let’s set up the project using the Husky init command:</p>
<pre><code class="lang-bash">npx husky init
</code></pre>
<p>After running this command, you will notice that a pre-commit file was created under <code>./husky</code>. Also, a <code>“prepare”</code> script was added in the package.json.</p>
<p>If you open the pre-commit file inside <code>./husky</code>, you will find the following content:</p>
<pre><code class="lang-bash">npm <span class="hljs-built_in">test</span>
</code></pre>
<p>As its name suggests, this file contains the code that executes before completing a commit. With everything set up as described, tests will run each time you attempt to create a new commit and new commits will be added only if all tests pass. </p>
<h4 id="heading-adding-more-git-hooks">Adding more git hooks</h4>
<p>Now, let’s change the content in the pre-commit file so the code linter also executes before creating a new commit. </p>
<p>You can open your preferred code editor and add <code>npm run lint</code> (or the corresponding ESLint script if you’re not using Next.js) in a new line in the pre-commit file. Alternatively, you can simply run the following command from the root folder of your project:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">echo</span> <span class="hljs-string">"npm run lint"</span> &gt;&gt; ./.husky/pre-commit
</code></pre>
<p>Now, each time you attempt to make a new commit, the tests and the linter will run, and the commit will be created – only if all tests are passing and no errors are found in the code.</p>
<h4 id="heading-setting-up-lint-staged">Setting up lint-staged</h4>
<p>You can go one step further and include a tool called <a target="_blank" href="https://github.com/lint-staged/lint-staged">lint-staged</a>. This tool will be especially useful if your project is large, because it allows you to run the Git hooks only for staged files. In this case, it will lint only the files that will be committed, avoiding wasting time by linting the entire project.</p>
<p>To start using lint-staged, let's add it as a dev dependency to the project:</p>
<pre><code class="lang-bash">npm install --save-dev lint-staged
</code></pre>
<p>There are <a target="_blank" href="https://github.com/lint-staged/lint-staged?tab=readme-ov-file#configuration">different ways to configure lint-staged</a> and you can choose the one that best suits your needs. I will add a <code>lint-staged</code> script and object to the package.json of my project with the following content:</p>
<pre><code class="lang-js">  <span class="hljs-string">"scripts"</span>: {
    <span class="hljs-string">"dev"</span>: <span class="hljs-string">"next dev"</span>,
    <span class="hljs-string">"build"</span>: <span class="hljs-string">"next build"</span>,
    <span class="hljs-string">"start"</span>: <span class="hljs-string">"next start"</span>,
    <span class="hljs-string">"lint"</span>: <span class="hljs-string">"next lint"</span>,
    <span class="hljs-string">"test"</span>: <span class="hljs-string">"vitest --no-watch"</span>,
    <span class="hljs-string">"prepare"</span>: <span class="hljs-string">"husky"</span>
  },
  <span class="hljs-string">"lint-staged"</span>: {
    <span class="hljs-string">"*.{js, jsx,ts,tsx}"</span>: [
        <span class="hljs-string">"eslint --fix"</span>
        ]
    },
</code></pre>
<p>Now, I can replace <code>npm run lint</code> with <code>npm run lint-staged</code> in the pre-commit file.</p>
<p>Each time I make a new commit, any <code>js</code>, <code>jsx</code>, <code>ts</code>, or <code>tsx</code> staged files will be linted and, if there are fixable issues, they will be automatically fixed.</p>
<p>Let's test that the pre-commit hook is working as expected by:</p>
<ol>
<li>Running <code>git add  .</code></li>
<li>Running <code>git commit</code></li>
<li>Waiting for the linter to run and entering a commit message when prompted</li>
<li>Running <code>git log</code> to confirm that the commit was properly created</li>
</ol>
<p>If you want, you can add more checks to your pre-commit file to fit your project's needs. For example, you could run a tool like Prettier to automatically format your code, or <a target="_blank" href="https://commitlint.js.org/">commitlint</a> to lint your commit messages.</p>
<p>Now, let’s move on to setting up a GitHub Actions workflow for the project. </p>
<h3 id="heading-step-3-create-a-github-actions-workflow">Step 3: Create a GitHub Actions Workflow</h3>
<p>With the first part complete, we can move on to the next step. Here, you will add a GitHub Actions workflow to ensure the smooth integration of changes into the entire project.</p>
<h4 id="heading-github-actions-basics">GitHub Actions Basics</h4>
<p>GitHub Actions is a CI/CD platform that allows you to automate the building, testing, and deployment of your project. It also lets you perform actions when certain activities happen in your repository, such as opening a pull request or creating an issue.</p>
<p>GitHub Actions are configured through workflows defined in YAML files. These workflows typically run when triggered by an event in the repository, but they can also be scheduled or run manually.</p>
<p>Workflows are located in the <code>.github/workflows</code> folder and run different jobs. Each job includes a set of steps that run in order on the same runner or server. A step can be either a shell script or an action (a reusable piece of code that helps reduce repetitive code in your workflows). </p>
<p>Let's put all this together by creating the first workflow.</p>
<h4 id="heading-creating-a-workflow-to-execute-when-you-push-to-main-branch">Creating a workflow to execute when you push to main branch</h4>
<p>First create a <code>.github/workflows/</code> under your project root. Then create a <code>run-test.yml</code> file. You will be adding content to this file to create a CI workflow.</p>
<p>The first line is optional and includes a name for the workflow. It will appear at the "Actions" tab in the GitHub repo:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">Run</span> <span class="hljs-string">linter</span> <span class="hljs-string">and</span> <span class="hljs-string">tests</span> <span class="hljs-string">on</span> <span class="hljs-string">push</span>
</code></pre>
<p>Then, you will use the <code>on</code> key to define the event or events that will trigger the workflow run. This can be an event in your repo or a time schedule. In this case, let's set it to run each time a push to the repo happens:</p>
<pre><code class="lang-yml"><span class="hljs-attr">on:</span>
  <span class="hljs-string">push</span>
</code></pre>
<p>You can also set options below the <code>on</code> keyword to limit the execution of a workflow to some branch or files – for example to run only on push to main branch:</p>
<pre><code class="lang-yml"><span class="hljs-attr">on:</span>
  <span class="hljs-attr">push:</span>
    <span class="hljs-attr">branches:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">main</span>
</code></pre>
<p>Below this, you will add the <code>jobs</code> key. It groups all the jobs in the workflow, followed by the name of the first job, in this case <code>run-linter-and-tests</code>. </p>
<p>The lines below that define workflow properties, configuring it to run on the latest version of an Ubuntu Linux runner and grouping all the steps that run on this job.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">run-linter-and-tests:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>

    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Checkout</span> <span class="hljs-string">code</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v4</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Install</span> <span class="hljs-string">dependencies</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">i</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Lint</span> <span class="hljs-string">code</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">run</span> <span class="hljs-string">lint</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Run</span> <span class="hljs-string">tests</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">test</span>
</code></pre>
<p>As mentioned before, each step can be either a shell script or an action. You can see the difference between the first and the second step in the previous code. </p>
<p>The first one specifies with the <code>uses</code> keyword that will run the <code>actions/checkout</code>. This action is used to checkout the repository onto the runner so the workflow can use the repository code. The second step <code>Install dependencies</code> uses the <code>run</code> keyword to tell the job to execute the <code>npm i</code> command on the runner.</p>
<p>This is the complete resulting file:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">CI</span> <span class="hljs-string">workflow</span>
<span class="hljs-attr">on:</span>
  <span class="hljs-string">push</span>

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">run-linter-and-tests:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>

    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Checkout</span> <span class="hljs-string">code</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v4</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">npm</span> <span class="hljs-string">install</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">i</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Lint</span> <span class="hljs-string">code</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">run</span> <span class="hljs-string">lint</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Run</span> <span class="hljs-string">tests</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">test</span>
</code></pre>
<p>Let's commit the changes and push them to the GitHub repository.</p>
<p>Now each time you push to your repository, the workflow will trigger. If you click on the "Actions" tab in your GitHub repository navigation bar, you will find a list of all the runs from all your workflows and its complete logs.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/Screenshot-2024-07-03-at-12.13.05-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>"Actions" tab in a GitHub repository navigation bar</em></p>
<p>Also, you will see that in the GitHub repository's "Code" tab, a green checkmark appears next to the last commit message. This means that workflows ran and finished successfully. </p>
<p>When jobs are still running, you'll see a brown dot, and a red cross when a workflow finished with an error.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/Screenshot_.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h4 id="heading-adding-a-second-workflow-to-run-when-a-pr-is-created">Adding a second workflow to run when a PR is created</h4>
<p>Each repository can have one or more workflows, so let's add a second workflow to run each time a PR is created. Let's run the code coverage report each time a PR is opened against the main branch of the repo.</p>
<p>First, create and checkout a new <code>add-wf</code> branch:</p>
<pre><code class="lang-yaml"><span class="hljs-string">git</span> <span class="hljs-string">checkout</span> <span class="hljs-string">-b</span> <span class="hljs-string">add-wf</span>
</code></pre>
<p>Then, create a new YAML file under the <code>.github/workflows</code> directory and start adding some content on it.</p>
<p>First, let's add the name and when to run the workflow with the <code>on</code> keyword:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">Run</span> <span class="hljs-string">Coverage</span> <span class="hljs-string">on</span> <span class="hljs-string">PR</span>
<span class="hljs-attr">on:</span> <span class="hljs-string">pull_request</span>
</code></pre>
<p>After that, you will use the <code>jobs</code> keyword to describe the jobs to run. Let's define the first one as <code>build-and-run-coverage</code> to run in <code>ubuntu-latest</code> runner:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">build-and-run-coverage:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
</code></pre>
<p>Now, let's add <code>steps</code> for this job:</p>
<pre><code class="lang-yaml">  <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Checkout</span> <span class="hljs-string">code</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v4</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Install</span> <span class="hljs-string">dependencies</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">i</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Build</span> <span class="hljs-string">code</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">run</span> <span class="hljs-string">build</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Run</span> <span class="hljs-string">tests</span> <span class="hljs-string">and</span> <span class="hljs-string">coverage</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">run</span> <span class="hljs-string">coverage</span>
</code></pre>
<p>Following is the complete resulting code:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">Run</span> <span class="hljs-string">Coverage</span> <span class="hljs-string">on</span> <span class="hljs-string">PR</span>
<span class="hljs-attr">on:</span> <span class="hljs-string">pull_request</span>

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">build-and-run-coverage:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>

      <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Checkout</span> <span class="hljs-string">code</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v4</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Install</span> <span class="hljs-string">dependencies</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">i</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Build</span> <span class="hljs-string">code</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">run</span> <span class="hljs-string">build</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Run</span> <span class="hljs-string">tests</span> <span class="hljs-string">and</span> <span class="hljs-string">coverage</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">run</span> <span class="hljs-string">coverage</span>
</code></pre>
<p>Now, you can push the change to your GitHub repo:</p>
<pre><code class="lang-bash">git add .
git commit -m <span class="hljs-string">'add a wf to run on opened PR'</span>
git push origin add-wf
</code></pre>
<p>Now you can open a PR against your <code>main</code> branch and and wait for the workflow to complete.</p>
<h5 id="heading-comment-coverage-report-in-the-pr">Comment coverage report in the PR</h5>
<p>As mentioned earlier in this article, actions are reusable pieces of code that avoid repetitive code in the workflow. One cool thing about them is that there are many already written by the community that you can use in your workflows, saving lots of time.</p>
<p>To complete the workflow we created, let's add a new step that uses an action to report coverage results as a comment on the pull request.</p>
<p>First, let's modify the <code>permissions</code> keyword to ensure the workflow has the right access to content and to create comments:</p>
<pre><code class="lang-yaml"> <span class="hljs-attr">permissions:</span>
      <span class="hljs-attr">contents:</span> <span class="hljs-string">read</span>
      <span class="hljs-attr">pull-requests:</span> <span class="hljs-string">write</span>
</code></pre>
<p>Then, let's use the <a target="_blank" href="https://github.com/marketplace/actions/vitest-coverage-report">Vitest Coverage Report</a> action by adding a <code>step</code> into the <code>build-and-run-coverage</code> job:</p>
<pre><code class="lang-yaml"><span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Report</span> <span class="hljs-string">Coverage</span>
        <span class="hljs-attr">uses:</span>  <span class="hljs-string">davelosert/vitest-coverage-report-action@v2</span>
</code></pre>
<p>The final <code>yaml</code> file will look like this:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">Run</span> <span class="hljs-string">Coverage</span> <span class="hljs-string">on</span> <span class="hljs-string">PR</span>
<span class="hljs-attr">on:</span> <span class="hljs-string">pull_request</span>

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">build-and-run-coverage:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>

    <span class="hljs-attr">permissions:</span>
      <span class="hljs-attr">contents:</span> <span class="hljs-string">read</span>
      <span class="hljs-attr">pull-requests:</span> <span class="hljs-string">write</span>

    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Checkout</span> <span class="hljs-string">code</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v4</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Install</span> <span class="hljs-string">dependencies</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">i</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Build</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">run</span> <span class="hljs-string">build</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Run</span> <span class="hljs-string">test</span> <span class="hljs-string">and</span> <span class="hljs-string">coverage</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">run</span> <span class="hljs-string">coverage</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Report</span> <span class="hljs-string">Coverage</span>
        <span class="hljs-attr">uses:</span>  <span class="hljs-string">davelosert/vitest-coverage-report-action@v2</span>
</code></pre>
<p>There is one more step to ensure all works as expected. You must add the <code>json-summary</code> reporter in the Vitest configuration:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> { defineConfig } <span class="hljs-keyword">from</span> <span class="hljs-string">"vitest/config"</span>;
<span class="hljs-keyword">import</span> react <span class="hljs-keyword">from</span> <span class="hljs-string">"@vitejs/plugin-react"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> defineConfig({
  plugins: [react()],
  test: {
    environment: <span class="hljs-string">"jsdom"</span>,
    coverage: {
      provider: <span class="hljs-string">"v8"</span>,
      extension: [<span class="hljs-string">".tsx"</span>],
      reporter: [<span class="hljs-string">'text'</span>, <span class="hljs-string">'json-summary'</span>, <span class="hljs-string">'json'</span>],
    },
  },
});
</code></pre>
<p>Now, make some changes in your project and add corresponding tests to check if the workflow is working as expected. </p>
<p>Once you push your changes to the GitHub repo, open a PR against the main branch of your project. After the workflows finish running, you should see a comment showing the coverage result:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/Screen-Shot-2024-07-12-at-19.18.05.png" alt="Image" width="600" height="400" loading="lazy">
<em>Coverage Report in a pull request comment</em></p>
<h3 id="heading-step-4-deploy-the-project">Step 4: Deploy the Project</h3>
<p>As a last step in this tutorial, let's deploy the project on <a target="_blank" href="https://vercel.com/">Vercel</a>. You will set up an automatic deployment through Git that will trigger a redeploy each time new changes are pushed or merged into the main branch.</p>
<p>First, log in to your Vercel account, or create one if you don't already have one. Then, in your dashboard, click on "Add New Project" and click on the "Import" button next to your repository name in the "Import Git Repository" section. </p>
<p>If you don't see your repository listed, it may be due to your GitHub app permissions configuration. You can manage them in your settings section in your GitHub account.</p>
<p>Finally, choose a name for the project in the "Configure Project" section and click on the "Deploy" button. You can now see the deploy details by clicking on the "Deployment" link.</p>
<p>Vercel automatic deployments ensure that the deployed project is always updated with the latest changes. They also have the benefit of <a target="_blank" href="https://vercel.com/docs/deployments/preview-deployments">Preview Deployments</a>, a preview URL that lets you test new features in advance of merging changes into production.</p>
<p>If you have followed along with the tutorial, with this step completed, you'll have completed the CD part of the CI/CD pipeline for your project. Now, you can be sure any code that is pushed to the main branch is linted and tested, and once all checks pass, it is automatically pushed to production.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this guide, you learned about the importance of CI/CD in today’s software development ecosystem and its main benefits. You also took your first steps in this area by creating your own CI/CD pipeline for your project, learning how to use Husky and GitHub Actions.</p>
<p>Now, you can keep learning more about these tools and improve your CI/CD pipeline by customizing it to better fit your project's needs.</p>
<p>I hope you were able to gain some new knowledge and enjoyed following along. Thanks for reading!</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
