<?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: Tierney Cyren</title>
    <description>The latest articles on DEV Community by Tierney Cyren (@bnb).</description>
    <link>https://dev.to/bnb</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%2F9233%2Fe31b00c6-7c41-4819-bf12-5c7487dd881a.jpg</url>
      <title>DEV Community: Tierney Cyren</title>
      <link>https://dev.to/bnb</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bnb"/>
    <language>en</language>
    <item>
      <title>Conditional Exports: Supporting both import and require()</title>
      <dc:creator>Tierney Cyren</dc:creator>
      <pubDate>Thu, 17 Jun 2021 02:22:50 +0000</pubDate>
      <link>https://dev.to/bnb/conditional-exports-supporting-both-import-and-require-3ihg</link>
      <guid>https://dev.to/bnb/conditional-exports-supporting-both-import-and-require-3ihg</guid>
      <description>&lt;p&gt;Now that we've both gone over how to make Node.js &lt;a href="https://dev.to/bnb/implicit-esm-in-node-js-with-type-module-np"&gt;implicitly&lt;/a&gt; and &lt;a href="https://dev.to/bnb/explicit-esm-in-node-js-with-mjs-3ooh"&gt;explicitly&lt;/a&gt; parse your code as ESM, we can get into some of the more meaty and interesting bits of ESM in Node.js.&lt;/p&gt;

