<?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" version="2.0"><channel><title><![CDATA[aythejuggernaut's blog]]></title><description><![CDATA[I'm a curious thinker. Exploring backend and blockchain technologies so I will write mostly about those aspect; frontend development will be once in a while.]]></description><link>https://aythejuggernaut.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Tue, 01 Sep 2026 22:50:21 GMT</lastBuildDate><atom:link href="https://aythejuggernaut.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Docker Port Forwarding: A Step-by-Step Guide to Exposing Container Services]]></title><description><![CDATA[When working with Docker containers, communicating with the outside world can be a challenge. By default, traffic coming into our host machine are not routed into the container. Containers are isolated from the host machine and other containers, so t...]]></description><link>https://aythejuggernaut.hashnode.dev/docker-port-forwarding-a-step-by-step-guide-to-exposing-container-services</link><guid isPermaLink="true">https://aythejuggernaut.hashnode.dev/docker-port-forwarding-a-step-by-step-guide-to-exposing-container-services</guid><category><![CDATA[Devops]]></category><category><![CDATA[Docker]]></category><category><![CDATA[docker images]]></category><category><![CDATA[Dockerfile]]></category><category><![CDATA[Docker compose]]></category><category><![CDATA[Frontend Development]]></category><category><![CDATA[backend]]></category><category><![CDATA[containers]]></category><dc:creator><![CDATA[Ayoola Adewale]]></dc:creator><pubDate>Tue, 11 Jun 2024 03:42:31 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1718072968990/95835c93-cbc8-4f44-98fb-296b848a6f46.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When working with Docker containers, communicating with the outside world can be a challenge. By default, traffic coming into our host machine are not routed into the container. Containers are isolated from the host machine and other containers, so they have their own isolated set of ports that can receive traffic.</p>
<p>That's where Docker port forwarding comes in - a powerful feature that allows you to expose container services to the host machine and beyond. In this article, we'll take a hands-on approach to exploring Docker port forwarding, walking you through the steps to expose your container services and unlock the full potential of your containerized applications.</p>
<h2 id="heading-what-is-docker">What is Docker?</h2>
<p>According to Docker Documentation, Docker provides the ability to package and run an application in a loosely isolated environment called a container. The isolation and security lets you run many containers simultaneously on a given host. Containers are lightweight and contain everything needed to run the application, so<br />you don't need to rely on what's installed on the host.</p>
<h2 id="heading-what-is-port-forwarding">What is Port Forwarding?</h2>
<p>Basically, when we make a request to a given port on our host machine or local network, we automatically forward that request into a port inside the container. For example, if you forward host port 8000 to container port 8080, any requests made to <a target="_blank" href="http://localhost:8000">localhost:8000</a> on the host machine will be forwarded to <a target="_blank" href="http://localhost:8080">localhost:8080</a> inside the container, where your application can handle the request.</p>
<p>Now that we've demystified Docker port forwarding, it's time to put our knowledge into action by building a simple web server application using node.js.</p>
<ol>
<li><p>Create a folder</p>
</li>
<li><p>Inside the folder, create a package.json file</p>
</li>
</ol>
<pre><code class="lang-javascript">{
  <span class="hljs-string">"dependencies"</span>: {
    <span class="hljs-string">"express"</span>: <span class="hljs-string">"*"</span>
  },
  <span class="hljs-string">"scripts"</span>: {
    <span class="hljs-string">"start"</span>: <span class="hljs-string">"node index.js"</span>
  }
}
</code></pre>
<ol start="3">
<li>Create an index.js file</li>
</ol>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">"express"</span>);

<span class="hljs-keyword">const</span> app = express();

app.get(<span class="hljs-string">"/"</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
    res.send(<span class="hljs-string">"Container Port Forwarding"</span>);
});

