<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ross Kaffenberger</title>
    <description>The latest articles on DEV Community by Ross Kaffenberger (@rossta).</description>
    <link>https://dev.to/rossta</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F613%2F05a6c9b6-de87-4111-a6e2-7af9c9c9e5e5.jpg</url>
      <title>DEV Community: Ross Kaffenberger</title>
      <link>https://dev.to/rossta</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rossta"/>
    <language>en</language>
    <item>
      <title>These Rails apps are overpacking their JavaScript bundles</title>
      <dc:creator>Ross Kaffenberger</dc:creator>
      <pubDate>Tue, 22 Sep 2020 01:57:35 +0000</pubDate>
      <link>https://dev.to/rossta/these-rails-apps-are-overpacking-their-javascript-bundles-3gl5</link>
      <guid>https://dev.to/rossta/these-rails-apps-are-overpacking-their-javascript-bundles-3gl5</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://rossta.net/blog/rails-apps-overpacking-with-webpacker.html?utm_source=dev.to"&gt;rossta.net&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href="https://unsplash.com/@jhaland" rel="noopener noreferrer"&gt;Photo by Jørgen Håland on Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You might think dividing your JavaScript into multiple bundles will help improve page load performance. When done incorrectly with Webpacker, it's possible to make things worse.&lt;/p&gt;

&lt;p&gt;This mistake appears relatively common. As I'll share in this post, I've discovered several of my favorite Rails applications are making browsers download and parse &lt;em&gt;more&lt;/em&gt; JavaScript than necessary even while attempting to send less.&lt;/p&gt;

&lt;p&gt;I believe Rails developers may think the mechanics of packaging JavaScript for the browsers work similarly in Webpacker as it does with the Rails asset pipeline. This assumption is fraught with peril!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Fcrash.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Fcrash.gif" alt="Crash bang warehouse accident"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As we'll see, Webpacker is a very different beast than the Rails asset pipeline. We need a different mental model to understand how it works. We should also follow a few basic guidelines to deliver JavaScript correctly and avoid falling victim to "bundle bloat."&lt;/p&gt;

&lt;p&gt;First, let's take a little safari and see what we can do to help a few companies correct their Webpacker usage out in the wild.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Help me help them&lt;/strong&gt;: My aim in highlighting these apps is to educate, not criticize!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you know anyone who works at any of the following companies, please share this post or ask them to reach out to me at ross at rossta dot net.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Case study: Podia
&lt;/h2&gt;

&lt;p&gt;Podia is a fantastic service that provides content creators with a platform to sell digital content, including e-books, online courses, and webinars.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Fpodia-homepage.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Fpodia-homepage.png" alt="Podia homepage"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can tell Podia uses Webpacker to bundle assets because it renders a Webpacker manifest at &lt;code&gt;https://app.podia.com/packs/manifest.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"admin/ui.css"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/packs/css/admin/ui-59291053.css"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"admin/ui.js"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/packs/js/admin/ui-931ad01f76a9c8b4c1af.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"admin/ui.js.map"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/packs/js/admin/ui-931ad01f76a9c8b4c1af.js.map"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"application.js"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/packs/js/application-42b89cd8ec22763d95ae.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"application.js.map"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/packs/js/application-42b89cd8ec22763d95ae.js.map"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;//...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The manifest contains URLs to many Webpacker "packs," also described as &lt;a href="https://webpack.js.org/concepts/#entry" rel="noopener noreferrer"&gt;&lt;em&gt;entry points&lt;/em&gt; in the webpack docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When I visit the public-facing storefront, my browser downloads the following "packs" from the Podia CDN:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/packs/js/storefront/index-1d9e9c36f5f9ab7056d1.js
/packs/js/storefront/current_time_ago-0c5c682d173647ef3199.js
/packs/js/storefront/messaging-60ddf6567eb7b74a1083.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By splitting JavaScript up across multiple files on this page, I believe Podia intends to deliver only required JavaScript to the client's browser. For example, there's no need to send JavaScript for the CMS UI to the public-facing storefront page.&lt;/p&gt;

&lt;p&gt;As we said earlier, the intent here is good.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;On closer look, though, something doesn't seem quite right. The payloads for these individual packs are, in fact, rather large.&lt;/p&gt;

&lt;p&gt;Take the "storefront/current_time_ago.js" bundle. It transfers as 73KB gzipped and comes out to 396KB of parsed JavaScript.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Does Podia's "storefront/current_time_ago" functionality need to be nearly 400KB?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If so, I'd be shocked. I imagine this pack's primary responsibility is similar to the tiny jQuery plugin &lt;a href="https://timeago.org/" rel="noopener noreferrer"&gt;timeago&lt;/a&gt;, which claims a 2KB size. As a comparison, a bundled version of &lt;code&gt;react-dom&lt;/code&gt; module parses at around ~150KB.&lt;/p&gt;

&lt;p&gt;Something's not right here.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exploring source maps
&lt;/h3&gt;

&lt;p&gt;I don't work at Podia, so I can't use my favorite tool, &lt;a href="https://rossta.net/blog/webpacker-output-analysis-with-webpack-bundle-analyzer.html" rel="noopener noreferrer"&gt;the webpack-bundle-analyzer&lt;/a&gt;, to peek inside the bundled JavaScript; this requires access to source code.&lt;/p&gt;

&lt;p&gt;But, there's another trick we can use. We can find out what's happening inside these bundles from Podia's source maps.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;It's like magic.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Fmagic.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Fmagic.gif" alt="Corny magician gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Source maps are included in production by default with Webpacker. You can find the URLs to source maps in the Webpacker manifest file, as shown above.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you're curious about why source maps in production are enabled by default in Webpacker, you may be interested in &lt;a href="https://github.com/rails/webpacker/issues/769" rel="noopener noreferrer"&gt;this GitHub issue thread&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Another place to find the URL to a source map is in the corresponding source file's last line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;//# sourceMappingURL=application-42b89cd8ec22763d95ae.js.map&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can analyze Podia's publicly available source maps using &lt;a href="https://github.com/danvk/source-map-explorer" rel="noopener noreferrer"&gt;source-map-explorer&lt;/a&gt;. It can provide a visualization of all the modules bundled on this page. Here's an example:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Fpodia-source-map-explorer-bare.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Fpodia-source-map-explorer-bare.png" alt="Treemap image example of webpack JavaScript bundles"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Podia storefront editor&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here's a screenshot of the source-map-explorer treemap for the three Webpacker packs rendered on the storefront editor page, with my annotations for emphasis:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Fpodia-source-map-explorer-annotated.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Fpodia-source-map-explorer-annotated.png" alt="Treemap image of duplicated JavaScript bundles loaded on Podia's storefront editor"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see the three JavaScript bundles in purple, blue, and orange, and with each, you can see included modules such as &lt;code&gt;actioncable&lt;/code&gt;, &lt;code&gt;stimulus&lt;/code&gt;, &lt;code&gt;moment.js&lt;/code&gt;, &lt;code&gt;core-js&lt;/code&gt;, and &lt;code&gt;cableready&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here's the problem: &lt;strong&gt;some modules appear twice on the same page!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Fmrbean.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Fmrbean.gif" alt="Mr. Bean is shocked"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Two bundles include both moment.js and all the 100+ moment-locale modules. That means the browser has to download and parse moment.js (52KB) and moment-locales (326KB) twice on the same page!&lt;/p&gt;

&lt;p&gt;Same for actioncable, cableready, stimulus, and core-js.&lt;/p&gt;

&lt;p&gt;In an attempt to deliver less JavaScript to the browser with page-specific bundles, they've ended up with even bigger payloads. Podia is &lt;a href="https://rossta.net/blog/overpacking-a-common-webpacker-mistake.html" rel="noopener noreferrer"&gt;"overpacking"&lt;/a&gt;, and it's resulting in the &lt;strong&gt;redundant module problem&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  More case studies
&lt;/h2&gt;

&lt;p&gt;It's not just Podia. I've recently discovered several other Rails applications with the same problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Funny or Die&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Fpage-funnyordie.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Fpage-funnyordie.png" alt="Funny or Die home page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm always up for a laugh, but you know what's &lt;em&gt;not&lt;/em&gt; funny? Duplicate &lt;code&gt;jquery&lt;/code&gt; on the &lt;a href="https://www.funnyordie.com" rel="noopener noreferrer"&gt;Funny or Die&lt;/a&gt; home page.&lt;/p&gt;

&lt;p&gt;That's an extra 80KB and, I would presume, a potential source of bugs for jquery plugins that assume only one instance of &lt;code&gt;$&lt;/code&gt; in the page scope.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Ffunnyordie-source-map-explorer-annotated.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Ffunnyordie-source-map-explorer-annotated.png" alt="Treemap image of duplicated JavaScript bundles loaded on Funny or Die's home page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dribbble&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Fpage-dribbble.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Fpage-dribbble.png" alt="Dribbble profile page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm whistling the &lt;a href="https://dribbble.com/dribbble" rel="noopener noreferrer"&gt;Dribbble profile page&lt;/a&gt; for multiple infractions, including duplicate instances of &lt;code&gt;vue&lt;/code&gt; and &lt;code&gt;axios&lt;/code&gt;. They could reduce their total payload size by up to 150KB.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Fdribbble-source-map-explorer-annotated.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Fdribbble-source-map-explorer-annotated.png" alt="Treemap image of duplicated JavaScript bundles loaded on Dribbble's profile page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Teachable&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Fpage-teachable.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Fpage-teachable.png" alt="Teachable course page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://www.jessicasprague.com/p/digibeginnerbundle" rel="noopener noreferrer"&gt;course page on Teachable&lt;/a&gt; must love &lt;code&gt;jquery&lt;/code&gt; and &lt;code&gt;lodash&lt;/code&gt;. They're both bundled twice across the three Webpacker packs rendered on this page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Fteachable-source-map-explorer-annotated.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Fteachable-source-map-explorer-annotated.png" alt="Treemap image of duplicated JavaScript bundles loaded on Teachable's student course page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Drizly&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Fpage-drizly.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Fpage-drizly.png" alt="Drizly search page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's raining JavaScript at &lt;a href="https://drizly.com/beer/c2" rel="noopener noreferrer"&gt;Drizly&lt;/a&gt;! The product search page renders three packs, each of which includes instances &lt;code&gt;material-ui&lt;/code&gt;, &lt;code&gt;react&lt;/code&gt;, and &lt;code&gt;lodash&lt;/code&gt;, among others. If Drizly were to introduce React hooks, I am relatively sure &lt;a href="https://reactjs.org/warnings/invalid-hook-call-warning.html#duplicate-react" rel="noopener noreferrer"&gt;multiple instances of React will cause issues&lt;/a&gt; if they haven't already.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Fdrizly-source-map-explorer-annotated.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Fdrizly-source-map-explorer-annotated.png" alt="Treemap image of duplicated JavaScript bundles loaded on Drizly's profile page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Strava's activity feed&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Fpage-strava.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Fpage-strava.png" alt="Strava activity feed"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As an endurance athlete in my spare time, I use Strava almost daily, where the activity feed forces me to render four instances of &lt;code&gt;react&lt;/code&gt;! Strava could reduce their activity feed payloads by a whopping 500KB by getting rid of their duplicated modules.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Fstrava-source-map-explorer-annotated.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Fstrava-source-map-explorer-annotated.png" alt="Treemap image of duplicated JavaScript bundles loaded on Strava's activity feed"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Analyzing JavaScript usage
&lt;/h3&gt;

&lt;p&gt;Another tool I recommend is &lt;a href="https://github.com/aholachek/bundle-wizard" rel="noopener noreferrer"&gt;bundle-wizard&lt;/a&gt;, which can be used to find unused JavaScript modules on page load.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npx &lt;span class="nt"&gt;-p&lt;/span&gt; puppeteer &lt;span class="nt"&gt;-p&lt;/span&gt; bundle-wizard bundle-wizard &lt;span class="nt"&gt;--interact&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tool turns the source-map-explorer into a heatmap representing code coverage across the bundled modules from high (green) to low (red).&lt;/p&gt;

&lt;p&gt;Here are the source maps from the Strava activity feed visualized again with bundle-wizard coverage heatmap:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Fbundle-wizard-strava-optimized.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Fbundle-wizard-strava-optimized.png" alt="Bundle wizard treemap with heatmap overlay"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;See all that red? Those extra React modules are unused on page load.&lt;/p&gt;
&lt;h3&gt;
  
  
  Measuring end user performance
&lt;/h3&gt;

&lt;p&gt;We can also see whether Google's &lt;a href="https://developers.google.com/web/tools/lighthouse" rel="noopener noreferrer"&gt;Lighthouse&lt;/a&gt; performance auditing tool would back these findings.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Lighthouse is an open-source, automated tool that can perform web page audits for performance, accessibility, among other quality indicators. &lt;a href="https://developers.google.com/web/tools/lighthouse" rel="noopener noreferrer"&gt;You can generate a Lighthouse report for almost any page you can access on the web through Chrome DevTools or a Firefox extension&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I generated &lt;a href="https://googlechrome.github.io/lighthouse/viewer/?gist=2a3785da1cfa4922190f3924d02edf39" rel="noopener noreferrer"&gt;this Lighthouse report for my Strava dashboard&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://googlechrome.github.io/lighthouse/viewer/?gist=2a3785da1cfa4922190f3924d02edf39" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Flighthouse-strava-optimized.png" alt="Lighthouse report screenshot for strava.com/dashboard"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The page scores 23/100 based on &lt;a href="https://web.dev/performance-scoring/" rel="noopener noreferrer"&gt;Lighthouse's performance metric scoring rubric&lt;/a&gt;, and, by far, the &lt;em&gt;biggest opportunity&lt;/em&gt; for improving page load performance is to remove unused JavaScript.&lt;/p&gt;

&lt;p&gt;This much is clear: JavaScript bloat is hampering the performance of these Rails apps.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why the redundant modules?
&lt;/h2&gt;

&lt;p&gt;It should be clear by now some Rails apps using Webpacker are bundling some modules unnecessarily across multiple bundles on a single page. As a result:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;JavaScript payloads are larger—not smaller—causing increased download and parse times for the end user&lt;/li&gt;
&lt;li&gt;Logic may assume "singleton" behavior or touch global concerns leading to confounding bugs&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So why is this happening?&lt;/p&gt;

&lt;p&gt;These Rails applications aren't intentionally bundling all this extra JavaScript. The fact that they are splitting up their bundles indicates they are attempting to be selective about what JavaScript is delivered on a given page.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Wait, so we can't split code into multiple bundles without duplicating modules in Webpacker?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Let's be clear that the practice of code-splitting isn't wrong; &lt;a href="https://web.dev/reduce-javascript-payloads-with-code-splitting/" rel="noopener noreferrer"&gt;it's a recommended best practice&lt;/a&gt; for improving page load performance.&lt;/p&gt;

&lt;p&gt;The problem with these examples is in the execution; it's not happening &lt;em&gt;the way webpack expects&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Consider &lt;a href="https://cookpad.com" rel="noopener noreferrer"&gt;Cookpad.com&lt;/a&gt;. It's a Rails app that renders numerous Webpacker bundles on its home page, yet no modules are duplicated:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Fcookpad-source-map-explorer-annotated-optimized.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Fcookpad-source-map-explorer-annotated-optimized.png" alt="Treemap of Cookpad source mapsl"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When it comes to Webpacker, the Cookpad recipe is top-notch.&lt;/p&gt;
&lt;h2&gt;
  
  
  A new mental model
&lt;/h2&gt;

&lt;p&gt;The redundant module problem highlights that although the Rails asset pipeline and webpack solve the same general problem, they do so in &lt;em&gt;fundamentally different ways&lt;/em&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Webpack is a module bundler.&lt;/p&gt;