&lt;p&gt;To me, one of the most interesting features is &lt;strong&gt;Conditional Exports&lt;/strong&gt;. With conditional exports, you can have a single module export both ESM (allowing it to be &lt;code&gt;import&lt;/code&gt;ed, with all the features of &lt;code&gt;import&lt;/code&gt; that you'd expect) and CommonJS (allowing it to be &lt;code&gt;require()&lt;/code&gt;ed.)&lt;/p&gt;

&lt;p&gt;From a broader perspective, this is an amazing tool for transition. Whether you're a maintainer of an open-source module or charged with supporting internal end-users on an SDK with a long support cycle, this helps ease the shock of going from CommonJS to ESM, or simply helps you support both use cases for as long as your consumers require.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up Conditional Exports
&lt;/h2&gt;

&lt;p&gt;Let's take the &lt;code&gt;package.json&lt;/code&gt; we used in the &lt;a href="https://dev.to/bnb/implicit-esm-in-node-js-with-type-module-np"&gt;Implicit ESM&lt;/a&gt; article, and exapand on that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;{
  "name": "apollo-lunar-module",
  "version": "0.0.1",
  "description": "A simple, fast, nice lunar lander module",
  "main": "index.js",
  "type": "module",
&lt;span class="gi"&gt;+ "exports": {
+   "import": "./main.js",
+   "require": "./main.cjs"
+ },
&lt;/span&gt;  "scripts": {
    "lint": "standard"
  },
  "author": "Tierney Cyren &amp;lt;hello@bnb.im&amp;gt; (https://bnb.im/)",
  "license": "MIT",
  "devDependencies": {
    "standard": "^16.0.3"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see we've added the following code:&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="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;"exports"&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;"import"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./main.js"&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;doesn't&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;have&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;be&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;`main`&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"require"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./main.cjs"&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;doesn't&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;have&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;be&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;`main`&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="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;You should note that we've got &lt;code&gt;"type": "module"&lt;/code&gt; in our package.json, meaning that &lt;code&gt;.js&lt;/code&gt; will be interpreted as ESM and to use CommonJS in this module, we'll need to use the &lt;code&gt;.cjs&lt;/code&gt; extension.&lt;/p&gt;

&lt;p&gt;The utility of having both ESM and CommonJS in the same project becomes apparent here. We're now able to enable &lt;em&gt;both&lt;/em&gt; ESM and CommonJS users to consume our package without having to install a different module.&lt;/p&gt;

&lt;p&gt;Now, it is worth noting that you can't just copy/paste your code from &lt;code&gt;main.js&lt;/code&gt; into &lt;code&gt;main.cjs&lt;/code&gt; - you'll actually need to make it work as CommonJS code, which probably also means figuring out how to support both use cases in both export styles. If you'd like a solid example of how to do this for realsies, &lt;a href="https://twitter.com/MylesBorins"&gt;Myles Borins&lt;/a&gt; built &lt;a href="https://github.com/mylesborins/node-osc"&gt;node-osc&lt;/a&gt; and has a &lt;a href="https://github.com/MylesBorins/node-osc/blob/main/rollup.config.mjs"&gt;rollup configuration&lt;/a&gt; that does ESM to CommonJS conversion for this exact use case. Additionally, there are a number of codemods that exist (and I've apparently &lt;a href="https://twitter.com/bitandbang/status/1404929283500478470"&gt;signed myself up&lt;/a&gt; to work on yet another codemod for this) that can help with this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Consuming a Module that has Conditional Exports
&lt;/h2&gt;

&lt;p&gt;Thankfully, conditional exports were built in such a way that they're &lt;em&gt;largely&lt;/em&gt; invisible to end-users of your module with &lt;em&gt;one&lt;/em&gt; caveat.&lt;/p&gt;

&lt;p&gt;The caveat: if your end-users are somehow consuming the same module both as ESM and as CommonJS, the &lt;em&gt;instance&lt;/em&gt; is of the ESM and CommonJS versions are not the same. Both ESM and CommonJS have been built so the instance is shared, but in the case of using &lt;em&gt;both&lt;/em&gt; the instance will not be the same. For most folks this &lt;em&gt;likely&lt;/em&gt; won't be problematic for a number of reasons, but it is still a possibility. The most likely way this'll surface is through &lt;em&gt;you&lt;/em&gt; using a conditionally exported module one way and a dependency in &lt;code&gt;node_modules&lt;/code&gt; using it a different way.&lt;/p&gt;

&lt;p&gt;Outside of that, you'd use modules with conditional exports however you would normally.&lt;/p&gt;

&lt;p&gt;Let's take the example of &lt;code&gt;apollo-lunar-module&lt;/code&gt; that we've been using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;apollo-lunar-module
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To use it in ESM:&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="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;lander&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;apollo-lunar-module&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And if we wanted to import (hypothetical) named exports from &lt;code&gt;main.js&lt;/code&gt; with ESM:&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;abortGuidancePanel&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="s2"&gt;apollo-lunar-module&lt;/span&gt;&lt;span class="dl"&gt;"&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;plssCondensateContainerAssy&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="s2"&gt;apollo-lunar-module&lt;/span&gt;&lt;span class="dl"&gt;"&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;crewLog&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="s2"&gt;apollo-lunar-module&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To use it in CommonJS:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lander&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="s2"&gt;apollo-lunar-module&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;And, again, if we wanted to consume (hypothetical) named exports, exposed by &lt;code&gt;main.cjs&lt;/code&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;abortGuidancePanel&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="s2"&gt;apollo-lunar-module&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;plssCondensateContainerAssy&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="s2"&gt;apollo-lunar-module&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;crewLog&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="s2"&gt;apollo-lunar-module&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;Either way, as an end-user, conditional exports make support for ESM or for CommonJS effectively invisible to those who are using your modules the other way. This ends up creating a pretty wonderful solution for end-users, enabling maintainers to ensure they're supporting both ESM and CommonJS consumers &lt;em&gt;if they want to&lt;/em&gt;.&lt;/p&gt;

</description>
      <category>node</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Implicit ESM in Node.js with "type": "module"</title>
      <dc:creator>Tierney Cyren</dc:creator>
      <pubDate>Wed, 16 Jun 2021 14:55:55 +0000</pubDate>
      <link>https://dev.to/bnb/implicit-esm-in-node-js-with-type-module-np</link>
      <guid>https://dev.to/bnb/implicit-esm-in-node-js-with-type-module-np</guid>
      <description>&lt;p&gt;Continuing the Node.js ESM content, I'd like to talk about the comparitively straightforward alternative to &lt;a href="https://dev.to/bnb/explicit-esm-in-node-js-with-mjs-3ooh"&gt;using .mjs&lt;/a&gt; to get your Node.js applications to run as ECMAScript Modules (ESM) rather than CommonJS: including &lt;code&gt;"type": "module"&lt;/code&gt; in your &lt;code&gt;package.json&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Usage of &lt;code&gt;"type": "module"&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Let's assume we've started with the following &lt;code&gt;package.json&lt;/code&gt; for a zero (production) dependency application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "name": "apollo-lunar-module",
  "version": "0.0.1",
  "description": "A simple, fast, nice lunar lander module",
  "main": "index.js",
  "scripts": {
    "lint": "standard"
  },
  "author": "Tierney Cyren &amp;lt;hello@bnb.im&amp;gt; (https://bnb.im/)",
  "license": "MIT",
  "devDependencies": {
    "standard": "^16.0.3"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To have implicit ESM - that is, have our &lt;code&gt;.js&lt;/code&gt; files parsed as ESM - we' need to make the following change:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;{
  "name": "apollo-lunar-module",
  "version": "0.0.1",
  "description": "A simple, fast, nice lunar lander module",
  "main": "index.js",
&lt;span class="gi"&gt;+ "type": "module",
&lt;/span&gt;  "scripts": {
    "lint": "standard"
  },
  "author": "Tierney Cyren &amp;lt;hello@bnb.im&amp;gt; (https://bnb.im/)",
  "license": "MIT",
  "devDependencies": {
    "standard": "^16.0.3"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This &lt;em&gt;specifically&lt;/em&gt; tells Node.js to parse your &lt;code&gt;.js&lt;/code&gt; files under this &lt;code&gt;package.json&lt;/code&gt; as ESM. Otherwise, by default (or when you use &lt;code&gt;"type": "commonjs"&lt;/code&gt;), Node.js will parse your &lt;code&gt;.js&lt;/code&gt; files as CommonJS. There's a few things to note:&lt;/p&gt;

&lt;p&gt;Node.js specifically looks for the &lt;em&gt;closest&lt;/em&gt; &lt;code&gt;package.json&lt;/code&gt; to determine whether or not to parse &lt;code&gt;.js&lt;/code&gt; as ESM or CommonJS.&lt;/p&gt;

&lt;p&gt;"&lt;em&gt;Closest&lt;/em&gt;" is important here. If there's a &lt;code&gt;package.json&lt;/code&gt; that's &lt;em&gt;closer&lt;/em&gt; to &lt;code&gt;.js&lt;/code&gt; files than your project's &lt;code&gt;package.json&lt;/code&gt;, and it &lt;em&gt;does not&lt;/em&gt; have &lt;code&gt;"type": "module"&lt;/code&gt; (or a &lt;a href="https://nodejs.org/api/packages.html#packages_dual_commonjs_es_module_packages"&gt;dual export&lt;/a&gt;, which is out of the scope of this post), CommonJS will be used for those &lt;code&gt;.js&lt;/code&gt; files. The most common/obvious example of this is the code within your &lt;code&gt;/node_modules/&lt;/code&gt; that may not be ESM, and shouldn't be parsed as such.&lt;/p&gt;

&lt;p&gt;Further, it's worth noting that explicitly using &lt;code&gt;.cjs&lt;/code&gt; overrides &lt;code&gt;"type": "module"&lt;/code&gt;. This is extremely useful if you're converting a codebase from CommonJS to ESM.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why &lt;code&gt;"type": "module"&lt;/code&gt;?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Quick Answer
&lt;/h3&gt;

&lt;p&gt;For you, the user, the straightforward answer to this is that using &lt;code&gt;"type": "module"&lt;/code&gt; is a better developer experience than having to explicitly use &lt;code&gt;.mjs&lt;/code&gt; in every single JavaScript file in your project if you're going to have a non-trivial number of files.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Answer With More Context
&lt;/h3&gt;

&lt;p&gt;Using &lt;code&gt;"type": "module"&lt;/code&gt; is often going to be a better developer experience for maintainers for a number of reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It minimizes manual changes and potential mistakes, allowing a single line of text to control parsing.&lt;/li&gt;
&lt;li&gt;It makes migrating from CommonJS to ESM easier.

&lt;ul&gt;
&lt;li&gt;It depends on how you'd like to do it, but one strategy is to chunk out work of converting your applications to ESM one bit at a time by setting &lt;code&gt;"type": "module"&lt;/code&gt; and converting all the CommonJS code to use the &lt;code&gt;.cjs&lt;/code&gt; file extension.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;It allows ecosystem tooling to quickly determine if your projects are using ESM or not.

&lt;ul&gt;
&lt;li&gt;Note that JSON modules (and therefore importing &lt;code&gt;package.json&lt;/code&gt;) are only supported behind the &lt;code&gt;--experimental-json-modules&lt;/code&gt; flag. It does seem that necessary proposals to streamline this seem to be making pretty decent progress through the relevant standards processes.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>node</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Explicit ESM in Node.js with .mjs</title>
      <dc:creator>Tierney Cyren</dc:creator>
      <pubDate>Mon, 14 Jun 2021 21:40:43 +0000</pubDate>
      <link>https://dev.to/bnb/explicit-esm-in-node-js-with-mjs-3ooh</link>
      <guid>https://dev.to/bnb/explicit-esm-in-node-js-with-mjs-3ooh</guid>
      <description>&lt;p&gt;A while ago, Node.js introduced support for ECMAScript Modules (ESM). ESM is the &lt;strong&gt;standardized&lt;/strong&gt; modules implementation that's been built-in to JavaScript. This differs rather significantly from CommonJS (CJS), which is the module system that Node.js has shipped with for over a decade that make them &lt;em&gt;relatively&lt;/em&gt; incompatible.&lt;/p&gt;

&lt;p&gt;There are a number of different components of Node.js that have been intentionally structured to allow you to use &lt;strong&gt;standard&lt;/strong&gt; (as in, how the ECMAScript Specification defines it) ESM by default and extend/augment that experience if you'd like to.&lt;/p&gt;

&lt;p&gt;Today, I want to get into one of the baisc elements of ESM in Node.js: the &lt;code&gt;.mjs&lt;/code&gt; and &lt;code&gt;.cjs&lt;/code&gt; extensions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why &lt;code&gt;.mjs&lt;/code&gt; (and &lt;code&gt;.cjs&lt;/code&gt;)?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Quick Answer
&lt;/h3&gt;

&lt;p&gt;The straightforward answer to this is that having different file extensions allows you to be explicit in how you want to run your code - &lt;code&gt;.mjs&lt;/code&gt; will always be run as ESM, &lt;code&gt;.cjs&lt;/code&gt; will always be run as CommonJS.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Answer With Context
&lt;/h3&gt;

&lt;p&gt;Because of the differences in how ESM and CommonJS work, Node.js runs them differently by default. This results in the runtime needing an indicator about which way you want to run your code - as ESM or as CommonJS.&lt;/p&gt;

&lt;p&gt;There's three different ways that this indicator could be expressed: explicitly, implicitly, and by default.&lt;/p&gt;

&lt;p&gt;To not break over a decade of projects and over a million modules that are expecting to Just Work, the default the project landed on was CommonJS - sensible, especially when you consider millions of lines of code and multitudes of applications already running in this way.&lt;/p&gt;

&lt;p&gt;The way to &lt;em&gt;explicitly&lt;/em&gt; assert that the code you're running is ESM and should be run as such is to just use the &lt;code&gt;.mjs&lt;/code&gt; file extension (which, if you're concerned, is also supported in web browsers as long as the &lt;code&gt;Content-Type: text/javascript&lt;/code&gt; header is sent and is actually &lt;a href="https://v8.dev/features/modules#mjs"&gt;recommended by V8&lt;/a&gt;). The official overview of this is documented in the &lt;a href="https://nodejs.org/api/packages.html#packages_determining_module_system"&gt;determining module system&lt;/a&gt; section of the Node.js Packages documentation.&lt;/p&gt;

&lt;p&gt;When you use &lt;code&gt;.mjs&lt;/code&gt;, Node.js &lt;em&gt;knows&lt;/em&gt; that you've written ESM and will parse your JavaScript as such. The same is true for &lt;code&gt;.cjs&lt;/code&gt; - Node.js &lt;em&gt;knows&lt;/em&gt; that &lt;code&gt;.cjs&lt;/code&gt; should run as CommonJS, and will parse your JavaScript as CommonJS.&lt;/p&gt;

</description>
      <category>node</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>beginners</category>
    </item>
    <item>
      <title>The New npm diff Command</title>
      <dc:creator>Tierney Cyren</dc:creator>
      <pubDate>Fri, 02 Apr 2021 16:53:41 +0000</pubDate>
      <link>https://dev.to/bnb/the-new-npm-diff-command-k0m</link>
      <guid>https://dev.to/bnb/the-new-npm-diff-command-k0m</guid>
      <description>&lt;p&gt;With the recent &lt;a href="https://github.blog/2021-02-02-npm-7-is-now-generally-available/"&gt;release of npm@7&lt;/a&gt;, we've gotten a few neat new features in npm.&lt;/p&gt;

&lt;p&gt;One of the ones that I imagine can go under the radar for most folks is the &lt;code&gt;npm diff&lt;/code&gt; command. It's a relatively... advanced command that has immense potential utility.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preface
&lt;/h2&gt;

&lt;p&gt;There's a few things we should establish as baseline assumptions before digging in.&lt;/p&gt;

&lt;p&gt;First, I'm going to be talking about a "local version" and a "remote version".&lt;/p&gt;

&lt;p&gt;The local version will be a module in your current working directory - so, if I wanted to diff my local &lt;code&gt;liblice&lt;/code&gt; module with the remote published version, I'd need to have that on disk and either have it as my current working directory or pass it as a path to the command. For the sake of this article, we're going to assume anytime we're diffing a local version it's in the current working directory.&lt;/p&gt;

&lt;p&gt;The remote version will be one that's on your default registry. For the vast majority of folks, this will be the default npm registry (a.k.a. &lt;a href="https://registry.npmjs.com"&gt;https://registry.npmjs.com&lt;/a&gt;). However, if you're trying to diff a module published to an alternative registry (say, an internal corporate registry) or if you've changed your default registry to a mirror or internal cache, that would be the registry the remote version would be checking. This is some super nice flexibility that comes free with the diff command that enables some pretty nice theoretical advanced workflows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Diffing the Local Version with the Latest Remote Version
&lt;/h2&gt;

&lt;p&gt;The raw command will diff the local version of a module with the remote version. This is particularly useful for module maintainers, contributors, and those floating local patches on a module (to patch a security vulnerability, for example).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm diff
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will output &lt;em&gt;all&lt;/em&gt; differences between the local version and the remote version. With a single change (replacing &lt;code&gt;pass&lt;/code&gt; with &lt;code&gt;return&lt;/code&gt;) in README.md to use a better word, here's an example of what output would look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;$ npm diff
&lt;span class="gh"&gt;diff --git a/README.md b/README.md
index v1.1.0..v1.1.0 100644
&lt;/span&gt;&lt;span class="gd"&gt;--- a/README.md
&lt;/span&gt;&lt;span class="gi"&gt;+++ b/README.md
&lt;/span&gt;&lt;span class="p"&gt;@@ -10,7 +10,7 @@&lt;/span&gt;
&lt;span class="err"&gt;
&lt;/span&gt; ## Usage
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gd"&gt;-temporalts can pass all Node.js LTS release line temporal information, or the temporal information for a _specific_ release line.
&lt;/span&gt;&lt;span class="gi"&gt;+temporalts can return all Node.js LTS release line temporal information, or the temporal information for a _specific_ release line.
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt; ### `temporalts()`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Diffing Individual Local File(s) with the Latest Remote Version
&lt;/h2&gt;

&lt;p&gt;If you've made more than a single tiny change to your module, diffing a single file from the local version with the remote version.&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="c"&gt;# the general structure&lt;/span&gt;
npm diff &lt;span class="o"&gt;[&lt;/span&gt;...paths]

&lt;span class="c"&gt;# specific examples&lt;/span&gt;
npm diff README.md
npm diff /lib/handler.js
npm diff SECURITY.md /public/index.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of getting a diff for all files, you'll only get diffs for any paths you passed. If you passed a single path, you'll get a single diff; if you passed multiple, you'll get multiple.&lt;/p&gt;

&lt;p&gt;This functionality can be &lt;em&gt;particularly&lt;/em&gt; useful in a handful of cases: generating changelogs, checking how something works in the currently published version, or even as a prepublish check to make sure you're only shipping changes you intended to ship.&lt;/p&gt;

&lt;h2&gt;
  
  
  Diffing Local Version with a Specific Remote Version
&lt;/h2&gt;

&lt;p&gt;Similar to Diffing the Local Version with the Latest Remote Version, you can diff your local version of a module with the remote version, but with any specific version.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm diff &lt;span class="nt"&gt;--diff&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;version&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As an example, here's an excerpt from running &lt;code&gt;npm diff --diff=1.0.1&lt;/code&gt; on &lt;a href="https://npm.im/temporalts"&gt;temporalts@1.1.0&lt;/a&gt;. There's a single version between these two - v1.0.1 was &lt;em&gt;also&lt;/em&gt; published, and we're able to compare what we &lt;em&gt;currently&lt;/em&gt; have with a &lt;em&gt;previous&lt;/em&gt; version that's not &lt;code&gt;@latest&lt;/code&gt;. There's a few uses for this, like checking what's changed in a module while upgrading, changelog authoring, or pre-publish change validation (especially if you're using &lt;code&gt;files&lt;/code&gt; in package.json to limit which files you're publishing).&lt;/p&gt;

&lt;p&gt;We can also diff &lt;em&gt;forward&lt;/em&gt; - for example, if I were to publish &lt;code&gt;temporalts@2.0.0&lt;/code&gt;, I'd be able to diff between v1.1.0 and v2.0.0. This is useful, particularly if you're looking forward for upgrades or at pre-release versions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;$ npm diff --diff==1.0.0                                                                                
&lt;span class="gh"&gt;diff --git a/examples/12.js b/examples/12.js
&lt;/span&gt;&lt;span class="p"&gt;deleted file mode 100644
&lt;/span&gt;&lt;span class="gh"&gt;index v1.0.0..v1.1.0 
&lt;/span&gt;&lt;span class="gd"&gt;--- a/examples/12.js
&lt;/span&gt;&lt;span class="gi"&gt;+++ b/examples/12.js
&lt;/span&gt;&lt;span class="p"&gt;@@ -1,12 +0,0 @@&lt;/span&gt;
&lt;span class="gd"&gt;-const temporalts = require('../')
-
-async function prettyPrint () {
-  const version = 'v12'
-  const data = await temporalts(version)
-
-  console.log()
-  console.log(`We are ${data.currentPercentOfLTSLifeSpanWithoutDecimal}% through the lifespan of the Node.js ${version} LTS release line.\n${data.currentPercentOfLTSLifeSpanAsProgressBar} `)
-  console.log()
-}
-
-prettyPrint()
&lt;/span&gt;\ No newline at end of file
&lt;span class="gh"&gt;diff --git a/helpers/fetchSchedule.js b/helpers/fetchSchedule.js
index v1.0.0..v1.1.0 100644
&lt;/span&gt;&lt;span class="gd"&gt;--- a/helpers/fetchSchedule.js
&lt;/span&gt;&lt;span class="gi"&gt;+++ b/helpers/fetchSchedule.js
&lt;/span&gt;&lt;span class="p"&gt;@@ -12,4 +12,4 @@&lt;/span&gt;
   }
 }
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gd"&gt;-module.exports = fetchSchedule
&lt;/span&gt;&lt;span class="gi"&gt;+module.exports.fetchSchedule = fetchSchedule
&lt;/span&gt;&lt;span class="gh"&gt;diff --git a/index.js b/index.js
index v1.0.0..v1.1.0 100644
&lt;/span&gt;&lt;span class="gd"&gt;--- a/index.js
&lt;/span&gt;&lt;span class="gi"&gt;+++ b/index.js
&lt;/span&gt;&lt;span class="p"&gt;@@ -1,3 +1,3 @@&lt;/span&gt;
&lt;span class="gd"&gt;-const lts = require('exports/lts.js')
&lt;/span&gt;&lt;span class="gi"&gt;+const lts = require('./exports/lts.js')
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;[... more file diffs, dropped for length]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Diffing Individual Local File(s) with a Specific Remote Version
&lt;/h2&gt;