app.listen(<span class="hljs-number">8000</span>, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Listening on port 8000"</span>);
});
</code></pre>
<ol start="4">
<li>Create a dockerfile</li>
</ol>
<pre><code class="lang-dockerfile"><span class="hljs-comment"># Specify a base image</span>
<span class="hljs-keyword">FROM</span> node:alpine

<span class="hljs-keyword">WORKDIR</span><span class="bash"> /usr/app</span>
<span class="hljs-keyword">COPY</span><span class="bash"> ./ ./</span>

<span class="hljs-comment"># Install some dependencies</span>
<span class="hljs-keyword">RUN</span><span class="bash"> npm install</span>

<span class="hljs-comment"># Default command</span>
<span class="hljs-keyword">CMD</span><span class="bash"> [ <span class="hljs-string">"npm"</span>, <span class="hljs-string">"start"</span> ]</span>
</code></pre>
<ol start="5">
<li><p>Build Image from Dockerfile:</p>
<p> a. Open your terminal and run:</p>
</li>
</ol>
<pre><code class="lang-bash">docker build -t aythejuggernaut/testapp .
</code></pre>
<p>Note: We use the -t flag to tag our image with a name, so whenever we want to use the image we make use of the tagged name instead of the image id.</p>
<p>Result:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1718076369220/a4d715f2-1286-4bca-8656-2bbd4545bba9.png" alt class="image--center mx-auto" /></p>
<ol start="6">
<li>Map the port</li>
</ol>
<pre><code class="lang-bash">docker run -p 8080:8080 aythejuggernaut/testapp
</code></pre>
<p>Result:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1718076490761/0bb6abc5-75e1-4db6-b624-41faea630bcd.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1718076670296/3b483a5d-d870-45e3-9ce8-93f11a7d07b7.png" alt class="image--center mx-auto" /></p>
<p>Note: By default, our container can make a request on its own. We saw that when we install a dependency during the build process. So this is only talking about incoming request.</p>
<p>Thanks for joining me on this journey into Docker port forwarding! You now have the tools to bridge the gap between containers and the outside world. Happy coding!🚀</p>
]]></content:encoded></item><item><title><![CDATA[Demystifying Tree Data Structure: A Journey into the World of Hierarchical Structures]]></title><description><![CDATA[Ever heard of trees in the world of programming? No, not the ones in your backyard but a fascinating concept that helps organize information in the digital world using a tree-like structure.
Whether you're a coding newbie or a seasoned developer, und...]]></description><link>https://aythejuggernaut.hashnode.dev/demystifying-tree-data-structure-a-journey-into-the-world-of-hierarchical-structures</link><guid isPermaLink="true">https://aythejuggernaut.hashnode.dev/demystifying-tree-data-structure-a-journey-into-the-world-of-hierarchical-structures</guid><category><![CDATA[data structures]]></category><category><![CDATA[TreeTraversals]]></category><category><![CDATA[programming languages]]></category><category><![CDATA[algorithms]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Computer Science]]></category><dc:creator><![CDATA[Ayoola Adewale]]></dc:creator><pubDate>Thu, 29 Feb 2024 00:26:57 GMT</pubDate><content:encoded><![CDATA[<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708955343126/c24b5f11-34cc-48ab-b2e6-6d259ce38010.jpeg" alt class="image--center mx-auto" /></p>
<p>Ever heard of trees in the world of programming? No, not the ones in your backyard but a fascinating concept that helps organize information in the digital world using a tree-like structure.</p>
<p>Whether you're a coding newbie or a seasoned developer, understanding the basics of tree structures can open up exciting possibilities in organizing data and creating smart algorithms. In this journey, we'll simplify the complex world of trees, starting from the basics and going even further. We'll break down the intricate details into easy-to-understand parts, making it a breeze to grasp.</p>
<p>So, get ready to explore the simplicity, elegance, and usefulness of tree structures in the coding universe. Welcome to "Demystifying Tree Data Structure: A Journey into the World of Hierarchical Structures! Let's dive in.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708955087568/309eaa49-6f81-4dc3-8fc9-69ac6091ba48.webp" alt="Tree data structure" class="image--center mx-auto" /></p>
<p>A tree data structure is <strong>a hierarchical structure that is used to represent and organize data in a way that is easy to navigate and search</strong>. Trees can have zero or more child nodes, so we have a parent-child relationship that is unidirectional.</p>
<p>A tree usually starts with a single root or parent node and every child of the tree descends from that root node; it's like an inversed tree. Within a tree, we can have <strong>sub-trees</strong>; from the diagram above, the sub-trees are [10, 5, 15] and [40, 35, 45]. Also, we have <strong>leaf nodes</strong> which are nodes that resides at the end of a branch in a tree and does not have any descendants; from the diagram above, the leaf nodes are [5, 15, 35, 45].</p>
<p>Tree data structures are of paramount importance as they find everyday applications, ranging from representing family trees to organizing the structure of web pages to representing the structure of a program or code.</p>
<p>One way to represent the structure of a program or code is through an abstract syntax tree (AST). An <strong>abstract syntax tree</strong> (<strong>AST</strong>) is a data structure used in <a target="_blank" href="https://en.wikipedia.org/wiki/Computer_science">computer science</a> to represent the structure of a program or code snippet. It is a <a target="_blank" href="https://en.wikipedia.org/wiki/Tree_(data_structure)">tree</a> representation of the <a target="_blank" href="https://en.wikipedia.org/wiki/Abstract_syntax">abstract syntactic</a> structure of text (often <a target="_blank" href="https://en.wikipedia.org/wiki/Source_code">source code</a>) written in a <a target="_blank" href="https://en.wikipedia.org/wiki/Formal_language">formal language</a>.</p>
<p>In the context of web development, the <a target="_blank" href="https://en.wikipedia.org/wiki/Document_Object_Model">Document Object Model (DOM)</a> tree plays a pivotal role. It serves as a structured and standardized interface, allowing web browsers and JavaScript to seamlessly interact with and manipulate the content of a web page.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1709120735747/57390c37-4f0c-41e8-ae40-758ef1904548.png" alt class="image--center mx-auto" /></p>
<h1 id="heading-binary-tree"><strong>BINARY TREE</strong></h1>
<p>A <strong>Binary Tree Data Structure</strong> is a hierarchical data structure in which each node has at most two children, referred to as the <strong>left child</strong> and the <strong>right child</strong>. It is commonly used in computer science for efficient storage and retrieval of data, with various operations such as insertion, deletion, and traversal.</p>
<pre><code class="lang-javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Node</span> </span>{
  <span class="hljs-keyword">constructor</span>(value) {
    <span class="hljs-built_in">this</span>.left = <span class="hljs-literal">null</span>;
    <span class="hljs-built_in">this</span>.right = <span class="hljs-literal">null</span>;
    <span class="hljs-built_in">this</span>.value = value;
  }
}
</code></pre>
<p>Several rules and properties govern binary trees. Here are some fundamental rules applied to binary trees:</p>
<ul>
<li><p>Each node in a binary tree contains a data element, often referred to as the "key" or "value."</p>
</li>
<li><p>Nodes may have zero, one, or two children.</p>
</li>
<li><p>Each child node can only have one parent.</p>
</li>
</ul>
<p>Binary trees are categorized into several special types based on their structural or functional properties. Here are some common types of binary trees:</p>
<ol>
<li><p><strong>Complete binary tree</strong>: A complete binary tree is a binary tree in which every level, except possibly the last, is completely filled, and all nodes are as left as possible.</p>
<pre><code class="lang-javascript">         A
       /   \
      B     C
     / \   
    D   E
</code></pre>
</li>
<li><p><strong>Perfect binary tree</strong>: A perfect binary tree is a specific type of binary tree in which all levels are completely filled, and all leaf nodes are at the same level. Additionally, every internal node has exactly two children. This means that every level of the tree is fully occupied, and the tree is perfectly balanced.</p>
<p> This type of binary tree is really efficient and desirable. When binary trees are perfect they have some interesting properties:</p>
<ul>
<li><p>On each level, the total number of nodes doubles as we move down the tree.</p>
</li>
<li><p>The total number of nodes on the last level is equal to the number of nodes on other levels plus 1.</p>
</li>
</ul>
</li>
</ol>
<pre><code class="lang-javascript">            A
          /   \
         B     C
        / \   / \
       D   E F   G
</code></pre>
<h1 id="heading-binary-search-tree"><strong>BINARY SEARCH TREE</strong></h1>
<p>A binary search tree (BST) is a fundamental data structure in computer science that organizes and stores data in a way that enables efficient search, insertion, and deletion operations. The defining characteristic of a binary search tree is the ordering of its nodes.</p>
<p>Some fundamental rules applied to binary search trees:</p>
<ul>
<li><p>The left child of a node contains a value that is less than or equal to the parent node's value.</p>
</li>
<li><p>The right child of a node contains a value that is greater than the parent node's value.</p>
</li>
</ul>
<p>This rules ensures that searching for a specific value can be done efficiently by traversing the tree based on the comparison of values.</p>
<p>Some key features and operations associated with binary search tree:</p>
<ol>
<li><p><strong>Search/Lookup Operation</strong>: The search operation in a BST is logarithmic in time complexity, i.e., O(log n) since at each step, the search space is effectively divided in half. This makes BSTs particularly efficient for search operations.</p>
</li>
<li><p><strong>Insertion Operation</strong>: Inserting a new element into a BST involves comparing the value of the new element with the values of nodes as it traverses the tree. Based on the comparisons, the new node is then appropriately placed as a left or right child.</p>
</li>
<li><p><strong>Deletion Operation</strong>: There's a bit of tough logic that happens when deleting a node from a BST, this operation requires careful consideration of its children. If the node has no children, it can be removed directly. If it has one child, the child takes its place. If it has two children, it can be replaced with its in-order successor (or predecessor), maintaining the BST properties.</p>
</li>
</ol>
<pre><code class="lang-javascript"><span class="hljs-comment">// Binary Search Tree</span>

<span class="hljs-comment">//         50</span>
<span class="hljs-comment">//       /    \</span>
<span class="hljs-comment">//      33     65</span>
<span class="hljs-comment">//     /  \   /  \</span>
<span class="hljs-comment">//    15  37 60   78</span>
</code></pre>
<p>For example, let's say we want to delete 65. First, from the parent/root node we need to get to 65, and then decided which node is going to take its place. In this case, the right child node (78) is greater than left child node (60), so the right child node (78) replace 65 then 60 becomes the left child node of 78.</p>
<h1 id="heading-balanced-vs-unbalanced-bst"><strong>BALANCED VS UNBALANCED BST</strong></h1>
<p>A balanced BST is a tree in which the heights of the left and right subtrees of every node differ by at most one. This ensures that the tree is relatively evenly distributed and resembles a well-structured hierarchy. Operations such as search, insertion, and deletion in a balanced BST have an average time complexity of O(log n) as each comparison reduces the search space by half, where n is the number of nodes.</p>
<p>An unbalanced BST is a tree in which the heights of the left and right subtrees of some nodes differ significantly. In extreme cases, an unbalanced BST can degenerate into a linked list, where all nodes have only one child. Operations on an unbalanced BST can have a worst-case time complexity of O(n), where n is the number of nodes. Unbalanced trees may occur due to poorly ordered insertions or deletions without proper rebalancing.</p>
<p><strong>How do we balance a tree?</strong> Ensuring the balance of a tree involves preserving its structural integrity, thereby guaranteeing that search, insertion, and deletion operations retain efficiency with a logarithmic time complexity. Algorithms such as AVL trees and Red-Black trees ensure that our binary search tree remains balanced.</p>
<h2 id="heading-pros-and-cons-of-a-bst"><strong>PROS AND CONS OF A BST</strong></h2>
<p><strong>PROS</strong></p>
<ul>
<li><p>Searching in a well-balanced BST has a time complexity of O(log n), making it efficient for large datasets.</p>
</li>
<li><p>The ordering of keys in a BST provides a natural way to traverse and process data in a sorted order using in-order traversal.</p>
</li>
<li><p>BSTs are relatively straightforward to implement, and their logic is easy to understand, making them suitable for a variety of applications.</p>
</li>
</ul>
<p><strong>CONS</strong></p>
<ul>
<li><p>It has no O(1) operation because we always have to do some traversal down through the tree for any sort of operation.</p>
</li>
<li><p>If the tree becomes unbalanced (skewed), the performance of operations degrades to O(n), resembling a linked list. This is a significant drawback.</p>
</li>
<li><p>The efficiency of a BST is highly dependent on the order in which elements are inserted. Poor insertion order can lead to unbalanced trees.</p>
</li>
<li><p>Deleting a node with two children in a BST can be complex and may require additional steps, such as finding the in-order successor or predecessor.</p>
</li>
</ul>
<h3 id="heading-bst-vs-hash-tables-vs-array"><strong>BST vs. Hash Tables vs. Array</strong></h3>
<p><strong>BST:</strong></p>
<ul>
<li><p>Efficient search with O(log n) time complexity in balanced trees.</p>
</li>
<li><p>Ordered structure, suitable for maintaining order.</p>
</li>
<li><p>More memory-efficient than hash tables.</p>
</li>
</ul>
<p><strong>Hash Tables:</strong></p>
<ul>
<li><p>Constant time complexity (O(1)) on average for search, insertion, and deletion.</p>
</li>
<li><p>Unordered structure, efficient for quick access.</p>
</li>
<li><p>Can consume more memory due to handling collisions.</p>
</li>
</ul>
<p><strong>Arrays:</strong></p>
<ul>
<li><p>Efficient for indexed access with O(log n) for sorted arrays.</p>
</li>
<li><p>Ordered by index, suitable for quick indexed access.</p>
</li>
<li><p>Memory-efficient for static datasets.</p>
</li>
</ul>
<p>Note: BSTs are efficient for ordered data and dynamic datasets, hash tables excel in quick access scenarios, and arrays are optimal for indexed access and static datasets.</p>
<p>In wrapping up our discussion on tree data structures, let's switch gears and have some fun! How about we roll up our sleeves and build our own binary search tree? Ready to dive in?</p>
<pre><code class="lang-javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Node</span> </span>{
  <span class="hljs-keyword">constructor</span>(value) {
    <span class="hljs-built_in">this</span>.left = <span class="hljs-literal">null</span>;
    <span class="hljs-built_in">this</span>.right = <span class="hljs-literal">null</span>;
    <span class="hljs-built_in">this</span>.value = value;
  }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BinarySearchTree</span> </span>{
  <span class="hljs-keyword">constructor</span>() {
    <span class="hljs-built_in">this</span>.root = <span class="hljs-literal">null</span>;
  }

  insert(value) {
    <span class="hljs-keyword">const</span> newNode = <span class="hljs-keyword">new</span> Node(value);

    <span class="hljs-comment">// validate inputted value</span>
    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> value !== <span class="hljs-string">"number"</span>) {
      <span class="hljs-keyword">return</span> <span class="hljs-string">"Invalid input"</span>;
    }

    <span class="hljs-comment">// check if root node is empty</span>
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.root === <span class="hljs-literal">null</span>) {
      <span class="hljs-built_in">this</span>.root = newNode;
      <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>;
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-keyword">let</span> currentNode = <span class="hljs-built_in">this</span>.root;
      <span class="hljs-keyword">while</span> (<span class="hljs-literal">true</span>) {
        <span class="hljs-keyword">if</span> (currentNode.value &gt; newNode.value) {
          <span class="hljs-comment">// GO LEFT</span>
          <span class="hljs-comment">// Check if the left side of the current node is empty</span>
          <span class="hljs-keyword">if</span> (!currentNode.left) {
            currentNode.left = newNode;
            <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>;
          }
          <span class="hljs-comment">// if it's not empty</span>
          <span class="hljs-comment">// update the current node</span>
          currentNode = currentNode.left;
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (currentNode.value &lt; newNode.value) {
          <span class="hljs-comment">// GO RIGHT</span>
          <span class="hljs-comment">// Check if the right side of the current node is empty</span>
          <span class="hljs-keyword">if</span> (!currentNode.right) {
            currentNode.right = newNode;
            <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>;
          }
          <span class="hljs-comment">// if it's not empty</span>
          <span class="hljs-comment">// update the current node</span>
          currentNode = currentNode.right;
        }
      }
    }
  }

  lookup(value) {
    <span class="hljs-keyword">const</span> newNode = <span class="hljs-keyword">new</span> Node(value);
    <span class="hljs-comment">// check if root node doesn't exists</span>
    <span class="hljs-keyword">if</span> (!<span class="hljs-built_in">this</span>.root) {
      <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
    }

    <span class="hljs-keyword">let</span> currentNode = <span class="hljs-built_in">this</span>.root;

    <span class="hljs-keyword">if</span> (currentNode.value === newNode.value) {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Node found!"</span>);
      <span class="hljs-keyword">return</span> currentNode;
    }

    <span class="hljs-keyword">while</span> (currentNode) {
      <span class="hljs-keyword">if</span> (currentNode.value &gt; newNode.value) {
        <span class="hljs-keyword">if</span> (currentNode.left.value === newNode.value) {
          <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Node was found on left wing"</span>);
          <span class="hljs-keyword">return</span> currentNode.left;
        }
        currentNode = currentNode.left;
      } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (currentNode.value &lt; newNode.value) {
        <span class="hljs-keyword">if</span> (currentNode.right.value === newNode.value) {
          <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Node was found on right wing"</span>);
          <span class="hljs-keyword">return</span> currentNode.right;
        }
        currentNode = currentNode.right;
      } <span class="hljs-keyword">else</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-string">"Node not found"</span>;
      }
    }
  }
}