&lt;p&gt;The asset pipeline is a file concatenator.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The asset pipeline builds a list of what the developer explicitly requires. Think of it as a stack. "What you see is what you get."&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Fanalog-sprockets-stack.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Fanalog-sprockets-stack.png" alt="Stack"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Webpack, on the other hand, recursively parses the import statements in all the dependencies within a single pack, such as &lt;code&gt;app/javascript/packs/application.js&lt;/code&gt;, like a directed graph.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Fanalog-webpack-graph.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Fanalog-webpack-graph.png" alt="Directed graph"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Webpack will include all imported modules in the output, ensuring that no import is included in the same bundle twice.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If that's true, why are there multiple instances modules in Podia's output, for example?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The reason: &lt;strong&gt;each pack is a separate dependency graph.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Consider this illustration of an imaginary project with multiple packs. One pack imports &lt;code&gt;moment&lt;/code&gt; explicitly, and the other pack imports a made-up &lt;code&gt;timeago&lt;/code&gt; plugin that depends on &lt;code&gt;moment&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Fimports-webpacker.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frossta.net%2Fassets%2Fimages%2Fblog%2Foverpacking-case-studies%2Fimports-webpacker.png" alt="Image of Webpacker bundling assets with multiple packs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;See that the &lt;code&gt;moment&lt;/code&gt; package is imported in both packs. There is an explicit import in the first pack, and an implicit import via &lt;code&gt;timeago&lt;/code&gt; in the other.&lt;/p&gt;

&lt;p&gt;So splitting your code into multiple packs can lead to this problem &lt;em&gt;if&lt;/em&gt; you don't configure webpack properly.&lt;/p&gt;

&lt;p&gt;What we want is a way to split code up into smaller pieces without all the overhead and potential bugs. It turns out, webpack was initially created to address precisely this: code-splitting.&lt;/p&gt;

&lt;p&gt;It's just done differently than you expect.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Webpacker Packing Checklist
&lt;/h2&gt;

&lt;p&gt;Now that we know what the problem is and how to diagnose it, what can we do about it?&lt;/p&gt;

&lt;p&gt;The key to addressing this kind of Webpacker code bloat is to keep &lt;em&gt;all dependencies in the same dependency graph&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Below, I summarize the steps I would take to help these companies, which you can apply in your applications. These steps are iterative; you need not complete all these actions to begin seeing benefits.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 1: Start with one entry point per page
&lt;/h3&gt;

&lt;p&gt;Webpack recommends one entry point per page. &lt;a href="https://webpack.js.org/concepts/entry-points" rel="noopener noreferrer"&gt;From the webpack docs&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As a rule of thumb: Use precisely one entry point for each HTML document.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's how webpack assumes your application will work out-of-the-box. Practically speaking, that means there would be only one usage of &lt;code&gt;javascript_pack_tag&lt;/code&gt; per page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%=&lt;/span&gt; &lt;span class="na"&gt;javascript_pack_tag&lt;/span&gt; &lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="na"&gt;application&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the companies described in this post, that would mean consolidating those separate packs into one on a page. Rendering multiple entry points on a single page &lt;em&gt;correctly&lt;/em&gt; requires additional configuration. We'll get to that, but "one pack per page" is how I recommend starting.&lt;/p&gt;

&lt;p&gt;Does this mean you have to put &lt;strong&gt;all&lt;/strong&gt; your JavaScript in one pack? No, but:&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Keep the number of packs small
&lt;/h3&gt;

&lt;p&gt;Don't split your JavaScript into a ton of little packs/entry points unless you understand the tradeoffs, and you're comfortable with webpack.&lt;/p&gt;

&lt;p&gt;For smaller applications, just an "application.js" may be well worth the tradeoff of having an application that's easier to maintain over the added cost of learning how to best split up JS code with webpack with little performance gain.&lt;/p&gt;

&lt;p&gt;Think of packs as the entry points to &lt;em&gt;distinct&lt;/em&gt; experiences rather than page-specific bundles.&lt;/p&gt;

&lt;p&gt;For Podia, this could be one pack for the public-facing storefront, one for the storefront editor, one for the customer dashboard. Maybe an employee admin area pack. That's it.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Render one pack per page?... Keep the number of packs small? ... these bundles could get huge!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Ok, now we've come to webpack's sweet spot:&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Use dynamic imports
&lt;/h3&gt;

&lt;p&gt;Webpack has several automated features for code-splitting that will never be supported in the Rails asset pipeline. The primary example of this is &lt;a href="https://webpack.js.org/guides/code-splitting/#dynamic-imports" rel="noopener noreferrer"&gt;dynamic imports&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Dynamic imports allow you to define split points &lt;em&gt;in code&lt;/em&gt; rather than by configuration or multiple entry points. Note the &lt;code&gt;import()&lt;/code&gt; function syntax:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Contrived examples&lt;/span&gt;

&lt;span class="c1"&gt;// Import page-specific chunks&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentPage&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;storefront&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../src/pages/storefront&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Import progressive enhancement chunks&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[data-timeago]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../src/initializer/current_time_ago&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Import bigger on-demand chunks following user interaction&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[data-open-trix-editor]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../src/components/trix_editor&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the example above, the imported modules are not separate packs. They are modules included in the same dependency graph but compiled as &lt;em&gt;separate files&lt;/em&gt;. Webpack will load dynamic imports asynchronously at runtime.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Dynamic imports allow you to divide your "packs" into smaller pieces while avoiding the redundant module problem.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Does this mean import every little module in little dynamic chunks? No. Measure, experiment. Consider the tradeoffs with handling asynchronous code loading. Timebox your efforts&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Go further with splitChunks, but only when you're ready
&lt;/h3&gt;

&lt;p&gt;For a more powerful combination, use page-specific dynamic imports combined with &lt;a href="https://help.github.com/en/github/managing-files-in-a-repository/getting-permanent-links-to-files" rel="noopener noreferrer"&gt;the splitChunks configuration API&lt;/a&gt; to split out bundles for vendor code that can be shared across packs. In other words, browsers wouldn't have to pay the cost of re-downloading bundles containing moment.js, lodash.js, etc., across multiple pages with a warm cache.&lt;/p&gt;

&lt;p&gt;Beware, though; this technique is a bit more advanced. It requires the use of separate Rails helpers, &lt;code&gt;javascript_packs_with_chunks_tag&lt;/code&gt; and &lt;code&gt;stylesheet_packs_with_chunks_tag&lt;/code&gt;, which will output multiple bundles produced from a single pack and these helpers should only be used once during the page render. It may take some &lt;a href="https://webpack.js.org/plugins/split-chunks-plugin/" rel="noopener noreferrer"&gt;reading up on the webpack docs&lt;/a&gt; and some experimentation with the chunking logic to achieve optimal results.&lt;/p&gt;

&lt;p&gt;Check out the open-source &lt;a href="https://github.com/forem/forem" rel="noopener noreferrer"&gt;Forem&lt;/a&gt; application (formerly dev.to) for an excellent example of how to do "splitChunks."&lt;/p&gt;

&lt;h2&gt;
  
  
  Summing up
&lt;/h2&gt;

&lt;p&gt;Webpack can be a bit confusing to understand at first. Webpacker goes a long way toward providing that "conceptual compression" to get developers up-and-running on Rails. Unfortunately, Webpacker doesn't yet offer &lt;em&gt;all&lt;/em&gt; the guard rails required to avoid problems like overpacking. As we've seen, some Rails apps are using Webpacker with an asset-pipeline mindset.&lt;/p&gt;

&lt;p&gt;Embracing new tools may mean a little more investment, along with letting go of the way we used to do things.&lt;/p&gt;

&lt;p&gt;Apply the Webpacker Packing Checklist to ensure a good experience for clients who desire faster webpages and developers who want fewer bugs.&lt;/p&gt;

</description>
      <category>rails</category>
      <category>webpack</category>
      <category>javascript</category>
      <category>webpacker</category>
    </item>
    <item>
      <title>The webpack plugin I can't live without</title>
      <dc:creator>Ross Kaffenberger</dc:creator>
      <pubDate>Thu, 28 May 2020 12:55:19 +0000</pubDate>
      <link>https://dev.to/rossta/the-webpack-plugin-i-can-t-live-without-380p</link>
      <guid>https://dev.to/rossta/the-webpack-plugin-i-can-t-live-without-380p</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://rossta.net/blog/reasons-to-switch-to-webpacker.html?utm_source=dev.to"&gt;rossta.net&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Photo by NeONBRAND on Unsplash&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;tl;dr Install the &lt;a href="https://github.com/webpack-contrib/webpack-bundle-analyzer" rel="noopener noreferrer"&gt;&lt;code&gt;webpack-bundle-analyzer&lt;/code&gt;&lt;/a&gt; to visualize what's included in your webpack bundles and debug common problems.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Does webpack feel still a bit scary? Maybe a bit too magical? Too much of &lt;em&gt;WTF is going on here?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It felt that way for me once. I was struggling to &lt;a href="https://rossta.net/blog/from-sprockets-to-webpack.html" rel="noopener noreferrer"&gt;switch from Sprockets to Webpacker in a large Rails app&lt;/a&gt;. With Sprockets, I could require a jQuery plugin through a magic comment (the require directive), and it would "Just Work."&lt;/p&gt;

&lt;p&gt;Such was not the case when I first started using webpack; ever seen an error like on the console?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Uncaught TypeError: $(...).fancybox is not a function&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yeah, you and me both.&lt;/p&gt;

&lt;p&gt;Then one day, it all clicked for me.&lt;/p&gt;

&lt;p&gt;My main problem was &lt;em&gt;I didn't have a good mental model how webpack worked.&lt;/em&gt; To form that mental model, I researched dozens of articles, watched numerous screencasts, and read a lot of source code. One thing helped "flip the switch" more than anything else: understanding the product of a webpack build, the output.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;It was right there in front of me the whole time.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now you might call me crazy to say, "you should read the source of your bundled output," even assuming we're talking about the unminified/unobfuscated development build, so I'm not going to tell you to go do that. (Not without some guidance; let's save that for a future project).&lt;/p&gt;

&lt;p&gt;But you can use a tool &lt;em&gt;right now&lt;/em&gt; to &lt;strong&gt;visualize&lt;/strong&gt; what's in your bundle. And that could be enough to make all the difference in helping you understand, at least at a high level, how webpack does its thing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Introducing the webpack-bundle-analyzer
&lt;/h3&gt;

&lt;p&gt;But, there is something else you can do that requires a lot less work: you can use the &lt;code&gt;webpack-bundle-analyzer&lt;/code&gt;. You can probably get it up-and-running in less time than it takes to read this article.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Curious about or need help with webpack? I may be able to help! I'm developing a course for webpack on Rails and I frequently write about it on this blog.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://little-fog-6985.ck.page/9c5bc129d8" rel="noopener noreferrer"&gt;&lt;strong&gt;Subscribe to my newsletter to get updates&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The webpack-bundle-analyzer is a tool that you can use to visualize the contents of a webpack build. It parses the "stats" output of a webpack build and constructs an interactive &lt;a href="https://www.jasondavies.com/voronoi-treemap/" rel="noopener noreferrer"&gt;Voronoi treemap&lt;/a&gt; using the &lt;a href="https://carrotsearch.com/foamtree/" rel="noopener noreferrer"&gt;FoamTree&lt;/a&gt; library.&lt;/p&gt;

&lt;p&gt;It might look a little something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F51mh7wmn5wghsjbebwyj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F51mh7wmn5wghsjbebwyj.png" alt="An example of a Voronoi treemap output by the webpack-bundle-analyzer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Funny story, this wasn't the first time I've come across Voronoi diagrams. The hands-down best Computer Science class I took at NYU was &lt;a href="https://cs.nyu.edu/courses/fall16/CSCI-GA.2965-001/" rel="noopener noreferrer"&gt;Heuristics&lt;/a&gt; with Dennis Shasha in which we learned algorithms for approximating solutions to NP-hard problems and applied them to compete in automated 2-player competitive battles including a &lt;a href="https://cs.nyu.edu/courses/fall16/CSCI-GA.2965-001/voronoi_gravitational.html" rel="noopener noreferrer"&gt;gravitation Voronoi game&lt;/a&gt;. My source code is up on GitHub somewhere useful to no one else, serving mostly as a reminder I can accomplish big things under challenging constraints.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The analyzer will represent multiple bundles as distinct colors with relative sizes:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvi3zfv4dg8r8f8yhuybk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvi3zfv4dg8r8f8yhuybk.png" alt="webpack-bundle-analyzer multiple bundles"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Individual modules are displayed in their relative sizes. Hover over bundles and modules to view statistics. Click or scroll to zoom in:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fsolku73zqnxngugzexkz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fsolku73zqnxngugzexkz.png" alt="webpack-bundle-analyzer module closeup"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Use the slide-out menu on the left to toggle the gzipped and parsed ("un"-gzipped) bundles:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2eotcn9g10d7hov6iker.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2eotcn9g10d7hov6iker.png" alt="webpack-bundle-analyzer close up of menu"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Highlight modules that match a search phrase, like "react":&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyv1ljpg84g98s0s7l704.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyv1ljpg84g98s0s7l704.png" alt="webpack-bundle-analyzer module highlight"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Are you using Moment.js? It might be including translations for all its locales by default at enormous cost. &lt;a href="https://github.com/jmblog/how-to-optimize-momentjs-with-webpack" rel="noopener noreferrer"&gt;Consider using only the locales you need&lt;/a&gt;.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fsl0xvhjiksn4r0lw61in.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fsl0xvhjiksn4r0lw61in.png" alt="webpack-bundle-analyzer moment locales"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Key questions
&lt;/h4&gt;

&lt;p&gt;Here are just some examples of questions the webpack-bundle-analyzer can help answer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Why is this bundle so large?&lt;/li&gt;
&lt;li&gt;What are the relative sizes of each &lt;em&gt;bundle&lt;/em&gt; in the webpack build?&lt;/li&gt;
&lt;li&gt;What are the relative sizes of each &lt;em&gt;module&lt;/em&gt; in the webpack build?&lt;/li&gt;
&lt;li&gt;Where is my business logic bundled?&lt;/li&gt;
&lt;li&gt;Are the modules I expect included?&lt;/li&gt;
&lt;li&gt;Are any modules included more than once?&lt;/li&gt;
&lt;li&gt;Are there modules I expect to be excluded?&lt;/li&gt;
&lt;li&gt;Which third-party libraries are bundled?&lt;/li&gt;
&lt;li&gt;Which bundle contains $MODULE_NAME?&lt;/li&gt;
&lt;li&gt;Is &lt;a href="https://webpack.js.org/guides/tree-shaking/" rel="noopener noreferrer"&gt;tree-shaking&lt;/a&gt;* working?&lt;/li&gt;
&lt;li&gt;WTF is in this bundle?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Glossary alert&lt;/strong&gt; "Tree shaking" is jargon for dead code elimination: the process of removing unreferenced code from your build. Webpack will perform tree shaking when running in "production" mode which is enabled when building assets using &lt;code&gt;rake assets:precompile&lt;/code&gt; or via &lt;code&gt;./bin/webpack&lt;/code&gt; with &lt;code&gt;RAILS_ENV=production&lt;/code&gt; and &lt;code&gt;NODE_ENV=production&lt;/code&gt;. I'll share more about how to take full advantage of tree shaking in future posts.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In short, webpack-bundle-analyzer graphs what is happening in your build. It can help you debug unexpected behavior or optimize your build output to reduce bundle size. All that, in service of better user experience!&lt;/p&gt;
&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;webpack-bundle-analyzer&lt;/code&gt; is distributed as an NPM package. To install via yarn:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add &lt;span class="nt"&gt;--dev&lt;/span&gt; webpack-bundle-analyzer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since this tool is typically only useful for local development, we add it to &lt;code&gt;devDependencies&lt;/code&gt; using the &lt;code&gt;--dev&lt;/code&gt; flag.&lt;/p&gt;

&lt;h3&gt;
  
  
  Usage
&lt;/h3&gt;

&lt;p&gt;To use the webpack-bundler-analyzer, you can either integrate it as a plugin to your Webpacker configuration or you use a two-step command line process.&lt;/p&gt;

&lt;p&gt;Typically, it makes the most sense to analyze the output of production builds since they will be what's delivered t the client and may contain several optimizations that will make the output differ significantly from the development build. Analyzing the development build can still be useful for additional context when debugging.&lt;/p&gt;

&lt;p&gt;Though the instructions are tailored to a Rails project using &lt;a href="https://github.com/rails/webpacker" rel="noopener noreferrer"&gt;Webpacker&lt;/a&gt;, you could adapt them to any webpack project.&lt;/p&gt;