&lt;p&gt;As an extension of &lt;a href=""&gt;Diffing Local Version with a Specific Remote Version&lt;/a&gt;, you can also pass in a single file to diff.&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="c"&gt;# the general structure&lt;/span&gt;
npm diff &lt;span class="nt"&gt;--diff&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;version&amp;gt; &lt;span class="o"&gt;[&lt;/span&gt;...paths]

&lt;span class="c"&gt;# specific examples&lt;/span&gt;
npm diff &lt;span class="nt"&gt;--diff&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;version&amp;gt; README.md
npm diff &lt;span class="nt"&gt;--diff&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;version&amp;gt; /lib/handler.js
npm diff &lt;span class="nt"&gt;--diff&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;version&amp;gt; SECURITY.md /public/index.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As an example, if we diff &lt;code&gt;index.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;$ npm diff --diff==1.0.0 index.js
&lt;span class="gh"&gt;diff --git a/index.js b/index.js
index v1.0.0..v1.1.0 100644
&lt;/span&gt;&lt;span class="gd"&gt;--- a/index.js
&lt;/span&gt;&lt;span class="gi"&gt;+++ b/index.js
&lt;/span&gt;&lt;span class="p"&gt;@@ -1,3 +1,3 @@&lt;/span&gt;
&lt;span class="gd"&gt;-const lts = require('exports/lts.js')
&lt;/span&gt;&lt;span class="gi"&gt;+const lts = require('./exports/lts.js')
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt; module.exports = lts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Diffing Two Remote Versions
&lt;/h2&gt;

&lt;p&gt;There is also a very valid reason you may want to diff two versions of the same module you've got that aren't locally stored. &lt;code&gt;npm diff&lt;/code&gt; allows you to do this with package identifiers (a.k.a. &lt;code&gt;pkg-identifier&lt;/code&gt;) which is something along the lines of &lt;code&gt;package@semver-range&lt;/code&gt; - so, for example, &lt;code&gt;node@12.10.0&lt;/code&gt;, &lt;code&gt;fastify@latest&lt;/code&gt;, &lt;code&gt;babel@7.0.0-rc.1&lt;/code&gt;, and &lt;code&gt;npm@7&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;&lt;span class="c"&gt;# the general structure&lt;/span&gt;
npm diff &lt;span class="nt"&gt;--diff&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;pkg-identifier&amp;gt; &lt;span class="nt"&gt;--diff&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;pkg-identifier&amp;gt;

&lt;span class="c"&gt;# specific example&lt;/span&gt;
npm diff &lt;span class="nt"&gt;--diff&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;gatsby@2.32.3 &lt;span class="nt"&gt;--diff&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;gatsby@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we try to run the latter command - comparing a slightly older version of Gatsby to the latest version - we'll get about 19mb of diff output at time of publishing (the latest version of Gatsby is presently &lt;code&gt;gatsby@3.2.0&lt;/code&gt; if you'd like to try to reproduce this output exactly). Unfortunately, that's far too much to include in a blog post, but you should try running it yourself.&lt;/p&gt;

&lt;p&gt;As with any actively developed module - or any sufficiently modified module from one package identifier to another - this diff will only get bigger as the maintainers published newer and newer versions, making more changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Diffing Individual Files from Two Remote Versions
&lt;/h2&gt;

&lt;p&gt;As with previous &lt;code&gt;npm diff&lt;/code&gt; commands, you can pass in individual files or paths to filter your diff's output and you'll get just a diff for that file or path.&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="c"&gt;# the general structure&lt;/span&gt;
npm diff &lt;span class="nt"&gt;--diff&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;pkg-identifier&amp;gt; &lt;span class="nt"&gt;--diff&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;pkg-identifier&amp;gt;

&lt;span class="c"&gt;# specific examples&lt;/span&gt;
npm diff &lt;span class="nt"&gt;--diff&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;fastify@3.13.0 &lt;span class="nt"&gt;--diff&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;fastify@latest package.json
npm diff &lt;span class="nt"&gt;--diff&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;fastify@3.13.0 &lt;span class="nt"&gt;--diff&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;fastify@latest /lib/errors.js
npm diff &lt;span class="nt"&gt;--diff&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;fastify@3.13.0 &lt;span class="nt"&gt;--diff&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;fastify@latest README.md /lib/context.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's what the output for the first command there looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;$ npm diff --diff=fastify@3.13.0 --diff=fastify@latest package.json
&lt;span class="gh"&gt;diff --git a/package.json b/package.json
index v3.13.0..v3.14.1 100644
&lt;/span&gt;&lt;span class="gd"&gt;--- a/package.json
&lt;/span&gt;&lt;span class="gi"&gt;+++ b/package.json
&lt;/span&gt;&lt;span class="p"&gt;@@ -1,6 +1,6 @@&lt;/span&gt;
 {
   "name": "fastify",
&lt;span class="gd"&gt;-  "version": "3.13.0",
&lt;/span&gt;&lt;span class="gi"&gt;+  "version": "3.14.1",
&lt;/span&gt;   "description": "Fast and low overhead web framework, for Node.js",
   "main": "fastify.js",
   "type": "commonjs",
&lt;span class="p"&gt;@@ -177,7 +177,7 @@&lt;/span&gt;
     "abstract-logging": "^2.0.0",
     "ajv": "^6.12.2",
     "avvio": "^7.1.2",
&lt;span class="gd"&gt;-    "fast-json-stringify": "^2.2.1",
&lt;/span&gt;&lt;span class="gi"&gt;+    "fast-json-stringify": "^2.5.2",
&lt;/span&gt;     "fastify-error": "^0.3.0",
     "fastify-warning": "^0.2.0",
     "find-my-way": "^4.0.0",
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Useful Flags
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;npm diff&lt;/code&gt; command also provides some helpful flags to limit the diff output to only &lt;em&gt;relevant&lt;/em&gt; changes, depending on your goal.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;--diff-ignore-all-space&lt;/code&gt;: Ignores all changes that are exclusively space. Extremely useful for limiting changes to only what matters, especially after linter runs.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--diff-name-only&lt;/code&gt;: Limits outputs to &lt;em&gt;only&lt;/em&gt; filenames of files with changes for the command. Extremely useful for getting an overview of what's changed and figuring out which files to drill down into.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>node</category>
    </item>
    <item>
      <title>Markdown Link Checking in GitHub with Actions</title>
      <dc:creator>Tierney Cyren</dc:creator>
      <pubDate>Fri, 05 Mar 2021 21:59:59 +0000</pubDate>
      <link>https://dev.to/bnb/markdown-link-checking-in-github-with-actions-5dp0</link>
      <guid>https://dev.to/bnb/markdown-link-checking-in-github-with-actions-5dp0</guid>
      <description>&lt;p&gt;Having been a part of the Node.js project since the io.js 1.0 announcement, one of the things I've grown extremely familiar with is how untouched Markdown documents that are supposed to provide a foundation can rot over time.&lt;/p&gt;

&lt;p&gt;More specifically, a project on GitHub can slightly tweak how it operates every now and then. Those changes might not be enough to justify a documentation change since they're not meaningfully different enough.&lt;/p&gt;

&lt;p&gt;If enough of these pile up you can end up with some blind spots on how your foundational documents haven't kept up with the times. This can often be remedied by manual inspection, but even then there's things that you might miss.&lt;/p&gt;

&lt;p&gt;One of those things I've often missed when doing that manual inspection is broken links. Specifically, if a file is moved at some point but all references to it aren't updated you end up in a situation where those references point to a 404.&lt;/p&gt;

&lt;p&gt;I've also had a handful of experiences with external links to smaller sites die because they decided to completely redesign the site and its structure... and if we're honest, I've only noticed those when I've really tried to find things that are broken. I'm &lt;strong&gt;sure&lt;/strong&gt; others who are less familiar with that documentation have hit them more often.&lt;/p&gt;

&lt;p&gt;Various forms of link rot like this are something that I've struggled to fight with different tooling for years. Now, thankfully, I've found the exact setup I've always wanted.&lt;/p&gt;

&lt;h2&gt;
  
  
  Linkinator and GitHub Actions
&lt;/h2&gt;

&lt;p&gt;A friend, &lt;a href="https://twitter.com/justinbeckwith"&gt;Justin Beckwith&lt;/a&gt;, published a tool that serves both as a CLI and a module called &lt;a href="https://github.com/JustinBeckwith/linkinator"&gt;Linkinator&lt;/a&gt; some time ago that focused on finding broken links within HTML sites. He extended it to work with Markdown &lt;a href="https://github.com/JustinBeckwith/linkinator/issues/73#issuecomment-737661545"&gt;relatively recently&lt;/a&gt; as well.&lt;/p&gt;

&lt;p&gt;He &lt;em&gt;also&lt;/em&gt; published a &lt;a href="https://github.com/JustinBeckwith/linkinator-action"&gt;Linkinator GitHub Action&lt;/a&gt; that consumes Linkinator as a module and uses that to cleanly integrate with GitHub repositories.&lt;/p&gt;

&lt;p&gt;Even more recently, he added &lt;a href="https://github.com/JustinBeckwith/linkinator-action/pull/45"&gt;the &lt;code&gt;retry&lt;/code&gt; functionality&lt;/a&gt; from the module to the Action.&lt;/p&gt;

&lt;p&gt;With &lt;code&gt;retry&lt;/code&gt; and the foundation of the rest of the work Justin's put into Linkinator, my problems with Markdown link rot in GitHub have now been entirely solved.&lt;/p&gt;

&lt;p&gt;Let's get into how.&lt;/p&gt;

&lt;h2&gt;
  
  
  Markdown Link Rot Begone: Using the Action
&lt;/h2&gt;

&lt;p&gt;The first space I've set up Linkinator is in the Node.js Community Committee repo via &lt;a href="https://github.com/nodejs/community-committee/pull/658"&gt;#658&lt;/a&gt;. Specifically, this PR adds the Linkinator GitHub Action and fixes all (but one, which has been fixed in a different unmerged PR) broken links in the repository. As it turns out, there were quite a few... including some in very notable places, like the README.&lt;/p&gt;

&lt;p&gt;The setup is pretty standard for a single purpose GitHub Action. There's some pretty decent documentation of the expected YAML on &lt;a href="https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions"&gt;GitHub's Docs site&lt;/a&gt;. I'll walk through each line with you:&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up Triggers
&lt;/h3&gt;

&lt;p&gt;To start, we set up &lt;a href="https://docs.github.com/en/actions/reference/events-that-trigger-workflows"&gt;the triggers&lt;/a&gt; for the Action. The first line will always be &lt;code&gt;on:&lt;/code&gt; but from there you can do a lot.&lt;/p&gt;

&lt;p&gt;In this specific case, I've set it up to run on push to the default branch (thanks to the handy &lt;code&gt;$default-branch&lt;/code&gt; macro, it doesn't matter what the name is!), on PRs (this could be more verbose to run less often), and on &lt;code&gt;workflow_dispatch&lt;/code&gt; which allows us to run it manually via the GitHub Actions UI if we want to.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;$default-branch&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Name
&lt;/h3&gt;

&lt;p&gt;Next, we have the name which is what will appear in the GitHub UI. In this case, I just went with &lt;code&gt;Linkinator CI&lt;/code&gt; but you can change this to whatever you'd like.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Linkinator CI&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Job
&lt;/h3&gt;

&lt;p&gt;The beginning of the jobs section is, again, relatively standard. We include the &lt;code&gt;jobs&lt;/code&gt; property under which we start defining the work that'll be done.&lt;/p&gt;

&lt;p&gt;In this case, we name the (only!) step &lt;code&gt;linkinator&lt;/code&gt; since I like to try to keep to as small yet as descriptive of a job name as is possible.&lt;/p&gt;