<span class="hljs-comment">//        9</span>
<span class="hljs-comment">//    4       20</span>
<span class="hljs-comment">//  1   6  15   170</span>

<span class="hljs-keyword">const</span> tree = <span class="hljs-keyword">new</span> BinarySearchTree();
tree.insert(<span class="hljs-number">9</span>);
tree.insert(<span class="hljs-number">4</span>);
tree.insert(<span class="hljs-number">20</span>);
tree.insert(<span class="hljs-number">1</span>);
tree.insert(<span class="hljs-number">6</span>);
tree.insert(<span class="hljs-number">15</span>);
tree.insert(<span class="hljs-number">170</span>);

<span class="hljs-built_in">console</span>.log(tree.lookup(<span class="hljs-number">20</span>));
</code></pre>
<p>Congratulations 🎉🎉!</p>
<p>You've successfully built your own Binary Search Tree. I hope this hands-on experience has deepened your understanding of tree data structures. Keep exploring and experimenting with code. Happy coding!"</p>
]]></content:encoded></item><item><title><![CDATA[Effortless Styling: A Guide to Tailwind CSS Integration with EJS Templates]]></title><description><![CDATA[Two months ago, I decided to pursue the aspects of tech that I'm passionate about which are backend, cloud, and blockchain engineering. It would be extremely hard to juggle the three at once, I did some research and found out it would be best for me ...]]></description><link>https://aythejuggernaut.hashnode.dev/effortless-styling-a-guide-to-tailwind-css-integration-with-ejs-templates</link><guid isPermaLink="true">https://aythejuggernaut.hashnode.dev/effortless-styling-a-guide-to-tailwind-css-integration-with-ejs-templates</guid><category><![CDATA[Frontend Development]]></category><category><![CDATA[frontend]]></category><category><![CDATA[backend]]></category><dc:creator><![CDATA[Ayoola Adewale]]></dc:creator><pubDate>Sat, 28 Oct 2023 14:31:54 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1698494578727/3b031a1e-b2b6-4243-b630-2148385839ee.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Two months ago, I decided to pursue the aspects of tech that I'm passionate about which are backend, cloud, and blockchain engineering. It would be extremely hard to juggle the three at once, I did some research and found out it would be best for me to start with backend engineering.</p>
<p>Two weeks ago, I paused my backend engineering course because I've learned quite a lot and instead of bombarding myself with more concepts, I should build a project with what have learned so far.</p>
<p>I came up with a project called "Book Buddy", a website where people can upload their favorite books, anyone who's interested in the book can download it, comment, rate it, and probably have some discussion about the book. For days, have been procrastinating so finally, today I started the project.</p>
<p>After installing the packages that would be needed, and creating the file structure, I started creating the layout and structure for the website using EJS templating engine and CSS. Being a front-end developer, I enjoy writing CSS but I mostly use tailwindCSS instead of vanilla CSS so writing EJS with CSS wasn't giving me the flow I needed for the project.</p>
<p>I did some research, and after a few installations and configurations, I was able to get the flow I was looking for.</p>
<p>Let's embark on a little EJS + tailwindcss journey</p>
<p>make sure you have expressJS and EJS installed, then run the following command:</p>
<pre><code class="lang-javascript">npm install tailwindcss postcss autoprefixer postcss-cli
</code></pre>
<p>To set up a <code>tailwind.config.js</code> file in your project directory, which you can then customize to tailor Tailwind CSS to your specific needs; run this command:</p>
<pre><code class="lang-javascript">npx tailwindcss init -p
</code></pre>
<p>Copy and paste the following code to your 'tailwind.config.js' file</p>
<pre><code class="lang-plaintext">/** @type {import('tailwindcss').Config} */
module.exports = {
  content: ["./views/**/*.ejs"],
  theme: {
    extend: {},
  },
  plugins: [
    {
      tailwindcss: {},
      autoprefixer: {},
    },
  ],
};
</code></pre>
<p>In your public folder, create a sub-folder named 'css'; in the public/css folder create a tailwind.css file, and add the following code to the file:</p>
<pre><code class="lang-css"><span class="hljs-keyword">@tailwind</span> base;
<span class="hljs-keyword">@tailwind</span> components;
<span class="hljs-keyword">@tailwind</span> utilities;
</code></pre>
<p>Add the following script to the scripts object inside your package.json file:</p>
<p><code>"tailwind": "postcss public/css/tailwind.css -o public/css/style.css -w"</code></p>
<p>In your ejs file, add the following line of code as a test:</p>
<p><code>&lt;h1 class="bg-red-500 text-white text-2xl"&gt;I love tailwindcss, God bless the team&lt;/h1&gt;</code></p>
<p>The above code does the following:</p>
<ul>
<li><p>change the background color to red</p>
</li>
<li><p>change the text color to white</p>
</li>
<li><p>increase the font size</p>
</li>
</ul>
<p>Open your vscode terminal using <code>ctrl+shift+` </code> for windows, and <code>cmd+shift+` </code> for mac. Run the tailwind script you added to your package.json: <code>npm run tailwind</code></p>
<p>To see the effect in action, open another terminal and start your server: <code>npm start</code></p>
<p>Open your browser and load localhost with the port specified in your app.js / server.js file.</p>
<p>Voila, we're done. Enjoy the beauty of tailwindcss.</p>
]]></content:encoded></item></channel></rss>