&lt;p&gt;When the analyzer is run, it will launch a local webserver; visit &lt;a href="http://locahost:8888" rel="noopener noreferrer"&gt;http://locahost:8888&lt;/a&gt; to view the treemap. The &lt;a href="https://github.com/webpack-contrib/webpack-bundle-analyzer#options-for-plugin" rel="noopener noreferrer"&gt;port is configurable&lt;/a&gt;, and you'll need to hit Ctrl+C to stop the server.&lt;/p&gt;

&lt;h4&gt;
  
  
  Option 1: Analyze JSON from command line
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;webpack-bundle-analyzer&lt;/code&gt; package ships with a command-line interface (CLI) that can ingest a webpack JSON stats file. In other words, it's a two-step process in which we generate a webpack build that's outputs build stats to a JSON file and then run the &lt;code&gt;webpack-bundle-analyzer&lt;/code&gt; CLI to analyze the build stats and the output bundles generated in the build:&lt;/p&gt;

&lt;p&gt;In a Rails project, we might typically first run the webpack build:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bin/webpack &lt;span class="nt"&gt;--profile&lt;/span&gt; &lt;span class="nt"&gt;--json&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; tmp/webpack-stats.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we would analyze the output with the command &lt;code&gt;webpack-bundle-analyzer [stats file] [output directory]&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx webpack-bundle-analyzer tmp/webpack-stats.json public/packs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;npx&lt;/code&gt; is a separate command-line interface that is installed along with &lt;code&gt;node&lt;/code&gt;. It will look for the command you specify in your locally installed &lt;code&gt;node_modules&lt;/code&gt;. In other words, this replaces &lt;code&gt;./bin/node_modules/webpack-bundle-analyzer ...&lt;/code&gt;.&lt;br&gt;
Get this: with &lt;code&gt;npx&lt;/code&gt;, the package script you're trying to run &lt;em&gt;doesn't even need to be installed&lt;/em&gt;! Yes, that's right: if you want, you can skip &lt;code&gt;yarn add webpack-bundle-analyzer&lt;/code&gt;. Use &lt;code&gt;npx webpack-bundler-analyzer&lt;/code&gt; as if it's installed globally. &lt;code&gt;npx&lt;/code&gt; will search your locally installed packages and will look up the package on the remote npm registry when not found locally. Pretty cool!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Since I don't want to type all that out every time, I put those commands in the &lt;code&gt;scripts&lt;/code&gt; section of my &lt;code&gt;package.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;package.json&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"webpack:analyze"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"yarn webpack:build_json &amp;amp;&amp;amp; yarn webpack:analyze_json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"webpack:build_json"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"RAILS_ENV=${RAILS_ENV:-production} NODE_ENV=${NODE_ENV:-production} bin/webpack --profile --json &amp;gt; tmp/webpack-stats.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"webpack:analyze_json"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"webpack-bundle-analyzer tmp/webpack-stats.json public/packs"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To analyze the build using these npm scripts, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn webpack:analyze
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You could instead write this as a rake tasks as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;namespace&lt;/span&gt; &lt;span class="ss"&gt;:webpack&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="s2"&gt;"Analyze the webpack build"&lt;/span&gt;
  &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ss"&gt;:analyze&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:build_json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:analyze_json&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ss"&gt;:build_json&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="nb"&gt;system&lt;/span&gt; &lt;span class="s2"&gt;"RAILS_ENV=&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'RAILS_ENV'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'production'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; \
     NODE_ENV=&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'NODE_ENV'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'production'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; \
     bin/webpack --profile --json &amp;gt; tmp/webpack-stats.json"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ss"&gt;:analyze_json&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="nb"&gt;system&lt;/span&gt; &lt;span class="s2"&gt;"npx webpack-bundle-analyzer tmp/webpack-stats.json public/packs"&lt;/span&gt;
  &lt;span class="k"&gt;rescue&lt;/span&gt; &lt;span class="no"&gt;Interrupt&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To analyze the build using these rake tasks, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rake webpack:analyze
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Option 2: Integrated setup
&lt;/h4&gt;

&lt;p&gt;Instead of using separate scripts to trigger the bundle analyzer, you can instead incorporate the webpack-bundle-analyzer into your webpack configuration. Doing so runs the webpack-bundle-analyzer localhost server as a side effect of running the build command.&lt;/p&gt;

&lt;p&gt;Below, we'll look at how you can integrate the analyzer into a Rails using &lt;a href="https://github.com/rails/webpacker" rel="noopener noreferrer"&gt;Webpacker&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// config/webpack/environment.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;environment&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@rails/webpacker&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WEBPACK_ANALYZE&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;BundleAnalyzerPlugin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;webpack-bundle-analyzer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;BundleAnalyzerPlugin&lt;/span&gt;
  &lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;BundleAnalyzerPlugin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BundleAnalyzerPlugin&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;environment&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that the plugin is incorporated into the webpack config only with the environment variable &lt;code&gt;WEBPACK_ANALYZE=true&lt;/code&gt;, so it is only added to the configuration as an opt-in feature.&lt;/p&gt;

&lt;p&gt;To visualize the production build, run this command instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;WEBPACK_ANALYZE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true &lt;/span&gt;&lt;span class="nv"&gt;RAILS_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;production &lt;span class="nv"&gt;NODE_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;production ./bin/webpack
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You could even run the analyzer server alongside your webpack-dev server with &lt;code&gt;WEBPACK_ANALYZE=true ./bin/webpack-dev-server&lt;/code&gt; to get instant feedback. Keep in mind that the bundle analysis while in development mode will yield different results from the production build.&lt;/p&gt;

&lt;h4&gt;
  
  
  Rails template
&lt;/h4&gt;

&lt;p&gt;For your convenience, I packaged &lt;a href="https://railsbytes.com/public/templates/Xo5sYr" rel="noopener noreferrer"&gt;this changeset as a Rails template&lt;/a&gt; on &lt;a href="https://railsbytes.com" rel="noopener noreferrer"&gt;railsbytes.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can preview this template at &lt;a href="https://railsbytes.com/public/templates/Xo5sYr" rel="noopener noreferrer"&gt;https://railsbytes.com/public/templates/Xo5sYr&lt;/a&gt;. To use the template, skip the steps above and run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rails app:template &lt;span class="nv"&gt;LOCATION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://railsbytes.com/script/Xo5sYr"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What's next?
&lt;/h3&gt;

&lt;p&gt;So you've set up the webpack-bundle-analyzer and started understanding what's happening in your webpack bundles, what now? You may have noticed some things you don't like. In future posts, I'll be examining how you can deal with the excesses, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Replacing libraries with built-in browser functionality or smaller packages&lt;/li&gt;
&lt;li&gt;Taking full advantage of tree-shaking with imports&lt;/li&gt;
&lt;li&gt;Using webpack to filter out unnecessary imports&lt;/li&gt;
&lt;li&gt;The "right way" to split bundles for multi-page applications&lt;/li&gt;
&lt;li&gt;Code-splitting with dynamic imports&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Until then, here are some more resources you can use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developers.google.com/web/fundamentals/performance/webpack/monitor-and-analyze" rel="noopener noreferrer"&gt;Google: Monitor and analyze the app&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=ltlxjq4YEKU" rel="noopener noreferrer"&gt;Video: How to use the webpack bundle analyzer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/jmblog/how-to-optimize-momentjs-with-webpack" rel="noopener noreferrer"&gt;How to optimize momentjs with webpack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.blazemeter.com/blog/the-correct-way-to-import-lodash-libraries-a-benchmark" rel="noopener noreferrer"&gt;The correct wat to import lodash&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=Da6VxdGU2Ig" rel="noopener noreferrer"&gt;Managing your bundle size (video)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>rails</category>
      <category>webpack</category>
      <category>javascript</category>
      <category>webpacker</category>
    </item>
    <item>
      <title>25 reasons to switch to Webpack(er)</title>
      <dc:creator>Ross Kaffenberger</dc:creator>
      <pubDate>Fri, 06 Mar 2020 00:14:27 +0000</pubDate>
      <link>https://dev.to/rossta/25-reasons-to-switch-to-webpacker-3g95</link>
      <guid>https://dev.to/rossta/25-reasons-to-switch-to-webpacker-3g95</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://rossta.net/blog/webpacker-output-analysis-with-webpack-bundle-analyzer.html?utm_source=dev.to"&gt;rossta.net&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Photo by Alice Donovan Rouse on Unsplash&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;​I've been getting this question lately from Rails developers in some form or another:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Is Webpack and Webpacker worth the hassle?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It's a good question, but my short answer is &lt;em&gt;yes&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Given the sharp rise of mindshare in the JavaScript community in recent years, there has been a great deal of innovation in tooling, development experience, and optimization for frontend development.&lt;/p&gt;

&lt;p&gt;Rails was once at the forefront—the Rails asset pipeline was a huge leap forward when it was released—but it hasn't kept up in this department. Outsourcing JavaScript and CSS dependency management and asset bundling is smart economics at this point.&lt;/p&gt;

&lt;p&gt;In this post, I will elaborate on why I think think it's a good idea to make the switch. But this will assume some prerequisites; in other words, we'll first consider why you might NOT want to switch and instead stick with the Rails asset pipeline.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://little-fog-6985.ck.page/9c5bc129d8"&gt;Subscribe to my newsletter&lt;/a&gt; to get help with using Webpack on Rails&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Why not switch?
&lt;/h3&gt;

&lt;p&gt;Here are a few reasons why Webpack and Webpacker might not be a good fit for you.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;You don't have the right application&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If your application doesn't use much JavaScript, it's probably not worth the switch. Do you spend less than 5-10% of your development time working on JavaScript? Your app might not warrant a heavier tool like Webpack.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;You don't have the time&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I'll be the first to admit that adopting Webpack for the first time requires patience. Things work differently than with Sprockets. You may need to invest time learning a new paradigm. Webpack and NPM dependencies are upgraded at a rapid pace, so you need to keep up with upgrades. You might also have to understand how JavaScript modules work—good news, those skills are transferrable.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;You don't have the right mindset&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes, Webpack is complex. Plenty of developers love to complain about this fact. If you think you're one of those developers, you probably won't enjoy the process of adopting Webpack. A lot of frustration can be eased through education. Make sure you've got a positive attitude going in.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;All that said, given a little time, the need, and the right mindset, you'll be successful upgrading to Webpacker. Here's a list of ways you'll benefit.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Webpacker is the future of Rails
&lt;/h3&gt;

&lt;p&gt;Webpacker is now the default JavaScript compiler for new Rails apps. Rails 6 apps will still include both Sprockets for managing CSS and images, but JavaScript dependencies are meant to be bundled by Webpacker. The Rails defaults fall in line with how Basecamp builds web applications and it may benefit your team to "go with the herd" to stay closer to Rails edge and attract candidates who are looking to work with more advanced tools.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Sprockets is dead; Long live Sprockets
&lt;/h3&gt;

&lt;p&gt;Sprockets development may have slowed in recent years, but it's not going away anytime soon. Sprockets version 4 was recently released, thanks to hard work led by Richard Schneeman. The default Rails setup encourages developers to use both Webpacker (for JavaScript compilation) and Sprockets (for CSS and images) side-by-side.&lt;/p&gt;

&lt;p&gt;The ability to use both compilers in the same application is a real advantage for teams making the switch; this opens the door to an iterative migration which may be desirable to de-risk the transition.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. It will change the way you write JavaScript for the better
&lt;/h3&gt;

&lt;p&gt;Prior to Rails support for Webpack through Webpacker, most of the Rails apps I've worked on or seen either directly on GitHub or implicitly through tutorials or presentations, have fallen into one of the following categories:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;jQuery spaghetti&lt;/li&gt;
&lt;li&gt;Bespoke module implementation&lt;/li&gt;
&lt;li&gt;Combination of 1. and 2.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What's wrong with this approach?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Accidentally leaking JavaScript into the global scope&lt;/li&gt;
&lt;li&gt;Difficult to share code&lt;/li&gt;
&lt;li&gt;Order-dependence when requiring code&lt;/li&gt;
&lt;li&gt;Very difficult to understand the implicit dependency graph&lt;/li&gt;
&lt;li&gt;Very difficult to load code asynchronously&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Writing your JavaScript source code within a module system allows you to take advantage of module scope within each file, i.e. no accidental leaking of code into the global scope. No more bespoke module implementations.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Enjoy the power of ES modules
&lt;/h3&gt;

&lt;p&gt;There seems to be little doubt now that ES modules are the future of JavaScript. As the new EcmaScript standard, eventually, we'll be able to use ES modules in browser and server-side runtimes, like Node.js. With support for both synchronous and asynchronous imports, they may eventually phase out early module specifications, like CommonJS and AMD altogether.&lt;/p&gt;

&lt;p&gt;Of note, ES modules employ live bindings, meaning when an exported module changes a value, it can be read in the importing module. In addition to being useful potentially for application logic, this feature allows ES modules to support cyclic dependencies.&lt;/p&gt;

&lt;p&gt;For more on how ES modules work, check out &lt;a href="https://hacks.mozilla.org/2018/03/es-modules-a-cartoon-deep-dive/"&gt;this cartoon deep dive&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. $JAVASCRIPT_FRAMEWORK not required
&lt;/h3&gt;

&lt;p&gt;Contrary to popular belief, you don't need to use a popular frontend framework, React, Vue, Angular, or Svelte, to take advantage of what Webpack has to offer. It works just great with "vanilla JS" or even jQuery-based apps.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VFjiRtey--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/rkxek4vyj57ypfg5hx9e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VFjiRtey--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/rkxek4vyj57ypfg5hx9e.png" alt="Webpack and JS"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Personally, I don't believe single page applications are worth the extra effort and complexity for the majority of CRUD-based apps—the Rails sweet-spot. Employing "JavaScript sprinkles" still makes a lot of sense in 2020 and Webpack should be considered an advantage.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Take advantage of alternative file structures
&lt;/h3&gt;

&lt;p&gt;Webpack opens the door to a great deal of customization of how JavaScript source files are structured. Perhaps the most popular JavaScript framework, React.js, introduced us to JSX, which allows developers to challenge the old notion of separation of concerns to write HTML-like JavaScript code to co-locate HTML and JavaScript source for components.&lt;/p&gt;

&lt;p&gt;Vue.js is famous, in part, for its support for Single File Components, which allows developers to co-locate HTML, CSS, and JavaScript as separate portions of a single file.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;Hello, &lt;span class="si"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="si"&gt;}}&lt;/span&gt;!&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;World&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;style&lt;/span&gt; &lt;span class="na"&gt;scoped&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;aliceblue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;style&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This is not (to my knowledge) an approach that would be easily handled in the Rails asset pipeline.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. You'll have a better way to manage dependencies
&lt;/h3&gt;

&lt;p&gt;I've always found Rails "asset gems" to be a major pain. In most cases, you can replace your asset gems with Node Package Manager, or NPM, dependencies.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZlCi_-UN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/sxl4il8f7qjy8467u65b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZlCi_-UN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/sxl4il8f7qjy8467u65b.png" alt="NPM logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;NPM has become the primary repository for distributing open-source JavaScript packages. Although originally designed for packages intended to be used with the Node.js runtime, over time, it has also become the default for browser-based packages. This means that both libraries that run on Node.js, like Webpack, and libraries in the browser, like React, Vue, and jQuery, can all be distributed over NPM. Using NPM is a huge improvement over the typical for sharing JavaScript and other assets for the Rails asset pipeline. One big point of friction with the latter approach is having to maintain both a Ruby version along with the version of the packaged assets. This technique has always felt cumbersome and bolted on.&lt;/p&gt;

&lt;p&gt;It's worth mentioning that you can still try managing assets via NPM and make them available to the Rails asset pipeline by adding node_modules to the Sprockets load path. Again, this approach is cumbersome and can potentially adversely affect build times depending on scope.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Stop using jQuery plugins (if you want)
&lt;/h3&gt;

&lt;p&gt;One benefit of jQuery plugins prior to the adoption of modules is that it provided a means to add functionality without polluting the global scope. With a proper module system, as you'd get with Webpack, you need not attach functionality to the jQuery instance to reference it across the application.&lt;/p&gt;

