<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Ryan Dunn</title>
    <description>The latest articles on Forem by Ryan Dunn (@ryandunn).</description>
    <link>https://forem.com/ryandunn</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%2F203809%2Ff25f61aa-9aec-4470-97d9-9496db88506d.png</url>
      <title>Forem: Ryan Dunn</title>
      <link>https://forem.com/ryandunn</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/ryandunn"/>
    <language>en</language>
    <item>
      <title>How to use Tailwind with Create React App and PostCSS with no hassle</title>
      <dc:creator>Ryan Dunn</dc:creator>
      <pubDate>Sun, 05 Jul 2020 08:05:27 +0000</pubDate>
      <link>https://forem.com/ryandunn/how-to-use-tailwind-with-create-react-app-and-postcss-with-no-hassle-2i09</link>
      <guid>https://forem.com/ryandunn/how-to-use-tailwind-with-create-react-app-and-postcss-with-no-hassle-2i09</guid>
      <description>&lt;p&gt;I really like styled components and CSS in JS in general, but this has quickly overtaken as my favourite way to do styling in React. It took a little while to figure out the configuration so I'm going to share that here.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/ryanantonydunn/cra-postcss-tailwind"&gt;Link if you just want to see the working starter&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The combination that works to make this seamless is as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://create-react-app.dev/docs/getting-started/"&gt;Create React App&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tailwindcss.com/"&gt;TailwindCSS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/postcss/postcss-nested"&gt;postcss-nested&lt;/a&gt;
Use SASS style nested CSS rules.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/package/@craco/craco"&gt;craco (Create-React-App-Configuration-Override)&lt;/a&gt;
Allow us to use PostCSS to compile tailwind and the other plugins with webpack without the need for ejecting.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Getting set up
&lt;/h2&gt;

&lt;p&gt;Using &lt;a href="https://create-react-app.dev/docs/getting-started/"&gt;Create React App&lt;/a&gt; is very well documented. We'll start a new project and install our dev dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-react-app cra-postcss-tailwind
&lt;span class="nb"&gt;cd &lt;/span&gt;cra-postcss-tailwind
yarn add &lt;span class="nt"&gt;-D&lt;/span&gt; @craco/craco autoprefixer postcss-nested tailwindcss
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Setting up the basic webpack config
&lt;/h2&gt;

&lt;p&gt;To allow us to customise the Create React App webpack config we'll be using Craco.&lt;/p&gt;

&lt;p&gt;Create a &lt;code&gt;tailwind.config.js&lt;/code&gt; file in the root of the project for whatever customisations you like. This is also where we set up the production purge to get rid of unused utilities and keep file size down.&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="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;purge&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./src/**/*.html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./src/**/*.jsx&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./src/**/*.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;screens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;max&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;400px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And create a &lt;code&gt;craco.config.js&lt;/code&gt; file to set up the postcss plugins:&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="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;postcss&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tailwindcss&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./tailwind.config.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's change the scripts inside &lt;code&gt;package.json&lt;/code&gt; to use &lt;code&gt;craco&lt;/code&gt; instead of &lt;code&gt;react-scripts&lt;/code&gt;. This is what allows us to bypass the restrictions with Create React App without ejecting.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;scripts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;start&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;craco start&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;build&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;craco build&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;craco test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, let's set up the global stylesheet. Adding to the start of &lt;code&gt;src/index.css&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;utilities&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it for the basics, you should now be able to use tailwind in your markup with all the benefits of CRA with impunity. Let's run the project with &lt;code&gt;yarn start&lt;/code&gt; and add a utility class to test it out:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RTMUbxFS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/o5r76xikq8u0y1g17a7m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RTMUbxFS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/o5r76xikq8u0y1g17a7m.png" alt="Setting up Tailwind CSS with Create React App"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Composition and modules
&lt;/h2&gt;

