<?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>Forem: Mike E</title>
    <description>The latest articles on Forem by Mike E (@mellis481).</description>
    <link>https://forem.com/mellis481</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%2F513926%2Fbb211358-955e-4aae-a774-a4c25bf43ecd.jpeg</url>
      <title>Forem: Mike E</title>
      <link>https://forem.com/mellis481</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/mellis481"/>
    <language>en</language>
    <item>
      <title>What are dist-tags in npm?</title>
      <dc:creator>Mike E</dc:creator>
      <pubDate>Thu, 21 Dec 2023 16:18:30 +0000</pubDate>
      <link>https://forem.com/mellis481/what-are-dist-tags-in-npm-3f5h</link>
      <guid>https://forem.com/mellis481/what-are-dist-tags-in-npm-3f5h</guid>
      <description>&lt;p&gt;Recently I had a need to use dist-tags tags when publishing a package with npm. It unfortunately took longer than I would have liked to fully understand it conceptually, so I thought I'd put this document together to provide all the information someone would need to get started.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are dist-tags?
&lt;/h2&gt;

&lt;p&gt;dist-tags or distribution tags are an optional way to provide an alias for a package that you are publishing. They are not to be confused with &lt;a href="https://git-scm.com/book/en/v2/Git-Basics-Tagging" rel="noopener noreferrer"&gt;Git tags&lt;/a&gt;. &lt;a href="https://docs.npmjs.com/cli/v10/commands/npm-dist-tag" rel="noopener noreferrer"&gt;Here&lt;/a&gt; is npm's documentation on dist-tags.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do you add a dist-tag when publishing a package?
&lt;/h2&gt;

&lt;p&gt;When you publish a package, you can add a dist-tag by including the &lt;code&gt;--tag&lt;/code&gt; option followed by the dist-tag you'd like to use. If you do not include the &lt;code&gt;--tag&lt;/code&gt; option, (meaning you just run &lt;code&gt;npm publish&lt;/code&gt;), the dist-tag &lt;code&gt;latest&lt;/code&gt; will be used by default. &lt;/p&gt;

&lt;p&gt;Here is an example where we publish a package with the &lt;code&gt;stable&lt;/code&gt; dist-tag:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

npm publish --tag stable


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

&lt;/div&gt;

&lt;p&gt;An important takeaway is that using the &lt;code&gt;stable&lt;/code&gt; dist-tag (or any dist-tag other than &lt;code&gt;latest&lt;/code&gt;) not only associates that alias with the version of that package, but it results in the package NOT being marked as &lt;code&gt;latest&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftegl0sln0cy8mq1ho7aj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftegl0sln0cy8mq1ho7aj.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As it turns out, this describes my original need for dist-tags. I had to publish a version of a package for a previous major version and needed to ensure the version of the package I was publishing was not going to be considered the latest.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do dist-tags come into play with installing a package?
&lt;/h2&gt;

&lt;p&gt;We are all familiar with how to install a specific version of a package. We'd do something like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

npm install some-package@3.2.0


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

&lt;/div&gt;

&lt;p&gt;Similarly, we can also target a specific Git tag when installing a package. Like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

npm install some-package@v3.2.0


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

&lt;/div&gt;

&lt;p&gt;Just as we can target a specific package version or Git tag, we can also target a specific dist-tag like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

npm install some-package@beta


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

&lt;/div&gt;

&lt;p&gt;This is why when you want to upgrade a package to the latest version, you run the following command:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

npm install some-package@latest


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

&lt;/div&gt;

&lt;p&gt;You are simply telling npm: &lt;em&gt;"Install the package with the &lt;code&gt;latest&lt;/code&gt; dist-tag."&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What values can I use for a dist-tag?
&lt;/h2&gt;

&lt;p&gt;There are certain dist-tags that it seems the industry has standardized on like &lt;code&gt;beta&lt;/code&gt;, &lt;code&gt;canary&lt;/code&gt;, and &lt;code&gt;next&lt;/code&gt;, but you can use almost any value that makes sense for your project.  Other than &lt;code&gt;latest&lt;/code&gt;, no tag has any special significance to npm itself.&lt;/p&gt;

&lt;p&gt;The only restrictions are that dist-tags share a namespace with versions and Git tags so your dist-tag cannot match one of those. You will actually get an error if you try to publish a package that appears to be a semantic version (eg. &lt;code&gt;3.2.0&lt;/code&gt;) or tag (&lt;code&gt;v3.2.0&lt;/code&gt;).&lt;/p&gt;