&lt;p&gt;Consider the touch-responsive carousel plugin &lt;a href="https://flickity.metafizzy.co/"&gt;Flickity&lt;/a&gt;. In the Rails asset pipeline, you might use it as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;//= require flickty&lt;/span&gt;

&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.main-carousel&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;flickity&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;contain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Flickity is also intended to work without jQuery meaning you can implement the Flickity module in a Webpack environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Flickity&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;flickity&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DOMContentLoaded&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;elem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.main-carousel&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;flkty&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Flickity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;elem&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;contain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can leave the jQuery out of this interaction altogether.&lt;/p&gt;

&lt;h3&gt;
  
  
  9. Compile ES2015+ syntax to ES5 with Babel
&lt;/h3&gt;

&lt;p&gt;CoffeeScript was popular when it was first introduced because it offered a cleaner, Ruby-ish syntax. Many of these ideas and more have made there way into recent versions of EcmaScript. I love writing JavaScript in ES syntax even more than I loved CoffeeScript.&lt;/p&gt;

&lt;p&gt;Here's a shortlist of just some of the great ways the language is evolving:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ES2015+ is a superset of ES5, so all your current ES5 code is also ES2015+ code&lt;/li&gt;
&lt;li&gt;Replace &lt;code&gt;var&lt;/code&gt; with scope-constrained &lt;code&gt;let/const&lt;/code&gt; &lt;a href="https://exploringjs.com/es6/ch_variables.html"&gt;https://exploringjs.com/es6/ch_variables.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Destructuring, Replace &lt;code&gt;arguments&lt;/code&gt; with ...rest parameters, &lt;a href="https://exploringjs.com/es6/ch_destructuring.html"&gt;https://exploringjs.com/es6/ch_destructuring.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Replace &lt;code&gt;apply()&lt;/code&gt; and &lt;code&gt;concat()&lt;/code&gt; with (...) spread operator&lt;/li&gt;
&lt;li&gt;Replace constructors with classes &lt;a href="https://exploringjs.com/es6/ch_classes.html"&gt;https://exploringjs.com/es6/ch_classes.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Arrow functions &lt;a href="https://exploringjs.com/es6/ch_arrow-functions.html"&gt;https://exploringjs.com/es6/ch_arrow-functions.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;New OOP features &lt;a href="https://exploringjs.com/es6/ch_oop-besides-classes.html"&gt;https://exploringjs.com/es6/ch_oop-besides-classes.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Replace function expressions in object literals to method definitions &lt;a href="https://exploringjs.com/es6/ch_oop-besides-classes.html#sec_new-features-obj-literals"&gt;https://exploringjs.com/es6/ch_oop-besides-classes.html#sec_new-features-obj-literals&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;New array and string methods, new number and Math features

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://exploringjs.com/es6/ch_arrays.html"&gt;https://exploringjs.com/es6/ch_arrays.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://exploringjs.com/es6/ch_strings.html"&gt;https://exploringjs.com/es6/ch_strings.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://exploringjs.com/es6/ch_numbers.html"&gt;https://exploringjs.com/es6/ch_numbers.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;New primitive type Symbol &lt;a href="https://exploringjs.com/es6/ch_symbols.html#sec_overview-symbols"&gt;&lt;/a&gt;&lt;a href="https://exploringjs.com/es6/ch_symbols.html#sec_overview-symbols"&gt;https://exploringjs.com/es6/ch_symbols.html#sec_overview-symbols&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Template literals &lt;a href="https://exploringjs.com/es6/ch_template-literals.html"&gt;&lt;/a&gt;&lt;a href="https://exploringjs.com/es6/ch_template-literals.html"&gt;https://exploringjs.com/es6/ch_template-literals.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Generators &lt;a href="https://exploringjs.com/es6/ch_generators.html"&gt;&lt;/a&gt;&lt;a href="https://exploringjs.com/es6/ch_generators.html"&gt;https://exploringjs.com/es6/ch_generators.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Proper Maps and Sets &lt;a href="https://exploringjs.com/es6/ch_maps-sets.html"&gt;&lt;/a&gt;&lt;a href="https://exploringjs.com/es6/ch_maps-sets.html"&gt;https://exploringjs.com/es6/ch_maps-sets.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;for-of loop &lt;a href="https://exploringjs.com/es6/ch_for-of.html"&gt;&lt;/a&gt;&lt;a href="https://exploringjs.com/es6/ch_for-of.html"&gt;https://exploringjs.com/es6/ch_for-of.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Promises &lt;a href="https://exploringjs.com/es6/ch_promises.html"&gt;&lt;/a&gt;&lt;a href="https://exploringjs.com/es6/ch_promises.html"&gt;https://exploringjs.com/es6/ch_promises.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Proxies, for metaprogramming &lt;a href="https://exploringjs.com/es6/ch_proxies.html"&gt;&lt;/a&gt;&lt;a href="https://exploringjs.com/es6/ch_proxies.html"&gt;https://exploringjs.com/es6/ch_proxies.html&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  10. Opt-in/out of experimental ES features
&lt;/h3&gt;

&lt;p&gt;The Babel integration allows developers to take advantage of next-level and experimental EcmaScript syntax.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;async/await &lt;a href="https://exploringjs.com/es2016-es2017/ch_async-functions.html"&gt;https://exploringjs.com/es2016-es2017/ch_async-functions.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;decorators &lt;a href="https://www.simplethread.com/understanding-js-decorators/"&gt;https://www.simplethread.com/understanding-js-decorators/&lt;/a&gt;, &lt;a href="https://www.sitepoint.com/javascript-decorators-what-they-are/"&gt;https://www.sitepoint.com/javascript-decorators-what-they-are/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;spread operator for object literals &lt;a href="https://exploringjs.com/es2018-es2019/ch_rest-spread-properties.html"&gt;https://exploringjs.com/es2018-es2019/ch_rest-spread-properties.html&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  11. Target specific browser versions
&lt;/h3&gt;

&lt;p&gt;Imagine how great it would be if you could code-ify your application's supported browsers? Well, with Webpacker, you can.&lt;/p&gt;

&lt;p&gt;Babel integrates with a package called browserlist which allows projects to codify the browsers they wish to target with their transpiled code. Developers set their version lists using queries, which can target specific browser versions or use semantics like &lt;code&gt;last 2 versions&lt;/code&gt; to avoid updating versions manually. Browserslist uses data provided by &lt;a href="https://caniuse.com/"&gt;Can I Use&lt;/a&gt; to determine browser support for newer frontend APIs.&lt;/p&gt;

&lt;p&gt;Now we can write future JS syntax:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;second&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Babel will compile it for Edge 16:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;first&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="nx"&gt;second&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Browserlist: &lt;a href="https://github.com/browserslist/browserslist"&gt;https://github.com/browserslist/browserslist&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  12. Polyfill newer browser APIs
&lt;/h3&gt;

&lt;p&gt;Building on number 11, Webpacker's use of &lt;code&gt;@babel/preset-env&lt;/code&gt; to makes it possible to specify more easily what new JavaScript APIs to polyfill automatically.&lt;/p&gt;

&lt;p&gt;It works by inserting this code at the top of your dependency graph:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;core-js/stable&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;chrome 71&lt;/code&gt; is targeted, then this will get replaced with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;core-js/modules/es.array.unscopables.flat&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;core-js/modules/es.array.unscopables.flat-map&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;core-js/modules/es.object.from-entries&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;core-js/modules/web.immediate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now you can start removing those conditionals you've been adding to test for browser support.&lt;/p&gt;

&lt;h3&gt;
  
  
  13. Use TypeScript
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.typescriptlang.org/"&gt;TypeScript&lt;/a&gt; has gained in popularity in recent years.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WQRpR5Zz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/j9k9dofcjv43i8icboue.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WQRpR5Zz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/j9k9dofcjv43i8icboue.png" alt="TypeScript is a superset of JavaScript"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It brings static-typing to frontend development, allowing developers to catch errors more easily and productivity gains via integrations with supporting JavaScript IDEs, like VS Code. It's even possible to adopt TypeScript iteratively; as a superset of plain JavaScript, any valid JavaScript program is a valid TypeScript program. Webpacker provides an installer to make it easier to add to your Rails project.&lt;/p&gt;

&lt;h3&gt;
  
  
  14. Unlock powerful new tools
&lt;/h3&gt;

&lt;p&gt;The Webpack compilation and build process provide a large number of hooks to allow behavior modification at nearly any stage. Here is a shortlist of ways you can extend Webpack to meet the needs of your system:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unit testing through the Rails asset pipeline has always felt like jumping through hoops; now take your pick of JavaScript unit testing tools like &lt;a href="https://mochajs.org/"&gt;Mocha&lt;/a&gt; or &lt;a href="https://jestjs.io/"&gt;Jest&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Integrate with &lt;a href="https://eslint.org/"&gt;eslint&lt;/a&gt; to standardize code style and syntax and automate fixes&lt;/li&gt;
&lt;li&gt;Add a plugin to analyze the size and contents of your bundles, e.g. &lt;a href="https://github.com/webpack-contrib/webpack-bundle-analyzer"&gt;WebpackBundlerAnalyzer&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Add a loader to parse your Rails i18n yaml files and provide them as JSON to your Webpack JavaScript modules&lt;/li&gt;
&lt;li&gt;Add a plugin to produce "unfingerprinted" clones of your bundles, as with &lt;a href="https://github.com/alexspeller/non-stupid-digest-assets"&gt;https://github.com/alexspeller/non-stupid-digest-assets&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One of my favorite Webpack-friendly addons is &lt;a href="https://storybook.js.org"&gt;Storybook&lt;/a&gt;. It's a newer tool that allows developers to build components in isolation from the Rails server. This is a great way to represent your UI in various states all in one place without having to mess with real data in your development environment.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oeO4tLp4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/8zscs9qnuise1e5atqgu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oeO4tLp4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/8zscs9qnuise1e5atqgu.png" alt="Storybook logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  15. Modify source code programmatically
&lt;/h3&gt;

&lt;p&gt;Webpack provides some configuration options that make it easy to modify the output of a module. For example, to "provide" the jQuery import to all modules in your source files, you can add the &lt;code&gt;ProvidePlugin&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This really becomes important if you're attempting to upgrade a legacy Rails app to Webpack. Many older jQuery plugins, for example, assume jQuery is available in the global scope. The &lt;code&gt;ProvidePlugin&lt;/code&gt; configured as follows will instruct Webpack to "shim" legacy modules with a &lt;code&gt;require('jquery')&lt;/code&gt; statement if necessary:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// config/webpack/environment.js&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;webpack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;webpack&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@rails/webpacker&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jquery&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// arbitrary name&lt;/span&gt;
   &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;webpack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ProvidePlugin&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jquery&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;jQuery&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jquery&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;window.jQuery&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jquery&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
   &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Documentation: &lt;a href="https://webpack.js.org/guides/shimming/"&gt;https://webpack.js.org/guides/shimming/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  16. You can still "require_tree" and then some
&lt;/h3&gt;

&lt;p&gt;Sprockets comes with a few conveniences for including files in your asset bundles including &lt;code&gt;require_tree&lt;/code&gt;. Similarly, Webpack also has a function for including multiple files in a single statement: &lt;code&gt;require.context&lt;/code&gt;. Though more verbose, it's also more powerful. It provides a file filter option, say if you only want to import &lt;code&gt;.svg&lt;/code&gt; files. You can also operate on the return value.&lt;/p&gt;

&lt;p&gt;Syntax:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;directory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useSubdirectories&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;regExp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="se"&gt;\.\/&lt;/span&gt;&lt;span class="sr"&gt;.*$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sync&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Example: require all the test files in the current and nested directories.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="sr"&gt;test&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="sr"&gt;js$/&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Example: import all the default exports in the current directory and re-export as named modules&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;requireModule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sr"&gt;/.js$/&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filename&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;moduleConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;requireModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// Get PascalCase name of module from filename&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;moduleName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;upperFirst&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;camelCase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\.\/&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\.\w&lt;/span&gt;&lt;span class="sr"&gt;+$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{[&lt;/span&gt;&lt;span class="nx"&gt;moduleName&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;moduleConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Documentation: &lt;a href="https://webpack.js.org/guides/dependency-management/#requirecontext"&gt;https://webpack.js.org/guides/dependency-management/#requirecontext&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  17. Automatic static code splitting
&lt;/h3&gt;

&lt;p&gt;In Sprockets, a common technique to reduce bundle size and improve cacheability is to move all the vendor code into a separate bundle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight erb"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- app/views/layouts.application.html.erb --&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;javascript_include_tag&lt;/span&gt; &lt;span class="s2"&gt;"vendor"&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;javascript_include_tag&lt;/span&gt; &lt;span class="s2"&gt;"application"&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;One headache with this approach is having to manually account divvy up the bundles and take great care to avoid load order issues or omitting key dependencies.&lt;/p&gt;

&lt;p&gt;Since Webpack statically analyzes your source code to build its dependency graph(s), it can also be configured to automatically create separate bundles for vendored and application code. This means, from a single "pack", Webpack will produce the vendor and application bundles for you, along with the Webpack runtime. Webpacker helpers and config can be used as follows to enable this behavior.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// config/webpack/environment.js&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;environment&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@rails/webpacker&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;splitChunks&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;environment&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight erb"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- app/views/layouts/application.html.erb --&amp;gt;&lt;/span&gt;

&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;javascript_packs_with_chunks_tag&lt;/span&gt; &lt;span class="s2"&gt;"application"&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!--
&amp;lt;script src="/packs/vendor-16838bab065ae1e314.chunk.js"&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script src="/packs/application~runtime-16838bab065ae1e314.chunk.js"&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script src="/packs/application-1016838bab065ae1e314.chunk.js"&amp;gt;&amp;lt;/script&amp;gt;
!&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;No more manual code splitting.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Documentation: &lt;a href="https://webpack.js.org/plugins/split-chunks-plugin/"&gt;https://webpack.js.org/plugins/split-chunks-plugin/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  18. Automatic dynamic code splitting
&lt;/h3&gt;

&lt;p&gt;An even better option to split your JavaScript code over multiple files is to use "dynamic imports". This approach requires absolutely zero config changes. It is the very reason that Webpack's creator made Webpack in the first place.&lt;/p&gt;

&lt;p&gt;When Webpack detects a dynamic import function, like the following, in your application code, it will create a separate bundle for that import and load it asynchronously when that code is executed in the browser.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pdfjs/webpack&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt;&lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pdfjs&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// async import!&lt;/span&gt;
  &lt;span class="nx"&gt;pdfjs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getDocument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://example.com/some.pdf&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This technique can help reduce initial download size, help avoid loading JavaScript code unnecessarily, and potentially improve time-to-interactive metric.&lt;/p&gt;

&lt;h3&gt;
  
  
  19. Use state-of-the-art CSS processing
&lt;/h3&gt;

&lt;p&gt;If you've used Rails long enough, there's a good chance you've adopted SASS or SCSS and you may love it. That's fine! Webpacker supports SASS/SCSS by default. That said, Webpacker also integrates with a newer tool called &lt;a href="https://postcss.org/"&gt;PostCSS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2xWBvagk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/b5efrlndvk06q6m93lr1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2xWBvagk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/b5efrlndvk06q6m93lr1.png" alt="PostCSS logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;PostCSS, relatively new on the scene, allows developers to transform CSS with JavaScript. It's a pluggable tool that can be configured to enable various capabilities; Webpack configures PostCSS to apply some fixes for flexbox bugs and to use a preset-env plugin to polyfill newer CSS capabilities for older browsers, similarly to @babel/preset-env does for JavaScript.&lt;/p&gt;

&lt;p&gt;One of my favorite PostCSS plugins is PurgeCSS, which lets you delete unused CSS by comparing your CSS with your HTML markup and/or templates. Such a tool is invaluable when adopting a framework like TailwindCSS, which provides a ton of utility classes, many of which you're unlikely to use in production code.&lt;/p&gt;

&lt;h3&gt;
  
  
  20. Get asset compilation out of the Rails developer server
&lt;/h3&gt;