&lt;p&gt;Then, we tell Actions to run this on &lt;code&gt;ubuntu-latest&lt;/code&gt; and add the property &lt;code&gt;steps&lt;/code&gt; to start defining what we're going to do in the job.&lt;/p&gt;

&lt;p&gt;From there, we then we declare that we want to use the &lt;a href="https://github.com/actions/checkout"&gt;actions/checkout&lt;/a&gt; action which by default checks out the repo this is running in and sets things up nicely for us.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;linkinator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we're going to actually include the &lt;code&gt;linkinator&lt;/code&gt; step. We call the Linkinator action from Justin's repo directly. We also pass a few of &lt;a href="https://github.com/JustinBeckwith/linkinator-action#inputs"&gt;Linkinator's inputs&lt;/a&gt; via the &lt;code&gt;with&lt;/code&gt; property:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;paths&lt;/code&gt;: we're specifically checking for all markdown files in the project, recursively with &lt;a href="https://en.wikipedia.org/wiki/Glob_(programming)"&gt;globbing&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;markdown: asserting to Linkinator that we're specifically looking for markdown files (as opposed to HTML files).&lt;/li&gt;
&lt;li&gt;retry: for GitHub repos that have links to GitHub this is super important - if we get timed out because of a rate limit, the Action will respectfully retry until they get a non-rate-limited response.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;JustinBeckwith/linkinator-action@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*.md"&lt;/span&gt;
          &lt;span class="na"&gt;markdown&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
          &lt;span class="na"&gt;retry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Whole Configuration
&lt;/h3&gt;

&lt;p&gt;Putting all of that together, we get the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;$default-branch&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Linkinator CI&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;linkinator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;JustinBeckwith/linkinator-action@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*.md"&lt;/span&gt;
          &lt;span class="na"&gt;markdown&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
          &lt;span class="na"&gt;retry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By popping this as a new file into &lt;code&gt;./github/workflows/&lt;/code&gt; (say, &lt;code&gt;./github/workflows/linkinator.yml&lt;/code&gt;) and pushing it to your repo, you'll start getting link checks on every push and PR plus whenever you want to manually run it.&lt;/p&gt;

&lt;p&gt;Genuinely happy with this solution and I hope it helps someone else as much as it's (going to be) helping me ❤️&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>opensource</category>
      <category>github</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Securely Automating npm publish with the New npm Automation Tokens</title>
      <dc:creator>Tierney Cyren</dc:creator>
      <pubDate>Fri, 02 Oct 2020 18:06:22 +0000</pubDate>
      <link>https://dev.to/bnb/securely-automating-npm-publish-with-the-new-npm-automation-tokens-oei</link>
      <guid>https://dev.to/bnb/securely-automating-npm-publish-with-the-new-npm-automation-tokens-oei</guid>
      <description>&lt;p&gt;Today, npm has now shipped automation tokens 🎉&lt;/p&gt;

&lt;p&gt;Previously, if you wanted to automatically publish an npm module from CI/CD you had a choice - have 2FA turned off and allow publishing via a token &lt;strong&gt;or&lt;/strong&gt; have 2FA turned on and build a custom tool to allow you to input a 2FA code when your CI/CD is trying to publish.&lt;/p&gt;

&lt;p&gt;This was a challenging system since it made users choose between smooth DX or security. This has been impactful historically - there have been cases (for example, the &lt;a href="https://eslint.org/blog/2018/07/postmortem-for-malicious-package-publishes"&gt;eslint-scope incident&lt;/a&gt;) where maintainers' accounts were hijacked and impactful modules were compromised since they didn't have 2FA for user publishes turned on.&lt;/p&gt;

&lt;p&gt;Since 2FA on publish was introduced, folks in the ecosystem have been asking for the ability to have some way to automatically publish modules from CI while also having 2FA for user-publishes turned on.&lt;/p&gt;

&lt;p&gt;Today, the npm team delivered one of the proposed solutions: automation tokens.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are Automation Tokens?
&lt;/h2&gt;

&lt;p&gt;Automation tokens are effectively publish tokens that a user can create to publish a module from an automated process. They skip the OTP (one-time password) check and ship it.&lt;/p&gt;

&lt;p&gt;Say, for example, that you're the maintainer of a module called &lt;code&gt;good-first-issue&lt;/code&gt;. Instead of having to pull &lt;code&gt;good-first-issue&lt;/code&gt; locally and publish after opening up your 2FA app and typing in the OTP, you could instead set up your favorite CI - GitHub Actions CI, CircleCI, Travis, or whatever else - to automatically publish whenever certain conditions are met. &lt;a href="https://semantic-release.gitbook.io/semantic-release/"&gt;Semantic Release&lt;/a&gt; is a pretty wonderful example of this kind of automation.&lt;/p&gt;

&lt;p&gt;This has the obvious benefit of streamlining workflows and reducing maintainer burden. It also helps reduce risk - in pulling down and publishing or having to build a custom publishing system both have their own additional levels of potential risk. With automation tokens, we can now pretty easily just ship code where we build it.&lt;/p&gt;

&lt;h2&gt;
  
  
  How can I Use Automation Tokens?
&lt;/h2&gt;

&lt;p&gt;To publish with Automation Tokens today, you'll want to do a few things to get going.&lt;/p&gt;

&lt;p&gt;First, to actually publish to a module with an automation token, you'll need to update the module's &lt;code&gt;Settings&lt;/code&gt;. Specifically, you'll need to change the module's &lt;code&gt;Publishing Access&lt;/code&gt; from whatever it was previously (either &lt;code&gt;Two-factor authentication is not required&lt;/code&gt; or &lt;code&gt;Require two-factor authentication to publish&lt;/code&gt;) to the new option, &lt;code&gt;Require two-factor authentication or automation tokens&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fiz61wxyav8obn4yvfyuj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fiz61wxyav8obn4yvfyuj.png" alt="Screenshot of npm's access page, showing off the new option" width="800" height="610"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you've updated that, you'll now be able to use Automation Tokens for publishing that module.&lt;/p&gt;

&lt;p&gt;To get an automation token, you'll want to head over to your user settings. From that, you'll open up the Access Tokens page and then create a new token. When you start the token creation flow, you'll have the option to select &lt;code&gt;Automation&lt;/code&gt;. Once you do, click &lt;code&gt;Generate Token&lt;/code&gt; and you'll be shown the token once - copy it, and you're all set.&lt;/p&gt;

&lt;h2&gt;
  
  
  Looking Forward
&lt;/h2&gt;

&lt;p&gt;There are a handful of use cases where this current implementation is extremely useful - specifically, my perspective is that it's most useful where you're an individual maintainer with a limited set of projects.&lt;/p&gt;

&lt;p&gt;That said, this is the first step in the right direction for more granular controls for all kinds of maintainers to securely manage their modules with a good DX while being as secure as possible. In speaking with the npm team, they're exploring further iteration in this space that I'm super excited for.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>node</category>
    </item>
    <item>
      <title>Jest and the `--changedSince` flag in GitHub Actions CI</title>
      <dc:creator>Tierney Cyren</dc:creator>
      <pubDate>Thu, 09 Apr 2020 22:33:13 +0000</pubDate>
      <link>https://dev.to/bnb/jest-and-the-changedsince-flag-in-github-actions-ci-468i</link>
      <guid>https://dev.to/bnb/jest-and-the-changedsince-flag-in-github-actions-ci-468i</guid>
      <description>&lt;p&gt;Recently, I've been working a lot more with GitHub Actions - both writing actions and creating CI pipelines for projects.&lt;/p&gt;

&lt;p&gt;Last week I picked up a project I started a bit ago: the &lt;a href="https://github.com/nodejs/examples"&gt;nodejs/examples&lt;/a&gt; repository.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The examples repository is still in its early stages. As such, there's still a bunch of WIP work we're doing - we've intentionally not talked a bunch publicly about it yet. That said, if you're interested in helping, feel free to reach out to me on &lt;a href="https://twitter.com/bitandbang"&gt;Twitter&lt;/a&gt; or the &lt;a href="http://slack.openjsf.org"&gt;OpenJS Slack&lt;/a&gt; ❤️&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The goal of this repository is to be home to a bunch of distinct and well-tested examples of real-world Node.js that go beyond "hello, world!". This means there's hopefully going to be a boatload of distinct projects in there.&lt;/p&gt;

&lt;p&gt;This structure presents a challenge when trying to be straightforward for new contributions; specifically, it's a barrier to run a full test suite for many projects when someone submitting a PR only needs to see the results of the one they've worked on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Jest's Solutions
&lt;/h2&gt;

&lt;p&gt;Jest has a super handy &lt;a href="https://jestjs.io/docs/en/cli.html#--onlychanged"&gt;&lt;code&gt;--onlyChanged&lt;/code&gt;&lt;/a&gt; feature that only tells you what has changed in the current repository. This is super duper handy, but the functionality is slightly unclear in one way: does it diff with master or just with the previous commit? It does indeed seem to be the latter (though I could totally be wrong!), which is not particularly helpful in the case of PRs with multiple commits.&lt;/p&gt;

&lt;p&gt;As such, I looked through the flags that Jest exposes and found the &lt;a href="https://jestjs.io/docs/en/cli.html#--changedsince"&gt;&lt;code&gt;--changedSince&lt;/code&gt;&lt;/a&gt; flag which compares the current work with a different branch. Since - in the case of nodejs/examples - master will always be a source of truth, this is perfect for the use case of potentially having multiple commits while still wanting to run only the tests relevant to a proposed change.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;--changedSince&lt;/code&gt; and GitHub Actions CI
&lt;/h2&gt;

&lt;p&gt;Previously, the &lt;code&gt;--onlyChanged&lt;/code&gt; flag worked flawlessly with GitHub Actions CI. When trying to simply change from &lt;code&gt;--onlyChanged&lt;/code&gt; to &lt;code&gt;--changedSince&lt;/code&gt;, the CI build immediately nuked itself with 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;  ● Test suite failed to run

    fatal: bad revision &lt;span class="s1"&gt;'^master'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This was bizarre to me since the test was working completely fine on my machine (shocker, I know). Upon investigating, this is a &lt;code&gt;git&lt;/code&gt; error and not a Jest error - Jest is merely acting as a courier for that error.&lt;/p&gt;

&lt;p&gt;It turns out that the &lt;code&gt;actions/checkout&lt;/code&gt; GitHub Action does not checkout your full repository, but only the code relevant to the PR. As such, &lt;code&gt;master&lt;/code&gt; as a branch did not exist. Further, my specific use case of wanting to have &lt;code&gt;master&lt;/code&gt; in the run but have the PR branch checked out is not particularly well supported by &lt;code&gt;actions/checkout&lt;/code&gt; at present since it is somewhat of an edge case (though I did &lt;a href="https://github.com/actions/checkout/issues/214"&gt;open an issue&lt;/a&gt; to request it).&lt;/p&gt;

&lt;p&gt;While the examples are helpful, they don't solve my somewhat complex but not over the top use case. Layer on that I'm not super excellent with git, and you have a challenging mixture. &lt;/p&gt;