&lt;p&gt;This setup comes with all the benefits of a normal CRA + PostCSS setup, which means we can compose classes inside CSS modules alongside regular CSS like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* App.css */&lt;/span&gt;
&lt;span class="nc"&gt;.App&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100vw&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100vh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="err"&gt;@apply&lt;/span&gt; &lt;span class="err"&gt;bg-green-500;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And with the inclusion of the &lt;code&gt;postcss-nested&lt;/code&gt; plugin we can have SASS style nesting as well:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// craco.config.js&lt;/span&gt;
&lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tailwindcss&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./tailwind.config.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;postcss-nested&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* App.css */&lt;/span&gt;
&lt;span class="nc"&gt;.App&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100vw&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100vh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="err"&gt;@apply&lt;/span&gt; &lt;span class="err"&gt;bg-green-500&lt;/span&gt; &lt;span class="err"&gt;flex&lt;/span&gt; &lt;span class="err"&gt;items-center&lt;/span&gt; &lt;span class="err"&gt;justify-center;&lt;/span&gt;

  &lt;span class="err"&gt;&amp;amp;-inner&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
    &lt;span class="err"&gt;@apply&lt;/span&gt; &lt;span class="err"&gt;bg-gray-900&lt;/span&gt; &lt;span class="err"&gt;text-white&lt;/span&gt; &lt;span class="err"&gt;p-4;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// App.js&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"App"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"App-inner border border-white"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Success!&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Resulting in this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iWnEpbqi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/hxfwi50me7wxpqgjfv9p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iWnEpbqi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/hxfwi50me7wxpqgjfv9p.png" alt="Setting up Tailwind CSS with Create React App and nesting"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And that's it. This is definitely my new favourite way to do styling in React. Enjoy.&lt;/p&gt;

</description>
      <category>react</category>
      <category>tailwindcss</category>
      <category>css</category>
    </item>
    <item>
      <title>In search of the ultimate number regex</title>
      <dc:creator>Ryan Dunn</dc:creator>
      <pubDate>Thu, 07 May 2020 11:06:30 +0000</pubDate>
      <link>https://forem.com/ryandunn/in-search-of-the-ultimate-number-regex-3kk</link>
      <guid>https://forem.com/ryandunn/in-search-of-the-ultimate-number-regex-3kk</guid>
      <description>&lt;p&gt;I was recently working on a number input field and ran into the age old problem of validating the user input to ensure a valid numerical value. This is simple enough to just validate once the complete value is inputted, but not so much while the user is still typing.&lt;/p&gt;

&lt;p&gt;We need the user to be able to input a &lt;code&gt;-&lt;/code&gt; on the way to typing &lt;code&gt;-1&lt;/code&gt; and to be able to type &lt;code&gt;1.&lt;/code&gt; on the way to typing &lt;code&gt;1.23&lt;/code&gt;, but remove any non-numerical characters smoothly. I was sure this could be accomplished with a single regex and set out to do it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Remove any characters that are not numerals, dots or dashes&lt;/li&gt;
&lt;li&gt;Remove any dashes not at the beginning of the string&lt;/li&gt;
&lt;li&gt;Allow one dot, remove any additional dots&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This should also result, at least in Javascript with a value that can almost always be correctly formatted with &lt;code&gt;parseFloat&lt;/code&gt; without any &lt;code&gt;NaN&lt;/code&gt; hijinks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Filtering non-numeric characters
&lt;/h2&gt;