&lt;p&gt;With Sprockets in development, automatic compilation and recompilation of static assets is handled through the Rails server. This can become a bottleneck with the ruby process doing double-duty. With the webpack-dev-server, however, asset compilation moves into a separate process so asset compilation can occur independently of the Rails server responding to requests.&lt;/p&gt;

&lt;p&gt;The webpack-dev-server is a simple Node.js web server that watches for file changes in your source code directory, triggers Webpack to recompile when changes are detected, and serves the compiles assets from memory. It can also, via websocket listener automatically inserted in the browser, autoreload the development browser window when autocompilation completes, if desired.&lt;/p&gt;

&lt;h3&gt;
  
  
  21. Update code in development without reloading the page
&lt;/h3&gt;

&lt;p&gt;Imagine being able to replace the implementation of a JavaScript module in the browser without having to reload the page. That's &lt;a href="https://webpack.js.org/guides/hot-module-replacement/"&gt;Hot Module Replacement&lt;/a&gt; (HMR). Not only does this allow for near-instant updates of only code that's changed, but application and DOM state is retained, meaning there's no need for extra clicks and typing to achieve the desired UI state. There are some &lt;a href="https://webpack.js.org/guides/hot-module-replacement/#gotchas"&gt;gotchas&lt;/a&gt; to be aware of when using this tool, but generally speaking, it's a powerful way to speed up development.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Documentation: &lt;a href="https://webpack.js.org/concepts/hot-module-replacement/"&gt;https://webpack.js.org/concepts/hot-module-replacement/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  22. Take advantage of source map options
&lt;/h3&gt;

&lt;p&gt;Given your JavaScript and CSS source code may be written in one form but compiled to another in development and production, source maps can help fill the gap. Most evergreen browsers support the loading and rendering of source maps in the browser dev tools to allow developers to link the code that's loaded in the browser to the code that lives in your source. It's a really good tool to have in your toolbelt.&lt;/p&gt;

&lt;p&gt;Sprockets recently brought source maps to the Rails asset pipeline. In Webpack, they've been there since its early days and they're highly customizable; there are over twenty types of source maps supported in Webpack meaning there's a strategy for almost every use case. One reason for this much variety is that source maps must be generated as a separate file from your ass bundles so there's a build performance cost. You can save time with the tradeoff of fidelity.&lt;/p&gt;

&lt;p&gt;The main point is with Webpack you've got a ton of choice.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;WTF is a source map? &lt;a href="https://schneems.com/2017/11/14/wtf-is-a-source-map/"&gt;https://schneems.com/2017/11/14/wtf-is-a-source-map/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Guide to source maps in sprockets: &lt;a href="https://github.com/rails/sprockets/blob/master/guides/source_maps.md"&gt;https://github.com/rails/sprockets/blob/master/guides/source_maps.md&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Webpack source map documentation: &lt;a href="https://webpack.js.org/configuration/devtool/"&gt;https://webpack.js.org/configuration/devtool/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  23. Implement performance budgets
&lt;/h3&gt;

&lt;p&gt;The first rule of optimization is "Measure first". When it comes to optimizing frontend performance, the first developer I look to for advice is &lt;a href="https://addyosmani.com/"&gt;Addy Osmani&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--i-xpvJbH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/83h2txrp6eig2sp48chd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--i-xpvJbH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/83h2txrp6eig2sp48chd.png" alt="Performance Budget Images"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One of his key strategies for measuring frontend performance is "performance budgeting" and how this relates to  "time-to-interactive" (TTI). The thinking is you may be able to put a value on the TTI experienced by users of your application and that value is closely correlated with the amount of JavaScript you force your users' browsers to download and execute. By limiting the payload size of the initial download, you may be able to improve TTI.&lt;/p&gt;

&lt;p&gt;What does this have to do with Webpack? Not only does Webpack make it easier to split up your bundles, as we saw with the code splitting sections above, but it also provides built-in support for &lt;a href="https://medium.com/webpack/webpack-performance-budgets-13d4880fbf6d"&gt;performance budgets&lt;/a&gt;. You can customize Webpack to print a warning or even raise an error if any bundle exceeds the configured &lt;code&gt;maxEntryPointSize&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start performance budgeting &lt;a href="https://addyosmani.com/blog/performance-budgets/"&gt;https://addyosmani.com/blog/performance-budgets/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Cost of JavaScript 2019 &lt;a href="https://medium.com/@addyosmani/the-cost-of-javascript-in-2018-7d8950fbb5d4"&gt;https://medium.com/@addyosmani/the-cost-of-javascript-in-2018-7d8950fbb5d4&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  24. Peek inside the bundles
&lt;/h3&gt;

&lt;p&gt;One of my favorite tools for debugging Webpack is the &lt;code&gt;webpack-bundler-analyzer&lt;/code&gt;. Add this to your build and it will generate an interactive treemap that visualizes the relative size and contents of all your bundles. Wondering how much &lt;code&gt;lodash&lt;/code&gt; is adding to your overall bundle size? Use the bundle analyzer tool. Think there's a bug in with one of your dependencies or in your Webpack output? The bundle analyzer may help you identify it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Project &lt;a href="https://github.com/webpack-contrib/webpack-bundle-analyzer"&gt;https://github.com/webpack-contrib/webpack-bundle-analyzer&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  25. Shaking the tree
&lt;/h3&gt;

&lt;p&gt;I'd be remiss if I didn't mention one of the favorite JavaScript bundle buzzwords, &lt;strong&gt;tree shaking&lt;/strong&gt;. All this means is that Webpack has the ability to remove unused code from your build when certain conditions are met. This typically means that the module(s) in question is an ES module, that Babel is configured to handle ES modules, and that there are no side effects from importing the module.&lt;/p&gt;

&lt;p&gt;A good use case for tree shaking is &lt;code&gt;lodash&lt;/code&gt;. When loaded in its entirety, the library adds around 75 kb to the resulting asset bundle.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lodash&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// OR&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;uniq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;tail&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lodash&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The following approach allows Webpack to limit the resulting file size:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;map&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lodash/map&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;uniq&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lodash/uniq&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;tail&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lodash/tail&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Lessons on tree-shaking Lodash with Webpack and Babel &lt;a href="https://www.azavea.com/blog/2019/03/07/lessons-on-tree-shaking-lodash/"&gt;https://www.azavea.com/blog/2019/03/07/lessons-on-tree-shaking-lodash/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Wrapping up
&lt;/h3&gt;

&lt;p&gt;There it is. I hope this has been a good introduction to some exciting possiblities and use cases for adopting Webpack in your Rails app via Webpacker. Like I said earlier, there is a tradeoff that comes with the overhead of managing many smaller JavaScript dependencies along with overcoming the "barrier to entry" in getting up to speed with how Webpack works.&lt;/p&gt;

&lt;p&gt;I, for one, feel the tradeoffs have been worthwhile.&lt;/p&gt;

</description>
      <category>rails</category>
      <category>webpack</category>
      <category>javascript</category>
      <category>webpacker</category>
    </item>
    <item>
      <title>A guide to NPM version constraints for Rubyists</title>
      <dc:creator>Ross Kaffenberger</dc:creator>
      <pubDate>Wed, 29 Jan 2020 21:06:44 +0000</pubDate>
      <link>https://dev.to/rossta/a-guide-to-npm-version-constraints-for-rubyists-13a4</link>
      <guid>https://dev.to/rossta/a-guide-to-npm-version-constraints-for-rubyists-13a4</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://rossta.net/blog/npm-version-constraints-for-rubyists.html?utm_source=dev.to"&gt;rossta.net&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In this post, I want to answer the following question for Rubyists:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What do the tilde &lt;code&gt;~&lt;/code&gt; and caret &lt;code&gt;^&lt;/code&gt; designations mean for version constraints in a &lt;code&gt;package.json&lt;/code&gt; file?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To answer this question, we'll compare how Rubyists declare Ruby project dependencies in a &lt;code&gt;Gemfile&lt;/code&gt; with conventions used to declare NPM module dependencies in a &lt;code&gt;package.json&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Of note, some projects use both Gemfile and package.json. For example, a newly created Rails 6 application will have generated a package.json file because, by default, it ships with Webpack and related NPM dependencies to compile JavaScript assets.&lt;/p&gt;

&lt;p&gt;It might include a section like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"@rails/ujs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^6.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"@rails/webpacker"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"~4.2.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If you're a Rubyist and the version syntax looks odd, then this post is for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Version constraints in Gemfile
&lt;/h2&gt;

&lt;p&gt;Like the &lt;code&gt;Gemfile&lt;/code&gt;, package.json has a convention to specify version constraints. Both Ruby and NPM dependencies usually follow SemVer, which will format a constraint as &lt;code&gt;major.minor.patch&lt;/code&gt;, i.e. the declaration &lt;code&gt;"webpack": "4.41.2"&lt;/code&gt; indicates Webpack major version 4, minor version 41, and patch version 2.&lt;/p&gt;

&lt;p&gt;Where they differ is in the use of special characters to declare acceptable ranges. Let's refresh the conventions used in the Gemfile.&lt;/p&gt;

&lt;p&gt;To lock a gem dependency to an exact version, we would declare the gem's name and its version as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"devise"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"4.7.1"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;A more optimistic constraint would be to provide an open-ended range that will install or update to a version of the gem that satisfies the range.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"devise"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&amp;gt;= 4.7"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To limit the upper end of the range, say, to allow minor updates up to the next major version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"devise"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&amp;gt;= 4.7"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt; 5"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This format has a shorthand notation, the squiggly arrow &lt;code&gt;~&amp;gt;&lt;/code&gt;, or the pessimistic version constraint.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"devise"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 4.7"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The upper-end of the range is determined by the smallest level of the declared constraint. For example,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;"~&amp;gt; 4.7.1"&lt;/code&gt; matches &lt;code&gt;"&amp;gt;= 4.7.1", "&amp;lt; 4.8.0"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;"~&amp;gt; 4.7"&lt;/code&gt;   matches &lt;code&gt;"&amp;gt;= 4.7.0", "&amp;lt; 5.0.0"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;"~&amp;gt; 4"&lt;/code&gt;     matches &lt;code&gt;"&amp;gt;= 4.0.0", "&amp;lt; 5.0.0"&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To specify "no constraint", simply omit the version argument.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"devise"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;For more info, check out &lt;a href="https://guides.rubygems.org/patterns/#declaring-dependencies"&gt;the guide on RubyGems&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Version constraints in package.json
&lt;/h2&gt;

&lt;p&gt;NPM conventions provide similar flexibility with alternate syntax.&lt;/p&gt;

&lt;p&gt;Let's consider a package.json file that declares &lt;code&gt;@rails/webpacker&lt;/code&gt; as a dependency, the following would enforce an exact version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"@rails/webpacker"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"4.2.1"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As with the Gemfile, comparison operators can be used as in the following examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;"&amp;gt;=4.2.1"&lt;/code&gt; matches greater or equal to 4.2.1&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;"&amp;gt;4.2.1"&lt;/code&gt; matches greater than 4.2.1&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;"&amp;gt;=4.2.1 &amp;lt;5"&lt;/code&gt; matches greater or equal to 4.2.1 and less than 5&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;"&amp;lt;5"&lt;/code&gt; matches less than 5&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;NPM supports alternate syntaxes for specifying ranges, including, but not limited to, caret &lt;code&gt;^&lt;/code&gt; and tilde &lt;code&gt;~&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tilde ranges
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;NPM ~ is like Gemfile ~&amp;gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Tilde ranges for NPM are equivalent to Ruby's pessimistic version constraint, the squiggly arrow &lt;code&gt;~&amp;gt;&lt;/code&gt;. In other words, the upper-end of the range is determined by the smallest level of the declared constraint:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;"~4.2.1"&lt;/code&gt; matches &lt;code&gt;"&amp;gt;= 4.2.1 &amp;lt;4.3.0"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;"~4.2"&lt;/code&gt;   matches &lt;code&gt;"&amp;gt;= 4.2.0 &amp;lt;5.0.0"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;"~4"&lt;/code&gt;     matches &lt;code&gt;"&amp;gt;= 4.0.0 &amp;lt;5.0.0"&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Caret ranges
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;NPM ^ is like Gemfile ~&amp;gt; x.0 for versions 1 and up and ~&amp;gt; 0.x.0 for versions less than 1 and greater than 0.0.1&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Caret ranges are another take on pessimistic version constraints that do not have a shorthand equivalent in Ruby, i.e., to my knowledge, they're a special breed. They allow patch and minor updates for versions &lt;code&gt;&amp;gt;1.0.0&lt;/code&gt;, patch updates for versions &lt;code&gt;&amp;lt;1.0.0 &amp;gt;=0.1.0&lt;/code&gt;, and no updates for versions &lt;code&gt;&amp;lt;0.1.0&lt;/code&gt; (except preleases, e.g. &lt;code&gt;0.0.3-beta&lt;/code&gt;). My understanding is that the caret is the answer for traditional SemVer, i.e., there will be breaking changes prior to 0.1.0, there may be breaking changes between minor versions prior to 1.0.0, and there may only be breaking changes between major versions above 1.0.0. Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;"^4.2.1"&lt;/code&gt; matches &lt;code&gt;"&amp;gt;=4.2.1 &amp;lt;5.0.0"&lt;/code&gt; or &lt;code&gt;"~4.2"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;"^0.2.2"&lt;/code&gt; matches &lt;code&gt;"&amp;gt;=0.2.2 &amp;lt;0.3.0"&lt;/code&gt; or &lt;code&gt;"~0.2.2"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;"^0.0.2"&lt;/code&gt; matches &lt;code&gt;"&amp;gt;=0.0.2 &amp;lt;0.0.3"&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Bonus syntax in package.json
&lt;/h2&gt;

&lt;p&gt;NPM also supports hyphen ranges and x-ranges, neither of which have Gemfile equivalents as well.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hyphen ranges
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;NPM hyphen-ranges are like separate comparison operators in a Gemfile&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For hyphen ranges, range inclusivity is tied to specificity of the declared versions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;"4.2.1 - 5.4.2"&lt;/code&gt; matches &lt;code&gt;"&amp;gt;=4.2.1 &amp;lt;=5.4.2"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;"4.2 - 5.4.2"&lt;/code&gt;   matches &lt;code&gt;"&amp;gt;=4.2.0 &amp;lt;=5.4.2"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;"4.2 - 5"&lt;/code&gt;       matches &lt;code&gt;"&amp;gt;=4.2.0 &amp;lt;=6.0.0"&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  X-ranges
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;NPM x-ranges behave like Gemfile ~&amp;gt; with exceptions&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;X-ranges are mostly self-explanatory as the &lt;code&gt;x&lt;/code&gt; denotes any value:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;"4.2.x"&lt;/code&gt; matches &lt;code&gt;"~4.2.0"&lt;/code&gt; matches &lt;code&gt;"&amp;gt;= 4.2.0 &amp;lt;4.3.0"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;"4.x"&lt;/code&gt;   matches &lt;code&gt;"~4.0"&lt;/code&gt;   matches &lt;code&gt;"&amp;gt;= 4.0.0 &amp;lt;5.0.0"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;"4.x.x"&lt;/code&gt; matches &lt;code&gt;"4.x"&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A partial version range is treated as an x-range:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;"4.2"&lt;/code&gt; matches "&lt;code&gt;4.2.x"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;"4"&lt;/code&gt;   matches "&lt;code&gt;4.x.x"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;""&lt;/code&gt;    matches "&lt;code&gt;*&lt;/code&gt;" matches any version&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;For Rubyists out there who needed an introduction to NPM version constraints, I hope this was a helpful guide, or perhaps, a future cheatsheet.&lt;/p&gt;

&lt;p&gt;Mostly I wrote this for myself because I tend to forget 😅.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>javascript</category>
    </item>
    <item>
      <title>What new/upcoming Web API(s) are you most excited about? Why?</title>
      <dc:creator>Ross Kaffenberger</dc:creator>
      <pubDate>Tue, 28 Jan 2020 13:16:36 +0000</pubDate>
      <link>https://dev.to/rossta/what-new-upcoming-web-api-s-are-you-most-excited-about-why-8mj</link>
      <guid>https://dev.to/rossta/what-new-upcoming-web-api-s-are-you-most-excited-about-why-8mj</guid>
      <description>&lt;p&gt;One of my favorite pages to explore on MDN is the directory of &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API"&gt;Web APIs&lt;/a&gt;. I barely know what many of them are, but it's interesting to learn about and test out newly available browser features and what may be lurking on the horizon.&lt;/p&gt;