&lt;p&gt;I reached out to &lt;a href="https://twitter.com/codebytere/"&gt;Shelley Vohr&lt;/a&gt;, who's extremely talented with git (amongst many other things) and explained what I was facing. She suggested that I'd need to go one step beyond what the &lt;code&gt;actions/checkout&lt;/code&gt; repo recommended:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git fetch &lt;span class="nt"&gt;--no-tags&lt;/span&gt; &lt;span class="nt"&gt;--prune&lt;/span&gt; &lt;span class="nt"&gt;--depth&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 origin +refs/heads/&lt;span class="k"&gt;*&lt;/span&gt;:refs/remotes/origin/&lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="c"&gt;# fetches all branches&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;... and needed to checkout &lt;code&gt;master&lt;/code&gt; with 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;git checkout &lt;span class="nt"&gt;-b&lt;/span&gt; master &lt;span class="c"&gt;# -b creates and checks out a new branch&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;... and then switch back to the PR branch. Luckily, GitHub provides that data in the YAML config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ github.event.pull_request.head.sha &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="c"&gt;# checks out the SHA of the HEAD from the PR&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This was all able to be combined as a part of a &lt;code&gt;run&lt;/code&gt; property in the YAML for the step, which runs whatever commands are passed to it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;git fetch --no-tags --prune --depth=1 origin +refs/heads/*:refs/remotes/origin/* # fetches all branches&lt;/span&gt;
        &lt;span class="s"&gt;git checkout -b master # -b creates and checks out a new branch&lt;/span&gt;
        &lt;span class="s"&gt;git checkout ${{ github.event.pull_request.head.sha }} # checks out the SHA of the HEAD from the PR&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, that's a rather bulky git fetch that can potentially artificially increase the build times as more branches are added to the repo. As such, I figured I should try to cut it down to just what I needed. After a bit of searching around, I found the &lt;code&gt;git fetch &amp;lt;remote&amp;gt; &amp;lt;branch&amp;gt;&lt;/code&gt; structure. Since I know I'll always want to use master, this was a pretty easy change (while also ditching &lt;code&gt;--prune&lt;/code&gt; since it seems potentially useless in this case):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;git fetch --no-tags --depth=1 origin master&lt;/span&gt;
        &lt;span class="s"&gt;git checkout -b master&lt;/span&gt;
        &lt;span class="s"&gt;git checkout ${{ github.event.pull_request.head.sha }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In addition to all this YAML CI config, I also included a new npm script called &lt;code&gt;test:changedsince&lt;/code&gt; which is a handy shortcut for the Jest command I want to run:&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="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;"test"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"jest --coverage"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"test:changedsince"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"jest --changedSince=master --coverage"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"lint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"standard"&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;This new npm script took the place of the previous &lt;code&gt;test:onlychanged&lt;/code&gt; npm script in my final GitHub Actions CI YAML config, seen below. &lt;strong&gt;Note&lt;/strong&gt;: if you copy-paste this config into your own CI, you'll need ensure that you have &lt;code&gt;jest&lt;/code&gt; as a &lt;code&gt;devDependency&lt;/code&gt; so it's installed on your CI build.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tests(push) - install, lint, test:changedsince&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ matrix.os }}&lt;/span&gt;
    &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;matrix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;os&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;ubuntu-latest&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;windows-latest&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;macOS-latest&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
        &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;10.x&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;12.x&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;git fetch --no-tags --depth=1 origin master&lt;/span&gt;
        &lt;span class="s"&gt;git checkout -b master&lt;/span&gt;
        &lt;span class="s"&gt;git checkout ${{ github.event.pull_request.head.sha }}&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Use Node.js ${{ matrix.node-version }} on ${{ matrix.os }}&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v1&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ matrix.node-version }}&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm install&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm install&lt;/span&gt;
      &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;CI&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; 
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run test:changedsince&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jest --changedSince=master --coverage&lt;/span&gt;
      &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;CI&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, this seems to be working perfectly - it'll diff changes between the current PR's &lt;code&gt;HEAD&lt;/code&gt; and &lt;code&gt;master&lt;/code&gt;, running only the tests that are different across &lt;em&gt;all&lt;/em&gt; commits and not just between the most recent commit and the one prior.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>beginners</category>
      <category>tutorial</category>
      <category>node</category>
    </item>
    <item>
      <title>An Unintentionally Comprehensive Introduction to GitHub Actions CI</title>
      <dc:creator>Tierney Cyren</dc:creator>
      <pubDate>Mon, 30 Sep 2019 16:59:04 +0000</pubDate>
      <link>https://dev.to/bnb/an-unintentionally-comprehensive-introduction-to-github-actions-ci-blm</link>
      <guid>https://dev.to/bnb/an-unintentionally-comprehensive-introduction-to-github-actions-ci-blm</guid>
      <description>&lt;p&gt;We're currently approaching GitHub Actions v2 shipping publicly for &lt;em&gt;everyone&lt;/em&gt; to use. I'm personally super excited about this because it means I don't need to configure an external service to run my CI – I can slap in some YAML, and I'm off with a cross-platform (!) CI system with multiple versions of Node.js installed.&lt;/p&gt;

&lt;p&gt;For me, that's bliss. No need to go to an external site; everything is very neatly contained. That said, when I've used other CI services in the past (primarily Travis CI and Azure Pipelines) I've generally just copy/pasted someone else's CI configuration from the beginning and then tweaked it with additional context.&lt;/p&gt;

&lt;p&gt;This time though, there's minimal prior context. During the beta of Actions v2, GitHub has published a few different CI templates that I could copy/paste certain parts from. However, there are a few standards I hold all of my projects to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;npm install&lt;/code&gt; should pass on the latest versions of all operating systems&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;npm test&lt;/code&gt; should pass on the latest versions of all operating systems&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;npm install&lt;/code&gt; and &lt;code&gt;npm test&lt;/code&gt; should succeed without fail on all &lt;a href="https://github.com/nodejs/release#release-schedule"&gt;currently supported&lt;/a&gt; Node.js versions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This ends up meaning I have a matrix of anywhere from 9 (3 versions multiplied by three operating systems) to 12 (4 versions multiplied by three operating systems) CI runs on every project at any time. I've found that the implementation of &lt;em&gt;how&lt;/em&gt; to achieve this varies greatly depending on the CI system.&lt;/p&gt;

&lt;p&gt;Given that there's not going to be a massive amount of prior art on release, I figured I'd begin building out some comprehensive templates so at launch people will have something to easily copy/paste and then tweak to suit their exact needs.&lt;/p&gt;

&lt;h1&gt;
  
  
  GitHub Actions CI Templates
&lt;/h1&gt;

&lt;p&gt;After working on adding GitHub Actions CI to &lt;a href="https://github.com/cutenode/good-first-issue"&gt;good-first-issue&lt;/a&gt;, I figured I should probably abstract the CI file into a repo, so it's a bit more accessible.&lt;/p&gt;

&lt;p&gt;As such, last night, I built out &lt;a href="https://github.com/cutenode/github-actions-ci-templates"&gt;GitHub Actions CI Templates&lt;/a&gt;. Initially, I shipped it with a single template that covered my needs around Node.js and npm, but as of about an hour ago I've added two additional templates: Node.js and Yarn, and Node.js and pnpm.&lt;/p&gt;

&lt;p&gt;If you'd like to check out the templates, they're all relatively straightforward as far as YAML goes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/cutenode/github-actions-ci-templates/blob/master/templates/javascript/nodejs-cross-platform-ci.yml"&gt;Node.js Cross-Platform&lt;/a&gt;:

&lt;ul&gt;
&lt;li&gt;Runs builds on:&lt;/li&gt;
&lt;li&gt;Ubuntu (Latest),&lt;/li&gt;
&lt;li&gt;Windows (Latest),&lt;/li&gt;
&lt;li&gt;macOS (Latest)&lt;/li&gt;
&lt;li&gt;Using all versions of Node.js that are &lt;a href="https://github.com/nodejs/release#release-schedule"&gt;currently supported&lt;/a&gt; by the Node.js project,&lt;/li&gt;
&lt;li&gt;Using &lt;code&gt;npm install&lt;/code&gt; and &lt;code&gt;npm test&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/cutenode/github-actions-ci-templates/blob/master/templates/javascript/yarn-nodejs-cross-platform-ci.yml"&gt;Node.js Cross-Platform (using Yarn)&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;Runs builds on:&lt;/li&gt;
&lt;li&gt;Ubuntu (Latest),&lt;/li&gt;
&lt;li&gt;Windows (Latest),&lt;/li&gt;
&lt;li&gt;macOS (Latest)&lt;/li&gt;
&lt;li&gt;Using all versions of Node.js that are &lt;a href="https://github.com/nodejs/release#release-schedule"&gt;currently supported&lt;/a&gt; by the Node.js project,&lt;/li&gt;
&lt;li&gt;Using &lt;code&gt;yarn install&lt;/code&gt; and &lt;code&gt;yarn test&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/cutenode/github-actions-ci-templates/blob/master/templates/javascript/pnpm-nodejs-cross-platform-ci.yml"&gt;Node.js Cross-Platform (using pnpm)&lt;/a&gt;:

&lt;ul&gt;
&lt;li&gt;Runs builds on:&lt;/li&gt;
&lt;li&gt;Ubuntu (Latest),&lt;/li&gt;
&lt;li&gt;Windows (Latest),&lt;/li&gt;
&lt;li&gt;macOS (Latest)&lt;/li&gt;
&lt;li&gt;Using all versions of Node.js that are &lt;a href="https://github.com/nodejs/release#release-schedule"&gt;currently supported&lt;/a&gt; by the Node.js project.&lt;/li&gt;
&lt;li&gt;Using &lt;code&gt;pnpm install&lt;/code&gt; and &lt;code&gt;pnpm test&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Dissecting the GitHub Actions YAML for the Templates
&lt;/h2&gt;

&lt;p&gt;The templates all follow a relatively similar structure. I figured I'd walk you through each line of code of the &lt;a href="https://github.com/cutenode/github-actions-ci-templates/blob/master/templates/javascript/nodejs-cross-platform-ci.yml"&gt;Node.js Cross-Platform&lt;/a&gt; file to help ensure that they're understandable to you. Let's go line by line, with code on the top and the description on the bottom:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Node.js Cross-platform CI (using Yarn)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above line is the title of the entire CI script, as it'll show up in the &lt;code&gt;Actions&lt;/code&gt; tab of the GitHub repo.&lt;/p&gt;

&lt;p&gt;Relevant docs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://help.github.com/en/articles/workflow-syntax-for-github-actions#name"&gt;Workflow syntax docs - &lt;code&gt;name&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above line indicates the trigger for a run. For most CI cases, &lt;code&gt;[push]&lt;/code&gt; will be ideal since you want it to run every time you push code to the repo or to a PR.&lt;/p&gt;

&lt;p&gt;Relevant docs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://help.github.com/en/articles/workflow-syntax-for-github-actions#on"&gt;Workflow syntax docs - &lt;code&gt;on&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://help.github.com/en/articles/events-that-trigger-workflows"&gt;Workflow trigger docs&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Workflows are composed of one or more jobs. This line is an indicator that we've got multiple jobs to be run.&lt;/p&gt;

&lt;p&gt;Relevant docs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://help.github.com/en/articles/workflow-syntax-for-github-actions#jobs"&gt;Workflow syntax docs - &lt;code&gt;jobs&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://help.github.com/en/articles/workflow-syntax-for-github-actions#usage-limits"&gt;Usage limits&lt;/a&gt;, for context on limits around jobs
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This one is the &lt;code&gt;job_id&lt;/code&gt; of our specific job. Since we're running a build, I named this &lt;code&gt;build&lt;/code&gt; but this specific name has no semantic meaning inside of GitHub Actions CI itself.&lt;/p&gt;

&lt;p&gt;Relevant docs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://help.github.com/en/articles/workflow-syntax-for-github-actions#jobsjob_id"&gt;Workflow syntax docs - &lt;code&gt;jobs.&amp;lt;job_id&amp;gt;&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ matrix.os }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a required property, which tells the CI run what kind of machine it should be running on. In our case, we've added some complexity by adding a matrix of operating systems that need to be built against. That said, the context of the matrix gets hoisted, and we can use that context here.&lt;/p&gt;

&lt;p&gt;One key thing to note from the docs:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Each job runs with a fresh instance of the virtual environment specified in by runs-on.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Meaning, every job is running a clean instance of whatever OS is selected. This is table stakes for CI, but it's always useful to keep it in mind. ❤️&lt;/p&gt;

&lt;p&gt;Relevant docs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://help.github.com/en/articles/workflow-syntax-for-github-actions#jobsjob_idruns-on"&gt;Workflow syntax docs - &lt;code&gt;jobs.&amp;lt;job_id&amp;gt;.runs-on&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://help.github.com/en/articles/virtual-environments-for-github-actions"&gt;Virtual environments for GitHub Actions&lt;/a&gt;, which lists all the possible supported values for this property
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;    &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Having a &lt;code&gt;strategy&lt;/code&gt; line is the way to begin defining a matrix of environments to run your builds in.&lt;/p&gt;