&lt;p&gt;Let's go ahead and try to format this horrible mess into a valid potential numeric value:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;-a[b1-2.cd.-e34--.5*(a67.ac&amp;amp;&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;The first part of the problem is simple, filter any characters that aren't numbers, dashes or dots:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[^\d&lt;/span&gt;&lt;span class="sr"&gt;.-&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// output "-1-2..-34--.567."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This looks mysterious if you haven't ever broken it down into pieces before, but I'll explain it bit by bit. We tell our match filter to find every match &lt;code&gt;/g&lt;/code&gt; from a whitelist group &lt;code&gt;[ ]&lt;/code&gt; that is not &lt;code&gt;^&lt;/code&gt; a digit &lt;code&gt;\n&lt;/code&gt;, a dot &lt;code&gt;.&lt;/code&gt;, or a dash &lt;code&gt;-&lt;/code&gt;. We use &lt;code&gt;replace&lt;/code&gt; to replace all matches with nothing.&lt;/p&gt;

&lt;p&gt;Note: normally the dot character would need escaping (&lt;code&gt;/\./g&lt;/code&gt; matches all dots) but doesn't within the group.&lt;/p&gt;

&lt;h2&gt;
  
  
  Removing improper dashes
&lt;/h2&gt;

&lt;p&gt;Next we need to remove any dashes that aren't at the beginning of the string. This is a little more esoteric:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;(?!&lt;/span&gt;&lt;span class="sr"&gt;^&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;-|&lt;/span&gt;&lt;span class="se"&gt;[^\d&lt;/span&gt;&lt;span class="sr"&gt;.-&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// output "-12..34.567."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here we're using a negative lookahead &lt;code&gt;(?! )&lt;/code&gt; to tell our matcher to fail if it finds the following match at the first-character position &lt;code&gt;^&lt;/code&gt; and then to match all dashes &lt;code&gt;-&lt;/code&gt;, ie: all dashes that are not the first character. Then we are using the or operator &lt;code&gt;|&lt;/code&gt; to tell it to search for that or anything from out previous matcher - anything non digit, dot or dash. Getting closer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Removing additional dots
&lt;/h2&gt;

&lt;p&gt;The final problem here is one that unfortunately &lt;em&gt;is&lt;/em&gt; solvable in a one-line regex, but not supported by several widely used browsers. We need to use a positive look-behind which isn't supported in Firefox, Safari, or IE11 as of the time of writing. Nevertheless here is the solution which will work in any environment that does support it, courtesy of a colleague of mine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;(?&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;=&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="sr"&gt;.*&lt;/span&gt;&lt;span class="se"&gt;)\.&lt;/span&gt;&lt;span class="sr"&gt;|&lt;/span&gt;&lt;span class="se"&gt;(?!&lt;/span&gt;&lt;span class="sr"&gt;^&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;-|&lt;/span&gt;&lt;span class="se"&gt;[^\d\.&lt;/span&gt;&lt;span class="sr"&gt;-&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// output "-12.34567"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here we use a positive lookbehind &lt;code&gt;(?&amp;lt;= )&lt;/code&gt; to tell our matcher to succeed only if it finds at least one dot &lt;code&gt;\..*&lt;/code&gt; behind it. We combine it with the or operator &lt;code&gt;|&lt;/code&gt; to the rest of our filters and get the final result.&lt;/p&gt;

&lt;p&gt;Unfortunately this won't work in several major browsers, so for now I have a short function to handle it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;formatNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// replace all non numeric, dots or dashes that aren't the first char&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filtered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;(?!&lt;/span&gt;&lt;span class="sr"&gt;^&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;-|&lt;/span&gt;&lt;span class="se"&gt;[^\d&lt;/span&gt;&lt;span class="sr"&gt;.-&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// remove all but the first dot&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;others&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;filtered&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;others&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;others&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)].&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;filtered&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;newValue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Final validation
&lt;/h2&gt;

&lt;p&gt;The above function is perfect for validating a changing user input, but when it comes to validating the final value and converting it to a float, we need to do a small final check.&lt;/p&gt;

&lt;p&gt;Running this filter over any string results almost always in a value that can be parsed correctly with &lt;code&gt;parseFloat&lt;/code&gt;. The exceptions are resulting strings containing only &lt;code&gt;-&lt;/code&gt;, &lt;code&gt;.&lt;/code&gt; or &lt;code&gt;-.&lt;/code&gt; which we can simply filter out and replace with zero. Or do a simple &lt;code&gt;NaN&lt;/code&gt; check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getNumeric&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;parseFloat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filterNumericInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;isNaN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</description>
      <category>javascript</category>
      <category>ux</category>
    </item>
    <item>
      <title>Should we set a default font-size? Ideals and practicalities</title>
      <dc:creator>Ryan Dunn</dc:creator>
      <pubDate>Tue, 25 Feb 2020 10:39:13 +0000</pubDate>
      <link>https://forem.com/ryandunn/should-we-set-a-default-font-size-ideals-and-practicalities-1k6c</link>
      <guid>https://forem.com/ryandunn/should-we-set-a-default-font-size-ideals-and-practicalities-1k6c</guid>
      <description>&lt;p&gt;Recently I had quite a productive conversation about default font sizes in browsers in a PR comment section. I thought I would preserve the outcome here for later reference.&lt;/p&gt;

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

&lt;p&gt;Most web browsers have a setting to customise what the default font size is. This can be used by visually impaired users to increase readability and comfort.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aVSwPzzK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/pztwd6yrny8elgbe1dqi.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aVSwPzzK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/pztwd6yrny8elgbe1dqi.jpg" alt="Chrome default font settings"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Chrome default font settings&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This can present challenges to developers with having the layout support a wide variety of text sizes while still being usable and presentable. This gets more challenging the more complex the website or web-app is. A lot of developers opt to set the font size explicitly, effectively disabling this feature. Including Google and Facebook.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--C63M57D8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/wmuo0542mjtq9l7m1ouh.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--C63M57D8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/wmuo0542mjtq9l7m1ouh.jpg" alt="Google body tag font settings"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Google body tag font settings&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Opinions on best practices here vary. Some say it’s better to have the browser zoom feature handle all font increases, preserving the layout. Some that the feature allows people to choose the method that most suits them. Even the accessibility specifications are quite vague on this.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Conversation
&lt;/h2&gt;

&lt;p&gt;We had a back-and-forth over this over several days. The following is roughly how the conversation went.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dev 1:&lt;/strong&gt;&lt;br&gt;
Font size missing from body. Not all browsers have a 16px default size.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dev 2:&lt;/strong&gt;&lt;br&gt;
Allowing the default is better for accessibility because some users use a higher default font size. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dev 1:&lt;/strong&gt;&lt;br&gt;
Users use a custom stylesheet now to set the default because sites like Google and Facebook all use a base pixel font. Not setting it will break the layout in some browsers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dev 2:&lt;/strong&gt;&lt;br&gt;
Some big sites do but others do not. Just because others don’t support default sizes doesn’t mean we shouldn’t either. Mobile browsers aren't displaying them incorrectly, we’re just not building our layout flexibly enough to accommodate varying text size.&lt;br&gt;
Reference: &lt;a href="https://www.w3.org/WAI/older-users/developing/#p"&gt;https://www.w3.org/WAI/older-users/developing/#p&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dev 1:&lt;/strong&gt;&lt;br&gt;
Agreed, but checking the spec here it looks like the zoom feature would be enough to meet their criteria.&lt;br&gt;
G142: Using a technology that has commonly-available user agents that support zoom&lt;br&gt;
Is there something more specific to do with default font sizes we can see?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dev 2:&lt;/strong&gt;&lt;br&gt;
It might be enough to simply meet the minimum standards but I think we should aim to support this feature. By explicitly setting a pixel font size we are choosing to disable it.&lt;/p&gt;

&lt;p&gt;From a survey conducted in 2018 with 248 respondents with impaired vision on how they use assistive technology:&lt;br&gt;
&lt;a href="https://webaim.org/projects/lowvisionsurvey2/"&gt;https://webaim.org/projects/lowvisionsurvey2/&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Response&lt;/th&gt;
&lt;th&gt;# of Respondents&lt;/th&gt;
&lt;th&gt;% of Respondents&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Screen reader&lt;/td&gt;
&lt;td&gt;112&lt;/td&gt;
&lt;td&gt;45.2%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Screen magnification software or system settings&lt;/td&gt;
&lt;td&gt;120&lt;/td&gt;
&lt;td&gt;48.4%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Browser zoom controls (zooms all page content)&lt;/td&gt;
&lt;td&gt;109&lt;/td&gt;
&lt;td&gt;44.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Browser text sizing settings&lt;/td&gt;
&lt;td&gt;91&lt;/td&gt;
&lt;td&gt;36.7%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;High contrast mode or settings&lt;/td&gt;
&lt;td&gt;76&lt;/td&gt;
&lt;td&gt;30.6%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Browser settings to change colors&lt;/td&gt;
&lt;td&gt;34&lt;/td&gt;
&lt;td&gt;13.7%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Custom styles (for example with Stylish, Stylus, or user style sheets)&lt;/td&gt;
&lt;td&gt;31&lt;/td&gt;
&lt;td&gt;12.5%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tools that highlight text as it is read&lt;/td&gt;
&lt;td&gt;25&lt;/td&gt;
&lt;td&gt;10.1%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Other&lt;/td&gt;
&lt;td&gt;21&lt;/td&gt;
&lt;td&gt;8.5%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I agree that on the surface it looks like zoom would be enough to meet the requirements, but the fact is that people use this feature. For whatever reason makes them comfortable with their particular disability they use it. I think we should support it for the small effort it takes to adjust our layout.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dev 1:&lt;/strong&gt;&lt;br&gt;
Cool. So we need to mitigate the problems that arise due to this.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;[list of observed issues, eg: buttons overflowing, scrollbars appearing on some elements, images unpredictably moving around]&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Also since not all the text has been done with rems and it's currently a mix of px and rems, some text is tiny while other text is huge. Based on this, do you think we should temporarily add the font-size in until we can attend to these?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dev 2:&lt;/strong&gt;&lt;br&gt;
Good point. Let’s put in a temporary base font size for now and we’ll make a ticket to revisit this across the app further down the roadmap.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons
&lt;/h2&gt;

&lt;p&gt;This was a very useful conversation. By approaching the problem with an open mind and looking into the evidence we came to some conclusions on both an ideal best practice and a pragmatic approach to getting there.&lt;/p&gt;

&lt;h3&gt;
  
  
  Things to remember
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Users may feel more comfortable using our products in ways we don’t expect.&lt;/li&gt;
&lt;li&gt;Just because someone else is doing it doesn’t mean it’s the correct approach, no matter how big they are.&lt;/li&gt;
&lt;li&gt;Sometimes the best approach has to be compromised for practical reasons like budget and timescale.&lt;/li&gt;
&lt;li&gt;Sometimes we need a temporary solution that can be improved further down the roadmap.&lt;/li&gt;
&lt;li&gt;Friendly pushback makes you justify what you think you know and really check why you think the way you do.&lt;/li&gt;
&lt;li&gt;Always be open to having your mind changed by new information.
‌&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>a11y</category>
      <category>css</category>
      <category>html</category>
      <category>typography</category>
    </item>
    <item>
      <title>Using my command history to decide some aliases</title>
      <dc:creator>Ryan Dunn</dc:creator>
      <pubDate>Tue, 11 Feb 2020 17:07:47 +0000</pubDate>
      <link>https://forem.com/ryandunn/using-my-command-history-to-decide-some-aliases-n7g</link>
      <guid>https://forem.com/ryandunn/using-my-command-history-to-decide-some-aliases-n7g</guid>
      <description>&lt;p&gt;Today I finally decided to set up some aliases to make my life easier in the terminal, however I was not so sure what would be most useful for me. There are a lot of resources out there with collections of aliases, but everyone's workflow is different - plus there are commands that I use just for the project I'm currently working on.&lt;/p&gt;

&lt;p&gt;The shell I use is zshell, which has a stored history of all the commands I have ever typed in the &lt;code&gt;.zsh_history&lt;/code&gt; file, there is a similar file for other shells. I decided to take a little dive into this history to see which commands I was using the most, then make some aliases based on that.&lt;/p&gt;

&lt;h2&gt;
  
  
  The history file
&lt;/h2&gt;

&lt;p&gt;Opening the history file from here &lt;code&gt;code ~/.zsh_history&lt;/code&gt;, the file looks something like this with thousands of lines for me:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;: 1580312682:0;docker-compose up -d
: 1574942146:0;git rebase -i HEAD~2
: 1575637243:0;git push -u origin hotfix/edge_bugs
: 1575637313:0;git checkout master
: 1575637328:0;git checkout -b hotfix/autocomplete
: 1581072502:0;cd ../
: 1581072502:0;ls
: 1575637359:0;git cherry-pick 3538df76a00a16aa04190d075
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Some very basic analysis
&lt;/h2&gt;

&lt;p&gt;I decided to try to take all of those commands and count how many times I had used each one, then sort them by most used - just to get a basic look at what I was typing the most.&lt;/p&gt;

&lt;p&gt;I made a quick nodejs script to do this. First reading the file, splitting each line into an array and removing the timestamp from the beginning. Then finally rewriting the file back into a text file in the same directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;historyFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;HOME&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.zsh_history&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;historyFile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;commands&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;buffer&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;line&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;commands&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;writeFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;result.txt&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Success&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;From the directory, running &lt;code&gt;node analyse.js&lt;/code&gt; this outputs a list of commands with no timestamps on them in a new text file in the same directory. Great.&lt;/p&gt;

&lt;p&gt;Next I needed to group and count all the commands, with some slight refactoring of the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// count all instances of each command&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;counts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
&lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;line&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// convert into a sorted list of commands&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;(([,&lt;/span&gt; &lt;span class="nx"&gt;countA&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[,&lt;/span&gt; &lt;span class="nx"&gt;countB&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;countB&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;countA&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; | &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This outputs the sorted list, which looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;118 | cd ../
114 | code .
114 | git push
93 | git pull
92 | yarn middleware
80 | yarn
79 | git add .
67 | yarn start --reset-cache
66 | docker-compose exec php-fpm bash
...
1 | git merge develop_SIT-608
1 | git merge develop_SIT-611
1 | git merge develop_SIT-615
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The top of the list contains the most obvious commands I type all the time, but towards the bottom there are the things I use a lot but aren't unique (eg: &lt;code&gt;git merge&lt;/code&gt;, &lt;code&gt;git checkout&lt;/code&gt;, etc). This could be made more accurate by adding a fuzzy search but I thought it was fun just to scan over the list and get a general idea.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the aliases
&lt;/h2&gt;

&lt;p&gt;To add an alias you need to edit the config file for your shell. For zshell that's the &lt;code&gt;.zshrc&lt;/code&gt; file, for bash it's the &lt;code&gt;.bashrc&lt;/code&gt; file. From looking at my command usage I decided on just a few that were going to make my life easier:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Misc helpers&lt;/span&gt;
&lt;span class="nb"&gt;alias pr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"cd ~/projects"&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;yarnclean&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"rm -rf node_modules &amp;amp;&amp;amp; yarn"&lt;/span&gt;

&lt;span class="c"&gt;#[company] helpers&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;rdw&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"cd ~/projects/[company]-web"&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;rdc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"cd ~/projects/[company]-cms"&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;sda&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"cd ~/projects/[company]-app"&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;ym&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"yarn middleware"&lt;/span&gt;
&lt;span class="nb"&gt;alias cp&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"docker-compose exec php-fpm clean-pimcore"&lt;/span&gt;

&lt;span class="c"&gt;# Git helpers&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;gclean&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"git remote prune origin &amp;amp;&amp;amp; git branch -vv | grep ': gone]' | awk '{print &lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;}' | xargs git branch -d"&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;gps&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"git push"&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;gpsu&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"gps -u origin HEAD"&lt;/span&gt;

&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;gpl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"git pull"&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;gplo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"git pull origin"&lt;/span&gt; &lt;span class="c"&gt;#branch-name&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;gplod&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"gplo develop"&lt;/span&gt;

&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;gc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"git checkout"&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;gb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"gc -b"&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;gcd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"gc develop"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;What's best for me isn't necessarily best for everyone else. For example, I like to do my commits from the vscode git diff screen because it's more obvious to me what's happening in my commits from there. As such I don't really need any &lt;code&gt;git add&lt;/code&gt; or &lt;code&gt;git commit&lt;/code&gt; aliases to speed up my workflow, but somebody else would. This applies to all kinds of ways your workflow is personal to you.&lt;/p&gt;

&lt;p&gt;Having used just these few for a day or so now I can really feel the difference.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>shell</category>
    </item>
  </channel>
</rss>