&lt;p&gt;A couple relatively new features are the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver"&gt;MutationObserver&lt;/a&gt; and &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API"&gt;IntersectionObserver&lt;/a&gt;. I've used both to solve different problems in recent projects of mine: to be notified when an element is added to the DOM asynchronously (mutation) or to be notified when an element comes enters the viewport (intersection).&lt;/p&gt;

&lt;p&gt;What WebAPI captures your interest? &lt;/p&gt;

</description>
      <category>discuss</category>
    </item>
    <item>
      <title>What programming language(s) do you want to learn in 2020?</title>
      <dc:creator>Ross Kaffenberger</dc:creator>
      <pubDate>Sun, 26 Jan 2020 13:56:34 +0000</pubDate>
      <link>https://dev.to/rossta/what-programming-language-s-do-you-want-to-learn-in-2020-4fne</link>
      <guid>https://dev.to/rossta/what-programming-language-s-do-you-want-to-learn-in-2020-4fne</guid>
      <description>&lt;p&gt;I’m not sure if this counts as a new language, but I want to learn TypeScript this year. I’ve used JavaScript my entire career and now I’m finally curious to see for myself what all the hype is about.&lt;/p&gt;

</description>
      <category>discuss</category>
    </item>
    <item>
      <title>What are your thoughts on how open source maintainers solicit for financial support? </title>
      <dc:creator>Ross Kaffenberger</dc:creator>
      <pubDate>Sat, 25 Jan 2020 14:52:59 +0000</pubDate>
      <link>https://dev.to/rossta/what-are-your-thoughts-on-how-open-source-maintainers-solicit-for-financial-support-4gii</link>
      <guid>https://dev.to/rossta/what-are-your-thoughts-on-how-open-source-maintainers-solicit-for-financial-support-4gii</guid>
      <description>

</description>
      <category>discuss</category>
    </item>
    <item>
      <title>3 ways Webpack surprises web developers</title>
      <dc:creator>Ross Kaffenberger</dc:creator>
      <pubDate>Fri, 17 Jan 2020 22:52:18 +0000</pubDate>
      <link>https://dev.to/rossta/3-ways-webpack-surprises-web-developers-4nml</link>
      <guid>https://dev.to/rossta/3-ways-webpack-surprises-web-developers-4nml</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://rossta.net/blog/three-ways-webpack-surprises-rails-developers.html?utm_source=dev.to"&gt;rossta.net&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When I first started working with Webpack, I didn't realize how under-prepared I was. I was tasked with &lt;a href="https://rossta.net/blog/from-sprockets-to-webpack.html"&gt;integrating Webpack into a large Rails app&lt;/a&gt; and I made a lot of mistakes along the way. I assumed how things should behave based on my previous experience with the Rails asset pipeline. Many of these assumptions turned out to be wrong. This was frustrating and humbling.&lt;/p&gt;

&lt;p&gt;And after spending the last month answering Webpack questions on StackOverflow, I've come across plenty of folks going through some of the same mental hurdles I've experienced. I came away with some perspective on what about Webpack most commonly trips up developers.&lt;/p&gt;

&lt;p&gt;The intended audience for this post has a general notion of "why use Webpack" or "why use an asset bundler", but for more on that, I recommend &lt;a href="https://www.swyx.io/writing/jobs-of-js-build-tools/"&gt;The Many Jobs of JS Build Tools&lt;/a&gt; and &lt;a href="https://what-problem-does-it-solve.com/webpack/index.html"&gt;Webpack from Nothing: What problem are we solving?&lt;/a&gt;. For a rigorous technical overview of the project, I suggest &lt;a href="https://webpack.js.org/"&gt;the Webpack docs&lt;/a&gt;; they have gotten quite good.&lt;/p&gt;

&lt;p&gt;For this post, we're going to look at three common surprises web developers face when learning Webpack: why using global variables doesn't behave the way you might think, how Webpack treats everything as a JavaScript module, and the big learning curve for configuring Webpack effectively.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Global variables are not your friend
&lt;/h3&gt;

&lt;p&gt;I learned to program using script tags and html files loaded directly in the browser. I tied everything together with global variables. It was great.&lt;/p&gt;

&lt;p&gt;And for better or worse, every Rails I've worked on, and it's been dozens over the years, has relied on global variables and script tag snippets to make things work. Here is a basic example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight erb"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- app/view/posts/index.html.erb --&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="vi"&gt;@posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"button--show-more"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Show more&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.button--show-more&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;MyApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fetchPosts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// etc...&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="c1"&gt;// MyApp and $ are global variables&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This approach is typical with old-school bundlers like the Rails asset pipeline because they concatenate JavaScript dependencies in the global scope. This, despite the general notion that &lt;a href="https://stackoverflow.com/questions/2613310/ive-heard-global-variables-are-bad-what-alternative-solution-should-i-use"&gt;global variables are bad&lt;/a&gt;. Notably, the Rails asset pipeline came into existence before the rise of Node.js and, subsequently, formal JavaScript modules, and it never adapted. Many prefer this way of doing things. I still lean on global variables now and then.&lt;/p&gt;

&lt;p&gt;Things work differently in Webpack. It does not expose its bundled modules to the global scope by default. To reference code in another module, it expects explicit imports that reference that module's explicit exports. The scope in which modules are evaluated is local, not global, i.e., the contents of each file are wrapped in a function.&lt;/p&gt;

&lt;p&gt;Things are trickier if we expect to access bundled JavaScript from HTML, like &lt;code&gt;MyApp.fetchPosts()&lt;/code&gt; above. Options include manually attaching variables to the global scope, e.g. &lt;code&gt;window.$ = require('jquery')&lt;/code&gt; or modify the Webpack configuration to "expose" variables globally, as is demonstrated in this &lt;a href="https://stackoverflow.com/questions/58580996/unable-to-access-jquery-from-my-views-on-ror/58751163#58751163"&gt;StackOverflow post&lt;/a&gt; (and many others).&lt;/p&gt;

&lt;p&gt;This serves as an illustration of how a legacy practice would be swimming upstream in a Webpacker-enabled app: it takes effort.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;But why?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Webpack is a module bundler
&lt;/h4&gt;

&lt;p&gt;Webpack describes itself as &lt;a href="https://webpack.js.org/conceptsl"&gt;"a static module bundler for modern JavaScript applications"&lt;/a&gt;. For developers used to unfettered access to JavaScript global scope, the switch to working in a modular system comes as a surprise. I argue that adopting Webpack effectively means understanding JavaScript modules.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;So what then is a JavaScript module?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For a fantastic introduction to JavaScript modules, I suggest Preethi Kasireddy's &lt;a href="https://www.freecodecamp.org/news/javascript-modules-a-beginner-s-guide-783f7d7a5fcc/"&gt;Javascript Modules: A Beginner's Guide&lt;/a&gt; on freeCodeCamp. I'll attempt to summarize.&lt;/p&gt;

&lt;p&gt;Generally speaking, a JavaScript module is a self-contained, reusable piece of code. This definition though is inadequate to capture the behavior of various flavors of JavaScript modules, ranging from simple patterns to formal systems supported by common JavaScript runtimes.&lt;/p&gt;

&lt;p&gt;In recent years, several popular JavaScript module definitions have become widely adopted, each with their own characteristics, including &lt;a href="https://requirejs.org/docs/commonjs.html"&gt;CommonJS&lt;/a&gt;, &lt;a href="https://requirejs.org/docs/whyamd.html#amd"&gt;Asynchronous Module Definition&lt;/a&gt; (AMD), and &lt;a href="https://exploringjs.com/es6/ch_modules.html"&gt;EcmaScript (ES) Modules&lt;/a&gt; to name a few.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vUL-O4NX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/frq2d7td6at9kcesz8jt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vUL-O4NX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/frq2d7td6at9kcesz8jt.png" alt="How did the big bang happen? require('everything')"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Webpack can be configured to recognize any of these module formats.&lt;/p&gt;

&lt;p&gt;Webpack transpiles your application's source files into JavaScript modules the browser can understand. It adds code to your bundle to tie these modules together. This has implications for how developers write code which means the old-school patterns that worked with the Rails asset pipeline may not work in the Webpack context.&lt;/p&gt;

&lt;h4&gt;
  
  
  Avoid legacy code if you can
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://stackoverflow.com/questions/28969861/managing-jquery-plugin-dependency-in-webpack"&gt;Some&lt;/a&gt; &lt;a href="https://stackoverflow.com/questions/59042437/gmaps-with-rails-6-webpack"&gt;of the&lt;/a&gt; &lt;a href="https://stackoverflow.com/questions/59670743/leaflet-with-webpack-in-rails-6-l-timeline-is-not-a-function"&gt;most&lt;/a&gt; &lt;a href="https://stackoverflow.com/questions/40575637/how-to-use-webpack-with-google-maps-api"&gt;frequent&lt;/a&gt; Webpack issues that pop up on StackOverflow highlight this disparity between the context in which Webpack works best and the context for which legacy code was written.&lt;/p&gt;

&lt;p&gt;Consider any jQuery plugin in your app that's more than a few years old; any one of them may not play nice with Webpack. The plugin system in a way is a relic of the pre-module era; attaching to a global variable was the easy way to reuse and reference functionality across the app.&lt;/p&gt;

&lt;p&gt;Many jQuery plugins (or many legacy plugins in general) have been written without awareness of JavaScript modules and assume execution within the global scope. Be ready to weigh the tradeoff of learning how to configure Webpack to play nicely with legacy code or replace it with something else altogether.&lt;/p&gt;

&lt;p&gt;In Webpack, global variables are not your friend, my friend.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Webpack treats everything as a JavaScript module
&lt;/h3&gt;

&lt;p&gt;Webpack is so committed to its "module bundler" role it treats other static assets, including CSS, images, fonts, etc., as JavaScript modules too.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Say what?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When I first learned this about Webpack, I was totally confused: How does Webpack produce stylesheets out of JS? How would I reference the an image tag's &lt;code&gt;src&lt;/code&gt; for bundled images? What does it mean to import an &lt;em&gt;image module&lt;/em&gt; in JavaScript?&lt;/p&gt;

&lt;p&gt;It helps to understand that Webpack must be configured, typically with &lt;a href="https://webpack.js.org/loaders/"&gt;loaders&lt;/a&gt; or &lt;a href="https://webpack.js.org/plugins/"&gt;plugins&lt;/a&gt;, to handle different various files types as modules. How Webpack processes various file types as output depends which loaders are used.&lt;/p&gt;

&lt;p&gt;Many projects integrate with Babel to process JavaScript files written with ES2015+ syntax. CSS files might be bundled as JavaScript Blob objects that are dynamically inserted in the DOM; otherwise it can be extracted into a CSS stylesheet a side-effect of module compilation.&lt;/p&gt;

&lt;p&gt;Webpack only needs one JavaScript file in your source code as an entry point to produce a dependency graph of all the JavaScript, CSS, images, fonts, svg, etc. that you intend to bundle as static assets for the browser.&lt;/p&gt;

&lt;p&gt;An interesting consequence of Webpack putting JavaScript first is there only needs to be one entry point to produce both a JavaScript and a CSS bundle. In the Rails asset pipeline, the JavaScript and CSS source code is kept completely separate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app/assets
├── javascripts
│   └── application.js   # produces js bundle
└── stylesheets
    └── application.css  # produces css bundle
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In Webpack everything hangs off the javascript entry point, or "packs". So assuming you have statements like &lt;code&gt;import 'styles.css'&lt;/code&gt; somewhere in your JavaScript dependency graph, both &lt;code&gt;application.js&lt;/code&gt; and &lt;code&gt;application.css&lt;/code&gt; bundles will be produced.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app/javascript
└── packs
    └── application.js   # produces both js and css bundles
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The mixing of CSS bundled in JavaScript and treated as JavaScript modules has isn't strictly necessary, but it most certainly a mental leap for the uninitiated.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Webpack configuration is extreme pluggable
&lt;/h3&gt;

&lt;p&gt;There's a reason Webpack configuration has such a high barrier to entry: Webpack is the ultimate delegator.&lt;/p&gt;

&lt;p&gt;Coming from Rails, which famously values "convention over configuration", the ergonomics of setting up a Webpack configuration cause discomfort. It aims to be extremely flexible and extensible; to that end, it succeeds superbly. To serve this goal, Webpack provides a large array of &lt;a href="https://webpack.js.org/configuration/"&gt;configuration options&lt;/a&gt;. On top of that, most Webpack configurations bring in a number of loader and plugins, each of which have their own configuration requirements.&lt;/p&gt;

&lt;p&gt;Faced having to learn Webpack, Babel, PostCSS, not to mention, Webpacker's abstractions around Webpack, it's no wonder we're intimidated. That's a lot to wrap your head around.&lt;/p&gt;

&lt;p&gt;One of Webpacker's goals, in a similar fashion to &lt;a href="https://github.com/facebook/create-react-app"&gt;create-react-app&lt;/a&gt; and the &lt;a href="https://cli.vuejs.org/"&gt;vue-cli&lt;/a&gt;, is to provide a Webpack config with sane defaults, i.e. the "convention". Depending on your project's needs, these "out-of-the-box" setups may get you quite far. Unfortunately, for any non-trivial modification, like getting a large legacy library to work with global variables or optimizing your build time by splitting out vendor dependencies, developers must be prepared to dive into the documentation and search for answers far and wide on StackOverflow and Medium.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---pYV4T28--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/3qjbqvi8bb55m4127jdz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---pYV4T28--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/3qjbqvi8bb55m4127jdz.png" alt="I'm not sure if I'm a good developer or good at googling"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Bonus: Webpack is a powerful tool
&lt;/h3&gt;

&lt;p&gt;I've grown to love Webpack and, I admit, this appreciation was hard-earned. As I've gotten over the initial hurdles of making my Webpack config work for my projects, I've come to value a number of Webpack's benefits, including optimizing bundle size through &lt;a href="https://webpack.js.org/guides/tree-shaking/"&gt;tree-shaking&lt;/a&gt;, code splitting via &lt;a href="https://webpack.js.org/guides/code-splitting/#dynamic-imports"&gt;asynchronous dynamic imports&lt;/a&gt; and the &lt;a href="https://webpack.js.org/plugins/split-chunks-plugin/"&gt;split chunks plugin&lt;/a&gt; and support for &lt;a href="https://webpack.js.org/guides/code-splitting/#prefetchingpreloading-modules"&gt;preloading and prefetching&lt;/a&gt;. All of these features are virtually non-existent in the Rails asset pipeline.&lt;/p&gt;

&lt;p&gt;These major strengths of Webpack all boil down to improving user experience: using it effectively can help improve metrics like &lt;a href="https://calendar.perfplanet.com/2017/time-to-interactive-measuring-more-of-the-user-experience/"&gt;Time-to-Interactive&lt;/a&gt; and &lt;a href="https://developers.google.com/web/fundamentals/performance/user-centric-performance-metrics#first_paint_and_first_contentful_paint"&gt;First Contentful Paint&lt;/a&gt;. These things matter and are ever more crucial as we lean more heavily on client-side code build rich interfaces delivered across a widening array of devices and networks.&lt;/p&gt;

&lt;p&gt;Webpack receives a fair number of criticisms regarding its complexity and some of its surprising traits, like the ones I highlighted here. To be fair, Webpack aims to solve a complex problem and solves it quite well. Other asset bundlers are worth your consideration, but, arguably, no other bundler has been as successful.&lt;/p&gt;




&lt;p&gt;As we saw in the &lt;a href="https://twitter.com/dhh/status/1046634277985611776"&gt;recent announcement from @dhh&lt;/a&gt; and the release of Rails 6 last year, Webpack is now the default JavaScript compiler for Rails. Looks like Rails developers will be looking to adopt Webpack in their applications, though as we've seen today, they may be in for a few surprises.&lt;/p&gt;