&lt;p&gt;Relevant docs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://help.github.com/en/articles/workflow-syntax-for-github-actions#jobsjob_idstrategy"&gt;Workflow syntax docs - &lt;code&gt;jobs.&amp;lt;job_id&amp;gt;.strategy&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;      &lt;span class="na"&gt;matrix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tl;dr of a matrix is that it's the set of all the pieces of context you'll want to run against. The most straightforward matrix is one row – for example, multiple Node.js versions on a &lt;em&gt;single&lt;/em&gt; platform. &lt;/p&gt;

&lt;p&gt;A simple matrix:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ubuntu-latest&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Node.js 8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Node.js 10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Node.js 12&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That said, JavaScript and Node.js applications are effectively run on all three of the major operating systems in the world as a part of developer workflows. Often, we'll want to run on the three major operating systems to ensure that there are no unexpected platform-specific bugs that are going to occur – especially in open source when there are very few direct paths to end-users. Luckily, a matrix makes this relatively straightforward.&lt;/p&gt;

&lt;p&gt;By adding in multiple operating systems, our matrix gets more complex:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ubuntu-latest&lt;/th&gt;
&lt;th&gt;macos-latest&lt;/th&gt;
&lt;th&gt;windows-latest&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Node.js 8&lt;/td&gt;
&lt;td&gt;Node.js 8&lt;/td&gt;
&lt;td&gt;Node.js 8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Node.js 10&lt;/td&gt;
&lt;td&gt;Node.js 10&lt;/td&gt;
&lt;td&gt;Node.js 10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Node.js 12&lt;/td&gt;
&lt;td&gt;Node.js 12&lt;/td&gt;
&lt;td&gt;Node.js 12&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;But... that's only the &lt;em&gt;latest&lt;/em&gt; versions of each platform. What about older versions that we may often need to support? Well, it turns out that we can also use older versions of each platform in GitHub Actions CI, which could even further complicate the matrix:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ubuntu-latest&lt;/th&gt;
&lt;th&gt;ubuntu-16.04&lt;/th&gt;
&lt;th&gt;macos-latest&lt;/th&gt;
&lt;th&gt;macOS-10.14&lt;/th&gt;
&lt;th&gt;windows-latest&lt;/th&gt;
&lt;th&gt;windows-2016&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Node.js 8&lt;/td&gt;
&lt;td&gt;Node.js 8&lt;/td&gt;
&lt;td&gt;Node.js 8&lt;/td&gt;
&lt;td&gt;Node.js 8&lt;/td&gt;
&lt;td&gt;Node.js 8&lt;/td&gt;
&lt;td&gt;Node.js 8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Node.js 10&lt;/td&gt;
&lt;td&gt;Node.js 10&lt;/td&gt;
&lt;td&gt;Node.js 10&lt;/td&gt;
&lt;td&gt;Node.js 10&lt;/td&gt;
&lt;td&gt;Node.js 10&lt;/td&gt;
&lt;td&gt;Node.js 10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Node.js 12&lt;/td&gt;
&lt;td&gt;Node.js 12&lt;/td&gt;
&lt;td&gt;Node.js 12&lt;/td&gt;
&lt;td&gt;Node.js 12&lt;/td&gt;
&lt;td&gt;Node.js 12&lt;/td&gt;
&lt;td&gt;Node.js 12&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;And this is currenlty a downtime for Node.js builds. Half of the year (every year) there are 4 supported release lines, which would look more like this:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ubuntu-latest&lt;/th&gt;
&lt;th&gt;ubuntu-16.04&lt;/th&gt;
&lt;th&gt;macos-latest&lt;/th&gt;
&lt;th&gt;macOS-10.14&lt;/th&gt;
&lt;th&gt;windows-latest&lt;/th&gt;
&lt;th&gt;windows-2016&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Node.js 8&lt;/td&gt;
&lt;td&gt;Node.js 8&lt;/td&gt;
&lt;td&gt;Node.js 8&lt;/td&gt;
&lt;td&gt;Node.js 8&lt;/td&gt;
&lt;td&gt;Node.js 8&lt;/td&gt;
&lt;td&gt;Node.js 8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Node.js 10&lt;/td&gt;
&lt;td&gt;Node.js 10&lt;/td&gt;
&lt;td&gt;Node.js 10&lt;/td&gt;
&lt;td&gt;Node.js 10&lt;/td&gt;
&lt;td&gt;Node.js 10&lt;/td&gt;
&lt;td&gt;Node.js 10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Node.js 12&lt;/td&gt;
&lt;td&gt;Node.js 12&lt;/td&gt;
&lt;td&gt;Node.js 12&lt;/td&gt;
&lt;td&gt;Node.js 12&lt;/td&gt;
&lt;td&gt;Node.js 12&lt;/td&gt;
&lt;td&gt;Node.js 12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Node.js 13&lt;/td&gt;
&lt;td&gt;Node.js 13&lt;/td&gt;
&lt;td&gt;Node.js 13&lt;/td&gt;
&lt;td&gt;Node.js 13&lt;/td&gt;
&lt;td&gt;Node.js 13&lt;/td&gt;
&lt;td&gt;Node.js 13&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A matrix is super useful in helping us programmatically define such a list without actually having to define each of these contexts individually. This utility mostly comes when you start adding more platforms and versions, but thankfully the overhead of doing that is incredibly low from the configuration side of things (see the following sections for more context)&lt;/p&gt;

&lt;p&gt;Relevant docs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://help.github.com/en/articles/workflow-syntax-for-github-actions#jobsjob_idstrategymatrix"&gt;Workflow syntax docs - &lt;code&gt;jobs.&amp;lt;job_id&amp;gt;.strategy.matrix&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;        &lt;span class="na"&gt;os&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;ubuntu-latest&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;windows-latest&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;macOS-latest&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above is effectively a variable that we're assigning to the matrix, which can be dynamically called. In our case, we're just saying that the &lt;code&gt;os&lt;/code&gt; variable on &lt;code&gt;matrix&lt;/code&gt; (so &lt;code&gt;matrix.os&lt;/code&gt;) is going to be each of these. The &lt;em&gt;how&lt;/em&gt; is still a bit magic to me, but... it works, seemingly by iterating over each of them when they're called. When used in conjunction with another variable (like &lt;code&gt;node-version&lt;/code&gt;), they're iterated over to create something like the tables above effectively.&lt;/p&gt;

&lt;p&gt;Relevant docs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://help.github.com/en/articles/virtual-environments-for-github-actions"&gt;Virtual environments for GitHub Actions&lt;/a&gt;, which is where you can find information about all of the operating systems currently available.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;        &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;8.x&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;10.x&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;12.x&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another variable where we're going to define the Node.js versions we'd want to be running.&lt;/p&gt;

&lt;p&gt;Relevant docs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/actions/setup-node"&gt;actions/setup-node&lt;/a&gt; – the GitHub Action we pass versions to, which defines the acceptable syntax for versions&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://help.github.com/en/articles/software-in-virtual-environments-for-github-actions"&gt;Software in virtual environments for GitHub Actions
&lt;/a&gt; – an exhaustive list of software available in each virtual environment (OS) by default
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each job contains a set of &lt;code&gt;steps&lt;/code&gt;. This specific line is where we indicate that we're going to begin defining the steps.&lt;/p&gt;

&lt;p&gt;Relevant docs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://help.github.com/en/articles/workflow-syntax-for-github-actions#jobsjob_idsteps"&gt;Workflow syntax docs - &lt;code&gt;jobs.&amp;lt;job_id&amp;gt;.steps&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tells our workflow that we're going to be using the GitHub Action that can be found at &lt;code&gt;actions/checkout&lt;/code&gt; which maps to the GitHub org/repo at [gihub.com/actions/checkout]. It's also worth noting that &lt;code&gt;@v1&lt;/code&gt; which is a tagged and released version that can be found in the &lt;a href="https://github.com/actions/checkout/releases/tag/v1.0.0"&gt;GitHub Releases&lt;/a&gt; for the repo.&lt;/p&gt;

