<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Vardan Hakobyan</title>
    <description>The latest articles on DEV Community by Vardan Hakobyan (@vardanarm_7).</description>
    <link>https://dev.to/vardanarm_7</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F230403%2Fda024d33-b1d3-4e77-a260-270a9c9c3a44.png</url>
      <title>DEV Community: Vardan Hakobyan</title>
      <link>https://dev.to/vardanarm_7</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vardanarm_7"/>
    <language>en</language>
    <item>
      <title>React Keys Demystified: When Using Index as a Key Isn’t That Bad</title>
      <dc:creator>Vardan Hakobyan</dc:creator>
      <pubDate>Mon, 30 Sep 2024 12:07:18 +0000</pubDate>
      <link>https://dev.to/vardanarm_7/react-keys-demystified-when-using-index-as-a-key-isnt-that-bad-1n18</link>
      <guid>https://dev.to/vardanarm_7/react-keys-demystified-when-using-index-as-a-key-isnt-that-bad-1n18</guid>
      <description>&lt;p&gt;As React developers, we’ve all heard the mantra: “Don’t use array index as a key!” It’s repeated so often that it’s become an unquestionable rule for many. But like many rules in programming, the reality is more nuanced. Today, we’re going to explore situations where using an index as a key might not be the cardinal sin it’s often made out to be.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Keys, Reconciliation, and the Render-Commit Cycle
&lt;/h2&gt;

&lt;p&gt;Before we dive into the controversy, let’s refresh our understanding of what keys do in React and how they fit into the bigger picture.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Reconciliation Process&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;React’s reconciliation process is at the heart of its efficiency. When a component’s state or props change, React creates a new virtual DOM and compares it with the previous one. This comparison, or “diffing,” allows React to minimize actual DOM manipulations, which are costly in terms of performance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Render-Commit Cycle&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Render Phase: React calls your components to figure out what should be on the screen. It creates a new virtual DOM based on the current state and props.&lt;/li&gt;
&lt;li&gt;Reconciliation: React compares the new virtual DOM with the previous one, identifying what has changed.&lt;/li&gt;
&lt;li&gt;Commit Phase: React applies the identified changes to the actual DOM.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;The Role of Keys&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Keys play a crucial role in the reconciliation process. They help React identify which items in a list have changed, been added, or been removed. A key is a special string attribute that you need to include when creating lists of elements.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Exactly Do Keys Solve?
&lt;/h2&gt;

&lt;p&gt;Keys solve the problem of efficient list updates. When you have a dynamic list (items can be added, removed, or reordered), keys help React track which specific items have changed.&lt;/p&gt;

&lt;p&gt;Without keys (or with poorly chosen keys), React might unnecessarily recreate DOM elements that haven’t actually changed, leading to performance issues and potential bugs with component state.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Case for Using Index as a Key
&lt;/h2&gt;