</description>
      <category>npm</category>
      <category>node</category>
      <category>publish</category>
      <category>package</category>
    </item>
    <item>
      <title>Tricking Dependabot into allowing multiple update configs for one package ecosystem</title>
      <dc:creator>Mike E</dc:creator>
      <pubDate>Mon, 02 Oct 2023 14:30:58 +0000</pubDate>
      <link>https://forem.com/mellis481/tricking-dependabot-to-have-multiple-configs-for-one-package-ecosystem-5b5g</link>
      <guid>https://forem.com/mellis481/tricking-dependabot-to-have-multiple-configs-for-one-package-ecosystem-5b5g</guid>
      <description>&lt;p&gt;Dependabot can be limiting in the way you can configure it in the &lt;code&gt;dependabot.yml&lt;/code&gt; file. There was a certain manner in which I wanted to configure Dependabot to automatically create updates which would seem unachievable based on documentation, but I was able to find a way to "trick" Dependabot into allowing it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Goal
&lt;/h2&gt;

&lt;p&gt;The way I wanted to configure Dependabot was to have PRs created for the following scenarios:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;All security updates.&lt;/li&gt;
&lt;li&gt;Major and minor version updates for any packages in my private registry.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is a configuration that allows for PRs for security updates to (the &lt;code&gt;open-pull-requests-limit: 0&lt;/code&gt; line does that), but does nothing for goal #2 above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: 2
updates:
  - package-ecosystem: 'npm'
    directory: '.'
    schedule:
      interval: 'daily'
    open-pull-requests-limit: 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is a configuration that allows for major and minor version updates for my private registry, but does nothing for goal #1 above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: 2
registries:
  mycompany:
    type: npm-registry
    url: 'https://npm.pkg.github.com'
updates:
  - package-ecosystem: 'npm'
    directory: '/'
    registries:
      - 'mycompany'
    schedule:
      interval: 'daily'
    allow:
      - dependency-name: '@mycompany/*'
    ignore:
      - dependency-name: '@mycompany/*'
        update-types: ['version-update:semver-patch']
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;The configuration above will allow PRs for version updates for &lt;code&gt;@mycompany&lt;/code&gt; dependencies to be created for major and minor version bumps.  Great!  The problem, however, is that this filters out all security updates.  I could get the security updates by removing the &lt;code&gt;allow&lt;/code&gt; and &lt;code&gt;ignore&lt;/code&gt; options, but then I'd get &lt;em&gt;all&lt;/em&gt; version updates which I don't want.&lt;/p&gt;