&lt;p&gt;Relevant docs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/actions/checkout"&gt;actions/checkout&lt;/a&gt;, an action that checks out your repository to &lt;code&gt;$GITHUB_WORKSPACE&lt;/code&gt; in the virtual environment.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://help.github.com/en/articles/workflow-syntax-for-github-actions#jobsjob_idstepsuses"&gt;Workflow syntax docs - &lt;code&gt;jobs.&amp;lt;job_id&amp;gt;.steps.uses&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Use Node.js ${{ matrix.node-version }} on ${{ matrix.os }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The name to display for the job in the UIs that it's rendered within, given the various variables that we've inserted using &lt;code&gt;matrix&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; There seems to be a bug where this does not render properly  – instead of rendering as a tagged template literal, the Actions UI renders as a string.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Relevant docs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://help.github.com/en/articles/workflow-syntax-for-github-actions#jobsjob_idname"&gt;Workflow syntax docs - &lt;code&gt;jobs.&amp;lt;job_id&amp;gt;.name&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Defines an external action – in this case, the [github.com/actions/setup-node] action at version 1.x.x (as released via the GitHub repo). In our case, this is an action that provides a super handy interface to install arbitrary versions of Node.js other than the version that comes baked into the VMs that are provided. My guess is that this will be a default action for &lt;em&gt;anyone&lt;/em&gt; who is running JavaScript or Node.js builds simply because it handles so much for you by default.&lt;/p&gt;

&lt;p&gt;It's worth noting that actions consumed with &lt;code&gt;uses:&lt;/code&gt; can be sourced from within the same repository, from a public repository, and from a Docker image published to Docker Hub.&lt;/p&gt;

&lt;p&gt;Relevant docs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://help.github.com/en/articles/workflow-syntax-for-github-actions#jobsjob_idstepsuses"&gt;Workflow syntax docs - &lt;code&gt;jobs.&amp;lt;job_id&amp;gt;.steps.uses&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/actions/setup-node"&gt;actions/setup-node&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a &lt;code&gt;map&lt;/code&gt; (my assumption is that this is a &lt;code&gt;map&lt;/code&gt; in the sense of YAML's definition of a map) of the parameters defined in the action. In our case, &lt;code&gt;actions/setup-node&lt;/code&gt; needs a version to run with.&lt;/p&gt;

&lt;p&gt;Relevant docs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://help.github.com/en/articles/workflow-syntax-for-github-actions#jobsjob_idstepswith"&gt;Workflow syntax docs - &lt;code&gt;jobs.&amp;lt;job_id&amp;gt;.steps.with&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;        &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ matrix.node-version }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;actions/setup-node&lt;/code&gt; action needs a version of Node.js to run, via the &lt;code&gt;node-version:&lt;/code&gt; property. Since we named the variable for Node.js versions in our Matrix &lt;code&gt;node-versions&lt;/code&gt;, we're able to pass &lt;code&gt;matrix.node-version&lt;/code&gt; to the &lt;code&gt;node-version:&lt;/code&gt; property.&lt;/p&gt;

&lt;p&gt;Relevant docs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://help.github.com/en/articles/workflow-syntax-for-github-actions#jobsjob_idstepswith"&gt;Workflow syntax docs - &lt;code&gt;jobs.&amp;lt;job_id&amp;gt;.steps.with&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/actions/setup-node"&gt;actions/setup-node&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm install and test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're again defining the name of a job. In this case, there's no dynamic information since the commands we're going to be running are pretty static.&lt;/p&gt;

&lt;p&gt;I use &lt;code&gt;npm install&lt;/code&gt; and &lt;code&gt;npm test&lt;/code&gt;, but your applications may vary in install/build/test/ci commands – my recommendation for this is to tweak both the title and the actual commands, so it's extremely clear what's being run.&lt;/p&gt;

&lt;p&gt;Relevant docs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://help.github.com/en/articles/workflow-syntax-for-github-actions#jobsjob_id"&gt;Workflow syntax docs - &lt;code&gt;jobs.&amp;lt;job_id&amp;gt;&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;npm install&lt;/span&gt;
        &lt;span class="s"&gt;npm test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is an interesting set of lines for those unfamiliar with YAML. We start with using a &lt;code&gt;run&lt;/code&gt; property for the job, which allows us to run any command on the system. In our case, we're going to use this to run &lt;code&gt;npm install&lt;/code&gt; and &lt;code&gt;npm test&lt;/code&gt;... but those are two different commands, that need to be run separately. The pipe (&lt;code&gt;|&lt;/code&gt;) is a tool defined in the &lt;a href="https://yaml.org/spec/1.2/spec.html#id2795688"&gt;YAML spec&lt;/a&gt; as Literal Style. In our case, it allows us to write multiple lines that execute independently without having to use multiple &lt;code&gt;run:&lt;/code&gt; commands or multiple jobs. Basically, it's shorthand that enables use to be looser in how we're able to build out our file.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; It may be worth using &lt;code&gt;npm ci&lt;/code&gt; rather than &lt;code&gt;npm install&lt;/code&gt; to install dependencies, given that &lt;code&gt;npm ci&lt;/code&gt; was tailor-made for CI environments. You can find more details on &lt;code&gt;npm ci&lt;/code&gt; in the &lt;a href="https://docs.npmjs.com/cli/ci"&gt;official documentation&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Relevant docs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://help.github.com/en/articles/workflow-syntax-for-github-actions#jobsjob_idstepsrun"&gt;Workflow syntax docs - &lt;code&gt;jobs.&amp;lt;job_id&amp;gt;.steps.run&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.npmjs.com/cli/install"&gt;npm install&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.npmjs.com/cli/test"&gt;npm test&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;      &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Allows us to set up environment variables in our virtual environments with relative ease.&lt;/p&gt;

&lt;p&gt;Relevant docs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://help.github.com/en/articles/workflow-syntax-for-github-actions#jobsjob_idstepsenv"&gt;Workflow syntax docs - &lt;code&gt;jobs.&amp;lt;job_id&amp;gt;.steps.env&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;        &lt;span class="na"&gt;CI&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This one is a personal preference, and also happens to be the default for the simplest Node.js workflow suggested by GitHub. Simply sets an environment variable that can be easily picked up on by various tools. GitHub&lt;/p&gt;

&lt;p&gt;Relevant docs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://help.github.com/en/articles/virtual-environments-for-github-actions#environment-variables"&gt;Virtual environments for GitHub Actions – Environment Variables&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Currently, GitHub Actions CI is in a semi-public beta as a part of GitHub Actions v2 – they've invited a bunch of folks who applied to use it. That said, if you feel like this is a repeat of what happened when GitHub Actions initially shipped last year, you'll be happy to know that in the &lt;a href="https://youtu.be/E1OunoCyuhY?t=2070"&gt;GitHub Special Event&lt;/a&gt; in which GitHub Actions CI and GitHub Actions v2 were shared, Nat Friedman said that GitHub Actions CI and GitHub Actions v2, along with GitHub Package Registry, is shipping to everyone on November 13th – the first day of &lt;a href="https://githubuniverse.com/"&gt;GitHub Universe&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So, in just over a month from the date of publishing this article, you'll be able to start using GitHub Actions CI on any and every public project for free. 🎉&lt;/p&gt;

&lt;p&gt;If you've got any questions or comments about what I've talked about in this post, or if there's more you'd like to learn about GitHub Actions CI or GitHub Actions v2, I'd be more than happy to see if I can either answer your questions in the comments directly, make good free and public repos that can help give you answers, or write more posts on the subject if you'd find that helpful!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>github</category>
    </item>
    <item>
      <title>Discuss: GitHub Special Event</title>
      <dc:creator>Tierney Cyren</dc:creator>
      <pubDate>Fri, 10 May 2019 14:00:56 +0000</pubDate>
      <link>https://dev.to/bnb/discuss-github-special-event-88f</link>
      <guid>https://dev.to/bnb/discuss-github-special-event-88f</guid>
      <description>&lt;p&gt;This week GitHub shared that they were planning a GitHub Special Event for... today 😱&lt;/p&gt;

&lt;h2&gt;
  
  
  The Details
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The event is currently planned for 1:30pm PT.&lt;/li&gt;
&lt;li&gt;The GitHub team has a special &lt;a href="https://live-stream.github.com/"&gt;livestream&lt;/a&gt; page set up

&lt;ul&gt;
&lt;li&gt;This page is using YouTube, which allows you to set reminders for when a scheduled stream goes live if you're signed into YouTube.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What We Know
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;GitHub is launching a new product (&lt;a href="https://twitter.com/natfriedman/status/1126127077806096385?s=20"&gt;ref&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;It's not a Responsive version of GitHub.com or Gist Notifications, since those have both already launched this week (&lt;a href="https://twitter.com/natfriedman/status/1126544306712350721?s=20"&gt;ref&lt;/a&gt;, &lt;a href="https://twitter.com/natfriedman/status/1126211245177094144?s=20"&gt;ref&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;???&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Who to Follow (Twitter)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://twitter.com/github"&gt;GitHub&lt;/a&gt;: I don't doubt that GitHub's socials will be actively tweeting whatever is happening.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://twitter.com/natfriedman"&gt;Nat Friedman&lt;/a&gt;: Nat is the CEO of GitHub and has been very actively hyping this up. Definitely a good person to follow if you want to catch the messages from the source via a human.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://twitter.com/clarkbw"&gt;Bryan Clark&lt;/a&gt;: Bryan is the individual who invited me to the event and is Director of Product for OSS Maintainers at GitHub. (That's a super awesome title, right?)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://twitter.com/bitandbang"&gt;Tierney Cyren&lt;/a&gt;: That's me! I'll be at the event and would be kidding myself if I were to say I'd be doing anything other than live-tweeting the event while I'm there. Super hyped 😱&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What Now?
&lt;/h2&gt;

&lt;p&gt;I figured it would be awesome to kick off a discuss post to keep up with what everyone is thinking about and feeling about the event leading up to it and talk about whatever happens while it's happening.&lt;/p&gt;

&lt;p&gt;A few questions I have for y'all to kick things off:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What do you think is going to be shared?&lt;/li&gt;
&lt;li&gt;What would you love to see?&lt;/li&gt;
&lt;li&gt;Do you think it's something that'll be available today or a longer-term thing?&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>discuss</category>
      <category>webdev</category>
      <category>opensource</category>
      <category>github</category>
    </item>
    <item>
      <title>What Makes Good Developer Tools... Good?</title>
      <dc:creator>Tierney Cyren</dc:creator>
      <pubDate>Thu, 02 May 2019 12:20:02 +0000</pubDate>
      <link>https://dev.to/bnb/what-makes-good-developer-tools-good-3lbm</link>
      <guid>https://dev.to/bnb/what-makes-good-developer-tools-good-3lbm</guid>
      <description>&lt;p&gt;I've known for a long time that developer tools are &lt;em&gt;the thing I care about&lt;/em&gt; in tech – making other developers lives even easier is something I aspire to. Often, though, I wonder if my ideas of what makes developer tools good is also what &lt;em&gt;others&lt;/em&gt; think makes developer tools good.&lt;/p&gt;

&lt;p&gt;So, I'd like to ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What makes your favorite developer tool &lt;em&gt;good&lt;/em&gt;?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Would love to hear from you in the comments so I can better understand from &lt;em&gt;your&lt;/em&gt; perspective ❤️&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>productivity</category>
    </item>
    <item>
      <title>The Awesome Features that Just Landed with Node.js v12</title>
      <dc:creator>Tierney Cyren</dc:creator>
      <pubDate>Thu, 25 Apr 2019 18:54:59 +0000</pubDate>
      <link>https://dev.to/bnb/the-awesome-features-that-just-landed-with-node-js-v12-178d</link>
      <guid>https://dev.to/bnb/the-awesome-features-that-just-landed-with-node-js-v12-178d</guid>
      <description>&lt;p&gt;This week, we saw the release of Node.js v12, the next Node.js release line that will become LTS. I wanted to go through the various posts that went out and the changelog and condense the information into an easily consumable digest of what's new in Node.js v12.x to share with everyone. 💖&lt;/p&gt;

&lt;h2&gt;
  
  
  The 🔥 Changes
&lt;/h2&gt;

&lt;p&gt;Let's dig into some of the most important and remarkable changes that have landed in v12.0.0!&lt;/p&gt;

&lt;h3&gt;
  
  
  New ES Modules, who dis
&lt;/h3&gt;

&lt;p&gt;With the release of Node.js v12.0.0, we see the introduction of a new implementation of ES Modules in Node.js. 🎉&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; ES Modules features are still &lt;strong&gt;Experimental&lt;/strong&gt; and as such should &lt;em&gt;not&lt;/em&gt; be used in production code until they are finalized.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At release, this new implementation has replaced the previous implementation behind the &lt;code&gt;--experimental-modules&lt;/code&gt; flag. This is intended to help get the new implementation out there and tested so the project can get feedback. If all goes well (🤞), this can ship unflagged once Node.js v12 goes LTS in October!&lt;/p&gt;

&lt;p&gt;Up front, I want to say this is going to be a tl;dr. If you're interested in a deeper dive into the new hotness around ESM in Node.js, please check out the blog post by &lt;a href="https://medium.com/@nodejs/announcing-a-new-experimental-modules-1be8d2d6c2ff"&gt;the Modules Team&lt;/a&gt; on Medium. &lt;/p&gt;

&lt;h4&gt;
  
  
  Previous implementation
&lt;/h4&gt;

&lt;p&gt;Many of the previous implementation's features carried over. This includes ES2015 &lt;code&gt;import&lt;/code&gt; statements, various kinds of &lt;code&gt;export&lt;/code&gt;, Node.js &lt;code&gt;export&lt;/code&gt; support on all core modules, WIP imports for CommonJS, &lt;strong&gt;very&lt;/strong&gt; WIP loader API, and explicit ESM parsing if the &lt;code&gt;.mjs&lt;/code&gt; file extension is present.&lt;/p&gt;

&lt;h4&gt;
  
  
  New implementation features
&lt;/h4&gt;

&lt;p&gt;These features are 100% new with the enhancements the Modules Team has been working on, and are available behind the &lt;code&gt;--experimental-modules&lt;/code&gt; flag in Node.js v12.0.0.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Import and export syntax in &lt;code&gt;.js&lt;/code&gt; files

&lt;ul&gt;
&lt;li&gt;there was lots of feedback that Node.js needs to provide a way to use import/export in &lt;code&gt;.js&lt;/code&gt; files.&lt;/li&gt;
&lt;li&gt;Two different solutions were implemented for this (keep reading!)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Support for &lt;code&gt;"type": "module"&lt;/code&gt; in &lt;code&gt;package.json&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;If this is detected, Node.js will treat &lt;em&gt;all&lt;/em&gt; &lt;code&gt;.js&lt;/code&gt; files in your project as ES Modules.&lt;/li&gt;
&lt;li&gt;If you still have CommonJS files, you can rename them with the &lt;code&gt;.cjs&lt;/code&gt; file extension, which will tell Node.js to parse them as CommonJS explicitly&lt;/li&gt;
&lt;li&gt;An &lt;code&gt;--input-type&lt;/code&gt; flag for cases like &lt;code&gt;--eval&lt;/code&gt; and STDIN&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Current WIP Features
&lt;/h4&gt;

&lt;p&gt;These features are currently being worked on by the Modules team and are either implemented but are likely going to change &lt;em&gt;or&lt;/em&gt; are being worked on but did not ship in Node.js v12.0.0.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JSON imports

&lt;ul&gt;
&lt;li&gt;Currently does not work, but is being actively worked on.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;import and require interop

&lt;ul&gt;
&lt;li&gt;️️⚠️ The Modules Team has requested that you do not publish ES Modules that can be used in Node.js until it's been resolved. I assume that modules published before this is resolved will likely break.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Module Loaders

&lt;ul&gt;
&lt;li&gt;⚠️  Very WIP&lt;/li&gt;
&lt;li&gt;A first implementation of the &lt;code&gt;--loader&lt;/code&gt; API has shipped, but it's going to be improved upon and, as such, &lt;em&gt;change&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;A simpler way to &lt;code&gt;require&lt;/code&gt; in ES Modules code.

&lt;ul&gt;
&lt;li&gt;The current implementation is a bit heavy-handed. The Modules team is working on lowering the barrier.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Package path maps

&lt;ul&gt;
&lt;li&gt;This would allow for less verbose imports in certain situations&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Automatic entry point module type detection

&lt;ul&gt;
&lt;li&gt;Effectively, static analysis that would allow Node.js to figure out if a module is a CommonJS module or an ES Module.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Quick ESM Examples
&lt;/h4&gt;

&lt;p&gt;If you're interested in seeing what ESM in Node.js looks like, you can check out two repos I pushed out yesterday:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/bnb/simple-esm"&gt;simple-esm&lt;/a&gt; – an example of what ESM in Node.js looks like with the current ESM implementation&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/bnb/simple-esm-usage"&gt;simple-esm-usage&lt;/a&gt; – an example of how you could use ESM modules from npm in Node.js if the current implementation were to ship unchanged (it's going to be changing, so this is more theory than practice)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm planning to keep these repos (and the version of simple-esm published to npm) both up-to-date as the ESM implementation changes both for my own understanding and as a community resource to have a minimum viable example of ESM in Node.js.&lt;/p&gt;