</description>
      <category>webpack</category>
      <category>rails</category>
      <category>webpacker</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Importing images with Webpack(er)</title>
      <dc:creator>Ross Kaffenberger</dc:creator>
      <pubDate>Thu, 19 Dec 2019 22:46:14 +0000</pubDate>
      <link>https://dev.to/rossta/importing-images-with-webpacker-2302</link>
      <guid>https://dev.to/rossta/importing-images-with-webpacker-2302</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://rossta.net/blog/importing-images-with-webpacker.html?utm_source=dev.to"&gt;rossta.net&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Webpack isn't just for JavaScript. You can bundle images with it too. &lt;a href="https://github.com/rails/webpacker"&gt;Webpacker&lt;/a&gt; makes it relatively easy to work with images, but it is admittedly confusing at first: &lt;em&gt;Images in JavaScript?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In this post, we'll demonstrate how to reference Webpacker images from your JavaScript, CSS, and Rails views. The following examples were created using Rails 6 and Webpacker 4, but may work with other versions as well. Pre-requisites for working with Webpacker in a Rails project also include &lt;a href="https://yarnpkg.com/"&gt;yarn&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Folder structure
&lt;/h3&gt;

&lt;p&gt;First, where should you put your images? It doesn't matter. The easiest place to start is under your &lt;code&gt;app/javascript&lt;/code&gt; folder, the default source path for Webpacker, such as &lt;code&gt;app/javascript/images&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For the rest of this guide, we'll assume the following directory structure and files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app/javascript
├── components
│   └── Taco.js
├── css
│   ├── main.css
├── images
│   ├── burritos.jpg
│   ├── guacamole.jpg
│   └── tacos.jpg
└── packs
    └── application.js
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Isn't weird to put images and css in a folder called "javascript"? Depends. If you consider, from Webpack's perspective, everything is a JavaScript module, it may not be so strange. Otherwise, it's possible to rename &lt;code&gt;app/javascript&lt;/code&gt; or place your images elsewhere. More on that below.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Images in JS
&lt;/h3&gt;

&lt;p&gt;To reference an image from JavaScript in your Webpacker build, simply import it like any other module. React is not required for this to work ;)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app/javascripts/components/Taco.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;TacoImage&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../images/tacos.jpg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`
  &amp;lt;div&amp;gt;
    &amp;lt;h1&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/h1&amp;gt;
    &amp;lt;p&amp;gt;&amp;lt;img src=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;TacoImage&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; alt="Tacos, yum" /&amp;gt;&amp;lt;/p&amp;gt;
  &amp;lt;/div&amp;gt;
  `&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In the example above, Webpack will import &lt;code&gt;TacoImage&lt;/code&gt; as a url to the file. In other words, an "image module" in Webpack exports a single default value, a string, representing the location of the file. Based on the default Webpacker configuration, the filename will look something like &lt;code&gt;/packs/media/images/tacos-abcd1234.jpg&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Importing a image also works if you're using "CSS in JS" to style a React component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;TacoImage&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../images/tacos.jpg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;backgroundImage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`url(&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;TacoImage&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;!
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;






&lt;h3&gt;
  
  
  Interested to learn more about &lt;strong&gt;Webpack on Rails&lt;/strong&gt;? I'm creating a course.
&lt;/h3&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://little-fog-6985.ck.page/9c5bc129d8"&gt;Subscribe to rossta.net to get updates&lt;/a&gt;.
&lt;/h3&gt;




&lt;h3&gt;
  
  
  Images in CSS
&lt;/h3&gt;

&lt;p&gt;In Sprockets, when referencing images in CSS, you would use a special &lt;code&gt;image-url()&lt;/code&gt; helper. In Webpack, simply use the standard &lt;code&gt;url()&lt;/code&gt; expression in CSS with a relative path.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* app/javascript/css/main.css */&lt;/span&gt;
&lt;span class="nc"&gt;.burritos&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sx"&gt;url("../images/burritos.jpg")&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The output for the style rule will, again, look something like &lt;code&gt;background-image: url(/packs/media/images/burritos-efgh5678.jpg);&lt;/code&gt;. This technique will also work for image paths in CSS Modules.&lt;/p&gt;

&lt;h3&gt;
  
  
  Images in CSS within NPM modules
&lt;/h3&gt;

&lt;p&gt;One tricky bit worth mentioning is bundling images referenced in SCSS within an imported NPM module. For example, many jQuery plugins bundle their own SCSS and image assets. When Webpack processes this vendored CSS, you may see an error like the following, like in &lt;a href="https://stackoverflow.com/questions/58727976/import-images-of-an-npm-package-with-webpacker-and-rails"&gt;this question on StackOverflow&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Module not found: Error: Can't resolve '../img/controls.png'
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The problem is the path does not resolve properly relative to the output for this vendored SCSS. From the &lt;a href="https://github.com/rails/webpacker/blob/76b491750993fada8b0b0cc2546dfcfbc4aaae13/docs/css.md#resolve-url-loader"&gt;Webpacker docs&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Since Sass/libsass does not provide url rewriting, all linked assets must be relative to the output. Add the missing url rewriting using the resolve-url-loader. Place it directly after the sass-loader in the loader chain.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To fix this, you may need to get your hands dirty with some Webpacker configuration. Add the &lt;code&gt;resolve-url-loader&lt;/code&gt; and configure in &lt;code&gt;config/webpack/environment.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add resolve-url-loader
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// config/webpack/environment.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;environment&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@rails/webpacker&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// resolve-url-loader must be used before sass-loader&lt;/span&gt;
&lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loaders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sass&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;splice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resolve-url-loader&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This loader rule, inserted in the loader pipeline for SASS/SCSS files, will ensure the proper url is written to the CSS output by Webpack.&lt;/p&gt;

&lt;h3&gt;
  
  
  Images in Rails views
&lt;/h3&gt;

&lt;p&gt;You may be accustomed to &lt;code&gt;&amp;lt;%= image_tag 'tacos.jpg' %&amp;gt;&lt;/code&gt; to reference a image bundled in the Rails asset pipeline. Webpack has a similar tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- app/views/lunches/index.html.erb --&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%=&lt;/span&gt; &lt;span class="na"&gt;image_pack_tag&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="na"&gt;media&lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="na"&gt;images&lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="na"&gt;guacamole.jpg&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Note, since Webpacker 4, the prefix &lt;code&gt;media/&lt;/code&gt; is necessary and the remaining path represents the location from your Webpack source path.&lt;/p&gt;

&lt;p&gt;There's a catch. This change may result in the following error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Webpacker::Manifest::MissingEntryError in Lunches#index
Showing /path/to/project/app/views/lunches/index.html.erb where line #4 raised:

Webpacker can't find media/images/guacamole.jpg in /path/to/project/public/packs/manifest.json.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;guacamole.jpg&lt;/code&gt; image was not found by Rails, but, if we were to try rendering the &lt;code&gt;tacos.jpg&lt;/code&gt; image in our template, i.e, &lt;code&gt;&amp;lt;%= image_pack_tag 'media/images/tacos.jpg %&amp;gt;&lt;/code&gt;, the taco image would happily render. What gives?&lt;/p&gt;

&lt;p&gt;Your Rails app is not being selective about cuisine. The difference is, we earlier imported the &lt;code&gt;tacos.jpg&lt;/code&gt; image in Webpack, but not &lt;code&gt;guacamole.jpg&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;One way to fix this issue is to import the &lt;code&gt;guacamole.jpg&lt;/code&gt; image somewhere in your Webpack dependency graph. It's not necessary to grab a reference to the imported variable because we only care about the side effect of emitting the file for Rails to reference in the view.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../images/guacamole.jpg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Another way to fix this issue is to import &lt;em&gt;all&lt;/em&gt; images in the &lt;code&gt;app/javascript/images&lt;/code&gt; directory. Webpack provides a special function to import many files in a directory in one expression: &lt;code&gt;require.context&lt;/code&gt;. You might add this to your &lt;code&gt;application.js&lt;/code&gt; pack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app/javascript/packs/application.js&lt;/span&gt;

&lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../images&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This expression will recursively require all the files in the &lt;code&gt;images&lt;/code&gt; directory. As a result, we can now render &lt;code&gt;guacamole.jpg&lt;/code&gt; in a Rails view.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: I only recommend using &lt;code&gt;require.context&lt;/code&gt; for your images if you need to render them in your Rails views; &lt;code&gt;require.context&lt;/code&gt; is NOT necessary to import images into JS files like your React components, as illustrated earlier.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Reconfiguring
&lt;/h3&gt;

&lt;p&gt;If you don't feel comfortable with &lt;code&gt;app/javascript&lt;/code&gt; as the source directory for &lt;code&gt;images&lt;/code&gt;, you can either rename the source path or add to the set of resolved paths.&lt;/p&gt;

&lt;p&gt;To rename &lt;code&gt;app/javascript&lt;/code&gt;, rename the directory and tell Rails about it in &lt;code&gt;config/webpacker.yml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nl"&gt;&amp;amp;default&lt;/span&gt;
  &lt;span class="na"&gt;source_path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app/frontend&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To add to the set of resolved paths where Webpack should look for assets besides in &lt;code&gt;app/javascript&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nl"&gt;&amp;amp;default&lt;/span&gt;
  &lt;span class="na"&gt;resolved_paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;app/assets&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Diving Deeper
&lt;/h3&gt;

&lt;p&gt;I have to admit, a few years ago, when I first heard about Webpack, I was super-confused. I understood it to be a JavaScript module bundler. &lt;em&gt;How on Earth does it handles images?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The short answer, of course, is &lt;em&gt;it depends&lt;/em&gt;. Generally, Webpack will treat everything it can understand as a JavaScript module. To help Webpack understand images, projects would add a "loader" (or loaders) to the Webpack configuration. A suitable loader would know how to handle an image file and output a representation of something, like an inlined base64 string, that can be manipulated in JavaScript.&lt;/p&gt;

&lt;p&gt;To help Webpack understand images, svg files, and fonts in your Rails project, Webpacker adds the &lt;code&gt;file-loader&lt;/code&gt; package. This package will emit the imported file as a side effect of the build and return a path to the file as the module contents.&lt;/p&gt;

&lt;p&gt;For more on how Webpack works with images, check out the &lt;a href="https://webpack.js.org/guides/asset-management/#loading-images"&gt;asset management docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I also put together a sample Rails 6 Webpacker demo project on GitHub for more context:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/rossta/rails6-webpacker-demo/compare/example/images"&gt;Images in JS, CSS, and Rails&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/rossta/rails6-webpacker-demo/compare/example/react-image"&gt;Images with CSS-in-JS in a React app&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webpack</category>
      <category>rails</category>
      <category>webpacker</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Overpacking: A Common Webpacker Mistake</title>
      <dc:creator>Ross Kaffenberger</dc:creator>
      <pubDate>Thu, 05 Dec 2019 22:52:00 +0000</pubDate>
      <link>https://dev.to/rossta/overpacking-a-common-webpacker-mistake-1pac</link>
      <guid>https://dev.to/rossta/overpacking-a-common-webpacker-mistake-1pac</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://rossta.net/blog/overpacking-a-common-webpacker-mistake.html?utm_source=dev.to"&gt;rossta.net&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I recently encountered a Rails app at work that was spending nearly seven minutes precompiling assets:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--q22Kj986--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/e4bilgzjlyktvehe9t8o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--q22Kj986--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/e4bilgzjlyktvehe9t8o.png" alt="CI Screenshot: Precompile assets, 6:56"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I looked in the &lt;code&gt;Gemfile&lt;/code&gt; and found the project was using Webpacker. My spidey sense started to tingle.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I've seen this before&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Leaning on prior experience, I found the problem, moved some files around, and pushed a branch with the fix up to CI.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bGJaSOb3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/810h6mr2urgpic709rw6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bGJaSOb3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/810h6mr2urgpic709rw6.png" alt="CI Screenshot: Precompile assets, 0:44"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The build step dropped from nearly seven minutes to less than one. Big improvement! When I heard from the team, the fix also greatly improved the local development experience; before, re-compiling Webpack assets on page refreshes would take a painfully long time.&lt;/p&gt;

&lt;p&gt;So what were the changes?&lt;/p&gt;

&lt;h3&gt;
  
  
  A Common Problem
&lt;/h3&gt;

&lt;p&gt;First, let's take a step back. If you're new to Webpack and Webpacker for Rails, chances are you may be making some simple mistakes.&lt;/p&gt;

&lt;p&gt;I know this because I was once in your shoes struggling to learn how Webpack works. I've also spent a lot of time helping others on my team, on StackOverflow, and via &lt;a href="https://github.com/rails/webpacker"&gt;&lt;code&gt;rails/webpacker&lt;/code&gt;&lt;/a&gt; Github issues.&lt;/p&gt;

&lt;p&gt;One of the most frequently-reported issues I've seen is slow build times. This is often coupled with high memory and CPU usage. For Heroku users on small dynos, resource-intensive asset precompilation can lead to failed deploys.&lt;/p&gt;

&lt;p&gt;More often than not, the root cause is a simple oversight in directory structure—a mistake I call "overpacking".&lt;/p&gt;

&lt;h3&gt;
  
  
  Overpacking explained
&lt;/h3&gt;

&lt;p&gt;Here's the layout of the &lt;code&gt;app/javascript&lt;/code&gt; directory in the Rails app &lt;em&gt;before&lt;/em&gt; I introduced the fix:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;rake assets:precompile — 6:56&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;app/
  javascript/
    packs/
      application.js
      components/     &lt;span class="c"&gt;# lots of files&lt;/span&gt;
      images/         &lt;span class="c"&gt;# lots of files&lt;/span&gt;
      stylesheets/    &lt;span class="c"&gt;# lots of files&lt;/span&gt;
      ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here's what the project looked like building in under a minute:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;rake assets:precompile — 0:44&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;app/
  javascript/
    components/
    images/
    stylesheets/
    ...
    packs/
      application.js    &lt;span class="c"&gt;# just one file in packs/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;See the difference?&lt;/p&gt;

&lt;p&gt;The primary change here was moving everything except &lt;code&gt;application.js&lt;/code&gt; outside of the &lt;code&gt;packs&lt;/code&gt; directory under &lt;code&gt;app/javascript&lt;/code&gt;. (To make this work properly, I also had to update some relative paths in &lt;code&gt;import&lt;/code&gt; statements.)&lt;/p&gt;

&lt;h3&gt;
  
  
  Webpack Entry Points
&lt;/h3&gt;

&lt;p&gt;So why did this matter?&lt;/p&gt;

&lt;p&gt;Webpack needs at least one &lt;strong&gt;entry&lt;/strong&gt; point to build the dependency graph for produce the JavaScript and CSS bundles and static assets (images, fonts, etc).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The Webpacker project refers to entries as &lt;strong&gt;packs&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;"Entry" is listed as the first key concept on Webpack's documentation site: &lt;a href="https://webpack.js.org/concepts/#entry"&gt;https://webpack.js.org/concepts/#entry&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Webpack will build a separate dependency graph for every entry specified in its configuration. The more entry points you provide, the more dependency graphs Webpack has to build.&lt;/p&gt;

&lt;p&gt;Since Webpack*er*, by default, treats &lt;em&gt;every file&lt;/em&gt; in the &lt;code&gt;packs&lt;/code&gt; directory as a separate entry, it will build a separate dependency graph for &lt;em&gt;every file&lt;/em&gt; located there.&lt;/p&gt;

&lt;p&gt;That also means, for &lt;em&gt;every file&lt;/em&gt; in the &lt;code&gt;packs&lt;/code&gt; directory, there will be at least one, possibly more, files emitted as output in the &lt;code&gt;public&lt;/code&gt; directory during precompilation. If you're not linking to these files anywhere in your app, then they don't need to be emitted as output. For a large project, that could be lot of unnecessary work.&lt;/p&gt;

&lt;p&gt;Here's a case where Rails tries to make things easier for you—by auto-configuring entry files—while also making it easier to shoot yourself in the foot.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Simple Rule
&lt;/h3&gt;