&lt;p&gt;This problem occurs because Dependabot only allows one update configuration per &lt;code&gt;package-ecosystem&lt;/code&gt; (&lt;a href="https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#package-ecosystem"&gt;documentation&lt;/a&gt;). Actually, to be accurate, it only allows for one update configuration per package-ecosystem-directory combination. This allows for different configurations for different packages in a mono repo.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;p&gt;When trying to find a solution for this limitation so I could get the Dependabot behavior I was seeking, I focused on how I could have multiple update configurations for the &lt;code&gt;npm&lt;/code&gt; &lt;code&gt;package-ecosystem&lt;/code&gt; while continuing to target the root directory in both configs (since I don't have a mono repo). Ultimately, I was able to leverage different strings that end up resolving to the root directory when the workflow executes.&lt;/p&gt;

&lt;p&gt;The default root path that you see in Dependabot documentation is &lt;code&gt;/&lt;/code&gt; which, in Linux, represents the "root" of the filesystem. Linux also supports &lt;code&gt;.&lt;/code&gt; which represents the current directory in the file system. I tested and confirmed both end up targeting the root of my codebase. This allows for two update configurations for the &lt;code&gt;npm&lt;/code&gt; &lt;code&gt;package-ecosystem&lt;/code&gt; being allowed, successfully targeting the root directory.&lt;/p&gt;

&lt;p&gt;Here was my final &lt;code&gt;dependabot.yml&lt;/code&gt; config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: 2
registries:
  mycompany:
    type: npm-registry
    url: 'https://npm.pkg.github.com'
updates:
  # npm packages for @mycompany major and minor updates only
  - package-ecosystem: 'npm'
    directory: '/'
    registries:
      - 'mycompany'
    schedule:
      interval: 'daily'
    allow:
      - dependency-name: '@mycompany/*'
    ignore:
      - dependency-name: '@mycompany/*'
        update-types: ['version-update:semver-patch']
  # npm packages for security updates only
  - package-ecosystem: 'npm'
    directory: '.'
    schedule:
      interval: 'daily'
    open-pull-requests-limit: 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>dependabot</category>
      <category>javascript</category>
      <category>github</category>
    </item>
    <item>
      <title>How to inspect transient DOM elements</title>
      <dc:creator>Mike E</dc:creator>
      <pubDate>Mon, 17 Jul 2023 15:04:21 +0000</pubDate>
      <link>https://forem.com/mellis481/how-to-inspect-transient-dom-elements-3h9d</link>
      <guid>https://forem.com/mellis481/how-to-inspect-transient-dom-elements-3h9d</guid>
      <description>&lt;p&gt;There are certain situations in web applications where a UI element will appear/disappear from the screen and it is challenging to inspect it.  This typically occurs when an element's presence in the DOM is based on &lt;code&gt;focus&lt;/code&gt; or &lt;code&gt;hover&lt;/code&gt; state which changes when you attempt to inspect it.  In this article, I'll cover a couple ways to overcome this.&lt;/p&gt;

&lt;h2&gt;
  
  
  The OK way
&lt;/h2&gt;

&lt;p&gt;An easy way to inspect an element which may be satisfactory in many situations is to use &lt;code&gt;setTimeout()&lt;/code&gt; in combination with &lt;code&gt;debugger;&lt;/code&gt; to effectively freeze the DOM, allowing you to then inspect anything at your leisure. The &lt;code&gt;debugger;&lt;/code&gt; statement (documented &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/debugger" rel="noopener noreferrer"&gt;here&lt;/a&gt;) invokes the Javascript debugger and completely pauses execution.  When used in the callback of a &lt;code&gt;setTimeout()&lt;/code&gt; timer, you can "schedule" the DOM to freeze after you've gotten the UI ready for inspection.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dkp79x.csb.app/" rel="noopener noreferrer"&gt;Here&lt;/a&gt; is a CodeSandbox example where you can play around with this technique.  In this example, if you click on the &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt;, an options menu will appear. If our goal was to inspect one of the options in the menu, we'd have to contend with the fact that the menu disappears when we click anywhere outside of the menu.&lt;/p&gt;

&lt;p&gt;To test this solution, open up the Developer Tools and add the following code to the Console tab:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;setTimeout(() =&amp;gt; { debugger; }, 3000)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once we submit this command in the console, you'll have three seconds to open the menu, before the execution is paused and the DOM is frozen.&lt;/p&gt;

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

&lt;p&gt;One drawback of this approach is the DOM is &lt;em&gt;completely&lt;/em&gt; frozen. This means that if we wanted to do something like check the hover behavior on one of the options menu, we couldn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  The better way
&lt;/h2&gt;

&lt;p&gt;A better way is to leverage Chrome's "Emulate a focused page" option in Developer Tools. You can quickly enable this option by using Chrome's &lt;a href="https://developer.chrome.com/docs/devtools/command-menu/#open" rel="noopener noreferrer"&gt;command palette&lt;/a&gt; by pressing &lt;code&gt;Control+Shift+P&lt;/code&gt; on Windows/Linux or &lt;code&gt;Command+Shift+P&lt;/code&gt; on Mac. Once open, start typing "Emulate a focused page" or "emfo" for short.&lt;/p&gt;

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

&lt;p&gt;Once enabled, you can hit the "Select an element in the page to inspect it" button in Developer Tools.&lt;/p&gt;

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

&lt;p&gt;Lastly, click on the options menu or one of the options.  You'll notice that the menu does not disappear and you can even see hover styles.&lt;/p&gt;

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

</description>
      <category>ui</category>
      <category>javascript</category>
      <category>frontend</category>
    </item>
    <item>
      <title>How to inspect files packaged by webpack before they are emitted</title>
      <dc:creator>Mike E</dc:creator>
      <pubDate>Thu, 30 Jun 2022 20:30:34 +0000</pubDate>
      <link>https://forem.com/mellis481/how-to-inspect-files-packaged-by-webpack-before-they-are-emitted-337j</link>
      <guid>https://forem.com/mellis481/how-to-inspect-files-packaged-by-webpack-before-they-are-emitted-337j</guid>
      <description>&lt;p&gt;I recently had a need to inspect files in my front-end project that are packaged by webpack before they were emitted.  In my pursuit to accomplish this an elegant and robust manner, I came across webpack hooks which are an exceedingly powerful way to tap into the inner workings of webpack.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is webpack?
&lt;/h2&gt;

&lt;p&gt;webpack is a module bundler for JavaScript.  Front-end applications contain many types of assets such as JavaScript, (HOPEFULLY) Typescript, JSON, HTML, CSS, and images.  webpack (after you've configure it to process files in a certain manner) will generate static assets, representing your applications modules so that they can be interpreted by a browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are webpack hooks?
&lt;/h2&gt;

&lt;p&gt;A "hook" in software development is a place in code that allows you to tap into a module to either provide different behavior or to react when something happens. webpack provides the following types of hooks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://webpack.js.org/api/compiler-hooks/"&gt;Compiler hooks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://webpack.js.org/api/compilation-hooks/"&gt;Compilation hooks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://webpack.js.org/api/contextmodulefactory-hooks/"&gt;ContextModuleFactory hooks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://webpack.js.org/api/parser/"&gt;JavascriptParser hooks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://webpack.js.org/api/normalmodulefactory-hooks/"&gt;NormalModuleFactory hooks&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How about an example?
&lt;/h2&gt;

&lt;p&gt;For an example scenario, let's pretend we want to make sure that, when we build our application, no file is outputted that contains the string &lt;code&gt;MY_SUPER_SECRET&lt;/code&gt;.  Perhaps we want to do this to provide a last line of defense from a developer including a sensitive value in our code and we want to prevent webpack from even compiling it.  If that string is detected, we'd like webpack to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;throw an error.&lt;/li&gt;
&lt;li&gt;not emit any files at any point during the build.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To do this, let's look at the &lt;a href="https://webpack.js.org/api/compiler-hooks/#shouldemit"&gt;&lt;code&gt;shouldEmit&lt;/code&gt;&lt;/a&gt; compiler hook. This hook is called &lt;em&gt;before&lt;/em&gt; assets are emitted and will allow us to error out and not emit assets if our validation fails.&lt;/p&gt;

&lt;p&gt;To start, let's create a new plugin class and add it to the &lt;code&gt;plugins&lt;/code&gt; block of our &lt;code&gt;webpack.config&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/webpack.config.ts&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;AssetValidatorPlugin&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;./plugins/asset-validator-plugin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&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="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{...},&lt;/span&gt;
    &lt;span class="na"&gt;module&lt;/span&gt;&lt;span class="p"&gt;:{...},&lt;/span&gt;
    &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;AssetValidatorPlugin&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="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that, while I've defined my plugin in a separate class/file, you could include it in your &lt;code&gt;webpack.config&lt;/code&gt; inline.&lt;/p&gt;

&lt;p&gt;Now, let's take a look at the plugin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/plugins/asset-validator-plugin.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;webpack&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;webpack&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;AssetValidatorPlugin&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;compiler&lt;/span&gt;&lt;span class="p"&gt;:&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;Compiler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;compiler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hooks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shouldEmit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AssetValidatorPlugin&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;compilation&lt;/span&gt;&lt;span class="p"&gt;:&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;compilation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Compilation&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;validateAssets&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;compilation&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;public&lt;/span&gt; &lt;span class="nx"&gt;validateAssets&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;compilation&lt;/span&gt;&lt;span class="p"&gt;:&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;compilation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Compilation&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;assets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;compilation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assets&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;regex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;RegExp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MY_SUPER_SECRET&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;g&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Loop through each asset and check to see if it contains any sensitive strings&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&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;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;assets&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="nx"&gt;i&lt;/span&gt;&lt;span class="o"&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="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="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;assets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&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;asset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;compilation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getAsset&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;source&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;contents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;convertSourceToString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;source&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;matches&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;contents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;regex&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;matches&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Our tool has identified the presence of the string 'MY_SUPER_SECRET' in your compiled code. Compilation has been aborted.&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;return&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;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// This function is only needed because asset.source.source() can be a string or ArrayBuffer&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;convertSourceToString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;ArrayBuffer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&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;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&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;return&lt;/span&gt; &lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;TextDecoder&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;source&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, let's review what is included our plugin.  We've defined our plugin class and, within, are able to &lt;a href="https://webpack.js.org/api/plugins/#tapable"&gt;tap&lt;/a&gt; into the &lt;code&gt;compiler.hooks.shouldEmit&lt;/code&gt; hook.  In the hook callback, we simply call a &lt;code&gt;validateAssets()&lt;/code&gt; function we've defined which loops through all assets that are part of the compilation and use regular expression matching to see if the string exists.  We throw an error if it does, short-circuiting the compilation and not emitting any files. If it doesn't contain our special string, we'll return &lt;code&gt;true&lt;/code&gt;, compilation will continue, emitting the packaged files as expected.&lt;/p&gt;

&lt;p&gt;If you have a need to pass any parameters to your plugin, that can easily be accomplished by defining a constructor in your plugin class like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MyPluginOptions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;options&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;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Hopefully you now have a better understanding of webpack hooks and how you can leverage them to provide additional behavior when your application's assets are packaged.&lt;/p&gt;

</description>
      <category>webpack</category>
      <category>javascript</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