&lt;h3&gt;
  
  
  V8 7.4
&lt;/h3&gt;

&lt;p&gt;This release included a major &lt;strong&gt;V8 upgrade&lt;/strong&gt;, jumping forward several releases to the most recent version of V8 at time of release. This upgrade includes a plethora of really fantastic enhancements. I'm personally most interested in &lt;a href="https://v8.dev/blog/v8-release-72#async-stack-traces"&gt;Zero-cost Async Stack Traces&lt;/a&gt;, but there are a plethora of additional enhancements that are better outlined by Mathias Bynens from the V8 team:&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1120700101637353473-131" src="https://platform.twitter.com/embed/Tweet.html?id=1120700101637353473"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1120700101637353473-131');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1120700101637353473&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;h3&gt;
  
  
  TLS 1.3
&lt;/h3&gt;

&lt;p&gt;Next up, we have &lt;strong&gt;official TLS 1.3 support&lt;/strong&gt;. This is an incredible improvement to previous TLS versions, and I'm super excited that it's now supported in a release line that'll be going LTS! Thankfully, this is a backward compatible change thanks to the underlying implementation in OpenSSL 1.1.1. Additionally, it's mentioned &lt;a href="https://github.com/nodejs/node/pull/26209"&gt;in the PR&lt;/a&gt; that it should be backported to other LTS release lines.&lt;/p&gt;

&lt;p&gt;If you're curious about the awesome parts of TLS 1.3, I recommend this &lt;a href="https://www.ietf.org/blog/tls13/"&gt;blog post&lt;/a&gt; from the IETF.&lt;/p&gt;

&lt;h3&gt;
  
  
  Worker Threads
&lt;/h3&gt;

&lt;p&gt;This is the first LTS release line that will include the currently-experimental work on Worker Threads. This release has removed the need to run Worker Threads with a flag, hopefully lowering the barrier to more widespread usage of the tool for parallelizing work in Node.js.&lt;/p&gt;

&lt;p&gt;If you're interested in trying out Worker Threads today, there are a few resources you can use to get started:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://medium.com/@Trott/using-worker-threads-in-node-js-80494136dbb6"&gt;Using worker_threads in Node.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hackernoon.com/simple-bidirectional-messaging-in-node-js-worker-threads-7fe41de22e3c"&gt;Simple bidirectional messaging in Node.js Worker Threads&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.logrocket.com/node-js-multithreading-what-are-worker-threads-and-why-do-they-matter-48ab102f8b10"&gt;Node.js multithreading: What are Worker Threads and why do they matter?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nodejs.org/api/worker_threads.html"&gt;Official Node.js Worker Threads Docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Built-in Heap Snapshotting
&lt;/h3&gt;

&lt;p&gt;In this release, we also see built-in heap snapshotting adapted from the &lt;a href="https://www.npmjs.com/package/heapdump"&gt;heapdump module&lt;/a&gt; on npm. This is exposed via &lt;code&gt;v8.getHeapSnapshot()&lt;/code&gt; and returns a readable stream. &lt;/p&gt;

&lt;h2&gt;
  
  
  Other Notable Changes and Improvements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Core Dependencies: 

&lt;ul&gt;
&lt;li&gt;Upgraded to OpenSSL &lt;a href="https://www.openssl.org/news/cl111.txt"&gt;1.1.1b&lt;/a&gt; (&lt;a href="https://github.com/nodejs/node/pull/26327"&gt;nodejs/node#26327&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Upgraded to ICU 63 (&lt;a href="https://github.com/nodejs/node/pull/25852"&gt;nodejs/node#25852&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;There is also currently an &lt;a href="https://github.com/nodejs/node/pull/27361"&gt;open PR&lt;/a&gt; to further update to ICU 64.2&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Node.js has started using &lt;a href="https://github.com/nodejs/llhttp"&gt;llhttp&lt;/a&gt; as its default parser (&lt;a href="https://github.com/nodejs/node/issues/24730"&gt;nodejs/node#24730&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Invalid &lt;code&gt;main&lt;/code&gt; entries in &lt;code&gt;package.json&lt;/code&gt; will now throw an error (&lt;a href="https://github.com/nodejs/node/pull/26823"&gt;nodejs/node#26823&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;node --debug&lt;/code&gt; is now EOL – use &lt;code&gt;node --inspect&lt;/code&gt; instead (&lt;a href="https://github.com/nodejs/node/pull/25828"&gt;nodejs/node#25828&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;TLS 1.0 and 1.1 are now disabled by default (&lt;a href="https://github.com/nodejs/node/pull/23814"&gt;nodejs/node#23814&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Fin
&lt;/h2&gt;

&lt;p&gt;Hopefully this overview of the new release is helpful to you! If you've got any questions about the new features that've shipped, when you can start expecting to use ESM in Node.js, or anything else about Node.js v12 I'm happy to be a resource for you to hopefully find the answers you're looking for!&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Using npx and npm scripts to Reduce the Burden of Developer Tools</title>
      <dc:creator>Tierney Cyren</dc:creator>
      <pubDate>Mon, 22 Apr 2019 17:01:07 +0000</pubDate>
      <link>https://dev.to/azure/using-npx-and-npm-scripts-to-reduce-the-burden-of-developer-tools-57f9</link>
      <guid>https://dev.to/azure/using-npx-and-npm-scripts-to-reduce-the-burden-of-developer-tools-57f9</guid>
      <description>&lt;p&gt;On Friday, I was working on a &lt;a href="https://github.com/bnb/step-by-step-express-workshop" rel="noopener noreferrer"&gt;workshop-ified version&lt;/a&gt; of &lt;a href="https://github.com/bnb/step-by-step-express" rel="noopener noreferrer"&gt;Step by Step Express&lt;/a&gt; for &lt;a href="http://flawlesshacks.com/" rel="noopener noreferrer"&gt;Flawless Hacks&lt;/a&gt; in Brooklyn.&lt;/p&gt;

&lt;p&gt;In the workshop-ified version, I've modified each step so there is an &lt;code&gt;app.js&lt;/code&gt; and an &lt;code&gt;app.complete.js&lt;/code&gt; so that attendees could start with a clean slate from the previous step and know what they're aiming for to complete in the step that they're working on.&lt;/p&gt;

&lt;p&gt;I figured there was probably a tool on npm that would allow me to lower the barrier even further to let attendees/users know what they need to do to complete the step and check their code against &lt;code&gt;app.complete.js&lt;/code&gt; if their code isn't doing what they think it is.&lt;/p&gt;

&lt;p&gt;After a bit of searching, I was able to find &lt;a href="https://www.npmjs.com/package/prettydiff" rel="noopener noreferrer"&gt;Pretty Diff&lt;/a&gt;, which exposes a CLI tool that allows you to diff two files, and show the difference in the console.&lt;/p&gt;

&lt;p&gt;I tested the CLI a bit after globally installing it and was able to figure out that because of how I structured the changes (&lt;code&gt;app.js&lt;/code&gt; and &lt;code&gt;app.complete.js&lt;/code&gt; in each folder in addition to each folder having its own &lt;code&gt;package.json&lt;/code&gt;), I was able to use the same command for every single step:&lt;/p&gt;

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

diff &lt;span class="nb"&gt;source&lt;/span&gt;:&lt;span class="s2"&gt;"app.js"&lt;/span&gt; diff:&lt;span class="s2"&gt;"app.complete.js"&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Awesome! I found a tool that will hopefully lower the barrier to finding success with the code that they'll be writing. There's only one problem: they'll need the CLI to be installed for the above command to work. That sounds like a &lt;em&gt;fantastic&lt;/em&gt; way to increase the barrier to entry and waste time on tooling that was intended to improve the experience, not take away from it 😱&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter npx
&lt;/h2&gt;

&lt;p&gt;Luckily, there's this excellent tool that everyone who has a modern version of &lt;code&gt;npm&lt;/code&gt; installed already has: &lt;code&gt;npx&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In case you're not familiar, &lt;code&gt;npx&lt;/code&gt; is a CLI that the &lt;code&gt;npm&lt;/code&gt; team ships which automagically executes a CLI from a module on the npm registry. Ideally, most modules will only ship one top-level command – for those modules, you can simply run &lt;code&gt;npx &amp;lt;module name&amp;gt;&lt;/code&gt; and the command will be executed.&lt;/p&gt;

&lt;p&gt;In our case, we're looking to run the &lt;code&gt;prettydiff&lt;/code&gt; module and pass the &lt;code&gt;diff&lt;/code&gt; command. Luckily, &lt;code&gt;npx&lt;/code&gt; makes this super easy:&lt;/p&gt;

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

npx prettydiff diff &lt;span class="nb"&gt;source&lt;/span&gt;:&lt;span class="s2"&gt;"app.js"&lt;/span&gt; diff:&lt;span class="s2"&gt;"app.complete.js"&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Workshop attendees can 100% run this in any of the steps' directories and they'll be able to see a diff of the before/after!&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%2F72qsdgrf9g7bm46wvoue.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%2F72qsdgrf9g7bm46wvoue.png" alt="What a terminal looks like after a participant runs  raw `npx prettydiff diff source:"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Awesome! I've found a workable solution... that is 58 characters long and has some weird syntax that may be difficult to remember for everyone. It works, but it's not necessarily ideal. Luckily, we can make it even easier.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using npm scripts
&lt;/h2&gt;

&lt;p&gt;npm scripts are a super handy utility in our toolbelt that makes repetitive tasks and long commands easy. Awesomely, you can use &lt;code&gt;npx&lt;/code&gt; inside of npm scripts – meaning you can use &lt;strong&gt;any&lt;/strong&gt; CLI on npm to do work in your project without ever needing to actually install it. This is fantastic for build steps, productivity tools, and (in our case) diffing code.&lt;/p&gt;

&lt;p&gt;In my case, I added a &lt;code&gt;diff&lt;/code&gt; command to my &lt;code&gt;package.json&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&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;"lint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"standard"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"diff"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx prettydiff diff source:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;app.js&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; diff:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;app.complete.js&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&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;Now, instead of needing to write out &lt;code&gt;npx prettydiff diff source:"app.js" diff:"app.complete.js"&lt;/code&gt; attendees of my workshop can just type &lt;code&gt;npm run diff&lt;/code&gt; and the command will execute 🤗&lt;/p&gt;

&lt;h2&gt;
  
  
  Fin
&lt;/h2&gt;

&lt;p&gt;I love npx and think npx + npm scripts is a super powerful combination that allows end-users of our JavaScript code to reduce the cognitive load of repetitive commands that aid their workflow. I wanted to share this quick example of how I've used it in hopes of enabling others to focus more on code rather than getting caught up on workflows ✨&lt;/p&gt;

&lt;p&gt;If you've got any questions about npx, npm scripts, or anything else I've talked about in this article, please don't hesitate to ask in the comments – more than happy to answer any questions you may have!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>productivity</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
