<?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[ Bundler - 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[ Bundler - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Mon, 08 Jun 2026 05:18:17 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/bundler/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Bundle a Simple React Application Using esbuild ]]>
                </title>
                <description>
                    <![CDATA[ Bundling is an important phase in the web development process, particularly when dealing with JavaScript frameworks like React. It entails combining all the various JavaScript files and dependencies into a single file for faster browser loading and e... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/bundle-a-basic-react-application-using-esbuild/</link>
                <guid isPermaLink="false">66ba6102bca875d7790d6aa6</guid>
                
                    <category>
                        <![CDATA[ Bundler ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ web performance ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ valentine Gatwiri ]]>
                </dc:creator>
                <pubDate>Tue, 22 Aug 2023 20:56:13 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/08/Screenshot-from-2023-08-21-16-04-04.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Bundling is an important phase in the web development process, particularly when dealing with JavaScript frameworks like React. It entails combining all the various JavaScript files and dependencies into a single file for faster browser loading and execution. </p>
<p>esbuild is a lightweight and efficient bundler for React apps. Here's an overview of how to use esbuild to bundle a basic React application.</p>
<h2 id="heading-how-to-install-esbuild-globally">How to Install esbuild Globally</h2>
<p>We'll start by installing esbuild globally in your system by running <code>npm install -g esbuild</code> in the command line. This will install the latest version of esbuild globally on your system. </p>
<p>After installation, you can access esbuild from the command line by typing <code>esbuild</code>.</p>
<h2 id="heading-how-to-create-a-new-directory-for-your-react-application">How to Create a New Directory for Your React Application</h2>
<p>To create a new directory for your React application, open the terminal and navigate to the directory where you want to create the new directory. Then run the following command:</p>
<pre><code class="lang-bash">mkdir my-react-app
</code></pre>
<p>This will create a new directory named <code>my-react-app</code>. You can replace it with whatever name you want to give your React application directory.</p>
<p>After creating the directory, navigate into it by running:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> my-react-app
</code></pre>
<p>Initialize a new <code>npm</code> project by running the following command and following the prompts:</p>
<pre><code class="lang-bash">npm init -y
</code></pre>
<p>Install React and React DOM by running <code>npm install react react-dom</code> in the terminal. This will install the latest versions of React and React DOM in your project, along with any required dependencies.</p>
<h2 id="heading-how-to-create-the-necessary-files-and-folders">How to Create the Necessary Files and Folders</h2>
<p>Let's create the necessary files and folders. Here's a basic structure:</p>
<pre><code>my-react-app
├── src
|   |
│   |── index.js
├── |--- index.html
│  
└── package.json
</code></pre><p>Add the code shown below in your app, following the above structure:</p>
<p><strong>index.html</strong>:</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">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1, shrink-to-fit=no"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Hello, esbuild!<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">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"root"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"Bundle.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></span>
</code></pre>
<p>The above code outlines the fundamental structure of an HTML5 web page. It starts with a declaration indicating the use of HTML5. The main structure consists of an <code>&lt;html&gt;</code> root element containing a <code>&lt;head&gt;</code> section for metadata, including character encoding and viewport settings for responsiveness.</p>
<p> The <code>&lt;title&gt;</code> element defines the browser tab's title, while the actual content resides in the <code>&lt;body&gt;</code> element. Within the <code>&lt;body&gt;</code>, a <code>&lt;div&gt;</code> element with the id "root" serves as a placeholder for potential dynamic content. </p>
<p>Additionally, there's a <code>&lt;script&gt;</code> tag pointing to an external JavaScript file named "Bundle.js," generated by esbuild, to be executed by the browser. </p>
<p>This structure sets the foundation for building a web page with HTML5, CSS, and JavaScript functionality.</p>
<p><strong>index.js</strong></p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> ReactDOM <span class="hljs-keyword">from</span> <span class="hljs-string">"react-dom"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Hello, esbuild! <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

ReactDOM.render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span></span>, <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"root"</span>));
</code></pre>
<p>Our React code sets up a simple React application with a single component App. It renders a <code>&lt;div&gt;</code> element with the text <code>Hello, esbuild!</code> and mounts it into the DOM, specifically into the element with the <code>id</code> of <code>root</code>.</p>
<h2 id="heading-how-to-create-the-build-function">How to Create the Build Function</h2>
<p>Let's add the following build script using the <code>esbuild</code> bundler 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">"esbuild src/index.js --bundle --outfile=Bundle.js --loader:.js=jsx --format=cjs"</span>
},
</code></pre>
<p>This build script starts with the entry point <code>src/index.js</code> and proceeds to bundle all the dependencies. The resulting bundled code is saved as <code>Bundle.js</code>. </p>
<p>The script also specifies that files with the <code>.js</code> extension should be treated as <code>jsx</code> files, indicating the usage of JSX syntax.</p>
<p>Finally, the output format is set to <code>CommonJS (cjs)</code> which is the module system utilized by Node.js. </p>
<p>By executing this build script, the <code>esbuild</code> bundler will process the files, apply the necessary transformations, and generate a single bundled JavaScript file ready for deployment or further usage.</p>
<h3 id="heading-overview-of-the-build-function-and-its-purpose">Overview of the Build Function and its Purpose</h3>
<p>The build script using esbuild is JavaScript code that bundles your JavaScript code into a single file. This is useful for optimizing your code for production environments, reducing the number of HTTP requests needed to load your application, and improving load times.</p>
<p>The build method takes an <code>options</code> object as its argument, which allows you to configure how your code is bundled. The options object specifies properties such as <code>entryPoints</code>, <code>outfile</code>, <code>format</code>, <code>bundle</code>, and <code>loader</code>.</p>
<p>Once the build method is configured with the desired options, the build function is called, which triggers the build process. This will output a single bundled file containing all of your JavaScript code.</p>
<p>Finally, the build script is run by executing the script using Node.js. You can do this by updating the <code>package.json</code> file to include a script that runs the build script, as shown above.</p>
<p>Build the React app using the following command:</p>
<pre><code class="lang-bash">npm run build
</code></pre>
<p>Then run the app using this command:</p>
<pre><code class="lang-bash">npx http-server
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>By following these steps, you can bundle your basic React application using esbuild and have it ready for deployment or further usage. Here is the <a target="_blank" href="https://github.com/gatwirival/esbuild-bundling-demo.git">demo.</a></p>
<p>Happy coding!</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>
        
            <item>
                <title>
                    <![CDATA[ Introducing Packem: a super fast experimental bundler written in Rust ]]>
                </title>
                <description>
                    <![CDATA[ By Bukhari Muhammad Packem is an experimental precompiled JavaScript module bundler primarily implemented in Rust. It can also handle a variety of other file types like YAML/TOML, fragment shader files and a lot more. Checkout the website or the GitH... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/introducing-packem-a-super-fast-experimental-bundler-written-in-rust-e981af875517/</link>
                <guid isPermaLink="false">66c3584939357f94469765ac</guid>
                
                    <category>
                        <![CDATA[ Bundler ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Node.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Rust ]]>
                    </category>
                
                    <category>
                        <![CDATA[ TypeScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 15 May 2019 16:36:27 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*AP72bMDkd2rDgR4txJreIQ.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Bukhari Muhammad</p>
<p>Packem is an experimental precompiled JavaScript module bundler primarily implemented in Rust. It can also handle a variety of other file types like YAML/TOML, fragment shader files and a lot more. Checkout the <a target="_blank" href="https://packem.github.io/">website</a> or the <a target="_blank" href="https://github.com/packem/packem">GitHub page</a> to quickly get started.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/qAPcGMSL2YG2dAXsQL0rzSN7vytigBv8HQd6" alt="Image" width="200" height="200" loading="lazy">
<em>Packem’s logo. Always soothes me.</em></p>
<p>Packem resolves a module’s dependencies and rehydrates them into a module graph, a flat list containing module interfaces which are essentially <strong>references to in-memory heap-based mutable data structures</strong> containing special metadata of a module in the module graph.</p>
<p>Most of the business logic is abstracted into Rust using FFI bindings to enable low level interactions between both ends. The Rusty binaries are available as precompiled Node C/C++ addons in <a target="_blank" href="https://github.com/packem/packem/tree/master/bin">Packem’s repo</a>. A cloud-based CI is used to run a few scripts with pre-gyp installations, yielding OS-specific binaries with support for later Node versions (8, 9, 10).</p>
<p>This layer of Packem’s core is what is referred to as the <strong>Logical Context (LC)</strong>. All the other operations that are not <em>explicitly prioritized</em> are regressed into Node’s general runtime, which in Packem’s terms is the <strong>Runtime Context (RC)</strong>. Read more on contexts <a target="_blank" href="https://packem.github.io/docs/execution-contexts.html">here</a>.</p>
<p>Theoretically, the module graph is kept flat to avoid common pitfalls that would lead to unnecessary traversals if a tree was used in place. This allows the RC to keep track of cases such as deep circular dependencies or heavily nested dynamic imports (code splitting), amongst others, appropriately with minimum performance implications or side effects as possible.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/Ig7Fy4kGltI7JTU9IqMpMBH7Gvq-ctV2z44f" alt="Image" width="800" height="378" loading="lazy">
<em>An overview of the bundling cycle from contexts.</em></p>
<blockquote>
<p>More details can be found at Packem’s <a target="_blank" href="https://github.com/packem/packem">README.md</a>.</p>
</blockquote>
<p>I’ve been having this idea in mind but never planned to execute it until I <em>joined forces</em> with <a target="_blank" href="https://www.freecodecamp.org/news/introducing-packem-a-super-fast-experimental-bundler-written-in-rust-e981af875517/undefined">Saddam M</a>. It has really been in my interest to see module bundling as a concept safe for anyone to learn, understand and implement. Having people struggle with configurations, documentation and plugins was extremely horrendous and I’d like to take the chance to change that. With you. With Packem.</p>
<h3 id="heading-quick-history">Quick history</h3>
<p>I took some time to exhaust most of the bundlers written in a non-JavaScript environment. I found out that most of them <em>forgot</em> that they’re supposed to be a bundler and not a C/C++ library from the dark ‘ol 19s.</p>
<p>What I wanted was a bundler that does most of the heavy-lifting in a <em>close-to-the-metal</em> language for the user without requiring any interaction with its internals. Then I found Rust. A smart and concise systems language that shows off some laudable features like a fearless concurrency model, type safety, and more! I would expect as much from using C/C++ but I’d rather stick with Rust since it’s pretty straightforward when it comes to memory management.</p>
<h3 id="heading-why-another-bundler">Why another bundler?</h3>
<p>So what’s the take here? Why do we need another build tool since we already have amazing ones like webpack, Parcel, Rollup, etc? I’ll take you along with a few reasons why. Perhaps you might have your own interests in having your development and production build times reduced heavily.</p>
<h4 id="heading-its-2019-we-dont-need-slow-tools-no-more">It’s 2019, we don’t need slow tools no more</h4>
<p>Even though Packem is faster than webpack 4, <strong>it is more than twice as fast as Parcel (with multicore compilation)</strong>. In a benchmark test, we bundled <a target="_blank" href="https://lodash.com/docs/4.17.11">Lodash v4.17.1</a> with both Packem and Parcel and this was the result:</p>
<blockquote>
<p>Never take any benches at face value. You can test it out for yourself <a target="_blank" href="https://github.com/bukharim96/packem-lodash-test">here</a>.</p>
</blockquote>
<p>The reason why I didn’t bother benchmarking Parcel against webpack was because webpack 4 is profoundly faster than Parcel. I proved this fact by using <a target="_blank" href="https://www.freecodecamp.org/news/introducing-packem-a-super-fast-experimental-bundler-written-in-rust-e981af875517/undefined">Sean T. Larkin</a>’s own benches and a thread to it on Twitter <a target="_blank" href="https://twitter.com/bukharim96/status/1099049693290680321?s=20">can be found here</a>.</p>
<h4 id="heading-because-we-can-anyone-can-right">Because we can. Anyone can, right?</h4>
<p>Of course, what will make the most sense, is because <em>we can</em>. We had the idea of having faster bundle times with a Rusty interface either with FFI or WASM (was still unsure by then). FFI was more reasonable as far as speed and DX was concerned, so we went with having Packem implemented in Rust FFI bindings.</p>
<p>We experienced a few thread-related issues so we didn’t make much use of the available resources. As a result we used multiple node child processes (with <a target="_blank" href="https://github.com/rvagg/node-worker-farm"><em>node-worker-farm</em></a><em>)</em>, the same technique Parcel uses for multicore compilation, but for larger module graphs since it adds a significant startup time on top of Node’s uptime when used with smaller module graphs.</p>
<h3 id="heading-configuration-style">Configuration style</h3>
<p>This was a tricky part. There were a lot of questions that needed a good answer to make up to picking the right configuration style. Static or dynamic? JSON/YAML/TOML? Our choice was based entirely on whether we <strong>needed</strong> Packem to:</p>
<ol>
<li>Have a neater configuration style, and</li>
<li>Be agnostic of other custom user configurations like <em>.babelrc</em> or <em>package.json</em>.</li>
</ol>
<p>Bottomline, we proceeded with a static configuration style since we found it to be exactly what we needed. Something that could <em>declaratively tell Packem how to manage the bundle cycle</em>. All the limits to having a static configuration were made clear.</p>
<p>Another aspect of interest was the type of file we should use for the configuration. JSON that is more common to an overwhelming majority of JavaScript developers or YAML/TOML/XML-style which are less common but have their own advantage(s). A suggestion was still made for JSON support (<a target="_blank" href="https://github.com/packem/packem/issues/5">#5</a>).</p>
<p>JSON just didn’t cut out because of all the unnecessary string quotes, curly &amp; block braces, which makes sense since it’s a <strong>data interchanging format</strong>. An XML-ish approach deserves no respect with regards to being used as a configuration format since it makes things worse than JSON as far as unnecessary characters are concerned. TOML introduced a lot of new lines, and debugging nested options didn’t appear to be eye-appealing since we knew that Packem plugins could get really nesty.</p>
<p>The final winner was YAML! It was able to pass through all aspects of being a proper configuration format (for Packem at least). It:</p>
<ol>
<li>Makes configuration painless.</li>
<li>Uses an elegant approach.</li>
<li>Is still familiar to the JavaScript eye</li>
<li>Was designed specifically for this use-case (configurations)<em>.</em></li>
</ol>
<p>Here’s an example of a typical Packem configuration (<em>packem.config.yml)</em>. Check for yourself and think about writing the same content in a JSON/TOML/XML-ish style.</p>
<p>FYI, only the first two options are necessary! ?</p>
<h4 id="heading-extending-packem">Extending Packem</h4>
<blockquote>
<p>This feature is not yet implemented.</p>
</blockquote>
<p>Sometimes we might need to use a feature that <strong>doesn’t yet exist</strong>, <strong>might not be implemented in Packem</strong> or is <strong>very specific to our project</strong>. For that case, you’d have two ways of solving your needs:</p>
<ol>
<li><a target="_blank" href="https://packem.github.io/docs/plugin-system.html">Create a Packem plugin</a> for your use case (which is the recommended option).</li>
<li>Build a custom RC on top of Packem’s binaries.</li>
</ol>
<p>Using Rust gives us the chance to reform the LC into other binary formats, such as WebAssembly, which will enable Packem to exhibit multiple compile targets:</p>
<ol>
<li>A NAPI-based C/C++ addon with platform-specific binaries required by Packem’s default RC.</li>
<li>A WebAssembly-based binary that is cross-platform and injected into the RC.</li>
<li>Packem’s default standalone which uses WebAssembly with a browser-compatible implementation of the RC.</li>
</ol>
<blockquote>
<p>The last two are not yet on the radar since internal refactorings are still being sorted out.</p>
</blockquote>
<p>The advanced guide is soon expected to show you how to <strong>build a custom build tool using Packem’s binaries</strong> to fit your own needs in case you need to use Packem outside the browser and Node environments. These binaries complete the entire graph generation, and duplicate filtering and other graph-related aspects. This means you can use your custom serializer, file watcher, plugin system, etc. It is much like how you can build your custom renderer over OpenGL.</p>
<ol>
<li>You can still embrace <a target="_blank" href="https://packem.github.io/docs/plugin-system.html">Packem’s plugin system</a> since it will allow you to integrate Packem’s ecosystem of plugins with your custom bundler.</li>
<li>If you’re uncertain whether or not you would need to build a custom bundler, know that you wouldn’t always need to. Please try filing an issue first.</li>
<li>It is a guarantee that these binaries will speed up your workflow depending on your specific use case(s).</li>
</ol>
<h4 id="heading-current-state">Current state</h4>
<ul>
<li>✂ <a target="_blank" href="https://packem.github.io/docs/code-splitting.html">Code Splitting</a> for development and production modes.</li>
<li>? Improved CLI (<code>— verbose</code>) for better information on bundling cycle.</li>
<li>? M<a target="_blank" href="https://packem.github.io/docs/advanced-plugin-apis.html#module-interfaces">odule Interfaces</a> to allow easy manipulation of the module graph.</li>
<li>✔ Proper priority. Native functionalities fit perfectly into the LC. This means there is greater chances of speedy builds.</li>
<li>? Export N<code>ativeUtils</code> for external usage of native functionalities including g<code>enerateModuleGraph</code> which reruns the process of generating a module graph. It is heavy but still useful in cases where you’d need a clone of the current active module graph. Using it means doubling the build time, so use it with care.</li>
</ul>
<h4 id="heading-whats-next">What’s next?</h4>
<p>These are the features we’re hoping to have soon in the upcoming releases. With your efforts we could <strong>get bundling done the right way</strong>. When Packem is at <em>1.0</em>, we’re expecting to have full support for all the features listed below and the others mentioned in <a target="_blank" href="https://packem.github.io/docs/roadmap.html">Packem’s roadmap</a>.</p>
<ul>
<li>A browser-compatible standalone of Packem with the LC in WebAssembly for closer integration with the underlying system. <a target="_blank" href="https://www.freecodecamp.org/news/introducing-packem-a-super-fast-experimental-bundler-written-in-rust-e981af875517/undefined">Axel Rauschmayer</a> already <a target="_blank" href="https://github.com/packem/packem/issues/1">made a feature request</a> to have a Node-compatible version in WASM. For the record, we’ll be working on both soon.</li>
<li>Treeshaking, but advanced. Resolving named/unnamed imports and stripping dead code should be a breeze. This means you can use libraries like <em>lodash</em> instead of <em>lodash-es</em> without worrying whether your code will be <strong>elided</strong> or not.</li>
<li>Auto Config. Like Zero Config, but defaults-oriented for extra flexibility.</li>
<li>Advanced CLI options to make development with Packem a second nature.</li>
<li>Better error reporting.</li>
<li>More environment targets. Packem can only bundle for the browser as of now. Eventually, we expect to support Node CJS and other formats as well.</li>
<li>More plugins. We need more plugins! Packem has a set of common plugins to get you started quicker. But to grow a community, we’ll need a great ecosystem of plugins. Check the <a target="_blank" href="https://packem.github.io/docs/common-plugins.html">common plugins</a> available or the <a target="_blank" href="https://packem.github.io/docs/plugin-system.html">plugins section</a> on the site to start developing a plugin right away.</li>
<li>And much more…</li>
</ul>
<h4 id="heading-resources">Resources</h4>
<ul>
<li><a target="_blank" href="https://github.com/packem/packem/">Packem on GitHub</a></li>
<li><a target="_blank" href="https://packem.github.io/docs/roadmap.html">Roadmap and Feature Requests</a></li>
<li><a target="_blank" href="https://packem.github.io/">Packem’s Official Site</a></li>
<li><a target="_blank" href="https://packem.github.io/docs/plugin-system.html">Creating Plugins with Packem</a></li>
<li><a target="_blank" href="https://packem.github.io/docs/code-splitting.html">Code Splitting with Packem</a></li>
<li><a target="_blank" href="https://packem.github.io/docs/the-module-graph.html">The Module Graph</a></li>
</ul>
<p><strong>Packem hasn’t reach <em>1.0</em> yet</strong>. If you have found Packem to be interesting at all to you, try contributing to Packem itself by creating plugins, updating the documentation, supporting us financially, representing Packem at conferences or any other means. We appreciate your efforts!</p>
<p>Happy bundling! ???</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