&lt;p&gt;Is your Webpacker compilation taking forever? You may be overpacking.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If any file in Webpacker's "packs" directory does not also have a corresponding &lt;code&gt;javascript_pack_tag&lt;/code&gt; in your application, then you're overpacking.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Be good to yourself and your development and deployment experience by being very intentional about what files you put in your "packs" directory.&lt;/p&gt;

&lt;p&gt;Don't overpack. At best, this is wasteful; at worst, this is a productivity killer.&lt;/p&gt;




&lt;h3&gt;
  
  
  Interested to learn more about &lt;strong&gt;Webpack on Rails&lt;/strong&gt;? I'm creating a course.
&lt;/h3&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://little-fog-6985.ck.page/9c5bc129d8"&gt;Subscribe to rossta.net to get updates&lt;/a&gt;.
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Cover photo by Brandless on Unsplash&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webpacker</category>
      <category>webpack</category>
      <category>rails</category>
      <category>ruby</category>
    </item>
    <item>
      <title>Vue.js is omakase</title>
      <dc:creator>Ross Kaffenberger</dc:creator>
      <pubDate>Wed, 09 Jan 2019 04:06:53 +0000</pubDate>
      <link>https://dev.to/rossta/vuejs-is-omakase-aej</link>
      <guid>https://dev.to/rossta/vuejs-is-omakase-aej</guid>
      <description>&lt;p&gt;I'm borrowing from David Heinemeier Hansson here. Six years ago, he wrote &lt;a href="https://dhh.dk//2012/rails-is-omakase.html" rel="noopener noreferrer"&gt;Rails is omakase&lt;/a&gt; to capture his notion of what makes a delicious software framework: it is heavily curated and borne of experience. I think of Vue.js the same way.&lt;/p&gt;

&lt;p&gt;Here's an excerpt from DHH's post:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There are lots of à la carte software environments in this world... I want this for my ORM, I want that for my template language, and let's finish it off with this routing library... It's a very popular way of consuming software. Rails is not that. Rails is omakase. A team of chefs picked out the ingredients, designed the APIs, and arranged the order of consumption on your behalf according to their idea of what would make for a tasty full-stack framework. The menu can be both personal and quirky. It isn't designed to appeal to the taste of everyone, everywhere.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I love this metaphor, because a) Rails, including all its API choices and baggage, has treated me very well throughout my career in tech, and b) I love me some agedashi tofu.&lt;/p&gt;

&lt;p&gt;What does this have to do with Vue? I believe Vue's growing popularity is partly due to its highly selective maintainers and that the recommended ingredients, though not to everyone's taste, are well-suited to most projects, big and small.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enjoy a multiple-course meal
&lt;/h3&gt;

&lt;p&gt;Vue articulates many courses making up the full meal for a frontend framework. These days, developers have come to expect a robust API to build components and a fast implementation built on top of a virtual dom. However, Vue.js doesn't stop there. For Vue developers, the framework and its ecosystem provide adequate if not excellent implementations of orthogonal dependencies that solve problems many non-trivial apps eventually need.&lt;/p&gt;

&lt;p&gt;The offering includes the Vue Router, Vuex for state management, and the Vue test utils for unit testing. Through the Vue CLI, developers also get sensible defaults in Webpack configuration for hot module replacement, code-splitting, tree-shaking, efficient long-term caching, while having access to pre-configured opt-ins for TypeScript, Progressive Web Apps, ESLint, and multiple test runners.&lt;/p&gt;

&lt;p&gt;There is great comfort in knowing that the Vue team is behind these projects and they complement one another appropriately in my Vue.js applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  Substitutions cost little extra
&lt;/h3&gt;

&lt;p&gt;So you may not agree with everything on the menu. That's fine! Many of the defaults are easily changed through configuration or add-ons. Want to use Redux? No problem! Class-style syntax? The customer is always right. Don't like mustache-style curly braces in templates? You can change it! Maybe you can't stand the fact that Vue has templates at all and would prefer to use JavaScript. Well, that's ok too; add another &lt;a href="https://github.com/vuejs/babel-plugin-transform-vue-jsx" rel="noopener noreferrer"&gt;Babel plugin&lt;/a&gt;, and you can write Vue components with JSX inside of render functions a lot like React.&lt;/p&gt;

&lt;p&gt;As another example, let's talk about Webpack. I think it is a fantastic piece of software. I've spent months learning how it works. I have given &lt;a href="https://rossta.net/talks/webpack-survival-guide-rails.html" rel="noopener noreferrer"&gt;a conference talk&lt;/a&gt; about it. However, usually, most of us, myself included, don’t want to maintain a custom configuration from project to project when we have deadlines to meet. The Vue CLI defaults are just fine. Still need to customize? Vue provides an API to extend the base configuration while making it easier to upgrade to take advantage of framework-supported improvements. There's also nothing stopping you from ditching Webpack for Parcel or Rollup or whatever other transpiler or module bundler you prefer.&lt;/p&gt;

&lt;h3&gt;
  
  
  An opinionated chef
&lt;/h3&gt;

&lt;p&gt;The core team consistently shows restraint in decided what features and improvements to fold into the framework. For example, much has been made of Vue's choice to avoid class syntax for components as the default, e.g. &lt;a href="https://github.com/vuejs/vue/issues/2371" rel="noopener noreferrer"&gt;this issue on GitHub&lt;/a&gt;. There are excellent reasons for this decision, one of which is for Vue to work without a build environment. As a feature, this makes Vue incredibly easy to get up-and-running, for beginners learning the framework or for seasoned developers trying out a quick prototype. "It will fail," some said. I suppose that remains to be seen, but after several years of arguing, the framework continues to thrive.&lt;/p&gt;

&lt;h3&gt;
  
  
  A consistent experience for all customers
&lt;/h3&gt;

&lt;p&gt;Scott Molinari made this comment on a previous post of mine:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;once the usage of the API is down pat, anyone and everyone who knows Vue is basically doing the same thing. This also means the need for best practices are held to a minimum and both of these advantages mean cognitive load over time is reduced. i.e. when you dig into someone else’s component, you understand it quickly. This all in turn means Vue code is more robust and in the end, it’s of higher quality.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This point is especially important for both beginners and experienced developers alike. One of the significant tradeoffs to cobbling libraries together is that it can be harder to transition into new projects or unfamiliar parts of a large codebase. This approach may pay off for the right teams. In most cases, those tradeoffs aren't worth it to me because I place much value on consistency.&lt;/p&gt;




&lt;p&gt;When my late wife and I lived in New York City, our favorite restaurant was &lt;a href="https://www.zenkichi.com/" rel="noopener noreferrer"&gt;Zenkichi&lt;/a&gt;. The cuisine is Japanese brasserie, but the experience is so much more. If you make it to the Williamsburg neighborhood in Brooklyn, you should try it.&lt;/p&gt;

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

&lt;p&gt;It's housed in a small building with a wooden exterior and no discernable markings. Located near the East River in the Williamsburg of Brooklyn, it's easy to miss from the outside.&lt;/p&gt;

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

&lt;p&gt;The interior is dark, romantic, hand-crafted. Each table upstairs is like a small private dining room with a pull-down curtain and a small buzzer to summon the wait staff.&lt;/p&gt;

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

&lt;p&gt;Everytime we ate there, we chose the omakase menu. We left all the decision-making up to the chef. It's difficult at first to place that kind of trust in someone else's judgment. Giving up control is uncomfortable. However, this led to some delightful discoveries. Of course, not all the courses were to our liking. Nevertheless, we loved the experience.&lt;/p&gt;




&lt;p&gt;The chef’s menu need not be reserved for special occasions in web development. With Vue.js, we have a framework that gives us all the ingredients we need to jump into building outstanding user interfaces. It also makes it relatively easy to swap out menu items to suit your preferences. So it would seem you &lt;a href="https://en.wikipedia.org/wiki/You_can%27t_have_your_cake_and_eat_it" rel="noopener noreferrer"&gt;can have your cake and eat it too&lt;/a&gt;? Just another reason why I find Vue.js so fulfilling.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Did you like this post? Subscribe to my newsletter on &lt;a href="https://rossta.net" rel="noopener noreferrer"&gt;rossta.net&lt;/a&gt; and I'll send you an occasional email about web development with Vue.js&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Originally published at &lt;a href="https://rossta.net/blog/vue-js-is-omakase.html" rel="noopener noreferrer"&gt;rossta.net&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>vue</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Seven reasons to learn Vue.js in 2019</title>
      <dc:creator>Ross Kaffenberger</dc:creator>
      <pubDate>Tue, 01 Jan 2019 13:00:09 +0000</pubDate>
      <link>https://dev.to/rossta/seven-reasons-learn-vuejs-in-2019-2n9o</link>
      <guid>https://dev.to/rossta/seven-reasons-learn-vuejs-in-2019-2n9o</guid>
      <description>&lt;p&gt;I love building applications in Vue.js and here's why I think the future is looking bright for the framework and its community.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. No build step required
&lt;/h3&gt;

&lt;p&gt;A critical aspect of the Vue philosophy is it be easy to get started. Unlike some other popular frameworks, it's not necessary to use a complex build tool like Webpack to build an application with it. Just include a script tag pointing to the &lt;a href="https://vuejs.org/v2/guide/installation.html#Direct-lt-script-gt-Include"&gt;latest release for development or production&lt;/a&gt;, and you have access to the Vue runtime.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Having a low barrier to entry makes Vue a worthy consideration as a first JS framework to learn.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. A world-class command line interface
&lt;/h3&gt;

&lt;p&gt;Of course, many developers are looking for advanced development features like ES or TypeScript transpilation, hot module replacement, and tree-shaking, made possible by build tools. Vue has you covered there as well.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install -g @vue/cli
vue create my-project
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This past year, the Vue core team re-wrote their command line interface from the ground up, resulting in Vue CLI 3. It's designed in such a way to promote best practices and a full-featured default Webpack configuration that should be easier to extend without making it difficult to upgrade, i.e., "no need to eject." Vue CLI provides a ton of useful additional features, including an interactive project initialization wizard (available through the terminal or a web-based UI), a plugin system to support generators and configuration for community add-ons, and the ability to specify alternative build targets, like web components or as libraries.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Friendly learning curve
&lt;/h3&gt;

&lt;p&gt;A common criticism I hear about Vue is that its API has a larger surface area than some other popular frameworks and I agree up to a point (depending on the framework). Ironically, another  thing I hear &lt;a href="https://hackernoon.com/should-you-learn-react-or-vue-first-7dc0d4dd8c04"&gt;over&lt;/a&gt; and &lt;a href="https://www.quora.com/How-does-Vue-js-compare-to-React-js"&gt;over&lt;/a&gt; is Vue is easy to learn. Though subjective and anecdotal, this has held for folks I've heard from regardless of previous experience with JavaScript frameworks and JavaScript in general.&lt;/p&gt;

&lt;p&gt;One reason, I believe, is that Vue is a "progressive JavaScript framework."&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ao7M8RNa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/jlme30ylv1zzv9vo9mr0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ao7M8RNa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/jlme30ylv1zzv9vo9mr0.png" alt="Vue is a Progressive JavaScript Framework"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No need to learn the whole API to get started with Vue, no need to learn a new syntax like JSX; only basic HTML, CSS, and JS knowledge is required to get started.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. A solid ecosystem
&lt;/h3&gt;

&lt;p&gt;Before Vue, I've gotten frustrated with the fractured nature of learning best practices beyond the basics. What client-side router should I use? Which data management/Flux implementation should I use? How do I test my components? How should I configure my build system? Over time, answering these questions has gotten easier, depending on the community, but I've liked Vue's approach since the start.&lt;/p&gt;

&lt;p&gt;Vue provides official support for several essential add-ons, including &lt;code&gt;vue-router&lt;/code&gt; for client-side routing, &lt;code&gt;vuex&lt;/code&gt; for managing state, &lt;code&gt;vue-test-utils&lt;/code&gt; for unit testing components, the &lt;code&gt;vue-devtools&lt;/code&gt; browser extension for debugging, Vue CLI as described earlier. None of these tools are required Vue can work quite well with alternatives for these libraries, like &lt;code&gt;redux&lt;/code&gt; or &lt;code&gt;mobx&lt;/code&gt; instead of &lt;code&gt;vuex&lt;/code&gt;, or another router. The critical point is that the community assists developers by supporting a set of very good recommended defaults, something that a backend framework like Ruby on Rails has traditionally done very well.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. The Vue instance
&lt;/h3&gt;

&lt;p&gt;The most potent aspect Vue is its &lt;a href="https://codingexplained.com/coding/front-end/vue-js/understanding-vue-js-reactivity"&gt;reactivity system&lt;/a&gt;. We can tap into it through &lt;a href="https://vuejs.org/v2/guide/instance.html"&gt;the &lt;code&gt;Vue&lt;/code&gt; instance&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;el&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#app&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This invocation is how every Vue application is initialized. It also creates a fully-reactive root component of the application. A Vue instance can also be used as an event bus or for tracking dependency changes separately from the application component tree, say, as an implementation detail of a Vue plugin.&lt;/p&gt;

&lt;p&gt;Vue's reactivity system is beautiful in its simplicity. Playing with the Vue instance is an excellent way to understanding how the reactivity system works and level up one's Vue, and JavaScript, skills in general.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Vue 3 lands this year
&lt;/h3&gt;

&lt;p&gt;Speaking of Vue's reactivity system, &lt;a href="https://medium.com/the-vue-point/plans-for-the-next-iteration-of-vue-js-777ffea6fabf"&gt;Vue 3 is expected to ship this year&lt;/a&gt;. Among some architectural and performance improvements and minor API changes, Vue 3 provides a new Proxy-based implementation of its reactivity system.&lt;/p&gt;

&lt;p&gt;The Proxy-based system solves &lt;a href="https://vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats"&gt;some of the known caveats with Vue change detection&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;In Vue 2, Vue cannot:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Detect property addition, e.g., &lt;code&gt;vm.b = 2&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Detect array modification through indexing or modifying length, e.g., &lt;code&gt;arr[0] = 2&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;The workound: use &lt;code&gt;Vue.set&lt;/code&gt;, e.g., &lt;code&gt;Vue.set(vm, 'b', 2)&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Vue 3 Proxy-based reactivity makes these annoying issues go away.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. An amazing community
&lt;/h3&gt;

&lt;p&gt;Since I've started using Vue, I've been fortunate to learn from a variety of Vue developers through forums, on Twitter and GitHub, and at local meetups. Vue has a distributed, hard-working core team, who are continually improving the framework without over-burdening developers with a bunch of fringe features or painful upgrades. The &lt;a href="https://forum.vuejs.org/"&gt;Vue forums&lt;/a&gt; is a great way to get insight from experts on tricky issues. Vue conferences, like &lt;a href="https://vueconf.us/"&gt;VueConf.us&lt;/a&gt; and &lt;a href="https://www.vuejs.amsterdam/"&gt;Vue Amsterdam&lt;/a&gt;, a great way to connect with other members of the community and attend more in-depth workshops, are already taking place all over the world. There's also &lt;a href="https://vuevixens.org/"&gt;Vue Vixens&lt;/a&gt;, an organization that provides safe environments for people who identify as women to learn Vue.js.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bonus. It's just plain fun
&lt;/h3&gt;

&lt;p&gt;I got my start in web development just as the Ruby and the Rails framework was taking off. One thing I have always loved about Ruby is creator Yukihiro Matsumoto's explicit (and, dare I say, audacious) goal of inventing a language optimized for developer happiness.&lt;/p&gt;

&lt;p&gt;I get these same feelings when I build interfaces with Vue.js. I was spending less time wrestling with configuration and APIs and more time building and having fun doing it.&lt;/p&gt;

&lt;p&gt;While I don't know that Vue.js was created so explicitly in the name of developer happiness, for, it has and continues to be fulfilling to that end. It's something I hear from many others who've taken time to learn the framework and probably the most important reason I'll recommend Vue.js in 2019.&lt;/p&gt;




&lt;p&gt;So what are you waiting for? Best of luck with your Vue.js journey in the coming year.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Did you like this post? Subscribe to my newsletter on &lt;a href="https://rossta.net"&gt;rossta.net&lt;/a&gt; and I'll send you an occasional email about web development with Vue.js&lt;/em&gt;&lt;/p&gt;

</description>
      <category>vue</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
