<?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[ dependency management - 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[ dependency management - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Tue, 09 Jun 2026 23:08:15 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/dependency-management/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ What is Minimum Stability In Composer? ]]>
                </title>
                <description>
                    <![CDATA[ Composer is a dependency management tool for projects running on PHP. PHP frameworks like Laravel, Symfony, and CodeIgniter use Composer to manage libraries and packages. In this tutorial, you’ll learn the following: Introduction to Composer. Minimu... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-is-minimum-stability-in-composer/</link>
                <guid isPermaLink="false">66ba2fe86e35b2ef1a340075</guid>
                
                    <category>
                        <![CDATA[ dependency management ]]>
                    </category>
                
                    <category>
                        <![CDATA[ PHP ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Sule-Balogun Olanrewaju ]]>
                </dc:creator>
                <pubDate>Wed, 09 Aug 2023 17:31:49 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/08/javier-garcia-chavez-bdZ3bzRde5g-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Composer is a dependency management tool for projects running on PHP. PHP frameworks like Laravel, Symfony, and CodeIgniter use Composer to manage libraries and packages.</p>
<p>In this tutorial, you’ll learn the following:</p>
<ul>
<li>Introduction to Composer.</li>
<li>Minimum stability in Composer.</li>
<li>Levels of stability, and the recommended version for production code.</li>
</ul>
<p>One of the benefits of using a dependency tool is that it makes it easy to declare the key-value pair of packages you need for your project. This way, you can install dependencies via the <code>composer install</code> command or update them via the <code>composer update</code> command in the terminal.</p>
<h2 id="heading-introduction-to-composer">Introduction to Composer</h2>
<p>In Laravel, the <code>composer.json</code> is a JSON file located at the root of the project directory. It contains sample configurations used for dependency management, such as the project name, type (optional), description (optional), and the list of required packages.</p>
<p>These packages are represented using key-value pairs (name and version to be installed). Additionally, the <code>composer.json</code> file includes some required packages for the development environment which can be added as part of the configuration setup.</p>
<p>Here's what a <code>composer.json</code> file looks like:</p>
<pre><code>{
    <span class="hljs-string">"name"</span>: <span class="hljs-string">"laravel/laravel"</span>,    
    <span class="hljs-string">"type"</span>: <span class="hljs-string">"project"</span>,    
    <span class="hljs-string">"description"</span>: <span class="hljs-string">"The Laravel Framework."</span>,    
    <span class="hljs-string">"keywords"</span>: [        
        <span class="hljs-string">"framework"</span>,        
        <span class="hljs-string">"laravel"</span>    
    ],    
    <span class="hljs-string">"license"</span>: <span class="hljs-string">"MIT"</span>,    
    <span class="hljs-string">"require"</span>: {        
       <span class="hljs-string">"php"</span>: <span class="hljs-string">"^8.1"</span>,        
       <span class="hljs-string">"laravel/framework"</span>: <span class="hljs-string">"^10.0"</span>,    
    },    
    <span class="hljs-string">"require-dev"</span>: {    
         .    
         .     
    },    
    <span class="hljs-string">"config"</span>: {    
         .    
         .    
    },    
    <span class="hljs-string">"minimum-stability"</span>: <span class="hljs-string">"dev"</span>| <span class="hljs-string">"alpha"</span>| <span class="hljs-string">"beta"</span>| <span class="hljs-string">"RC"</span>|<span class="hljs-string">"stable"</span>, <span class="hljs-comment">//stable</span>
}
</code></pre><h2 id="heading-what-is-minimum-stability">What is Minimum Stability?</h2>
<p>In Composer, the “minimum-stability” configuration specifies the minimum stability level for all installed packages.</p>
<p>Packages to be installed or updated will use the <code>minimum-stability</code> value to determine version limitations during dependency resolution.</p>
<h3 id="heading-levels-of-stability">Levels of Stability</h3>
<p>The following are the different stability levels:</p>
<ul>
<li><code>dev</code>: This is the least stable version, and should never be used in production. It often includes packages under active development that may contain bugs or breaking changes and may still undergo significant modifications. It is only recommended for local development purposes.</li>
<li><code>alpha</code>: It's a version also undergoing development but in a more stable state. It usually contains fewer breaking changes and features nearing final completion or awaiting a beta release. However, it is also not highly recommended for production environments.</li>
<li><code>beta</code>: This version is currently being tested, and minor bugs, when noticed, will need to be fixed. However, it is more stable than the alpha and dev versions, but it's still not recommended for production purposes.</li>
<li><code>RC</code>: The RC (Release Candidate) is a version pending official release. It's the closest to being stable, but the version requires community testing and feedback prior to the final release. Undiscovered bugs can also be identified during this phase, so it's best practice not to use it for production purposes.</li>
<li><code>stable</code>: This is the required level for production purposes. It includes all packages that have gone through significant changes, bug fixes, community testing, feedback, and is now ready to use.</li>
</ul>
<p>In your <code>composer.json</code>, you can specify the minimum stability by doing the following:</p>
<pre><code>{
    <span class="hljs-string">"minimum-stability"</span>: <span class="hljs-string">"stable"</span>
}
</code></pre><h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, you have learned about Composer, the <code>composer.json</code> file, minimum stability, and, most importantly, the levels of stability offered by Composer. </p>
<p>For your application, you should carefully choose the stability level that satisfies your production needs, while keeping security and downtime issues in mind. Remember, your application should only depend on stable and reliable packages.</p>
<p>I hope you now have a better understanding of minimum stability.</p>
<p>Keep learning, and Happy Coding!</p>
<p>You can find me on <a target="_blank" href="https://www.linkedin.com/in/suleolanrewaju/">LinkedIn</a> and <a target="_blank" href="https://twitter.com/bigdevlarry">Twitter</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Keep Your Package Dependencies Up to Date on Azure DevOps ]]>
                </title>
                <description>
                    <![CDATA[ By Apoorv Tyagi As a developer, how often have you seen a repository with packages that are out of date? New package updates generally include new features, performance improvements, and security fixes. But keeping track of all outdated dependencies ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/keep-package-dependencies-up-to-date-on-azure-devops/</link>
                <guid isPermaLink="false">66d45d9b787a2a3b05af437c</guid>
                
                    <category>
                        <![CDATA[ Azure ]]>
                    </category>
                
                    <category>
                        <![CDATA[ dependency management ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Devops ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 18 Jan 2022 20:15:51 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/01/photo-1587620962725-abab7fe55159-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Apoorv Tyagi</p>
<p>As a developer, how often have you seen a repository with packages that are out of date?</p>
<p>New package updates generally include new features, performance improvements, and security fixes. But keeping track of all outdated dependencies in your project can be really boring and a time consuming task, especially if you have lots of them.</p>
<p>So to do this sort of housekeeping, I tried out <a target="_blank" href="https://github.blog/2020-06-01-keep-all-your-packages-up-to-date-with-dependabot/">Dependabot</a>.</p>
<h2 id="heading-how-dependabot-works">How Dependabot Works</h2>
<p>Dependabot goes through the dependency files of your project. For instance, it searches your <code>package.json</code> or <code>pom.xml</code> files and inspects for any outdated or insecure dependencies. If it finds any, it opens individual pull requests to update each one of them.</p>
<p>This tool is natively integrated with GitHub. But recently, I had to solve this problem of updating dependencies for a project running in Azure DevOps. So I decided to find a workaround to integrate Dependabot with Azure Pipelines. In this blog post, I will share my solution.</p>
<p>If you go to <a target="_blank" href="https://marketplace.visualstudio.com/azuredevops">Azure DevOps Extension Marketplace</a> and search for "Dependabot", you will find an <a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=tingle-software.dependabot">extension</a> by Tingle Software. Using this extension we can easily integrate Dependabot with our repos in Azure DevOps.</p>
<p>You can check if you have this extension in your "Organization Settings" in Azure DevOps. If not, make sure you have it installed before proceeding.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/1-2.png" alt="Image" width="600" height="400" loading="lazy">
<em>Installed Extensions - Azure DevOps</em></p>
<h2 id="heading-how-to-create-the-azure-pipeline">How to Create the Azure Pipeline</h2>
<p>Let's now create start with creating a new <code>YAML</code> file for your azure pipeline:</p>
<pre><code>trigger: none

<span class="hljs-attr">stages</span>:
  - stage: CheckDependencies
    <span class="hljs-attr">displayName</span>: <span class="hljs-string">'Check Dependencies'</span>
    <span class="hljs-attr">jobs</span>:
      - job: Dependabot
        <span class="hljs-attr">displayName</span>: <span class="hljs-string">'Run Dependabot'</span>
        <span class="hljs-attr">pool</span>:
          vmImage: <span class="hljs-string">'ubuntu-latest'</span>
        <span class="hljs-attr">steps</span>:
          - task: dependabot@<span class="hljs-number">1</span>
            <span class="hljs-attr">displayName</span>: <span class="hljs-string">'Run Dependabot'</span>
            <span class="hljs-attr">inputs</span>:
              packageManager: <span class="hljs-string">'npm'</span>
              <span class="hljs-attr">targetBranch</span>: <span class="hljs-string">'develop'</span>
              <span class="hljs-attr">openPullRequestsLimit</span>: <span class="hljs-number">10</span>
</code></pre><p>In the task parameters, I have specified three params:</p>
<ol>
<li><strong>packageManager</strong>: It specifies the type of packages to check for dependency upgrades. Examples: <code>nuget</code>, <code>maven</code>, <code>gradle</code>, <code>npm</code>, and so on.</li>
<li><strong>targetBranch</strong>: It is an optional parameter that defines the branch to be targeted when creating pull requests. When not specified, Dependabot will pick the <code>default</code> branch of the repository. </li>
<li><strong>openPullRequestsLimit</strong>: This is again an optional parameter that specifies the maximum number of open pull requests to have at any one time. By default, it opens 5 pull requests at a time.</li>
</ol>
<p>You can go through all the <a target="_blank" href="https://github.com/tinglesoftware/dependabot-azure-devops/blob/main/src/extension/README.md#task-parameters">Task Parameters</a> that the extension supports to tweak your implementation. Now just simply configure this YAML file with a new azure pipeline and then you're ready to run it.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/3-2.png" alt="Image" width="600" height="400" loading="lazy">
<em>Pipeline Configuration - Azure DevOps</em></p>
<p>The next step is to give your repository's <code>Project Collection Build Service</code> access so that Dependabot can create the pull request to your project's repositories.</p>
<p>For that, go to your project settings. Here, you click on the repositories and search for the repo where you have integrated the pipeline.</p>
<p>After you have selected that, click on the security tab and search for <strong>project collection build service</strong>. You have to allow the following access to it:</p>
<ul>
<li>Contribute</li>
<li>Contribute to pull request</li>
<li>Create Branch</li>
<li>Create Tag</li>
<li>Force Push</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/2-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Access to raise PR in Repo</em></p>
<p>With this, you're completely ready to run the pipeline. Once you do it, you'll start receiving pull requests in your repository with the updated packages.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/5-3.png" alt="Image" width="600" height="400" loading="lazy">
<em>PR raised by Dependabot</em></p>
<h2 id="heading-how-to-schedule-the-pipeline">How to Schedule the Pipeline</h2>
<p>Up to this point, you've had to manually trigger the pipeline to run. To make it run automatically, you can configure schedules for your pipelines. This will trigger your pipeline to start based on a schedule.</p>
<p>Use the following syntax and add it to the very top of your <code>YAML</code> file:</p>
<pre><code>schedules:
- cron: string
  <span class="hljs-attr">displayName</span>: string
  <span class="hljs-attr">branches</span>:
    include: [ string ]
  <span class="hljs-attr">always</span>: boolean
</code></pre><p>The branche<em>s’</em> <code>include</code> parameter specifies which branches the schedule applies to.</p>
<p>The <code>always</code> parameter specifies whether to "always" run the pipeline or only if there have been any source code changes since the last successful scheduled run. The default is false. </p>
<p>For this case, you set its value to <strong>true</strong> as Dependabot updates are independent of any code changes.</p>
<p>The time zone for cron schedules is UTC and cron syntax is as follows:</p>
<pre><code>mm HH DD MM DW
 \  \  \  \  \__ Days <span class="hljs-keyword">of</span> week
  \  \  \  \____ Months
   \  \  \______ Days
    \  \________ Hours
     \__________ Minutes
</code></pre><p>So if you want to run your pipeline every week on Sunday at 12pm UTC, you would need to write - <code>cron: "0 12 * * 0"</code> (update the cron to suit your needs).</p>
<p>This is how your final <code>YAML</code> should look like after adding a schedule:</p>
<pre><code>schedules:
  - cron: <span class="hljs-string">"0 12 * * 0"</span>
    <span class="hljs-attr">displayName</span>: Weekly Dependency Updates
    <span class="hljs-attr">branches</span>:
      include:
      - develop
    <span class="hljs-attr">always</span>: <span class="hljs-literal">true</span>

<span class="hljs-attr">trigger</span>: none

<span class="hljs-attr">stages</span>:
  - stage: CheckDependencies
    <span class="hljs-attr">displayName</span>: <span class="hljs-string">'Check Dependencies'</span>
    <span class="hljs-attr">jobs</span>:
      - job: Dependabot
        <span class="hljs-attr">displayName</span>: <span class="hljs-string">'Run Dependabot'</span>
        <span class="hljs-attr">pool</span>:
          vmImage: <span class="hljs-string">'ubuntu-latest'</span>
        <span class="hljs-attr">steps</span>:
          - task: dependabot@<span class="hljs-number">1</span>
            <span class="hljs-attr">displayName</span>: <span class="hljs-string">'Run Dependabot'</span>
            <span class="hljs-attr">inputs</span>:
              packageManager: <span class="hljs-string">'npm'</span>
              <span class="hljs-attr">targetBranch</span>: <span class="hljs-string">'develop'</span>
              <span class="hljs-attr">openPullRequestsLimit</span>: <span class="hljs-number">10</span>
</code></pre><p>This pipeline does the following for you:</p>
<p>It runs on a weekly basis (Sunday 12pm UTC in this case) and looks for any outdated or insecure dependency. If it finds any, it opens pull requests to update each one of them individually.</p>
<p>Hopefully, this will help you to keep your project dependencies up to date in Azure DevOps!</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>With this, we come to the end of the article. My DMs are always open if you want to discuss further on any tech topic or if you've got any questions, suggestions, or feedback in general:</p>
<ul>
<li><a target="_blank" href="https://twitter.com/apoorv__tyagi">Twitter</a></li>
<li><a target="_blank" href="https://www.linkedin.com/in/apoorvtyagi/">LinkedIn</a></li>
<li><a target="_blank" href="https://github.com/apoorvtyagi">GitHub</a></li>
<li><a target="_blank" href="https://apoorvtyagi.tech/">Blog</a></li>
</ul>
<p>Happy learning! 💻 😄</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Release Management for Modern Software Development – How to Manage Dependencies, SemVer, and Build Systems for Beginners ]]>
                </title>
                <description>
                    <![CDATA[ By Nabil Tharwat Releasing modern software might seem daunting and complicated. In this article, I'll expand on the concepts involved in the process, from managing dependencies to building in the cloud. Articles and tutorials usually cover a specific... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/release-management-modern-software-development/</link>
                <guid isPermaLink="false">66d460414bc8f441cb6df813</guid>
                
                    <category>
                        <![CDATA[ dependency management ]]>
                    </category>
                
                    <category>
                        <![CDATA[ deployment ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ versioning ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 31 Aug 2021 17:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/08/xavi-cabrera-kn-UmDZQDjM-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Nabil Tharwat</p>
<p>Releasing modern software might seem daunting and complicated. In this article, I'll expand on the concepts involved in the process, from managing dependencies to building in the cloud.</p>
<p>Articles and tutorials usually cover a specific tool and dive right into it before laying down the foundational knowledge. In this article, I'll provide that foundation by introducing the concepts that go into these tools.</p>
<p>The topics I'll cover include dependency management (and what dependencies really are!), build systems, and continuous integration systems with a little bit of icing on the cake. Having this background will help set you up for what's to come.</p>
<h2 id="heading-what-are-libraries">What are Libraries?</h2>
<p>Say you're chipping away dutifully at your tasks. You create a collection of utilities that make your job easier. You're then assigned to a different project in which you need the same utilities, and copy them over. Congratulations, you just created a library and used it across two projects! 😁</p>
<p>Libraries are collections of pre-written code that developers use to optimise tasks. They boost our productivity by abstracting away the boring and repetitive stuff. Numpy, Matplotlib, Lodash, jQuery, and React are all examples of popular, open-source libraries.</p>
<p>You've probably noticed that each of these libraries (or any other library) has a version number. It's usually constructed as a few numeric fields separated by periods: <code>v1.0.0</code> or just <code>1.0.0</code>. These numbers are not random! There are many schemes for defining a version of a product.</p>
<p>Some products use the build number generated by a compiler or CI/CD tool (we'll look into these in a minute). Other products use the date of the build instead of the build number. Others use a build <a target="_blank" href="https://www.freecodecamp.org/news/p/70791fa1-2b5b-4ebc-9927-0e1c06895d4c/%5B%3Chttps://en.wikipedia.org/wiki/Hash_function%3E%5D(%3Chttps://en.wikipedia.org/wiki/Hash_function%3E)">hash</a>.</p>
<p>The most prominent versioning scheme is called <em>Semantic Versioning</em>. It's what most (if not all) code libraries use.</p>
<h2 id="heading-what-is-semantic-versioning-semver">What is Semantic Versioning (Semver)?</h2>
<p>Semantic versioning is a versioning scheme in which you have 3 fields, each separated by a dot. For now, we'll call the first field (on the left side) <em>Major</em>, the one in the middle <em>Minor</em>, and the last one <em>Patch</em>. It looks exactly like this, with some derivations: <code>Major.Minor.Patch</code>.</p>
<p>Per the Semver standard, all fields must increment only. You can't decrement any of them. When a parent version is incremented, all children are reset. So incrementing <em>Major</em> resets <em>Minor</em> and <em>Patch</em> to 0.</p>
<h3 id="heading-the-patch-version">The patch version</h3>
<p>The <em>Patch</em> version is the most frequently changing number. When this number is incremented, it indicates a change that doesn't add new features or break existing functionality. These may be security fixes, performance optimisations, bug fixes, and so on. </p>
<p>Changes to the <em>Patch</em> version are always two-way compatible, as long as parent versions are the same. Code written on <code>v1.0.1</code> will work on <code>v1.0.0</code> and <code>v1.0.2</code>.</p>
<h3 id="heading-the-minor-version">The minor version</h3>
<p>The <em>Minor</em> version is the second most frequently changing number. A change to this number indicates a feature update that doesn't break existing functionality. </p>
<p>Changes to the Minor version are always forward compatible, as long as the Major version is the same. </p>
<p>Code written with <code>v1.1.0</code> <em>will</em> work with <code>v1.2.0</code> but <em>may</em> not work with <code>v1.0.0</code>, as you may be using features added in the more recent version.</p>
<h3 id="heading-the-major-version">The major version</h3>
<p>The <em>Major</em> version is the highest priority and the most "dangerous" field of the three. When this number is incremented, it indicates breaking changes. These are usually API/interface changes and/or entity renaming and removal. </p>
<p>A new Major version is not meant to be compatible with any other Major version, so don't expect <code>v1.0.0</code> to work with <code>v2.0.0</code> or vice versa. Your code <em>may</em> compile after an upgrade, but that's just pure luck. </p>
<p>There are cases in which library authors break underlying logic without affecting the public API you use, so it doesn't break your code. But these are exceptions.</p>
<p>Python 2 and Python 3 are examples of breaking changes. Python 2 print statements don't work on the Python 3 interpreter, and vice versa. Some of it may work, like for loops and other basic structs, but that's about it.</p>
<p>It's recommended that you stay up to date as much as possible with the <em>Patch</em> version. If you need the new features, upgrade your <em>Minor</em> version. A change in <em>Major</em> indicates enormous changes. So be careful when you're upgrading. </p>
<p>There's usually a migration guide with each major release that you should follow. You can read more about Semver in the <a target="_blank" href="https://www.freecodecamp.org/news/p/70791fa1-2b5b-4ebc-9927-0e1c06895d4c/%5B%3Chttps://semver.org/%3E%5D(%3Chttps://semver.org/%3E)">official documentation</a>.</p>
<p>So... how do we install and use external libraries written by other people in the first place?</p>
<h2 id="heading-how-to-manage-your-projects-dependencies">How to Manage Your Project's Dependencies</h2>
<p>In the past, the best that we could do was to actually copy the source code of the libraries we were using into our projects. We applied changes to the library's code, fixed bugs before they were released, and had control over the code. </p>
<p>But this practice, commonly referred to as <em>vendoring</em>, has fallen out of favour for multiple reasons.</p>
<p>If you had applied changes and a new version was released, you had to re-apply all those changes again. It's a manual process that needs to happen every time you update or download a library. It's cumbersome, takes a lot of time, and may break extra functionality that you added.</p>
<p>This quickly gets out of hand when increasing the project's complexity and scale, which leaves us with the better option: <em>Dependency Managers</em>.</p>
<h3 id="heading-what-is-a-dependency-manager">What is a Dependency Manager?</h3>
<p>A dependency is a library or utility that your project needs to work. Simply put, if Program A requires Program B to compile and/or run, Program A is dependent on Program B. A program can depend on multiple other programs. </p>
<p>A dependency manager is a tool that automatically keeps track of a project's dependencies. It allows you to run simple commands in the terminal to install, update, and remove dependencies. NPM, Yarn, Composer, Gradle, and Bundler are all examples of dependency managers.</p>
<p>Don't confuse these with Package Managers, as those are tools that manage system-wide packages. apt-get, yum, Homebrew, and Chocolatey are package managers.</p>
<p>Some package managers can manage system-wide packages and project dependencies. NPM and Yarn are examples of this.</p>
<h3 id="heading-how-does-a-dependency-manager-work">How does a dependency manager work?</h3>
<p>A dependency manager uses two main files: a manifest and a lock file. </p>
<p>The manifest is a list of your project's direct dependencies. It lists the dependencies that you directly specified when installing something. So when you run <code>npm install jsdom</code>, it adds the <code>jsdom</code> package to the list of dependencies in the project's manifest.</p>
<p>But the manifest is not enough. A dependency may have dependencies, and those may have dependencies as well, and so on, forming a <em>dependency graph</em>. A manifest includes only <em>direct</em> dependencies. </p>
<p>Therefore, when you run <code>npm install jsdom</code>, the manifest will only list <code>jsdom</code> despite jsdom having other dependencies of its own. So, how do dependency managers keep track of the whole dependency graph?</p>
<h3 id="heading-what-are-lock-files">What are Lock Files?</h3>
<p>A lock file is a log that lists <em>all</em> the project's dependencies. This includes direct dependencies (listed in the manifest) and the whole dependency graph. It lists every dependency with a specific version, the repository it was fetched from, and other details.</p>
<p>This image shows a comparison between the dependency graph (listed in the lock file) and the direct dependency list (listed in the manifest) of <code>jsdom</code>, a JavaScript implementation of many web standards for testing.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/08/lock-vs-manifest.png" alt="lock vs manifest.png" width="600" height="400" loading="lazy"></p>
<p>Okay, we know the exact dependency graph, but so what? So everything! We often have multiple developers working on the same project. A dependency manager may install different versions of a library if multiple developers install the project's dependencies using only the manifest.</p>
<p>A lock file locks each dependency in the graph to a specific version, allowing us to have <em>reproducible builds on different machines</em>. This means that every time someone runs <code>npm install</code>, the code <em>is guaranteed to</em> work. This also makes it easier to report bugs by including a lock file in the report.</p>
<p>Lock files also allow dependency managers to reuse cached packages instead of downloading the latest version every time you build your project.</p>
<p>So we've learned what libraries, semantic versioning, and dependency managers are. Now it's time to build our project. </p>
<h2 id="heading-what-are-build-systems">What are Build Systems?</h2>
<p>Every build process is a build system in one way or another. A build system is a set of transformations that transform a source into an artifact. It may be a simple command that starts up a compiler, a script to generate pdf from text files, or even a GUI solution that builds your project and generates a binary.</p>
<p>A build system generally consists of 3 components: </p>
<ul>
<li>Targets</li>
<li>Dependencies</li>
<li>Rules </li>
</ul>
<p>A target is the desired output. If you want a binary called "test.exe", then your target is just that. Dependencies are project dependencies and may include environment utilities like having the C++ compiler installed, npm available, and so on. Rules define how you go from source to target. They may also be the commands used.</p>
<p>A build system may be configured to test your app, generate coverage reports, and lint sources before building as part of its rules. But a build system is manual and local by default. You have to start it up yourself, and it only produces an output on your local machine. </p>
<p>So... what if you want multiple developers to be able to release versions of your app incrementally? This is where CI/CD comes in!</p>
<h2 id="heading-continuous-integration-systems">Continuous Integration Systems</h2>
<p>In short, Continuous Integration (CI) is a paradigm in which you continuously validate changes to a product. A CI system automatically builds and tests every change to avoid problems that may arise when waiting for a release.</p>
<p>Continuous Delivery (CD) is the practice of automating the release process. Major releases are automatically deployed to staging and production, providing an automated release process.</p>
<p>Continuous Deployment (CD) is a step-up from Continuous Delivery. It's the practice of automatically deploying every change if it passes all stages of your production pipeline, without waiting for any explicit approval. This practice emphasizes test automation and user feedback, often leading to multiple software updates a month, week, or even a day!</p>
<p>It's a broad concept that you can read more about in <a target="_blank" href="https://www.atlassian.com/continuous-delivery/principles/continuous-integration-vs-delivery-vs-deployment">this article</a>. For now, we'll refer to the systems that host these practices collectively as Continuous Integration Systems.</p>
<p>A continuous integration system (CI for short) is a build system in the cloud that activates a project's build system on demand and automatically. It's a keystone in the success of agile teams. </p>
<p>CIs consist of three main components:</p>
<ul>
<li>Triggers</li>
<li>Actions</li>
<li>Recipes</li>
</ul>
<p>Triggers are events that the CI listens for to start the build system. These events may be a commit on main branch, a pull request for feature previews, or one of many others. Each platform supports several events.</p>
<p>Actions are commands and scripts that are started upon triggers. You may say: "Build project upon commit on main branch" in the system's language.</p>
<p>Recipes are configurations that specify triggers and actions, environment setup, environment variables, build systems, and system dependencies. They're the system's language. </p>
<blockquote>
<p>Note that you can have multiple build systems on the same CI, each with different targets and rules.</p>
</blockquote>
<p>TravisCI, Jenkins, CircleCI, GitHub Actions, and GitLab CI/CD are examples of CIs we come across every day. The following is an example GitHub Actions recipe to release new versions of a program and send them to GitHub Releases:</p>
<pre><code class="lang-yaml"><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> <span class="hljs-string">//</span> <span class="hljs-string">will</span> <span class="hljs-string">start</span> <span class="hljs-string">the</span> <span class="hljs-string">CI</span> <span class="hljs-string">when</span> <span class="hljs-string">a</span> <span class="hljs-string">push</span> <span class="hljs-string">to</span> <span class="hljs-string">branch</span> <span class="hljs-string">main</span> <span class="hljs-string">is</span> <span class="hljs-string">made</span>

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">release_linux:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span> <span class="hljs-string">//</span> <span class="hljs-string">must</span> <span class="hljs-string">be</span> <span class="hljs-string">run</span> <span class="hljs-string">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">check</span> <span class="hljs-string">out</span> <span class="hljs-string">git</span> <span class="hljs-string">repository</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v1</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">install</span> <span class="hljs-string">Node.js,</span> <span class="hljs-string">npm</span> <span class="hljs-string">and</span> <span class="hljs-string">yarn</span> <span class="hljs-string">//</span> <span class="hljs-string">required</span> <span class="hljs-string">env</span> <span class="hljs-string">tools</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/setup-node@v1</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">install</span> <span class="hljs-string">deb</span> <span class="hljs-string">packages</span> <span class="hljs-string">//</span> <span class="hljs-string">required</span> <span class="hljs-string">env</span> <span class="hljs-string">dependencies</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">sudo</span> <span class="hljs-string">apt-get</span> <span class="hljs-string">install</span> <span class="hljs-string">fakeroot</span> <span class="hljs-string">dpkg</span> <span class="hljs-string">rpm</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">build</span> <span class="hljs-string">and</span> <span class="hljs-string">release</span> <span class="hljs-string">app</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">kl13nt/action-electron-forge@master</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-string">//</span> <span class="hljs-string">release</span> <span class="hljs-string">to</span> <span class="hljs-string">github</span> <span class="hljs-string">releases</span> <span class="hljs-string">after</span> <span class="hljs-string">successful</span> <span class="hljs-string">build</span>
          <span class="hljs-attr">release:</span> <span class="hljs-string">${{</span> <span class="hljs-string">startsWith(github.ref,</span> <span class="hljs-string">'refs/tags/v'</span><span class="hljs-string">)</span> <span class="hljs-string">}}</span>
</code></pre>
<p>I've omitted a ton of config stuff in there, but you get the idea. I specified the trigger as a commit on "main" branch and the actions to clone the project's repository, install NodeJS, npm, yarn, and other environment dependencies. </p>
<p>The build stage will run an <a target="_blank" href="https://docs.npmjs.com/cli/v7/commands/npm-run-script/">npm-scripts</a> build system which will lint and test the code before building. The CI will then send the output binaries to the project's GitHub Releases page.</p>
<p>A lock file also comes into play when pushing to a CI as well! If the CI installs different versions of dependencies than the ones you have locally, it may fail. This is why a lock file is as necessary for CIs as it's for developers, so you can rest assured that the code that worked on your machine will work the same way on the CI.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>If you've made it this far, I really hope this was an inspiring (and gentle!) learning experience. You can find more of my content on my <a target="_blank" href="https://iamnabil.netlify.app/">website</a>. Thanks for reading!</p>
<h2 id="heading-further-reading">Further Reading</h2>
<ul>
<li><a target="_blank" href="https://snyk.io/blog/what-is-package-lock-json">What is Package Lock</a></li>
<li><a target="_blank" href="https://missing.csail.mit.edu/2020/metaprogramming">The Missing Semester of Your CS Education - Metaprogramming</a></li>
<li><a target="_blank" href="https://blog.tidelift.com/the-simple-magic-of-package-manifests-and-lockfiles">The Simple Magic of Package Manifests and Lockfiles</a></li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Manage Code Dependencies by Shimming Your Abstractions ]]>
                </title>
                <description>
                    <![CDATA[ Dependencies are a very common part of any sufficiently mature codebase. And it's important to cleanly handle any third party code that your program relies on to function. There are multiple ways to get third party code included and updated. And I re... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/manage-code-dependencies-by-shimming-your-abstractions/</link>
                <guid isPermaLink="false">66bc55e3d94fa6cb67b84525</guid>
                
                    <category>
                        <![CDATA[ clean code ]]>
                    </category>
                
                    <category>
                        <![CDATA[ dependency management ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Kealan Parr ]]>
                </dc:creator>
                <pubDate>Mon, 19 Apr 2021 23:19:44 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/04/Always-Shim-your-Abstractions.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Dependencies are a very common part of any sufficiently mature codebase. And it's important to cleanly handle any third party code that your program relies on to function.</p>
<p>There are multiple ways to get third party code included and updated. And I read something recently which has easily become my favourite way of doing this, so I had to share it.</p>
<p>This method is to <strong>Always Shim Your Abstractions.</strong></p>
<p>To properly break down what this means, let's define each word before we talk about the bigger idea that it encompasses.</p>
<h2 id="heading-abstractions">Abstractions</h2>
<p>Developers often use <strong>abstractions</strong> in code to simplify a system.</p>
<p><strong>Abstractions</strong> are a way of hiding complicated code inside something, and they normally provide an easy interface to use it. </p>
<p>So for example, let's say we have some complex code that ends up doing lots of very specific math. We can wrap all that logic up in a function and provide a really easy interface where you just pass in your number and the function will do the work.</p>
<p>We are essentially not forcing the person who uses our code to worry about the implementation details. They can just call the function and they'll get their answer back – they don't have to worry about what the function is doing "under the hood".</p>
<p><em>That's</em> the strength of abstracting details away in your code. </p>
<p>You can abstract things away in a multitude of data structures or code architecture. And you can abstract implementation details inside a prototype, class, function or more.  </p>
<p>If you had to understand every single line of code in a big codebase (let's say a 2 million line codebase) you'd never be able to start coding.</p>
<p>You can create a reusable, simple to understand, and easily changeable codebase by <strong>abstracting</strong> away certain details into the correct modules/separating out your code.</p>
<h3 id="heading-how-code-abstraction-works">How code abstraction works</h3>
<p>An example of abstracting away logic would be: imagine if you were creating a machine to make coffee for your users. There could be two approaches:</p>
<h4 id="heading-how-to-create-it-with-abstraction">How to Create it With Abstraction</h4>
<ul>
<li>Have a button with the title "Make coffee"</li>
</ul>
<h4 id="heading-how-to-create-it-without-abstraction">How to Create it Without Abstraction</h4>
<ul>
<li>Have a button with the title "Boil the water"</li>
<li>Have a button with the title "Add the cold water to the kettle"</li>
<li>Have a button with the title "Add 1 spoon of ground coffee to a clean cup"</li>
<li>Have a button with the title "Clean any dirty cups"</li>
<li>And all the other buttons</li>
</ul>
<p>Can you see how when we use abstraction we don't expect the user to know how the machine makes coffee? But in the machine without <strong>abstraction</strong>, the user has to know in which order to press each button which forces the user to understand how the coffee is made.</p>
<p>There's one definition we need to cover before we can move on and understand the concept I introduced at the beginning (always shim your abstractions), and that's shimming.</p>
<h2 id="heading-shimming">Shimming</h2>
<p><strong>Shimming</strong> is the act of putting something in front of something else to intercept data being passed. </p>
<p>Let's look at an example of how it works.</p>
<p>Let's say a bank has a really old API that doesn't accept JSON due to some technical legacy defect. Instead it can only accept XML. We'll call this <strong>LegacyAPI</strong>.</p>
<p>But a high percentage of developers who want to hit this bank API want to send JSON. The bank refuses to change LegacyAPI as it's too risky and might break the API. So much of their system depends on it, and they can't risk doing lots of new development and taking huge parts of their system down if they make a mistake.</p>
<p>They could always <strong>shim</strong> LegacyAPI if they don't want to do new development on it.</p>
<p>They could do this by creating an API that sits "in front" of LegacyAPI. We'll call it <strong>NewAPI</strong>. </p>
<p>The wording "in front" just means the order of who first deals with the network request. By "in front" we just mean NewAPI will be the first to receive the network requests. </p>
<p>You would tell the developers they can now hit NewAPI with JSON as they wanted, and NewAPI will turn the JSON into XML for the LegacyAPI and both parties can be satisfied.</p>
<p>The bank can now expand their services (they can accept JSON, for example) via the NewAPI without changing their old legacy API that they were wary of changing.</p>
<p>This is just one example of <strong>shimming</strong>. And just to review, it is essentially adding something in front of something else to act like a man in the middle to pass data to something else.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/image-50.png" alt="Image" width="600" height="400" loading="lazy">
<em>A diagram of how <strong>NewAPI</strong> intercepts <strong>LegacyAPI</strong> network requests.</em></p>
<p>Hopefully you have a good understanding of what shimming is and what abstractions are. Let's bring both definitions together to define what we mean by <strong>Always Shim Your Abstractions</strong>.</p>
<h2 id="heading-why-you-should-always-shim-your-abstractions">Why You Should Always Shim Your Abstractions</h2>
<h3 id="heading-the-problem">The problem</h3>
<p>Whenever we need to manage our dependencies, we want to make sure we stop the third party code "leaking" all over our main code.</p>
<p>By "leaking", I mean that the dependency code is imported multiple times to different places that need it in your code.</p>
<p>If you let a dependency "invade" your source code, you are becoming increasingly tightly coupled to it each time you import it.</p>
<p>This can (at times!) mean you will be forced to code in the direction the library choses as you are tightly coupled to it. This may end up leading to significant cognitive overhead as you are increasingly trying to make this library work in your code, but it isn't in keeping with the rest of your architectural decisions.</p>
<p>This can make any refactoring you need to do take much longer than if you isolated it. For example, if the dependency changes, what arguments would it need to accept to create an object in the dependency?</p>
<p>In addition to it being difficult to keep your build working well with the dependency, if it no longer suits your needs or you find a better library to replace it, your refactor becomes much more difficult to actually get rid of it.</p>
<h3 id="heading-the-solution">The solution</h3>
<p>To try and stop all the above from happening, firstly let's put any dependencies we need into their own modules where they're only referenced once in your codebase. </p>
<p>This is in essence our <strong>shim</strong>.</p>
<p>Whenever you need the third party dependency, you just have to import the wrapper module we put around it, to act like a "man in the middle", to provide a level before we call into our third-party dependency.</p>
<p>This <strong>shim</strong> module also allows us to make our dependencies <strong>abstractions</strong>. The developers who need to use our third party dependencies can just use an abstraction instead (you'll probably end up just wrapping it in a function or simple class). You'll default the arguments to sensible defaults and try to remove as much of the nitty gritty implementation details as you can.</p>
<p>Anywhere else that needs this dependency will just load your module and then that module can be injected where necessary.</p>
<p><strong>Why?</strong> One big reason we already discussed is that it stops your dependencies and your code from being too tightly coupled. </p>
<p>This works when you only have it in only one module. As long as everyone that is loading your module respects an interface/data contract for that module, everywhere else "gets it for free". Then you only have to change one module for lots of other places to get access to something.</p>
<p>This then allows us to make changes far more easily, and keeps a clean separation of concerns in the code.</p>
<p>We have only spoken here about one dependency – but you can see how much worse this may get if, for example, you are relying on 25 other custom libraries and you need to understand how they work. This would generally be a pretty fragile codebase, and would be a code smell.</p>
<h2 id="heading-http-dependency-example">HTTP dependency example</h2>
<p>Let's look at an example of a dependency you might use that makes a simple HTTP client.</p>
<p>It's a basic dependency that lets you hit endpoints and pass JSON etc as data.</p>
<p>Let's imagine then we currently are using <strong>Fetch</strong> in Node and we want to use <strong>Axios</strong> (another HTTP client we want to now switch to). We've decided to drop Fetch and switch to Axios because our application is growing in complexity and we have found that Axios now fits our use-cases better.</p>
<p>If Fetch has leaked all over our codebase, then our refactor to remove it is going to be much harder than it needs to be.</p>
<p>Rather than just go to our one module where we <strong>shimmed</strong> the function call, we now have to go to every place where we use it. This creates a domino effect in the source code that inevitably will occur from changing something in multiple places.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// You're now going to have to find any place you imported fetch</span>
<span class="hljs-comment">// Any place you alias'd it</span>
<span class="hljs-comment">// And deal with any source code failures wrapping around where you have used it once it's removed</span>
<span class="hljs-comment">// Which might be more complex than just simply searching for</span>
<span class="hljs-keyword">const</span> fetch = <span class="hljs-built_in">require</span>(<span class="hljs-string">'node-fetch'</span>);
</code></pre>
<p>We can improve this by wrapping the dependency into an appropriate <strong>shimmed abstraction</strong> and isolating its usage to one place.</p>
<p>You also get a win when onboarding people. They'll be able to see abstractions called <code>API</code> or <code>DataStore</code> which become clear signposts as to what your classes do (rather than a library that a developer may not be familiar with). </p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In your abstractions, you get the power to give it a descriptive</span>
<span class="hljs-comment">// name, if the current name isn't clear in your code too, maybe like:</span>

<span class="hljs-keyword">var</span> Money = <span class="hljs-built_in">require</span>(<span class="hljs-string">'dinero'</span>)
</code></pre>
<p>This won't be an issue for well known dependencies like <strong>Express</strong> or <strong>Lodash</strong> maybe. But I don't have a perfect memory of every NPM package and what they do. </p>
<p>When you've properly <strong>shimmed</strong> it, it doesn't even matter to the developers using your shim if you are using Fetch or Axios "under the hood". They'll never know the difference if you change it, as long as you are sensible with the shim.</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>I hope this gave a good overview of the benefits of <strong>shimming</strong>, and how it helps you maintain your dependencies.</p>
<p>This whole article was influenced by the writings of Sarah Dayan, found <a target="_blank" href="https://twitter.com/frontstuff_io/status/1264189583220244480">here</a>, and shared with her consent.</p>
<p>I share my writing on <a target="_blank" href="https://twitter.com/kealanparr">Twitter</a> if you enjoyed this article and want to see more.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Choose and Care for a Secure Open Source Project ]]>
                </title>
                <description>
                    <![CDATA[ A few tricks for assessing the security of an open source project. There is a rather progressive sect of the software development world called the open source community.  This community believes that most people would be a lot happier and get a lot m... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-choose-and-care-for-a-secure-open-source-project/</link>
                <guid isPermaLink="false">66bd8f426d46d5e73b73e911</guid>
                
                    <category>
                        <![CDATA[ Application Security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ cybersecurity ]]>
                    </category>
                
                    <category>
                        <![CDATA[ dependency management ]]>
                    </category>
                
                    <category>
                        <![CDATA[ information security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ open source ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Security ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Victoria Drake ]]>
                </dc:creator>
                <pubDate>Thu, 28 May 2020 12:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/05/cover-2.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <h3 id="heading-a-few-tricks-for-assessing-the-security-of-an-open-source-project">A few tricks for assessing the security of an open source project.</h3>
<p>There is a rather progressive sect of the software development world called the open source community. </p>
<p>This community believes that most people would be a lot happier and get a lot more work done if they stopped building things that someone else has already built and offered up for free use. They want you to take their stuff.</p>
<p><img src="https://victoria.dev/blog/how-to-choose-and-care-for-a-secure-open-source-project/wheels.png" alt="A comic I drew about using other people’s stuff, with the wheel as an example." width="600" height="400" loading="lazy"></p>
<p>Besides existing without you having to lift a finger, open source tools and software have some distinct advantages. Especially in the case of well-established projects, it’s highly likely that someone else has already worked out all the most annoying bugs for you. </p>
<p>Thanks to the ease with which users can view and modify source code, it’s also more  likely that a program has been tinkered with, improved, and secured over time. </p>
<p>When many developers contribute, they bring their own unique expertise and experiences. This can result in a product far more robust and capable than one a single developer can produce.</p>
<p>Of course, being as varied as the people who build them, not all open source projects are created equal, nor maintained to be equally secure. </p>
<p>There are many factors that affect a project’s suitability for your use case. Here are a few general considerations that make a good starting point when choosing an open source project.</p>
<h2 id="heading-how-to-choose-an-open-source-project">How to choose an open source project</h2>
<p>As its most basic requirements, a good software project is reliable, easy to understand, and has up-to-date components and security. There are several indicators that can help you make an educated guess about whether an open source project satisfies these criteria.</p>
<h3 id="heading-whos-using-it">Who’s using it</h3>
<p>Taken in context, the number of people already using an open source project may be indicative of how good it is. </p>
<p>If a project has a hundred users, for instance, it stands to reason that someone has tried to use it at least a hundred times before you found it. Thus by the ancient customs of “I don’t know what’s in that cave, you go first,” it’s more likely to be fine.</p>
<p>You can draw conclusions about a project’s user base by looking at available statistics. Depending on your platform, these may include the number of downloads, reviews, issues or tickets, comments, contributions, forks, or “stars,” whatever those are.</p>
<p>Evaluate social statistics on platforms like GitHub with a grain of salt. They can help you determine how popular a project may be, but only in the same way that restaurant review apps can help you figure out if you should eat at Foo’s Grill &amp; Bar. </p>
<p>Depending on where Foo’s Grill  &amp; Bar is, when it opened, and how likely people are to be near it when the invariable steak craving should call, having twenty-six reviews may be a good sign or a terrible one. </p>
<p>While you would not expect a project that addresses a very obscure use case or technology to have hundreds of users, having a few active users is, in such a case, just as confidence-inspiring.</p>
<p>External validation can also be useful. For example, packages that are included in a Linux operating system distribution (distro) must conform to stringent standards and undergo vetting. Choosing software that is included in a distro’s default repositories can mean it’s more likely to be secure.</p>
<p>Perhaps one of the best indications to look for is whether a project’s development team is using their own project. Look for issues, discussions, or blog posts that show that the project’s creators and maintainers are using what they’ve built themselves. Commonly referred to as <a target="_blank" href="https://en.wikipedia.org/wiki/Eating_your_own_dog_food">“eating your own dog food,"</a> or “dogfooding,” it’s an indicator that the project is most likely to be well-maintained by its developers.</p>
<h3 id="heading-whos-building-it">Who’s building it</h3>
<p>The main enemy of good open source software is usually a lack of interest. The parties involved in an open source project can make the difference between a flash-in-the-pan library and a respected long-term utility. Multiple committed maintainers, even making contributions in their spare time, have a much higher success rate of sustaining a project and generating interest.</p>
<p>Projects with healthy interest are usually supported by, and in turn cultivate, a community of contributors and users. </p>
<p>New contributors may be actively welcomed, clear guides are available explaining how to help, and project maintainers are available and approachable when people have inevitable questions. </p>
<p>Some communities even have chat rooms or forums where people can interact outside of contributions. Active communities help sustain project interest, relevance, and its ensuing quality.</p>
<p>In a less organic fashion, a project can also be sustained through organizations that sponsor it. Governments and companies with financial  interest are open source patrons too, and a project that enjoys public sector use or financial backing has added incentive to remain relevant  and useful.</p>
<h3 id="heading-how-alive-is-it">How alive is it</h3>
<p>The recency and frequency of an open source project’s activity is perhaps the best indicator of how much attention is likely paid to its security. Look at releases, commit history, changelogs, or documentation revisions to determine if a project is active. As projects vary in size and scope, here are some general things to look for.</p>
<p>Maintaining security is an ongoing endeavor that requires regular monitoring and updates, especially for projects with third-party components. These may be libraries or any part of the project that relies on something outside itself, such as a payment gateway integration. </p>
<p>An inactive project is more likely to have outdated code or use outdated versions of components. For a more concrete determination, you can research a project’s third-party components and compare their most recent patches or updates with the project’s last updates.</p>
<p>Projects without third-party components may have no outside updates to apply. In these cases, you can use recent activity and release notes to determine how committed a project’s maintainers may be. </p>
<p>Generally, active projects should show updates within the last months, with a notable release within the last year. This can be a good indication of whether the project is using an up-to-date version of its language or framework.</p>
<p>You can also judge how active a project may be by looking at the project maintainers themselves. Active maintainers quickly respond to feedback or new issues, even if it’s just to say, “We’re on it.” </p>
<p>If the project has a community, its maintainers are a part of it. They may have a dedicated website or write regular blogs. They may offer ways to contact them directly and privately, especially to raise security concerns.</p>
<h3 id="heading-can-you-understand-it">Can you understand it</h3>
<p>Having documentation is a baseline requirement for a project that’s intended for anyone but its creator to use. Good open source projects have documentation that is easy to follow, honest, and thorough.</p>
<p>Having <a target="_blank" href="https://victoria.dev/blog/word-bugs-in-software-documentation-and-how-to-fix-them/">well-written documentation</a> is one way a project can stand out and demonstrate the thoughtfulness and dedication of its maintainers. </p>
<p>A “Getting Started” section may detail all the requirements and initial set up for running the project. An accurate list of topics in the documentation enables users to quickly find the information they need. A clear license statement leaves no doubt as to how the project can be used, and for what purposes. </p>
<p>These are characteristic aspects of documentation that serves its users.</p>
<p>A project that is following sound coding practices likely has code that is as readable as its documentation. Code that is easy to read lends itself to being understood. Generally, it has clearly defined and appropriately-named functions and variables, a logical flow, and apparent purpose. Readable code is easier to fix, secure, and build upon.</p>
<h3 id="heading-how-compatible-is-it">How compatible is it</h3>
<p>A few factors will determine how compatible a project is with your  goals. These are objective qualities, and can be determined by looking at a project’s repository files. They include:</p>
<ul>
<li>Code language</li>
<li>Specific technologies or frameworks</li>
<li>License compatibility</li>
</ul>
<p>Compatibility doesn’t necessarily mean a direct match. Different code languages can interact with each other, as can various technologies and frameworks. You should carefully read a project’s license to understand if it permits usage for your goal, or if it is compatible with a license you would like to use.</p>
<p>Ultimately, a project that satisfies all these criteria may still not quite suit your use case. Part of the beauty of open source software, however, is that you may still benefit from it by making alterations that better suit your usage. If those alterations make the project better for everyone, you can pay it back and pay it forward by contributing your work to the project.</p>
<h2 id="heading-proper-care-and-feeding-of-an-open-source-project">Proper care and feeding of an open source project</h2>
<p>Once you adopt an open source project, a little attention is required to make sure it continues to be a boon to your goals. </p>
<p>While its maintainers will look after the upstream project files, you alone are responsible for your own copy. Like all software, your open source project must be well-maintained in order to remain as secure and useful as possible.</p>
<p>Have a system that provides you with notifications when updates for your software are made available. Update software promptly, treating each patch as if it were vital to security – it may well be. </p>
<p>Keep in mind  that open source project creators and maintainers are, in most cases, acting only out of the goodness of their own hearts. If you’ve got a particularly awesome one, its developers may make updates and security patches available on a regular basis. It’s up to you to keep tabs on updates and promptly apply them.</p>
<p>As with most things in software, keeping your open source additions modular can come in handy. You might use <a target="_blank" href="https://git-scm.com/book/en/v2/Git-Tools-Submodules">git submodules</a>, branches, or environments to isolate your additions. This can make it easier to apply updates or pinpoint the source of any bugs that arise.</p>
<p>So although an open source project may cost no money, <em>caveat emptor,</em> which means, “Jimmy, if we get you a puppy, it’s your responsibility to take care of it.”</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use Dependabot to Keep Your Environment Up to Date ]]>
                </title>
                <description>
                    <![CDATA[ By Leonardo Faria Adding dependencies to a project often helps you not reinvent the wheel. But at the same time it can cause issues in many different aspects of the project: Versioning: sometimes dependencies can require specific versions of other d... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/using-dependabot-to-keep-your-environment-up-to-date/</link>
                <guid isPermaLink="false">66d85182ef84e4cc27cfbe58</guid>
                
                    <category>
                        <![CDATA[ dependency management ]]>
                    </category>
                
                    <category>
                        <![CDATA[ npm ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 18 May 2020 22:28:59 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/05/zhang-kenny-2CeWChQ7AD8-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Leonardo Faria</p>
<p>Adding dependencies to a project often helps you not reinvent the wheel. But at the same time it can cause issues in many different aspects of the project:</p>
<ul>
<li>Versioning: sometimes dependencies can require specific versions of other dependencies and this can cause hiccups in your app</li>
<li>Bundling: you need to be careful not to end up with too much extra code that will bloat your bundles</li>
<li>Updating: JavaScript moves fast, and if you don't update packages regularly you'll be playing Jenga in the future.</li>
</ul>
<p>There are different tools to cover the task of updating dependencies, like <a target="_blank" href="https://dependencies.io">Dependencies.io</a>, <a target="_blank" href="https://snyk.io/">Snyk</a>, and <a target="_blank" href="https://dependabot.com/">Dependabot</a>. Since I have been using Dependabot for a while, I decided to write about my experience.</p>
<p>Dependabot is a tool acquired by GitHub a year ago that checks dependency files from different languages (Ruby, JavaScript, Python, PHP, Elixir, to name a few) and finds new versions of libraries you are using in your project. Here is the setup:</p>
<p><img src="https://leonardofaria.net/wp-content/uploads/2020/05/dependabot.jpg" alt="Dependabot screenshot" width="1560" height="1242" loading="lazy"></p>
<p>Daily updates can be overwhelming, and I think that weekly updates have a better cost/benefit. Also, I assign myself the Pull Requests so I can get notifications as soon they are opened.</p>
<h2 id="heading-how-to-use-dependabot-effectively">How to use Dependabot effectively</h2>
<p>Dependabot includes, in each PR, release notes, changelogs, commit links and vulnerability details whenever available. This is useful because you can take a look at the information and decide to proceed or not.</p>
<p>However, as pragmatic programmers, we want to ensure things won't break. The PR details are important but more than that, we want a simulation of all (or almost all) deliverables that the project has.</p>
<p><img src="https://leonardofaria.net/wp-content/uploads/2020/05/semaphore.jpg" alt="CI Integration" width="1288" height="882" loading="lazy"></p>
<p>This screenshot shows what happens every time a PR is opened in the components library codebase of my work.</p>
<ul>
<li><strong>Tests (Jest / Bundle)</strong>: the Jest task will test the React components while the Bundle task will simulate the bundling commands we run when we want to update the package in the NPM registry</li>
<li><strong>Linters (Stylesheets / JavaScript)</strong>: the stylesheet files follow a custom sass-lint setup and the JS code follows a series of ESLint rules. If a PR introduces a new version of a linter with new rules, we will be able to capture that.</li>
<li><strong>Cypress (Screenshot Testing / Accessibility Testing)</strong>: if a new package introduces changes that may be reflected in the look and feel of components, Cypress will capture the difference, screenshot it, and store in S3. Since Cypress needs a live version of the documentation website, we also get the Gatsby build process covered.</li>
</ul>
<p>With all these steps, it is very unlikely an external package will break our master branch. Kudos to my co-worker Grant Lee that also works on this project.</p>
<p>_Also posted on <a target="_blank" href="https://bit.ly/2ZhD9GC">my blog</a>. If you like this content, follow me on <a target="_blank" href="https://twitter.com/leozera">Twitter</a> and <a target="_blank" href="https://github.com/leonardofaria">GitHub</a>. Cover photo by <a target="_blank" href="https://unsplash.com/@kennyzhang29?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Zhang Kenny</a> on <a target="_blank" href="https://unsplash.com/s/photos/dependency-tree?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a>_</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Create a Production-Ready Webpack 4 Config From Scratch ]]>
                </title>
                <description>
                    <![CDATA[ By Tyler Hawkins Webpack is a powerful bundler and dependency manager used by many enterprise-level companies as tooling for their front-end code. Typically, webpack is configured when a project is first set up, and small tweaks are then made to the ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/creating-a-production-ready-webpack-4-config-from-scratch/</link>
                <guid isPermaLink="false">66d461714bc8f441cb6df82f</guid>
                
                    <category>
                        <![CDATA[ Bundler ]]>
                    </category>
                
                    <category>
                        <![CDATA[ dependency management ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Developer Tools ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Software Engineering ]]>
                    </category>
                
                    <category>
                        <![CDATA[ webpack ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Sun, 29 Mar 2020 02:40:01 +0000</pubDate>
                <media:content url="https://cdn-media-2.freecodecamp.org/w1280/5f9c9beb740569d1a4ca2ec5.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Tyler Hawkins</p>
<p><a target="_blank" href="https://webpack.js.org/">Webpack</a> is a powerful bundler and dependency manager used by many enterprise-level companies as tooling for their front-end code.</p>
<p>Typically, webpack is configured when a project is first set up, and small tweaks are then made to the config files as needed from time to time. Because of this, many developers don’t have a lot of experience working with webpack.</p>
<p>In this hands-on tutorial, we’ll go through the basics of setting up your very own production-ready webpack config using webpack 4. We’ll discuss output management, asset management, dev and prod configs, Babel, minification, cache busting, and more.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/webpack-js-opt.png" alt="Webpack bundles your code" width="600" height="400" loading="lazy">
<em>Webpack bundles your code</em></p>
<p>Let's get started!</p>
<h2 id="heading-demo-app">Demo App</h2>
<p>For the purposes of this demo, we'll be setting up a webpack config from scratch using webpack 4. Our app will just use vanilla JavaScript so that we don't get bogged down with any framework-specific details. The actual app code will be pretty small so that we can focus more on webpack.</p>
<p>If you'd like to follow along, all of the code in this article can be found in GitHub. The <a target="_blank" href="https://github.com/thawkin3/webpack-training-1/tree/demo/start">starting point is found here</a>, and the <a target="_blank" href="https://github.com/thawkin3/webpack-training-1">finished result is found here</a>.</p>
<h2 id="heading-starting-point">Starting Point</h2>
<p>To begin, we'll start out with just a few files in our project directory. The directory structure looks like this:</p>
<pre><code>webpack-demo
 |_ src
    |_ index.js
 |_ .gitignore
 |_ index.html
 |_ package.json
 |_ README.md
 |_ yarn.lock
</code></pre><p>The <code>index.html</code> file is nice and simple, just a page header and a <code>script</code> tag:</p>
<pre><code class="lang-html"><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>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Webpack Training 1<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">h1</span>&gt;</span>Webpack Training 1<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"./src/index.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</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 <code>script</code> tag references our <code>./src/index.js</code> file, which has just a few lines of JavaScript in it that outputs the text, "Hello from webpack!":</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> p = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">'p'</span>)
p.textContent = <span class="hljs-string">'Hello from webpack!'</span>
<span class="hljs-built_in">document</span>.body.append(p)
</code></pre>
<p>If you drag the <code>index.html</code> file into your browser, you should be able to view our simple web page:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/Screen-Shot-2020-03-27-at-3.10.23-PM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Demo app output 1 - hello from webpack</em></p>
<hr>
<h2 id="heading-install-dependencies">Install Dependencies</h2>
<p>I've included <code>webpack</code> and <code>webpack-cli</code> as <code>devDependencies</code> in the <code>package.json</code> file.</p>
<p>To install those, run:</p>
<pre><code class="lang-bash">yarn install
</code></pre>
<h2 id="heading-webpack-test-run">Webpack Test Run</h2>
<p>Webpack 4 is set up as a "zero config" tool, meaning that you can run it out of the box without doing any initial configuration. Now, for any real project you <em>will</em> need to do some configuration, but it's nice that you can at least do a quick sanity check to ensure that webpack is able to run without having to go through a bunch of initial configuration steps.</p>
<p>So, let's check it out. Run:</p>
<pre><code class="lang-bash">yarn webpack
</code></pre>
<p>You should now see a <code>dist</code> directory created in your project directory. And inside it you should see a <code>main.js</code> file, which is our minified code.</p>
<p>Great! Webpack appears to be working.</p>
<h2 id="heading-reference-the-output-code">Reference the Output Code</h2>
<p>OK, now that we have JavaScript code in our <code>dist</code> directory, let's have our <code>index.html</code> file reference that. Instead of the <code>script</code> tag looking like this:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"./src/index.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>Let's change it to this:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"./dist/main.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>Now, refresh the page in your browser, and you should still see the exact same output, only this time the "Hello from webpack!" text is being generated by the <code>./dist/main.js</code> file now.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/Screen-Shot-2020-03-27-at-3.10.23-PM-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Demo app output 2 - no changes</em></p>
<h2 id="heading-create-a-webpack-config-file">Create a Webpack Config File</h2>
<p>Now that we have webpack installed and have gone through a quick sanity check exercise, let's create an actual webpack config file. Create a file called <code>webpack.config.js</code> and place the following code inside it:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> path = <span class="hljs-built_in">require</span>(<span class="hljs-string">'path'</span>)

<span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-attr">entry</span>: <span class="hljs-string">'./src/index.js'</span>,
  <span class="hljs-attr">output</span>: {
    <span class="hljs-attr">filename</span>: <span class="hljs-string">'main.js'</span>,
    <span class="hljs-attr">path</span>: path.resolve(__dirname, <span class="hljs-string">'dist'</span>)
  }
}
</code></pre>
<p>The <code>entry</code> property tells webpack where our source code is located. It is the "entry point" for our app.</p>
<p>The <code>output</code> property tells webpack what to call the output file and which directory to place it in.</p>
<p>Simple enough, right?</p>
<p>Now let's create an npm script in our <code>package.json</code> file:</p>
<pre><code class="lang-json"><span class="hljs-string">"scripts"</span>: {
  <span class="hljs-attr">"build"</span>: <span class="hljs-string">"webpack --config=webpack.config.js"</span>
}
</code></pre>
<p>Now we can run our build process with the command <code>yarn build</code>. Go ahead and run that command to verify you have things set up properly. You could even delete your <code>dist</code> directory prior to running the <code>yarn build</code> command to verify that the directory is being generated.</p>
<h2 id="heading-change-the-output-file-name">Change the Output File Name</h2>
<p>Now, just for fun, let's change the output file name. To do this, we'll open up our <code>webpack.config.js</code> file and change the <code>output</code> property from this:</p>
<pre><code class="lang-javascript">output: {
  <span class="hljs-attr">filename</span>: <span class="hljs-string">'main.js'</span>,
  <span class="hljs-attr">path</span>: path.resolve(__dirname, <span class="hljs-string">'dist'</span>)
}
</code></pre>
<p>To this:</p>
<pre><code class="lang-javascript">output: {
  <span class="hljs-attr">filename</span>: <span class="hljs-string">'tacos.js'</span>,
  <span class="hljs-attr">path</span>: path.resolve(__dirname, <span class="hljs-string">'dist'</span>)
}
</code></pre>
<p>Now run <code>yarn build</code> again to generate the output. You should see a <code>tacos.js</code> file in your <code>dist</code> directory now.</p>
<p>But wait! We also see the old <code>main.js</code> file in our <code>dist</code> directory too! Wouldn't it be nice if webpack could delete the old unneeded output each time we do a new build?</p>
<p>There's got to be a plugin for that.</p>
<h2 id="heading-webpack-plugins">Webpack Plugins</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/image-178.png" alt="Image" width="600" height="400" loading="lazy">
_Photo by [Unsplash](https://unsplash.com/@feelfarbig?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit"&gt;Feelfarbig Magazine / &lt;a href="https://unsplash.com/?utm_source=ghost&amp;utm_medium=referral&amp;utm<em>campaign=api-credit)</em></p>
<p>Webpack has a rich ecosystem of modules called "<a target="_blank" href="https://webpack.js.org/concepts/#plugins">plugins</a>", which are libraries that can modify and enhance the webpack build process. We'll explore a handful of helpful plugins as we continue to improve our webpack config throughout the rest of this article.</p>
<h2 id="heading-cleanwebpackplugin">CleanWebpackPlugin</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/image-179.png" alt="Image" width="600" height="400" loading="lazy">
_Photo by [Unsplash](https://unsplash.com/@honest?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit"&gt;The Honest Company / &lt;a href="https://unsplash.com/?utm_source=ghost&amp;utm_medium=referral&amp;utm<em>campaign=api-credit)</em></p>
<p>OK, back to our problem. It'd be nice if we could clean up the <code>dist</code> directory before each new build. There's a plugin for that!</p>
<p>We can use the <a target="_blank" href="https://github.com/johnagan/clean-webpack-plugin">CleanWebpackPlugin</a> to help us here. First, we need to install it in our project:</p>
<pre><code class="lang-bash">yarn add --dev clean-webpack-plugin
</code></pre>
<p>To use it, we'll simply <code>require</code> the plugin in our <code>webpack.config.js</code> file and then include it in the <code>plugins</code> array in our config setup:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> path = <span class="hljs-built_in">require</span>(<span class="hljs-string">'path'</span>)
<span class="hljs-keyword">const</span> { CleanWebpackPlugin } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'clean-webpack-plugin'</span>)

<span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-attr">entry</span>: <span class="hljs-string">'./src/index.js'</span>,
  <span class="hljs-attr">output</span>: {
    <span class="hljs-attr">filename</span>: <span class="hljs-string">'main.js'</span>,
    <span class="hljs-attr">path</span>: path.resolve(__dirname, <span class="hljs-string">'dist'</span>)
  },
  <span class="hljs-attr">plugins</span>: [
    <span class="hljs-keyword">new</span> CleanWebpackPlugin()
  ]
}
</code></pre>
<p>Now run <code>yarn build</code> again, and you should see only a single output file in your <code>dist</code> directory. Problem solved!</p>
<h2 id="heading-htmlwebpackplugin">HTMLWebpackPlugin</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/image-180.png" alt="Image" width="600" height="400" loading="lazy">
_Photo by [Unsplash](https://unsplash.com/@rxspawn?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit"&gt;Florian Olivo / &lt;a href="https://unsplash.com/?utm_source=ghost&amp;utm_medium=referral&amp;utm<em>campaign=api-credit)</em></p>
<p>One other thing that's a little annoying with our setup is that any time we change the <code>output</code> file name in our <code>webpack.config.js</code> file, we also have to change that file name we reference in our <code>script</code> tag in our <code>index.html</code> file. Wouldn't it be nice if webpack could manage that for us?</p>
<p>There's a plugin for that! We can use the <a target="_blank" href="https://webpack.js.org/plugins/html-webpack-plugin/">HTMLWebpackPlugin</a> to help us manage our HTML file. Let's install it in our project now:</p>
<pre><code class="lang-bash">yarn add --dev html-webpack-plugin
</code></pre>
<p>Now let's move our <code>index.html</code> file inside our <code>src</code> directory so that it's a sibling to the <code>index.js</code> file.</p>
<pre><code>webpack-demo
 |_ src
    |_ index.html
    |_ index.js
 |_ .gitignore
 |_ package.json
 |_ README.md
 |_ yarn.lock
</code></pre><p>We can also delete the <code>script</code> tag in our <code>index.html</code> file since we'll have webpack handle inserting the appropriate <code>script</code> tag for us. Delete that line so that your <code>index.html</code> file looks like this:</p>
<pre><code class="lang-html"><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>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Webpack Training 1<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">h1</span>&gt;</span>Webpack Training 1<span class="hljs-tag">&lt;/<span class="hljs-name">h1</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>Now let's <code>require</code> this plugin in our <code>webpack.config.js</code> file and then include it in the <code>plugins</code> array in our config setup, just like we did for the first plugin:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> path = <span class="hljs-built_in">require</span>(<span class="hljs-string">'path'</span>)
<span class="hljs-keyword">const</span> { CleanWebpackPlugin } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'clean-webpack-plugin'</span>)
<span class="hljs-keyword">const</span> HtmlWebpackPlugin = <span class="hljs-built_in">require</span>(<span class="hljs-string">'html-webpack-plugin'</span>)

<span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-attr">entry</span>: <span class="hljs-string">'./src/index.js'</span>,
  <span class="hljs-attr">output</span>: {
    <span class="hljs-attr">filename</span>: <span class="hljs-string">'main.js'</span>,
    <span class="hljs-attr">path</span>: path.resolve(__dirname, <span class="hljs-string">'dist'</span>)
  },
  <span class="hljs-attr">plugins</span>: [
    <span class="hljs-keyword">new</span> CleanWebpackPlugin(),
    <span class="hljs-keyword">new</span> HtmlWebpackPlugin({
      <span class="hljs-attr">filename</span>: <span class="hljs-string">'index.html'</span>,
      <span class="hljs-attr">inject</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">template</span>: path.resolve(__dirname, <span class="hljs-string">'src'</span>, <span class="hljs-string">'index.html'</span>),
    }),
  ]
}
</code></pre>
<p>In those options for the <code>HtmlWebpackPlugin</code>, we specify the <code>filename</code> for what we'd like the output file to be called.</p>
<p>We specify for <code>inject</code> that we would like our JavaScript file to be injected into the <code>body</code> tag by setting the value to <code>true</code>.</p>
<p>And finally, for the <code>template</code> we supply the location of our <code>index.html</code> file in the <code>src</code> directory.</p>
<h2 id="heading-sanity-check">Sanity Check</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/image-181.png" alt="Image" width="600" height="400" loading="lazy">
_Photo by [Unsplash](https://unsplash.com/@glenncarstenspeters?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit"&gt;Glenn Carstens-Peters / &lt;a href="https://unsplash.com/?utm_source=ghost&amp;utm_medium=referral&amp;utm<em>campaign=api-credit)</em></p>
<p>OK, let's make sure everything is still working properly. Run <code>yarn build</code>, and verify that you see two files in your <code>dist</code> directory: <code>index.html</code> and <code>main.js</code>.</p>
<p>If you look closely in your <code>index.html</code> file, you'll see the <code>main.js</code> file referenced.</p>
<p>Now, open the <code>./dist/index.html</code> file in your browser to verify that your page loads correctly. If you followed these steps correctly, your page should still be working:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/Screen-Shot-2020-03-27-at-3.10.23-PM-2.png" alt="Image" width="600" height="400" loading="lazy">
<em>Demo app output 3 - no changes</em></p>
<h2 id="heading-create-a-development-server">Create a Development Server</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/image-182.png" alt="Image" width="600" height="400" loading="lazy">
_Photo by [Unsplash](https://unsplash.com/@tvick?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit"&gt;Taylor Vick / &lt;a href="https://unsplash.com/?utm_source=ghost&amp;utm_medium=referral&amp;utm<em>campaign=api-credit)</em></p>
<p>We've made some good improvements so far using the <code>CleanWebpackPlugin</code> and the <code>HtmlWebpackPlugin</code>. As we've made these changes, we've had to manually run the <code>yarn build</code> command each time to see new changes in our app. We've also just been viewing the file in our browser rather than viewing the content served from a server running locally. Let's improve our process by creating a development server.</p>
<p>To do this, we'll use <code>webpack-dev-server</code>. First, we'll need to install it:</p>
<pre><code class="lang-bash">yarn add --dev webpack-dev-server
</code></pre>
<p>Now, let's split up our single <code>webpack.config.js</code> file into two separate config files, one for production and one for development. We'll call the file for production <code>webpack.config.prod.js</code> and the file for development <code>webpack.config.dev.js</code>.</p>
<h2 id="heading-development-webpack-config">Development Webpack Config</h2>
<p>Here's our development config file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> path = <span class="hljs-built_in">require</span>(<span class="hljs-string">'path'</span>)
<span class="hljs-keyword">const</span> { CleanWebpackPlugin } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'clean-webpack-plugin'</span>)
<span class="hljs-keyword">const</span> HtmlWebpackPlugin = <span class="hljs-built_in">require</span>(<span class="hljs-string">'html-webpack-plugin'</span>)

<span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-attr">mode</span>: <span class="hljs-string">'development'</span>,
  <span class="hljs-attr">devtool</span>: <span class="hljs-string">'inline-source-map'</span>,
  <span class="hljs-attr">devServer</span>: {
    <span class="hljs-attr">contentBase</span>: <span class="hljs-string">'./dist'</span>,
  },
  <span class="hljs-attr">entry</span>: <span class="hljs-string">'./src/index.js'</span>,
  <span class="hljs-attr">output</span>: {
    <span class="hljs-attr">filename</span>: <span class="hljs-string">'main.js'</span>,
    <span class="hljs-attr">path</span>: path.resolve(__dirname, <span class="hljs-string">'dist'</span>)
  },
  <span class="hljs-attr">plugins</span>: [
    <span class="hljs-keyword">new</span> CleanWebpackPlugin(),
    <span class="hljs-keyword">new</span> HtmlWebpackPlugin({
      <span class="hljs-attr">filename</span>: <span class="hljs-string">'index.html'</span>,
      <span class="hljs-attr">inject</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">template</span>: path.resolve(__dirname, <span class="hljs-string">'src'</span>, <span class="hljs-string">'index.html'</span>),
    }),
  ]
}
</code></pre>
<p>Note that we've specified the <code>mode</code> as <code>development</code> now, and we've specified that we would like an <code>inline-source-map</code> for our JavaScript files, meaning that a source map is included at the end of each JavaScript file. For our dev server, we've specified that our content will be found in the <code>dist</code> directory.</p>
<p>All the rest of the development config has stayed the same.</p>
<h2 id="heading-production-webpack-config">Production Webpack Config</h2>
<p>Now, here's our production config file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> path = <span class="hljs-built_in">require</span>(<span class="hljs-string">'path'</span>)
<span class="hljs-keyword">const</span> { CleanWebpackPlugin } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'clean-webpack-plugin'</span>)
<span class="hljs-keyword">const</span> HtmlWebpackPlugin = <span class="hljs-built_in">require</span>(<span class="hljs-string">'html-webpack-plugin'</span>)

<span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-attr">mode</span>: <span class="hljs-string">'production'</span>,
  <span class="hljs-attr">devtool</span>: <span class="hljs-string">'source-map'</span>,
  <span class="hljs-attr">entry</span>: <span class="hljs-string">'./src/index.js'</span>,
  <span class="hljs-attr">output</span>: {
    <span class="hljs-attr">filename</span>: <span class="hljs-string">'main.js'</span>,
    <span class="hljs-attr">path</span>: path.resolve(__dirname, <span class="hljs-string">'dist'</span>)
  },
  <span class="hljs-attr">plugins</span>: [
    <span class="hljs-keyword">new</span> CleanWebpackPlugin(),
    <span class="hljs-keyword">new</span> HtmlWebpackPlugin({
      <span class="hljs-attr">filename</span>: <span class="hljs-string">'index.html'</span>,
      <span class="hljs-attr">inject</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">template</span>: path.resolve(__dirname, <span class="hljs-string">'src'</span>, <span class="hljs-string">'index.html'</span>),
    }),
  ]
}
</code></pre>
<p>This file also looks very similar to our original config file. Here we've specified that the <code>mode</code> is <code>production</code> and that we would like the <code>source-map</code> option for source maps, which provides separate source map files for minified code.</p>
<h2 id="heading-production-and-development-npm-scripts">Production and Development NPM Scripts</h2>
<p>Finally, let's add a few more npm scripts in our <code>package.json</code> file so that we can work with our development and production webpack configs:</p>
<pre><code class="lang-json"><span class="hljs-string">"scripts"</span>: {
  <span class="hljs-attr">"build"</span>: <span class="hljs-string">"webpack --config=webpack.config.prod.js"</span>,
  <span class="hljs-attr">"build-dev"</span>: <span class="hljs-string">"webpack --config=webpack.config.dev.js"</span>,
  <span class="hljs-attr">"start"</span>: <span class="hljs-string">"webpack-dev-server --config=webpack.config.dev.js --open"</span>
}
</code></pre>
<p>Now, let's try out each of these scripts.</p>
<p>Run <code>yarn build</code> to see the production build output. You should see that the <code>main.js</code> file in your <code>dist</code> directory is minified and that it has an accompanying <code>main.js.map</code> source map file.</p>
<p>Now run <code>yarn build-dev</code> to see the development build output. You should see the <code>main.js</code> file in your <code>dist</code> directory, but now note that it is <strong>not</strong> minified.</p>
<p>Lastly, run <code>yarn start</code> to start up the development server. This will open up the app on <code>http://localhost:8080/</code>. No more having to view the files directly by just pulling them into your browser! We now have a real live development server!</p>
<p>The output you see should still look the same as it always has:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/Screen-Shot-2020-03-27-at-3.10.23-PM-3.png" alt="Image" width="600" height="400" loading="lazy">
<em>Demo app output 4 - no changes</em></p>
<h2 id="heading-making-changes-during-development">Making Changes During Development</h2>
<p>Now that we have a working dev server, let's experiment with making some simple changes to our <code>./src/index.js</code> file. Instead of outputting "Hello from webpack!", let's change it to say "Hello from dev server!".</p>
<p>Save the file, and then see the page on your dev server automatically reload and update for you! That'll be a nice boost to your developer productivity.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/Screen-Shot-2020-03-27-at-4.16.13-PM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Demo app output 5 - hello from dev server</em></p>
<h2 id="heading-dont-repeat-yourself-dry">Don't Repeat Yourself (DRY)</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/image-183.png" alt="Image" width="600" height="400" loading="lazy">
_Photo by [Unsplash](https://unsplash.com/@tobey_j?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit"&gt;Tobias Jelskov / &lt;a href="https://unsplash.com/?utm_source=ghost&amp;utm_medium=referral&amp;utm<em>campaign=api-credit)</em></p>
<p>Now that we have two separate webpack config files, one for development and one for production, you may have noticed that we have a lot of duplicated code between the two files.</p>
<p>Every developer out there has had the DRY principle drilled into their heads since day one: Don't repeat yourself. If you find yourself writing the same code in multiple places, it may be a good idea to turn that into shared code that can be written in one place and then used in multiple places. That way when you need to make changes, you only need to implement those changes in one place.</p>
<p>So, how can we clean up the duplication in our webpack config files? There's a plugin for that!</p>
<h2 id="heading-webpackmerge">WebpackMerge</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/merge.png" alt="Merge" width="600" height="400" loading="lazy">
<em>Merge</em></p>
<p>We can use the <a target="_blank" href="https://github.com/survivejs/webpack-merge">webpack-merge</a> plugin to manage shared code that multiple config files rely on. To do this, we'll first install the package:</p>
<pre><code class="lang-bash">yarn add --dev webpack-merge
</code></pre>
<p>Now we'll create a third webpack config file called <code>webpack.config.common.js</code>. This is where we'll keep our shared code. Right now, our development and production config files share the same entry point, output, and plugins. All that differs between the two files are the mode, source map, and dev server.</p>
<p>So, the contents of our <code>webpack.config.common.js</code> file will be:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> path = <span class="hljs-built_in">require</span>(<span class="hljs-string">'path'</span>)
<span class="hljs-keyword">const</span> { CleanWebpackPlugin } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'clean-webpack-plugin'</span>)
<span class="hljs-keyword">const</span> HtmlWebpackPlugin = <span class="hljs-built_in">require</span>(<span class="hljs-string">'html-webpack-plugin'</span>)

<span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-attr">entry</span>: <span class="hljs-string">'./src/index.js'</span>,
  <span class="hljs-attr">output</span>: {
    <span class="hljs-attr">filename</span>: <span class="hljs-string">'main.js'</span>,
    <span class="hljs-attr">path</span>: path.resolve(__dirname, <span class="hljs-string">'dist'</span>)
  },
  <span class="hljs-attr">plugins</span>: [
    <span class="hljs-keyword">new</span> CleanWebpackPlugin(),
    <span class="hljs-keyword">new</span> HtmlWebpackPlugin({
      <span class="hljs-attr">filename</span>: <span class="hljs-string">'index.html'</span>,
      <span class="hljs-attr">inject</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">template</span>: path.resolve(__dirname, <span class="hljs-string">'src'</span>, <span class="hljs-string">'index.html'</span>),
    }),
  ]
}
</code></pre>
<p>And now, we can merge this shared config object into our development config like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> merge = <span class="hljs-built_in">require</span>(<span class="hljs-string">'webpack-merge'</span>)
<span class="hljs-keyword">const</span> commonConfig = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./webpack.config.common'</span>)

<span class="hljs-built_in">module</span>.exports = merge(commonConfig, {
  <span class="hljs-attr">mode</span>: <span class="hljs-string">'development'</span>,
  <span class="hljs-attr">devtool</span>: <span class="hljs-string">'inline-source-map'</span>,
  <span class="hljs-attr">devServer</span>: {
    <span class="hljs-attr">contentBase</span>: <span class="hljs-string">'./dist'</span>,
  },
})
</code></pre>
<p>And we can merge the shared config object into our production config like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> merge = <span class="hljs-built_in">require</span>(<span class="hljs-string">'webpack-merge'</span>)
<span class="hljs-keyword">const</span> commonConfig = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./webpack.config.common'</span>)

<span class="hljs-built_in">module</span>.exports = merge(commonConfig, {
  <span class="hljs-attr">mode</span>: <span class="hljs-string">'production'</span>,
  <span class="hljs-attr">devtool</span>: <span class="hljs-string">'source-map'</span>,
})
</code></pre>
<p>Look how much shorter and cleaner those two files look! Beautiful!</p>
<h2 id="heading-styling-our-app">Styling Our App</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/image-184.png" alt="Image" width="600" height="400" loading="lazy">
_Photo by [Unsplash](https://unsplash.com/@madebyvadim?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit"&gt;Vadim Sherbakov / &lt;a href="https://unsplash.com/?utm_source=ghost&amp;utm_medium=referral&amp;utm<em>campaign=api-credit)</em></p>
<p>Things are looking pretty good with our webpack configs so far. We have a working dev server and we've split out our code into development, production, and shared configuration files.</p>
<p>Let's start working on our actual app code now. The plain black and white page is a little boring to look at. Let's style it up!</p>
<p>In our <code>src</code> directory, let's create an <code>index.css</code> file and place the following lines of CSS inside it:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">background</span>: deeppink;
  <span class="hljs-attribute">color</span>: white;
}
</code></pre>
<p>Then, in our <code>./src/index.js</code> file, let's import that CSS file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> <span class="hljs-string">'./index.css'</span>
</code></pre>
<p>Now, run <code>yarn start</code> to get our development server running again.</p>
<p>Oh no! We get an error!</p>
<pre><code>ERROR <span class="hljs-keyword">in</span> ./src/index.css <span class="hljs-number">1</span>:<span class="hljs-number">5</span>
Module parse failed: Unexpected token (<span class="hljs-number">1</span>:<span class="hljs-number">5</span>)
You may need an appropriate loader to handle <span class="hljs-built_in">this</span> file type, currently no loaders are configured to process <span class="hljs-built_in">this</span> file. See https:<span class="hljs-comment">//webpack.js.org/concepts#loaders</span>
&gt; body {
|   background: deeppink;
|   color: white;
 @ ./src/index.js <span class="hljs-number">1</span>:<span class="hljs-number">0</span><span class="hljs-number">-20</span>
</code></pre><p>What are these "loaders" it speaks of?</p>
<h2 id="heading-webpack-loaders">Webpack Loaders</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/image-185.png" alt="Image" width="600" height="400" loading="lazy">
_Photo by [Unsplash](https://unsplash.com/@kevin_butz?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit"&gt;Kevin Butz / &lt;a href="https://unsplash.com/?utm_source=ghost&amp;utm_medium=referral&amp;utm<em>campaign=api-credit)</em></p>
<p>Earlier, we discussed webpack plugins, which let you extend the webpack build process. There is also an ecosystem of webpack "<a target="_blank" href="https://webpack.js.org/loaders/">loaders</a>", which help webpack know how to understand and load different file types. Out of the box, webpack understands how to handle our JavaScript files, but it doesn't know what to do with CSS files yet. Let's fix that.</p>
<h2 id="heading-styleloader-and-cssloader">StyleLoader and CSSLoader</h2>
<p>There are two loaders in particular that will be helpful for us here: <a target="_blank" href="https://webpack.js.org/loaders/style-loader/">style-loader</a> and <a target="_blank" href="https://webpack.js.org/loaders/css-loader/">css-loader</a>. Let's get those included in our project and then discuss how they work.</p>
<p>To start, as always, we'll need to install those two dependencies:</p>
<pre><code class="lang-bash">yarn add --dev style-loader css-loader
</code></pre>
<p>Then we can add them to our <code>webpack.config.common.js</code> file in the module rules section down at the bottom:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> path = <span class="hljs-built_in">require</span>(<span class="hljs-string">'path'</span>)
<span class="hljs-keyword">const</span> { CleanWebpackPlugin } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'clean-webpack-plugin'</span>)
<span class="hljs-keyword">const</span> HtmlWebpackPlugin = <span class="hljs-built_in">require</span>(<span class="hljs-string">'html-webpack-plugin'</span>)

<span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-attr">entry</span>: <span class="hljs-string">'./src/index.js'</span>,
  <span class="hljs-attr">output</span>: {
    <span class="hljs-attr">filename</span>: <span class="hljs-string">'main.js'</span>,
    <span class="hljs-attr">path</span>: path.resolve(__dirname, <span class="hljs-string">'dist'</span>)
  },
  <span class="hljs-attr">plugins</span>: [
    <span class="hljs-keyword">new</span> CleanWebpackPlugin(),
    <span class="hljs-keyword">new</span> HtmlWebpackPlugin({
      <span class="hljs-attr">filename</span>: <span class="hljs-string">'index.html'</span>,
      <span class="hljs-attr">inject</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">template</span>: path.resolve(__dirname, <span class="hljs-string">'src'</span>, <span class="hljs-string">'index.html'</span>),
    }),
  ],
  <span class="hljs-attr">module</span>: {
    <span class="hljs-attr">rules</span>: [
      {
        <span class="hljs-attr">test</span>: <span class="hljs-regexp">/\.css$/</span>,
        use: [<span class="hljs-string">'style-loader'</span>, <span class="hljs-string">'css-loader'</span>]
      }
    ]
  }
}
</code></pre>
<p>This section sets up rules for webpack so it knows what to do with each file it encounters. The <code>test</code> property is a regular expression that webpack checks against the file name. In this case, we want to handle files with a <code>.css</code> extension.</p>
<p>Then, the <code>use</code> property tells webpack what loader or loaders to use to handle files matching the criteria. Note that the order here matters!</p>
<p>Webpack loaders are read from right to left. So first the <code>css-loader</code> will be applied, and then the <code>style-loader</code> will be applied.</p>
<p>Now, what do these loaders actually do for us?</p>
<p><code>css-loader</code> interprets and resolves imported CSS files that you reference in your JavaScript. So in this case, <code>css-loader</code> helps make this line work:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> <span class="hljs-string">'./index.css'</span>
</code></pre>
<p>Next, <code>style-loader</code> injects the CSS into the DOM. By default, <code>style-loader</code> takes the CSS it encounters and adds it to the DOM inside a <code>style</code> tag.</p>
<p>Let's restart our dev server by killing the current process (if you still have it running) and then starting it again with <code>yarn start</code>. Now, in the web browser, you should see this on <code>https://localhost:8080/</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/Screen-Shot-2020-03-28-at-1.07.03-PM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Demo app output 6 - adds pink and white colors</em></p>
<p>Oooh, so colorful!</p>
<h2 id="heading-a-note-on-other-webpack-loaders">A Note on Other Webpack Loaders</h2>
<p>We won't cover loaders for other file types in this article, but be aware that there's a loader for everything imaginable! You can use <a target="_blank" href="https://webpack.js.org/loaders/file-loader/">file-loader</a> or <a target="_blank" href="https://webpack.js.org/loaders/url-loader/">url-loader</a> for loading images and other assets. You can use <a target="_blank" href="https://webpack.js.org/loaders/sass-loader/">sass-loader</a> to handle converting Sass/SCSS files to CSS before piping that output to <code>css-loader</code> and <code>style-loader</code>. Webpack can handle Less files too with <a target="_blank" href="https://webpack.js.org/loaders/less-loader/">less-loader</a> if that's your preference.</p>
<p>The moral of the story is: For any given file type, there's a loader that can handle it.</p>
<h2 id="heading-babelloader">BabelLoader</h2>
<p>Ok, back to our demo app. We've written just a few lines of JavaScript so far. It'd be nice if we could write our JavaScript using new features that aren't well-supported in every browser yet. <a target="_blank" href="https://babeljs.io/">Babel</a> is a JavaScript compiler that can turn ES6+ code into ES5 code. </p>
<p>And (you guessed it), there's a loader for that: <a target="_blank" href="https://babeljs.io/setup#installation">babel-loader</a>.</p>
<p>To set up <code>babel-loader</code>, we'll follow the instructions on their installation guide linked above.</p>
<p>First, we'll install our dependencies:</p>
<pre><code class="lang-bash">yarn add --dev babel-loader @babel/core
</code></pre>
<p>Next, we'll add a new rule to our module rules array in our <code>webpack.config.common.js</code> file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> path = <span class="hljs-built_in">require</span>(<span class="hljs-string">'path'</span>)
<span class="hljs-keyword">const</span> { CleanWebpackPlugin } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'clean-webpack-plugin'</span>)
<span class="hljs-keyword">const</span> HtmlWebpackPlugin = <span class="hljs-built_in">require</span>(<span class="hljs-string">'html-webpack-plugin'</span>)

<span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-attr">entry</span>: <span class="hljs-string">'./src/index.js'</span>,
  <span class="hljs-attr">output</span>: {
    <span class="hljs-attr">filename</span>: <span class="hljs-string">'main.js'</span>,
    <span class="hljs-attr">path</span>: path.resolve(__dirname, <span class="hljs-string">'dist'</span>)
  },
  <span class="hljs-attr">plugins</span>: [
    <span class="hljs-keyword">new</span> CleanWebpackPlugin(),
    <span class="hljs-keyword">new</span> HtmlWebpackPlugin({
      <span class="hljs-attr">filename</span>: <span class="hljs-string">'index.html'</span>,
      <span class="hljs-attr">inject</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">template</span>: path.resolve(__dirname, <span class="hljs-string">'src'</span>, <span class="hljs-string">'index.html'</span>),
    }),
  ],
  <span class="hljs-attr">module</span>: {
    <span class="hljs-attr">rules</span>: [
      {
        <span class="hljs-attr">test</span>: <span class="hljs-regexp">/\.css$/</span>,
        use: [<span class="hljs-string">'style-loader'</span>, <span class="hljs-string">'css-loader'</span>]
      },
      {
        <span class="hljs-attr">test</span>: <span class="hljs-regexp">/\.(js|jsx)$/</span>,
        exclude: <span class="hljs-regexp">/[\\/]node_modules[\\/]/</span>,
        use: {
          <span class="hljs-attr">loader</span>: <span class="hljs-string">'babel-loader'</span>,
        },
      },
    ]
  }
}
</code></pre>
<p>This will tell webpack that when it encounters <code>.js</code> or <code>.jsx</code> files to use Babel to transform the code. We use the <code>exclude</code> property to make sure Babel doesn't try to transform JavaScript files in our <code>node_modules</code> directory. Those are third-party dependencies that should already have been taken care of by their creators.</p>
<p>Next, we'll add one more dependency for a Babel preset:</p>
<pre><code class="lang-bash">yarn add --dev @babel/preset-env
</code></pre>
<p>And then we'll create a <code>.babelrc</code> file where we can do other Babel configuration as needed. We'll keep our file pretty simple and just specify the Babel preset that we want to use:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"presets"</span>: [<span class="hljs-string">"@babel/preset-env"</span>]
}
</code></pre>
<p>And finally, let's write some ES6 code in our <code>./src/index.js</code> file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> <span class="hljs-string">'./index.css'</span>

<span class="hljs-keyword">const</span> p = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">'p'</span>)
p.textContent = <span class="hljs-string">'Hello from webpack!'</span>
<span class="hljs-built_in">document</span>.body.appendChild(p)

<span class="hljs-keyword">const</span> p2 = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">'p'</span>)
<span class="hljs-keyword">const</span> numbers1 = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>, <span class="hljs-number">6</span>]
<span class="hljs-keyword">const</span> numbers2 = [<span class="hljs-number">7</span>, <span class="hljs-number">8</span>, <span class="hljs-number">9</span>, <span class="hljs-number">10</span>]
<span class="hljs-keyword">const</span> numbers3 = [...numbers1, ...numbers2]
p2.textContent = numbers3.join(<span class="hljs-string">' '</span>)
<span class="hljs-built_in">document</span>.body.appendChild(p2)
</code></pre>
<p>This is a really trivial example, but we're using the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax">spread operator</a> here to concatenate two arrays.</p>
<p>Now, if we kill our running process and run <code>yarn start</code> again, we should see this in the browser:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/Screen-Shot-2020-03-28-at-1.25.19-PM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Demo app output 7 - adds numbers</em></p>
<p>Great! Everything is working nicely.</p>
<h2 id="heading-temporarily-missing-styles">Temporarily Missing Styles</h2>
<p>If you disable the cache in your browser and reload the page for our demo app, you may notice a slight blip in which the page appears with just the un-styled HTML, and then the page background turns pink and the text turns white as the styles are applied.</p>
<p>This behavior results from how <code>style-loader</code> works. As mentioned above, <code>style-loader</code> takes CSS and places it in a <code>style</code> tag in your HTML. Because of that, there's a brief period of time in which the <code>style</code> tag hasn't been appended yet!</p>
<p>Now, this is OK for a development environment, but we definitely wouldn't want this kind of behavior occurring in production. Let's fix that.</p>
<h2 id="heading-minicssextractplugin">MiniCssExtractPlugin</h2>
<p>Rather than injecting CSS into our HTML as <code>style</code> tags, we can use the <a target="_blank" href="https://webpack.js.org/plugins/mini-css-extract-plugin/">MiniCssExtractPlugin</a> to generate separate CSS files for us. We'll use this in our production config while still just using <code>style-loader</code> in our development config.</p>
<p>First, let's install the dependency in our project:</p>
<pre><code class="lang-bash">yarn add --dev mini-css-extract-plugin
</code></pre>
<p>Now in our <code>webpack.config.common.js</code> file let's remove the CSS rule since we'll be handling this differently in development and production. We're left with this in our shared config:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> path = <span class="hljs-built_in">require</span>(<span class="hljs-string">'path'</span>)
<span class="hljs-keyword">const</span> { CleanWebpackPlugin } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'clean-webpack-plugin'</span>)
<span class="hljs-keyword">const</span> HtmlWebpackPlugin = <span class="hljs-built_in">require</span>(<span class="hljs-string">'html-webpack-plugin'</span>)

<span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-attr">entry</span>: <span class="hljs-string">'./src/index.js'</span>,
  <span class="hljs-attr">output</span>: {
    <span class="hljs-attr">filename</span>: <span class="hljs-string">'main.js'</span>,
    <span class="hljs-attr">path</span>: path.resolve(__dirname, <span class="hljs-string">'dist'</span>)
  },
  <span class="hljs-attr">plugins</span>: [
    <span class="hljs-keyword">new</span> CleanWebpackPlugin(),
    <span class="hljs-keyword">new</span> HtmlWebpackPlugin({
      <span class="hljs-attr">filename</span>: <span class="hljs-string">'index.html'</span>,
      <span class="hljs-attr">inject</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">template</span>: path.resolve(__dirname, <span class="hljs-string">'src'</span>, <span class="hljs-string">'index.html'</span>),
    }),
  ],
  <span class="hljs-attr">module</span>: {
    <span class="hljs-attr">rules</span>: [
      {
        <span class="hljs-attr">test</span>: <span class="hljs-regexp">/\.(js|jsx)$/</span>,
        exclude: <span class="hljs-regexp">/[\\/]node_modules[\\/]/</span>,
        use: {
          <span class="hljs-attr">loader</span>: <span class="hljs-string">'babel-loader'</span>,
        },
      },
    ]
  }
}
</code></pre>
<p>Now, in our <code>webpack.config.dev.js</code> file, let's add back in <code>style-loader</code> and <code>css-loader</code> that we just removed from our shared config:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> merge = <span class="hljs-built_in">require</span>(<span class="hljs-string">'webpack-merge'</span>)
<span class="hljs-keyword">const</span> commonConfig = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./webpack.config.common'</span>)

<span class="hljs-built_in">module</span>.exports = merge(commonConfig, {
  <span class="hljs-attr">mode</span>: <span class="hljs-string">'development'</span>,
  <span class="hljs-attr">devtool</span>: <span class="hljs-string">'inline-source-map'</span>,
  <span class="hljs-attr">devServer</span>: {
    <span class="hljs-attr">contentBase</span>: <span class="hljs-string">'./dist'</span>,
  },
  <span class="hljs-attr">module</span>: {
    <span class="hljs-attr">rules</span>: [
      {
        <span class="hljs-attr">test</span>: <span class="hljs-regexp">/\.css$/</span>,
        use: [<span class="hljs-string">'style-loader'</span>, <span class="hljs-string">'css-loader'</span>]
      },
    ]
  }
})
</code></pre>
<p>And finally, in our <code>webpack.config.prod.js</code> file, let's add in our new <code>mini-css-extract-plugin</code>:</p>
<pre><code><span class="hljs-keyword">const</span> merge = <span class="hljs-built_in">require</span>(<span class="hljs-string">'webpack-merge'</span>)
<span class="hljs-keyword">const</span> MiniCssExtractPlugin = <span class="hljs-built_in">require</span>(<span class="hljs-string">'mini-css-extract-plugin'</span>);
<span class="hljs-keyword">const</span> commonConfig = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./webpack.config.common'</span>)

<span class="hljs-built_in">module</span>.exports = merge(commonConfig, {
  <span class="hljs-attr">mode</span>: <span class="hljs-string">'production'</span>,
  <span class="hljs-attr">devtool</span>: <span class="hljs-string">'source-map'</span>,
  <span class="hljs-attr">module</span>: {
    <span class="hljs-attr">rules</span>: [
      {
        <span class="hljs-attr">test</span>: <span class="hljs-regexp">/\.css$/</span>,
        use: [
          MiniCssExtractPlugin.loader,
          <span class="hljs-string">'css-loader'</span>,
        ],
      },
    ],
  },
  <span class="hljs-attr">plugins</span>: [
    <span class="hljs-keyword">new</span> MiniCssExtractPlugin({
      <span class="hljs-attr">filename</span>: <span class="hljs-string">'[name].[contenthash].css'</span>,
    }),
  ]
})
</code></pre><p>This one is a little different because it actually is both a plugin <em>and</em> a loader, so it goes in the module rules and in the plugins sections.</p>
<p>Also note that we use the square brackets in our file name to dynamically set the <code>name</code> to the original source file's name and also include the <code>contenthash</code>, which is a hash (an alphanumeric string) that represents the file's contents.</p>
<p>Now if you run <code>yarn build</code> this time to generate the production build, you should get some output in your terminal that looks like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/Screen-Shot-2020-03-28-at-1.57.28-PM.png" alt="Webpack production build output" width="600" height="400" loading="lazy">
<em>Webpack production build output</em></p>
<p>Note that it actually generates a CSS file now, and the content hash is included in the file name.</p>
<p>Alright, problem solved! No more blip when the page loads in production since we have the styles included as a <code>link</code> tag to an actual CSS file.</p>
<h2 id="heading-cache-busting">Cache Busting</h2>
<p>Since we've included the content hash in the generated CSS file, now is a good time to talk about cache busting. Why, you ask, would we want the content hash included in our file names? To help the browser understand when a file has changed!</p>
<p>Your browser tries to be helpful by caching files it has seen before. For example, if you've visited a website, and your browser had to download assets like JavaScript, CSS, or image files, your browser may cache those files so that it doesn't have to request them from the server again.</p>
<p>This means that if you visit the site again, your browser can use the cached files instead of requesting them again, so you get a faster page load time and a better experience.</p>
<p>So, what's the problem here? Imagine if we had a file called <code>main.js</code> used in our app. Then, a user visits your app and their browser caches the <code>main.js</code> file. </p>
<p>Now, at some later point in time, you've released new code for your app. The contents of the <code>main.js</code> file have changed. But, when this same user visits your app again, the browser sees that it needs a <code>main.js</code> file, notes that it has a cached <code>main.js</code> file, and just uses the cached version. The user doesn't get your new code!</p>
<p>To solve this problem, a common practice is to include the content hash in each file's name. As discussed earlier, the content hash is a string representation of the file's contents. If the file's contents don't change, the content hash doesn't change. But, if the file's contents <em>do</em> change, then the content hash <em>also</em> changes.</p>
<p>Because the file name will now change when the code changes, the browser will download the new file since it won't have that specific file name in its cache.</p>
<h2 id="heading-including-the-content-hash">Including the Content Hash</h2>
<p>To include the content hash in our JavaScript file names, we'll modify just one line of code in our <code>webpack.config.common.js</code> file. This line:</p>
<pre><code class="lang-javascript">filename: <span class="hljs-string">'main.js'</span>
</code></pre>
<p>Will change to this line:</p>
<pre><code class="lang-javascript">filename: <span class="hljs-string">'[name].[contenthash].js'</span>
</code></pre>
<p>So that the entire file looks like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> path = <span class="hljs-built_in">require</span>(<span class="hljs-string">'path'</span>)
<span class="hljs-keyword">const</span> { CleanWebpackPlugin } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'clean-webpack-plugin'</span>)
<span class="hljs-keyword">const</span> HtmlWebpackPlugin = <span class="hljs-built_in">require</span>(<span class="hljs-string">'html-webpack-plugin'</span>)

<span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-attr">entry</span>: <span class="hljs-string">'./src/index.js'</span>,
  <span class="hljs-attr">output</span>: {
    <span class="hljs-attr">filename</span>: <span class="hljs-string">'[name].[contenthash].js'</span>, <span class="hljs-comment">// this line is the only difference</span>
    <span class="hljs-attr">path</span>: path.resolve(__dirname, <span class="hljs-string">'dist'</span>)
  },
  <span class="hljs-attr">plugins</span>: [
    <span class="hljs-keyword">new</span> CleanWebpackPlugin(),
    <span class="hljs-keyword">new</span> HtmlWebpackPlugin({
      <span class="hljs-attr">filename</span>: <span class="hljs-string">'index.html'</span>,
      <span class="hljs-attr">inject</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">template</span>: path.resolve(__dirname, <span class="hljs-string">'src'</span>, <span class="hljs-string">'index.html'</span>),
    }),
  ],
  <span class="hljs-attr">module</span>: {
    <span class="hljs-attr">rules</span>: [
      {
        <span class="hljs-attr">test</span>: <span class="hljs-regexp">/\.(js|jsx)$/</span>,
        exclude: <span class="hljs-regexp">/[\\/]node_modules[\\/]/</span>,
        use: {
          <span class="hljs-attr">loader</span>: <span class="hljs-string">'babel-loader'</span>,
        },
      },
    ]
  }
}
</code></pre>
<p>Now if you run <code>yarn build</code>, you'll see that both your JavaScript and your CSS have content hashes included:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/Screen-Shot-2020-03-28-at-2.12.27-PM.png" alt="Webpack production build output with content hashes included" width="600" height="400" loading="lazy">
<em>Webpack production build output with content hashes included</em></p>
<p>If you run <code>yarn build</code> again and compare your new output to your old output, you'll notice that the content hashes are exactly the same both times.</p>
<p>But, if you edit your <code>./src/index.js</code> file in any way and then run <code>yarn build</code> again, you'll get a new content hash because the content has changed! Try it!</p>
<h2 id="heading-minifying-css">Minifying CSS</h2>
<p>Last but not least, we may want to minify our CSS. We're already minifying our JavaScript for the production build, but we're not minifying our CSS yet. Let's do that.</p>
<p>We can minimize our CSS by using the <a target="_blank" href="https://github.com/NMFR/optimize-css-assets-webpack-plugin">optimize-css-assets-webpack-plugin</a>. Let's install that dependency now:</p>
<pre><code class="lang-bash">yarn add --dev optimize-css-assets-webpack-plugin
</code></pre>
<p>Now we can add that to an optimization section of our <code>webpack.config.prod.js</code> file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> merge = <span class="hljs-built_in">require</span>(<span class="hljs-string">'webpack-merge'</span>)
<span class="hljs-keyword">const</span> MiniCssExtractPlugin = <span class="hljs-built_in">require</span>(<span class="hljs-string">'mini-css-extract-plugin'</span>)
<span class="hljs-keyword">const</span> OptimizeCssAssetsPlugin = <span class="hljs-built_in">require</span>(<span class="hljs-string">'optimize-css-assets-webpack-plugin'</span>)
<span class="hljs-keyword">const</span> commonConfig = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./webpack.config.common'</span>)

<span class="hljs-built_in">module</span>.exports = merge(commonConfig, {
  <span class="hljs-attr">mode</span>: <span class="hljs-string">'production'</span>,
  <span class="hljs-attr">devtool</span>: <span class="hljs-string">'source-map'</span>,
  <span class="hljs-attr">module</span>: {
    <span class="hljs-attr">rules</span>: [
      {
        <span class="hljs-attr">test</span>: <span class="hljs-regexp">/\.css$/</span>,
        use: [
          MiniCssExtractPlugin.loader,
          <span class="hljs-string">'css-loader'</span>,
        ],
      },
    ],
  },
  <span class="hljs-attr">plugins</span>: [
    <span class="hljs-keyword">new</span> MiniCssExtractPlugin({
      <span class="hljs-attr">filename</span>: <span class="hljs-string">'[name].[contenthash].css'</span>,
    }),
  ],
  <span class="hljs-attr">optimization</span>: {
    <span class="hljs-attr">minimizer</span>: [
      <span class="hljs-keyword">new</span> OptimizeCssAssetsPlugin({
        <span class="hljs-attr">cssProcessorOptions</span>: {
          <span class="hljs-attr">map</span>: {
            <span class="hljs-attr">inline</span>: <span class="hljs-literal">false</span>,
            <span class="hljs-attr">annotation</span>: <span class="hljs-literal">true</span>,
          },
        },
      }),
    ],
  },
})
</code></pre>
<p>Now if we run <code>yarn build</code> and then check out the contents of our <code>dist</code> directory, we can see that the resulting CSS is minified. Nice!</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">body</span>{<span class="hljs-attribute">background</span>:<span class="hljs-number">#ff1493</span>;<span class="hljs-attribute">color</span>:<span class="hljs-number">#fff</span>}
<span class="hljs-comment">/*# sourceMappingURL=main.66e0d6aeae6f3c6fb895.css.map */</span>
</code></pre>
<p>But wait! If we look at our resulting JavaScript file, it's not minified! Hmmm. It <em>was</em> minified before, so what happened here?</p>
<p>The issue is that we're now manually configuring the optimization minimizer section of our webpack config. When that section isn't in the webpack config file, webpack defaults to using its own minimizer preferences, which includes minifying JavaScript when the <code>mode</code> is set to <code>production</code>.</p>
<p>Since we're now overriding those defaults by adding in our preferences for minifying CSS assets, we'll need to also explicitly include instructions for how we want webpack to minify JavaScript assets.</p>
<h2 id="heading-terserwebpackplugin">TerserWebpackPlugin</h2>
<p>We can minify our JavaScript files using the <a target="_blank" href="https://webpack.js.org/plugins/terser-webpack-plugin/">TerserWebpackPlugin</a>. Let's start by installing that dependency:</p>
<pre><code class="lang-bash">yarn add --dev terser-webpack-plugin
</code></pre>
<p>Then, in our <code>webpack.config.prod.js</code> file, let's add the <code>terser-webpack-plugin</code> to our optimization minimizer settings at the bottom of the file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> merge = <span class="hljs-built_in">require</span>(<span class="hljs-string">'webpack-merge'</span>)
<span class="hljs-keyword">const</span> MiniCssExtractPlugin = <span class="hljs-built_in">require</span>(<span class="hljs-string">'mini-css-extract-plugin'</span>)
<span class="hljs-keyword">const</span> OptimizeCssAssetsPlugin = <span class="hljs-built_in">require</span>(<span class="hljs-string">'optimize-css-assets-webpack-plugin'</span>)
<span class="hljs-keyword">const</span> TerserPlugin = <span class="hljs-built_in">require</span>(<span class="hljs-string">'terser-webpack-plugin'</span>)
<span class="hljs-keyword">const</span> commonConfig = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./webpack.config.common'</span>)

<span class="hljs-built_in">module</span>.exports = merge(commonConfig, {
  <span class="hljs-attr">mode</span>: <span class="hljs-string">'production'</span>,
  <span class="hljs-attr">devtool</span>: <span class="hljs-string">'source-map'</span>,
  <span class="hljs-attr">module</span>: {
    <span class="hljs-attr">rules</span>: [
      {
        <span class="hljs-attr">test</span>: <span class="hljs-regexp">/\.css$/</span>,
        use: [
          MiniCssExtractPlugin.loader,
          <span class="hljs-string">'css-loader'</span>,
        ],
      },
    ],
  },
  <span class="hljs-attr">plugins</span>: [
    <span class="hljs-keyword">new</span> MiniCssExtractPlugin({
      <span class="hljs-attr">filename</span>: <span class="hljs-string">'[name].[contenthash].css'</span>,
    }),
  ],
  <span class="hljs-attr">optimization</span>: {
    <span class="hljs-attr">minimizer</span>: [
      <span class="hljs-keyword">new</span> OptimizeCssAssetsPlugin({
        <span class="hljs-attr">cssProcessorOptions</span>: {
          <span class="hljs-attr">map</span>: {
            <span class="hljs-attr">inline</span>: <span class="hljs-literal">false</span>,
            <span class="hljs-attr">annotation</span>: <span class="hljs-literal">true</span>,
          },
        },
      }),
      <span class="hljs-keyword">new</span> TerserPlugin({
        <span class="hljs-comment">// Use multi-process parallel running to improve the build speed</span>
        <span class="hljs-comment">// Default number of concurrent runs: os.cpus().length - 1</span>
        <span class="hljs-attr">parallel</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-comment">// Enable file caching</span>
        <span class="hljs-attr">cache</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">sourceMap</span>: <span class="hljs-literal">true</span>,
      }),
    ],
  },
})
</code></pre>
<p>Now if we run <code>yarn build</code> and look at the output in the <code>dist</code> directory, we should see that both our CSS files and our JavaScript files are minified. There we go!</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>If you've followed along this far, I commend you!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/image-186.png" alt="Image" width="600" height="400" loading="lazy">
_Photo by [Unsplash](https://unsplash.com/@katya?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit"&gt;Katya Austin / &lt;a href="https://unsplash.com/?utm_source=ghost&amp;utm_medium=referral&amp;utm<em>campaign=api-credit)</em></p>
<p>Let's review what we've learned so far:</p>
<ul>
<li>Webpack is a build tool for asset bundling and dependency management.</li>
<li>Webpack can be configured by a config file.</li>
<li>Plugins modify and extend the webpack build process.</li>
<li>Loaders instruct webpack how to handle different file types.</li>
<li>The <code>clean-webpack-plugin</code> can be used to remove old build artifacts from the <code>dist</code> directory.</li>
<li>The <code>html-webpack-plugin</code> helps manage the HTML file, including injecting JavaScript into the file via <code>script</code> tags.</li>
<li><code>webpack-dev-server</code> creates a dev server to make local development easier.</li>
<li>It's helpful to have separate webpack configs for development and production. You can share and merge config files using the <code>webpack-merge</code> plugin.</li>
<li>We can handle styling our app by including loaders like <code>css-loader</code>, <code>style-loader</code>, <code>sass-loader</code>, <code>less-loader</code>, and the <code>mini-css-extract-plugin</code> (which functions as both a plugin and a loader).</li>
<li>We can include new JavaScript syntax and features by using Babel and <code>babel-loader</code>.</li>
<li>We can include content hashes in our file names to help with cache busting and managing new versions of our released code.</li>
<li>We can minify our CSS with the <code>optimize-css-assets-webpack-plugin</code>.</li>
<li>We can minify our JavaScript with the <code>terser-webpack-plugin</code>.</li>
</ul>
<h2 id="heading-whats-next">What's Next?</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/image-187.png" alt="Image" width="600" height="400" loading="lazy">
_Photo by [Unsplash](https://unsplash.com/@tomparkes?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit"&gt;Tom Parkes / &lt;a href="https://unsplash.com/?utm_source=ghost&amp;utm_medium=referral&amp;utm<em>campaign=api-credit)</em></p>
<p>Throughout this article, we've created a pretty respectable webpack config. All of these techniques we've discussed are industry standards and are common to use in enterprise-level projects.</p>
<p>But there's still more! Other advanced webpack topics include <a target="_blank" href="https://webpack.js.org/guides/code-splitting/">code splitting</a>, <a target="_blank" href="https://webpack.js.org/guides/lazy-loading/">lazy loading</a>, <a target="_blank" href="https://webpack.js.org/guides/tree-shaking/">tree shaking</a>, and more!</p>
<p>If you're interested in exploring webpack more on your own, I'd highly recommend reading through the official <a target="_blank" href="https://webpack.js.org/guides/">webpack guides</a>.</p>
<p>Again, all of the code we've gone through in this tutorial can be found in GitHub. The <a target="_blank" href="https://github.com/thawkin3/webpack-training-1/tree/demo/start">starting point is found here</a>, and the <a target="_blank" href="https://github.com/thawkin3/webpack-training-1">finished result is found here</a>.</p>
<p>Thanks for reading, and happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