&lt;p&gt;Now, let’s look at why using an index as a key isn’t always bad. Consider this scenario:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const NumberList = ({ numbers }) =&amp;gt; {
  return (
    &amp;lt;ul&amp;gt;
      {numbers.map((number, index) =&amp;gt; (
        &amp;lt;li key={index}&amp;gt;{number}&amp;lt;/li&amp;gt;
      ))}
    &amp;lt;/ul&amp;gt;
  );
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, using the index as a key is perfectly fine if:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The list is static (items are not added, removed, or reordered).&lt;/li&gt;
&lt;li&gt;The items in the list have no ids (otherwise we could use the id instead of the index).&lt;/li&gt;
&lt;li&gt;The list is never reordered or filtered.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Under these conditions, the index is stable and using it as a key won’t cause any issues.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Problem: Unstable Keys
&lt;/h2&gt;

&lt;p&gt;The issue isn’t really about using the index itself, but about using unstable keys. An index becomes problematic when it doesn’t consistently refer to the same item. This happens when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Items are added to or removed from the beginning or middle of the list.&lt;/li&gt;
&lt;li&gt;The list is reversed or sorted.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In these cases, the index of each item changes, leading React to misidentify components and potentially cause bugs or unnecessary re-renders.&lt;/p&gt;

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

&lt;p&gt;While it’s generally a good practice to use unique and stable identifiers as keys, dogmatically avoiding index as a key in all situations is unnecessary. Understanding the reconciliation process and the purpose of keys allows you to make informed decisions about when using an index is acceptable or even preferable.&lt;/p&gt;

&lt;p&gt;Remember, the key rule (pun intended) is stability. As long as your key consistently refers to the same item across re-renders, whether it’s an id, a unique attribute, or yes, sometimes even an index, you’re on the right track.&lt;/p&gt;

&lt;p&gt;So next time you reach for that index as a key, don’t feel guilty — just make sure you understand the implications and that it’s the right tool for your specific use case.&lt;/p&gt;

&lt;p&gt;P.S. You can find more information on React docs.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you want to stay updated with the latest JavaScript and software development news, join my Telegram channel: &lt;a href="https://t.me/javascriptsavvy" rel="noopener noreferrer"&gt;TechSavvy: Frontend &amp;amp; Backend&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>list</category>
      <category>key</category>
    </item>
    <item>
      <title>Job Scams: How Developers Are Tricked into Running Data-Stealing Code, and How to Spot It</title>
      <dc:creator>Vardan Hakobyan</dc:creator>
      <pubDate>Thu, 26 Sep 2024 09:45:47 +0000</pubDate>
      <link>https://dev.to/vardanarm_7/job-scams-how-developers-are-tricked-into-running-data-stealing-code-and-how-to-spot-it-41e9</link>
      <guid>https://dev.to/vardanarm_7/job-scams-how-developers-are-tricked-into-running-data-stealing-code-and-how-to-spot-it-41e9</guid>
      <description>&lt;p&gt;I recently shared a &lt;a href="https://dev.to/vardanarm_7/beware-of-malicious-code-a-developers-experience-with-a-suspicious-request-3nma"&gt;story&lt;/a&gt; about a scam job posting on Codementor where the goal was to trick developers into running malicious code on their machines. Fortunately, I discovered the issue before executing the code, and the account of the job poster has since been suspended.&lt;/p&gt;

&lt;p&gt;However, it turns out this wasn’t just a one-time occurrence. I received a similar request yesterday. The “client,” who was looking for a developer to add new features to his project, shared a private GitHub repository and asked me to run the project to verify that it worked correctly, as “it was last developed about three months ago.” When I checked the repository, I found the last commit was made just 18 hours ago. The one before that was indeed a few months old.&lt;/p&gt;

&lt;p&gt;This was the first warning sign: The author, who did the last commit yesterday, didn’t run the code before/after the commit? The commit included changes to 89(!) files.&lt;/p&gt;

&lt;p&gt;I tried to find out what was in that commit. The commit message was “Style js files” and was mostly about file formatting changes (as if someone ran &lt;code&gt;prettier&lt;/code&gt; on the entire codebase). After looking into bunch of files, I didn’t find anything immediately suspicious.&lt;/p&gt;

&lt;p&gt;Next, I checked the entry point of the application. The App.js file looked like a plain React component with routing and a simple &lt;code&gt;useEffect&lt;/code&gt; — nothing dangerous there. While there could be malicious code buried deeper in the project, going through every file could take hours…&lt;/p&gt;

&lt;p&gt;What I learned from my last experience is that if there is something malicious, it will most probably run when you start the app. Since I didn’t find anything suspicious in the top-level file, I decided to check what happens when I want run the app. So I opened &lt;code&gt;package.json&lt;/code&gt; and inspected what’s in the &lt;code&gt;scripts&lt;/code&gt; section. Here’s what I found:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"start": "npm run config &amp;amp;&amp;amp; react-scripts --openssl-legacy-provider start || exit 1",
"build": "npm run config &amp;amp;&amp;amp; react-scripts --openssl-legacy-provider build || exit 1",
...
"config": "node src/check_node_version.js",
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That &lt;code&gt;config&lt;/code&gt; script stood out, so I opened the &lt;code&gt;check_node_version.js&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffwwidkr72tbz5tbocf9l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffwwidkr72tbz5tbocf9l.png" alt="check_node_version.js"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At first glance, nothing seemed off — until I noticed the “Symbols” panel on the right side. Aha! Functions with cryptic names started showing up. But wait, where did these functions come from? The file is only 14 lines long… I clicked on one, and a mysterious ellipsis icon appeared at line 10, which looked empty at first.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fso5e0o3srbfou0zlwl19.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fso5e0o3srbfou0zlwl19.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hmm, very strange. What if I check the DevTools - will it show anything else? Strange. Could there be hidden code? I checked the DevTools, and sure enough, more information appeared there. The DevTools revealed code that wasn’t visible on GitHub. I didn’t clone the repository, so I’m not sure if it would have been visible locally either. And here is what I found there:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm41s737f9asbuiy4ocfn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm41s737f9asbuiy4ocfn.png" alt="DevTools reveals much more information"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And here is our hidden code! I’m not sure why it isn’t visible on GitHub, anyway I didn’t clone the code to my machine to see if it would be visible there.&lt;/p&gt;

&lt;p&gt;The next thing to do is to try to understand what the code is doing. I deobfuscated it using &lt;a href="https://obf-io.deobfuscate.io/" rel="noopener noreferrer"&gt;Deobfuscator&lt;/a&gt; and ran it through Gemini to explain its functionality. Here is Gemin’s answer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;This code is obfuscated Javascript and it appears to be malicious. Here’s a breakdown of its functionality:&lt;/em&gt;&lt;br&gt;&lt;br&gt;
    &lt;strong&gt;&lt;em&gt;1. Function Definitions:&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
    &lt;em&gt;The code defines several functions with cryptic names (_0x11bb, _0xc5de3a, etc.). These functions are likely used to perform specific tasks within the script.&lt;/em&gt;&lt;br&gt;&lt;br&gt;
    &lt;strong&gt;&lt;em&gt;2. String Decoding:&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
    &lt;em&gt;The function _0x11bb seems to be responsible for decoding obfuscated strings. It takes two arguments: an encoded string and a key. The function uses the key to shift characters in the encoded string, revealing the original text.&lt;/em&gt; &lt;br&gt;&lt;br&gt;
    &lt;strong&gt;&lt;em&gt;3. File System Interaction:&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
    &lt;em&gt;The code utilizes functions from the fs module to interact with the file system. It can access, read, and copy files.&lt;/em&gt;&lt;br&gt;&lt;br&gt;
    &lt;strong&gt;&lt;em&gt;4. Browser Extension Data Collection:&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
    &lt;em&gt;Functions like _0x4574da and _0x589215 seem to target specific browser directories (Chrome, Firefox) and search for local storage files associated with extensions. It then attempts to read these files, potentially gathering sensitive data.&lt;/em&gt;&lt;br&gt;&lt;br&gt;
    &lt;strong&gt;&lt;em&gt;5. System Information Collection:&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
    &lt;em&gt;The code retrieves information about the system, including hostname, platform, home directory, and temporary directory.&lt;/em&gt;&lt;br&gt;&lt;br&gt;
    &lt;strong&gt;&lt;em&gt;6. Solana ID Extraction (Optional):&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
    &lt;em&gt;It checks for the presence of a file named id.json in the Solana configuration directory and attempts to read it if found.&lt;/em&gt;&lt;br&gt;&lt;br&gt;
    &lt;strong&gt;&lt;em&gt;7. Data Exfiltration:&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
    &lt;em&gt;The collected data (potentially browser extension data and system information) is uploaded to a remote server using the request library.&lt;/em&gt;&lt;br&gt;&lt;br&gt;
    &lt;em&gt;&lt;strong&gt;In summary, this code appears to be designed to steal data from web browsers, potentially including login credentials or other sensitive information stored in extensions. It also gathers system information and might attempt to extract data related to Solana cryptocurrency wallets.&lt;/strong&gt;&lt;/em&gt;&lt;br&gt;&lt;br&gt;
    &lt;em&gt;&lt;strong&gt;It’s important to never run such scripts as they can compromise your system’s security.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Bingo! Once again, this attack involved stealing system information and browser data, along with targeting Solana files.&lt;/p&gt;

&lt;p&gt;I first read about such scam attempts just a month ago. And in less than 2 weeks I personally encountered 2 similar attempts. This seems to be a growing trend of targeting developers to steal their information.&lt;/p&gt;

&lt;p&gt;To help protect against these types of scams, I’ve put together a list of precautionary actions. If you have more ideas, feel free to add them in the comments!&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Minimize Risk from Scam Attempts:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Check the repository&lt;/strong&gt;. Look at the commit history. Does it contain just 1 or 2 commits pushing an entire codebase for a large application?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Examine critical files&lt;/strong&gt;. Focus on entry files (like &lt;code&gt;app.js&lt;/code&gt; or &lt;code&gt;index.js&lt;/code&gt;) and `package.json. Be on the lookout for suspicious dependencies or scripts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use a Virtual Machine or Docker&lt;/strong&gt;. If you’re uncertain about the code’s safety, run it in a VM or Docker container to isolate your main environment.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That’s it, stay cautious and safe!&lt;/p&gt;

&lt;p&gt;P.S. For more context, you can read my &lt;a href="https://dev.to/vardanarm_7/beware-of-malicious-code-a-developers-experience-with-a-suspicious-request-3nma"&gt;previous article&lt;/a&gt; on a similar scam attempt.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you want to stay updated with the latest JavaScript and software development news, join my Telegram channel: &lt;a href="https://t.me/javascriptsavvy" rel="noopener noreferrer"&gt;TechSavvy: Frontend &amp;amp; Backend&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>freelance</category>
      <category>malicious</category>
      <category>code</category>
    </item>
    <item>
      <title>Implementing the Fibonacci Sequence in JavaScript: Common Approaches and Variations</title>
      <dc:creator>Vardan Hakobyan</dc:creator>
      <pubDate>Mon, 23 Sep 2024 16:21:27 +0000</pubDate>
      <link>https://dev.to/vardanarm_7/implementing-the-fibonacci-sequence-in-javascript-common-approaches-and-variations-3k5h</link>
      <guid>https://dev.to/vardanarm_7/implementing-the-fibonacci-sequence-in-javascript-common-approaches-and-variations-3k5h</guid>
      <description>&lt;p&gt;As a developer, you’ve likely encountered the task of writing a function to calculate values in the Fibonacci sequence. This classic problem often appears in coding interviews, typically asking for a recursive implementation. However, interviewers may sometimes request specific approaches. In this article, we’ll explore the most common Fibonacci sequence implementations in JavaScript.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the Fibonacci Sequence?
&lt;/h3&gt;

&lt;p&gt;First, let’s refresh our memory. The Fibonacci sequence is a series of numbers where each number is the sum of the two preceding ones. It starts with 0 and 1:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, …&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Common Implementation Approaches
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Recursive Approach&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The most traditional request is for a recursive implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function fibonacciRecursive(n) {
  if (n &amp;lt; 1) {
    return 0;
  }
  if (n === 1) {
    return 1;
  }
  return fibonacciRecursive(n - 1) + fibonacciRecursive(n - 2);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While straightforward, this approach isn’t performant for large values of n. On a MacBook Pro i9 with 16 GB RAM, calculating the 40th Fibonacci number took about 1.5 seconds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;console.time('Recursive');
fibonacciRecursive(40);
console.timeEnd('Recursive');

VM379:3 Recursive: 1521.569091796875 ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Attempting to calculate the 50th number caused the Chrome tab to become unresponsive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Recursive Approach with Caching (Memoization)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The next variation of this question is to improve performance by adding a caching mechanism to our recursive implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function fibonacciCached(n, cached = {[0]: 0, [1]: 1}) {
  if (n &amp;lt; 1) {
    return 0;
  }
  if (n === 1) {
    return 1;
  }

  if (cached[n]) {
    return cached[n];
  }

  cached[n] = 
    fibonacciCached(n - 1, cached) + fibonacciCached(n - 2, cached);

  return cached[n];
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach introduces a &lt;code&gt;cached&lt;/code&gt; object with initial values for 0 and 1. For any given number, we first check if we've already calculated its Fibonacci value. If so, we return the cached result instead of recalculating it. Otherwise, we calculate that value and store it in &lt;code&gt;cached&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The performance improvement is significant (due to the additional memory used, of course). Calculating the 40th Fibonacci number took ~0.02 ms:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;console.time('Recursive, with caching');
fibonacciCached(40);
console.timeEnd('Recursive, with caching');

VM382:3 Recursive, with caching: 0.01806640625 ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Iterative Approach with a &lt;code&gt;for&lt;/code&gt; Loop&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Another common variation is implementing the Fibonacci sequence using a &lt;code&gt;for&lt;/code&gt; loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function fibonacciWithIteration(n) {
    if (n &amp;lt;= 0) {
        return 0;
    }
    if (n === 1) {
        return 1;
    }

    let prev = 0;
    let next = 1;
    let result = 1;

    for (let i = 2; i &amp;lt;= n; i++) {
        result = prev + next;
        [prev, next] = [next, prev + next];
    }
    return result;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach is much faster than the basic recursive method (the one without caching):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;console.time('With iteration');
fibonacciWithIteration(40);
console.timeEnd('With iteration');

VM44:22 With iteration: 0.10107421875 ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The iterative approach can handle very large input values efficiently:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;console.time('With iteration');
const result = fibonacciWithIteration(1400);
console.log(result);
console.timeEnd('With iteration');

VM325:22 1.7108476902340223e+292
VM325:23 With iteration: 0.5830078125 ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Bonus: Returning the Fibonacci Sequence as an Array
&lt;/h3&gt;

&lt;p&gt;Interviewers might also ask you to return the entire Fibonacci sequence up to the &lt;em&gt;n&lt;/em&gt;-th number as an array. Let’s implement this using both recursive and iterative approaches.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recursive approach&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function fibonacciSequence(n) {
  if (n === 0) {
      return [0];
  }
  if (n === 1) {
      return [0, 1];
  }

  const arr = fibonacciSequence(n - 1);
  const currentValue = arr[n - 1] + arr[n - 2];

  return [...arr, currentValue];
}

console.log(fibonacciSequence(5)); // [0, 1, 1, 2, 3, 5]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function works as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;For 0 and 1, we return hardcoded arrays.&lt;/li&gt;
&lt;li&gt;For other cases:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;We get the sequence for the previous number and store it in &lt;code&gt;arr&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;We calculate &lt;code&gt;currentValue&lt;/code&gt; by summing the last two values of &lt;code&gt;arr&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;We combine &lt;code&gt;arr&lt;/code&gt; and &lt;code&gt;currentValue&lt;/code&gt; in a new array and return it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Iterative Approach&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function fibonacciSequenceWithIteration(n) {
  if (n &amp;lt; 1) {
    return [0];
  }

  let prev = 0;
  let next = 1;
  const arr = [prev, next];

  for (let i = 2; i &amp;lt;= n; i++) {
    arr.push(prev + next);
    [prev, next] = [next, prev + next];
  }
  return arr;
}

console.log(fibonacciSequenceWithIteration(5)); // [0, 1, 1, 2, 3, 5]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function works as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If the input is 0, we return an array with only the element 0.&lt;/li&gt;
&lt;li&gt;For other cases:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;We initialize &lt;code&gt;prev&lt;/code&gt; and &lt;code&gt;next&lt;/code&gt; variables to store the previous and next values.&lt;/li&gt;
&lt;li&gt;We create &lt;code&gt;arr&lt;/code&gt; with initial values &lt;code&gt;[0, 1]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;We iterate from 2 to n, pushing the sum of &lt;code&gt;prev&lt;/code&gt; and &lt;code&gt;next&lt;/code&gt; to &lt;code&gt;arr&lt;/code&gt; in each iteration.&lt;/li&gt;
&lt;li&gt;We update &lt;code&gt;prev&lt;/code&gt; and &lt;code&gt;next&lt;/code&gt; values and continue to the next iteration.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;While this article covers several common Fibonacci sequence implementations, it’s not an exhaustive list. If you’ve encountered other variations in interviews or your work, please share them in the comments!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Stay updated with the latest JavaScript and software development news! Join my Telegram channel for more insights and discussions: &lt;a href="https://t.me/javascriptsavvy" rel="noopener noreferrer"&gt;TechSavvy: Frontend &amp;amp; Backend&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>simulation</category>
      <category>montyhall</category>
      <category>puzzle</category>
    </item>
    <item>
      <title>Unveiling the Monty Hall Problem: A JavaScript Simulation</title>
      <dc:creator>Vardan Hakobyan</dc:creator>
      <pubDate>Sat, 21 Sep 2024 06:42:09 +0000</pubDate>
      <link>https://dev.to/vardanarm_7/unveiling-the-monty-hall-problem-a-javascript-simulation-g82</link>
      <guid>https://dev.to/vardanarm_7/unveiling-the-monty-hall-problem-a-javascript-simulation-g82</guid>
      <description>&lt;p&gt;Have you ever pondered the Monty Hall problem? This classic probability puzzle has baffled both mathematicians and casual thinkers for years. Today, we’re going to demystify this counterintuitive puzzle using the power of JavaScript.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Monty Hall Problem: A Quick Recap&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Imagine this scenario:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You’re on a game show facing three closed doors.&lt;/li&gt;
&lt;li&gt;Behind one door lies a shiny new car; behind the other two, just goats.&lt;/li&gt;
&lt;li&gt;You pick a door (let’s call it Door A), hoping for the car.&lt;/li&gt;
&lt;li&gt;The host, Monty Hall, who knows what’s behind each door, opens another door revealing a goat.&lt;/li&gt;
&lt;li&gt;Now, Monty offers you a choice: stick with Door A or switch to the remaining unopened door.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here’s the million-dollar question: Should you switch doors or stay put? Does it even matter?&lt;/p&gt;

&lt;p&gt;Surprisingly, the odds aren’t 50–50. If you switch, you’ll win the car 2/3 of the time! Sounds counterintuitive, right? Let’s prove it with code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Setting Up Our JavaScript Simulator&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;First, let’s create a simple Node.js app. If you’re familiar with the process, feel free to skip this section.&lt;/p&gt;

&lt;p&gt;Otherwise, follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open your terminal and navigate to your desired project folder.&lt;/li&gt;
&lt;li&gt;Run these commands:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir monty-hall-problem
cd monty-hall-problem
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, create an entry file, where we will write the actual code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;touch index.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s it! Now, open this file let’s start the actual coding!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Coding the Monty Hall Simulation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let’s break down our simulation into manageable steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Model three doors&lt;/li&gt;
&lt;li&gt;Randomly place the car behind one door&lt;/li&gt;
&lt;li&gt;Simulate the player’s initial choice&lt;/li&gt;
&lt;li&gt;Simulate Monty opening a door with a goat&lt;/li&gt;
&lt;li&gt;Simulate choosing the remaining door when the player decides to switch&lt;/li&gt;
&lt;li&gt;Calculate wins for both strategies: switching and staying&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let’s introduce a constant for the doors count so we won’t have the magic number &lt;code&gt;3&lt;/code&gt; in our code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const DOORS_COUNT = 3;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We’ll keep the win numbers in respective variables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let winsWithoutDoorChange = 0;
let winsWithDoorChange = 0;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s create a function that randomly generates an integer between &lt;code&gt;0&lt;/code&gt; and given &lt;code&gt;maxNumber&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const generateRandomNumber = (maxNumber) =&amp;gt; {
  return Math.floor(Math.random() * maxNumber);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have 3 doors, starting from index with &lt;code&gt;0&lt;/code&gt;, so &lt;code&gt;maxNumber&lt;/code&gt; will be &lt;code&gt;2&lt;/code&gt;. Let’s randomly select our door with car and the one the player chose:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const doorWithCar = generateRandomNumber(DOORS_COUNT);
const chosenDoor = generateRandomNumber(DOORS_COUNT);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, we need to choose some door that the host will open. It must not be the one the player chose, and also must not be one with car. We can do that with this code (one of rare cases when &lt;em&gt;do/while&lt;/em&gt; is actually appropriate):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;do {
  openDoorWithGoat = generateRandomNumber(DOORS_COUNT);
} while ([chosenDoor, doorWithCar].includes(openDoorWithGoat));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ok, now we have one door chosen by player and another open door with a goat. The player can change their decision and choose the last door. Let’s simulate it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const newChosenDoor = [0, 1, 2]
      .find(door =&amp;gt; ![chosenDoor, openDoorWithGoat].includes(door));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we iterate over an array of 3 elements (doors), and select the only one remaining (the door that is not selected and is not open). This is the new door that the player chooses.&lt;/p&gt;

&lt;p&gt;All that remains is to check whether the player has won and increase the corresponding counter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (chosenDoor === doorWithCar) {
  winsWithoutDoorChange++;
}

if (newChosenDoor === doorWithCar) {
  winsWithDoorChange++;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s it! Let’s put this logic in a &lt;code&gt;for&lt;/code&gt; loop and try iterating with different numbers. Remember, the more iterations, the more accurate the final result will be.&lt;/p&gt;

&lt;p&gt;Here’s the complete code for our simulation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const ATTEMPTS_COUNT = 1000_000;
const DOORS_COUNT = 3;

const generateRandomNumber = (maxNumber) =&amp;gt; {
  return Math.floor(Math.random() * maxNumber);
}

const simulateMontyHall = (attempts) =&amp;gt; {
  let winsWithoutDoorChange = 0;
  let winsWithDoorChange = 0;

  for (let i = 0; i &amp;lt; attempts; i++) {
    const doorWithCar = generateRandomNumber(DOORS_COUNT);
    const chosenDoor = generateRandomNumber(DOORS_COUNT);

    let openDoorWithGoat;

    do {
      openDoorWithGoat = generateRandomNumber(DOORS_COUNT);
    } while ([chosenDoor, doorWithCar].includes(openDoorWithGoat));

    const newChosenDoor = [0, 1, 2]
      .find(door =&amp;gt; ![chosenDoor, openDoorWithGoat].includes(door));

    if (chosenDoor === doorWithCar) {
      winsWithoutDoorChange++;
    }

    if (newChosenDoor === doorWithCar) {
      winsWithDoorChange++;
    }
  }

  return {
    winsWithoutDoorChange,
    winsWithDoorChange,
  }
}

const {
  winsWithoutDoorChange,
  winsWithDoorChange,
} = simulateMontyHall(ATTEMPTS_COUNT);

const withoutChangeWinProbability = (winsWithoutDoorChange / ATTEMPTS_COUNT * 100).toFixed(2);
const withChangeWinProbability = (winsWithDoorChange / ATTEMPTS_COUNT * 100).toFixed(2);

console.log(
  `Without change, won ${winsWithoutDoorChange} out of ${ATTEMPTS_COUNT} attempts. Probability is ${withoutChangeWinProbability}%`,
);
console.log(
  `With change, won ${winsWithDoorChange} out of ${ATTEMPTS_COUNT} attempts. Probability is ${withChangeWinProbability}%`,
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To start the program, simply run &lt;code&gt;node index.js&lt;/code&gt; in terminal. You will have ~33.3% of wins if the player doesn’t change their initial choice, and ~66.6% of wins in case of change.&lt;/p&gt;

&lt;p&gt;If you don’t want to create and run the program locally, here is a link to Codepen. Run it and check the results.&lt;/p&gt;

&lt;p&gt;Hope you enjoyed it! If you have any notes, remarks or questions, please share them in the comments.&lt;/p&gt;

&lt;p&gt;Prefer watching instead? Check out the video on &lt;a href="https://www.youtube.com/watch?v=oOrjru8Pgc0" rel="noopener noreferrer"&gt;YouTube&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Stay updated with the latest JavaScript and software development news! Join my Telegram channel for more insights and discussions: &lt;a href="https://t.me/javascriptsavvy" rel="noopener noreferrer"&gt;TechSavvy: Frontend &amp;amp; Backend&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>montyhall</category>
      <category>puzzle</category>
      <category>simulation</category>
    </item>
    <item>
      <title>When do (and don’t) children re-render in React?</title>
      <dc:creator>Vardan Hakobyan</dc:creator>
      <pubDate>Thu, 19 Sep 2024 06:57:30 +0000</pubDate>
      <link>https://dev.to/vardanarm_7/when-do-and-dont-children-re-render-in-react-3j8</link>
      <guid>https://dev.to/vardanarm_7/when-do-and-dont-children-re-render-in-react-3j8</guid>
      <description>&lt;p&gt;When writing React components, we always strive to keep optimization in mind. It’s always useful to know when unnecessary re-rendering occurs in our code, especially if we have heavy components in our app.&lt;/p&gt;

&lt;p&gt;So let’s dive in and see what happens with child components when their parents re-render.&lt;/p&gt;

&lt;p&gt;In most cases we use child components by their name. Let’s examine the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useState } from "react";

const Parent = () =&amp;gt; {
  const [number, setNumber] = useState(0);

  console.log('&amp;lt;Parent&amp;gt; renders');

  return (
    &amp;lt;div&amp;gt;
      Number is {number}
      &amp;lt;div&amp;gt;
        &amp;lt;button onClick={() =&amp;gt; setNumber(prev =&amp;gt; prev + 1)}&amp;gt;
          Increment
        &amp;lt;/button&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;Child /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

const Child = () =&amp;gt; {
  // Some time-consuming logic
  console.log('&amp;lt;Child&amp;gt; renders');

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;div&amp;gt;Child component&amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

const App = () =&amp;gt; {
  return (
    &amp;lt;Parent /&amp;gt;
  );
};

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

&lt;/div&gt;



&lt;p&gt;Every time the button is pressed, the state of the &lt;code&gt;&amp;lt;Parent /&amp;gt;&lt;/code&gt; component changes and it re-renders, which causes re-rendering &lt;code&gt;&amp;lt;Child /&amp;gt;&lt;/code&gt; component as well.&lt;/p&gt;

&lt;p&gt;How can we prevent unnecessary re-renders for the &lt;code&gt;Child&lt;/code&gt; component? Let’s explore two approaches to achieve this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Approach 1: Our friend &lt;code&gt;React.memo&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If we wrap the Child component into &lt;a href="https://react.dev/reference/react/memo" rel="noopener noreferrer"&gt;React.memo&lt;/a&gt;, the &lt;code&gt;Parent&lt;/code&gt;’s re-render will not cause the &lt;code&gt;Child&lt;/code&gt; to re-render.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Quick reminder — &lt;code&gt;React.memo&lt;/code&gt; memoizes components, ensuring they are not re-rendered when their props remain unchanged.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { memo, useState } from "react";

const Parent = () =&amp;gt; {
  const [number, setNumber] = useState(0);

  console.log('&amp;lt;Parent&amp;gt; renders');

  return (
    &amp;lt;div&amp;gt;
      Number is {number}
      &amp;lt;div&amp;gt;
        &amp;lt;button onClick={() =&amp;gt; setNumber(prev =&amp;gt; prev + 1)}&amp;gt;
          Increment
        &amp;lt;/button&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;Child /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

const Child = memo(() =&amp;gt; {
  // Some time-consuming logic
  console.log('&amp;lt;Child&amp;gt; renders');

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;div&amp;gt;Child component&amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  );
});

const App = () =&amp;gt; {
  return (
    &amp;lt;Parent /&amp;gt;
  );
};

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Approach 2: Using &lt;code&gt;{children}&lt;/code&gt; prop&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We can use &lt;a href="https://react.dev/learn/passing-props-to-a-component#passing-jsx-as-children" rel="noopener noreferrer"&gt;{children}&lt;/a&gt; prop to achieve the same result. Let’s see it in action.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;code&gt;{children}&lt;/code&gt; prop allows the parent component to accept and render its children components dynamically.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {useState} from "react";

const Parent = ({children}) =&amp;gt; {
  const [number, setNumber] = useState(0);

  console.log('&amp;lt;Parent&amp;gt; renders');

  return (&amp;lt;div&amp;gt;
    Number is {number}
    &amp;lt;div&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; setNumber(prev =&amp;gt; prev + 1)}&amp;gt;
        Increment
      &amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
    {children}
  &amp;lt;/div&amp;gt;);
};

const Child = () =&amp;gt; {
  // Some time-consuming logic
  console.log('&amp;lt;Child&amp;gt; renders');

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;div&amp;gt;Child component&amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

const App = () =&amp;gt; {
  return (
    &amp;lt;Parent&amp;gt;
      &amp;lt;Child /&amp;gt;
    &amp;lt;/Parent&amp;gt;
  );
};

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

&lt;/div&gt;



&lt;p&gt;Using &lt;code&gt;children&lt;/code&gt; prop here makes the code easier to follow, and also removes extra clutter coming from &lt;code&gt;memo&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;While these two approaches help us remove unnecessary re-rendering child components, bear in mind that we don’t need to blindly optimize everything. If our component doesn’t involve heavy calculations or other performance bottlenecks, we usually shouldn’t prematurely optimize it. Always strive to keep components small and easy to follow, and optimize them only when necessary.&lt;/p&gt;

&lt;p&gt;Thanks for reading! If you have any notes, remarks or questions, please share them in the comments.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Stay updated with the latest JavaScript and software development news! Join my Telegram channel for more insights and discussions: &lt;a href="https://t.me/javascriptsavvy" rel="noopener noreferrer"&gt;TechSavvy: Frontend &amp;amp; Backend&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>children</category>
      <category>performance</category>
      <category>memoization</category>
    </item>
    <item>
      <title>Mastering Email-Ready HTML: Automated Style Inlining with Tailwind CSS</title>
      <dc:creator>Vardan Hakobyan</dc:creator>
      <pubDate>Wed, 18 Sep 2024 07:17:38 +0000</pubDate>
      <link>https://dev.to/vardanarm_7/mastering-email-ready-html-automated-style-inlining-with-tailwind-css-538c</link>
      <guid>https://dev.to/vardanarm_7/mastering-email-ready-html-automated-style-inlining-with-tailwind-css-538c</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh3jq90kc6rzuwq0vqdw7.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh3jq90kc6rzuwq0vqdw7.jpg" alt="Image description" width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;
In the world of email development, ensuring consistent styling across various email clients is a significant challenge. Email clients are notoriously inconsistent in their CSS support. Many strip out &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; tags or ignore external stylesheets. So ensuring consistent appearance across various email clients often requires inline CSS styles. This requirement can conflict with modern development practices, especially when using utility-first CSS frameworks like Tailwind.&lt;/p&gt;

&lt;p&gt;Recently, while working on a project that required sending various emails to users, I faced this exact dilemma. We were using Tailwind for our main application, and I wanted to maintain this efficient workflow for our email templates as well. However, the need for inline styles in emails posed a significant hurdle.&lt;/p&gt;

&lt;p&gt;I considered several approaches:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Creating email templates with inline styles from the start.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pros: Guaranteed compatibility with email clients.&lt;/li&gt;
&lt;li&gt;Cons: Time-consuming to write and maintain, prone to errors, and incompatible with Tailwind.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Using online converters to transform Tailwind-styled templates into inline styles. Then, save the HTML with inline styles as a separate file to be sent via email.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pros: Allows use of familiar Tailwind syntax during development.&lt;/li&gt;
&lt;li&gt;Cons: Requires keeping two versions of each template (original and converted).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Utilizing an npm package to convert templates to inline styles at runtime.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pros: It’s time-efficient and allows me to maintain only one version of each email template using Tailwind.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Cons: I did come across some packages like &lt;a href="https://www.npmjs.com/package/@jyotirmay/tailwind-to-css" rel="noopener noreferrer"&gt;tailwind-to-css&lt;/a&gt; or &lt;a href="https://www.npmjs.com/package/tw-to-css" rel="noopener noreferrer"&gt;tw-to-css&lt;/a&gt;, but while they have their merits, I encountered the following issues:&lt;/p&gt;

&lt;p&gt;❌ &lt;code&gt;tailwind-to-css&lt;/code&gt; generates random class names in the result HTML&lt;br&gt;
❌ &lt;code&gt;tw-to-css&lt;/code&gt; requires calling a converter function for every Tailwind class usage.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After evaluating these options and finding existing tools lacking, I decided to implement a custom solution. In this article, I’ll guide you through the development of a TypeScript module that automates the process of inlining Tailwind classes for email-ready HTML.&lt;/p&gt;

&lt;p&gt;I want to highlight that the code actually runs on the Node.js server, so I aimed to use the bare minimum from the frontend world necessary to make the logic work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Actual implementation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The main logic is resided in &lt;code&gt;makeStylesInline&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const makeStylesInline: TMakeStylesInline = async (
  templatePath,
  data,
) =&amp;gt; {
  const templateSource = fs.readFileSync(templatePath, 'utf8');
  const template = Handlebars.compile(templateSource);
  const html = template(data);
  return inlineStyles(html);
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function takes a template path and optional data, compiles the template with Handlebars, and processes the resulting HTML to inline styles.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Harnessing the Power of Tailwind CSS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A key component is the &lt;code&gt;processTailwindCSS&lt;/code&gt; function, which applies Tailwind CSS to our HTML:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const processTailwindCSS = async (html: string): Promise&amp;lt;string&amp;gt; =&amp;gt; {
  const tailwindConfig = {
    content: [{ raw: html, extension: 'html' }],
    corePlugins: {
      preflight: false,
    },
  };

  const result = await postcss([
    tailwindcss(tailwindConfig),
    autoprefixer,
  ]).process('@tailwind components; @tailwind utilities;', {
    from: undefined,
  });

  return result.css;
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function sets up a minimal Tailwind configuration and uses &lt;a href="https://www.npmjs.com/package/postcss" rel="noopener noreferrer"&gt;PostCSS&lt;/a&gt; to generate the necessary CSS.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Simplifying and Optimizing CSS for Emails&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Given the limited CSS support in email clients, the &lt;code&gt;simplifyColors&lt;/code&gt; function optimizes the generated CSS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const simplifyColors = (css: string): string =&amp;gt; {
  const generalSimplifications = css
    .replace(/rgb\(([^)]+)\) \/ var\(--tw-[^)]+\)/g, 'rgb($1)')
    .replace(
      /rgba\(([^,]+),([^,]+),([^,]+),var\(--tw-[^)]+\)\)/g,
      'rgba($1,$2,$3,1)'
    )
    .replace(/var\(--tw-[^)]+\)/g, '1')
    .replace(/--tw-[^:]+:[^;]+;/g, '');

  return generalSimplifications.replaceAll(
    /(rgba?\(\d+\s+\d+\s+\d+\s*\/.*\))/g,
    (match) =&amp;gt; rgbToHex(match)
  );
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function removes Tailwind-specific CSS variables and converts RGB colors to hexadecimal for better email client support.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Art of Style Inlining&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For the actual inlining process, we use the &lt;a href="https://www.npmjs.com/package/juice" rel="noopener noreferrer"&gt;juice&lt;/a&gt; library:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const inlineStyles = async (html: string): Promise&amp;lt;string&amp;gt; =&amp;gt; {
  const tailwindCss = await processTailwindCSS(html);
  const simplifiedCss = simplifyColors(tailwindCss);

  return juice(html, {
    extraCss: simplifiedCss,
    applyStyleTags: true,
    removeStyleTags: true,
    preserveMediaQueries: true,
    preserveFontFaces: true,
    preserveImportant: true,
    inlinePseudoElements: true,
  });
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function processes the HTML with Tailwind, simplifies the resulting CSS, and then uses &lt;code&gt;juice&lt;/code&gt; to inline the styles. It preserves important structures like media queries and font faces.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Handling Dynamic Content with Handlebars&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The solution integrates &lt;a href="https://www.npmjs.com/package/handlebars" rel="noopener noreferrer"&gt;Handlebars&lt;/a&gt; for template compilation, allowing for dynamic content insertion:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const templateSource = fs.readFileSync(templatePath, 'utf8');
const template = Handlebars.compile(templateSource);
const html = template(data);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach enables the use of placeholder values in email templates, enhancing flexibility and reusability.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This TypeScript code offers an automated solution for generating email-ready HTML with inlined styles. By leveraging Tailwind CSS, PostCSS, and careful CSS optimization, it significantly streamlines the email development process. The result is consistently styled, cross-client compatible email HTML, generated with minimal manual intervention.&lt;/p&gt;

&lt;p&gt;For developers looking to improve their email development workflow, this solution provides a robust starting point. It combines the utility-first approach of Tailwind CSS with the practicality of automated style inlining, all while maintaining the flexibility needed for dynamic email content.&lt;/p&gt;

&lt;p&gt;For the full source code and more detailed implementation, visit the &lt;a href="https://github.com/vardan-arm/tailwind-to-inline" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It’s important to note that this is version 1 of the solution, and as such, it may not cover all possible use cases or have all desired features. There’s always room for improvement and expansion, and I welcome feedback from developers who try this solution in their projects.&lt;/p&gt;

&lt;p&gt;Thanks for reading! If you have any question or need some clarification, feel free to reach out.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Stay updated with the latest JavaScript and software development news! Join my Telegram channel for more insights and discussions&lt;/em&gt;: &lt;a href="https://t.me/javascriptsavvy" rel="noopener noreferrer"&gt;TechSavvy: Frontend &amp;amp; Backend&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>tailwindcss</category>
      <category>html</category>
    </item>
    <item>
      <title>Beware of Malicious Code: A Developer’s Experience with a Suspicious Request</title>
      <dc:creator>Vardan Hakobyan</dc:creator>
      <pubDate>Tue, 17 Sep 2024 19:15:24 +0000</pubDate>
      <link>https://dev.to/vardanarm_7/beware-of-malicious-code-a-developers-experience-with-a-suspicious-request-3nma</link>
      <guid>https://dev.to/vardanarm_7/beware-of-malicious-code-a-developers-experience-with-a-suspicious-request-3nma</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjiqsse0axfkozxippehi.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjiqsse0axfkozxippehi.jpg" alt="Image of a lock" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’ve been doing mentoring and freelancing on &lt;a href="https://www.codementor.io/@vardanhakobyan" rel="noopener noreferrer"&gt;Codementor&lt;/a&gt; for a while now. Recently, I applied for a project titled “Front-end Design Developer (React.js, Three.js)”. The client asked me to install their code locally and “fix the problem,” after which they’d set up a call with their CTO. They shared a Bitbucket link to their codebase.&lt;/p&gt;

&lt;p&gt;So, I cloned the repository and ran npm install, but it failed due to a React version mismatch. I let the client know about the issue and asked if fixing the installation error was the main goal of this request. The error was apparently unexpected for him too, and he suggested running the install with the --force flag. He then said that once I did that, he’d explain what needed to be fixed.&lt;/p&gt;

&lt;p&gt;This is when things started to feel suspicious.&lt;/p&gt;

&lt;p&gt;I took a closer look at the files and found something odd — an obfuscated file named &lt;a href="https://bitbucket.org/ghost1895/racing-project/src/main/backend/middlewares/helpers/error.js" rel="noopener noreferrer"&gt;error.js&lt;/a&gt;, which was imported into &lt;a href="https://bitbucket.org/ghost1895/racing-project/src/bfba6bb483ccd899fdd63e857524907b67968344/backend/app.js#lines-6" rel="noopener noreferrer"&gt;backend/app.js&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcgdzf9u5jhf0bp2pmryt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcgdzf9u5jhf0bp2pmryt.png" alt="error.js" width="800" height="385"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since it was an immediately invoked function expression (IIFE), it would execute as soon as it was imported. This, combined with the client’s refusal to provide any further details, raised major red flags.&lt;/p&gt;

&lt;p&gt;I decided to report the situation to Codementor’s support team for further investigation. Meanwhile, the client kept insisting that I proceed with the installation, promising he’d “guide me” through the process afterward.&lt;/p&gt;

&lt;p&gt;I had heard of scammers tricking developers into installing malicious code under the guise of fixing a bug. During the installation or run phase, these apps can search for sensitive data like cryptocurrency wallet information on your device, leading to potential theft.&lt;/p&gt;

&lt;p&gt;And, guess what? A smart person on Reddit &lt;a href="https://www.reddit.com/r/Frontend/comments/1fhy1p0/comment/lne6gcy/?context=3" rel="noopener noreferrer"&gt;dug into&lt;/a&gt; the code of &lt;code&gt;error.js&lt;/code&gt; file with the help of Gemini, and it turns out it is indeed malicious. It collects user data, crypto wallet information (Exodus), system data, and sends it to a remote server.&lt;/p&gt;

&lt;p&gt;This is the detailed response from Gemini:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Data Theft:
The script focuses on stealing browsing data from various browsers (Chrome, Brave, Opera, Firefox) and cryptocurrency wallet information (Exodus). It achieves this by:

Identifying browser extension and profile folders.
Searching for specific files within those folders (likely containing browsing history, cookies, etc.).
Extracting the content of those files.
Sending the extracted data to a remote server controlled by the attacker.

Obfuscation:

The script uses various techniques to obfuscate its code and make it harder to understand:

Base-decoding for strings.
Self-referential tricks.
Closures to limit function execution.

Overall, this script is malicious and should not be run. It can steal sensitive information from your computer and send it to an attacker. If you suspect this script might be running on your system, it's crucial to take immediate action.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;For the first time in my life I’m happy that the npm install command failed 😅 As I didn't run the code, I don’t think any harm was done. But I’ve definitely learned a lesson: never install code from strangers without inspecting it first (something I admittedly didn’t do well enough this time). As someone on Reddit wisely pointed out, a good practice is to always run unfamiliar code on a virtual machine to protect your system.&lt;/p&gt;

&lt;p&gt;Stay safe, and be cautious when dealing with unvetted code!&lt;/p&gt;

</description>
      <category>malicious</category>
      <category>code</category>
      <category>development</category>
      <category>sensitive</category>
    </item>
  </channel>
</rss>
