<?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: Ash Connolly</title>
    <description>The latest articles on DEV Community by Ash Connolly (@ashconnolly).</description>
    <link>https://dev.to/ashconnolly</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%2F204950%2Fac281f92-162f-4f59-91bf-2fbcd762187d.jpeg</url>
      <title>DEV Community: Ash Connolly</title>
      <link>https://dev.to/ashconnolly</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ashconnolly"/>
    <language>en</language>
    <item>
      <title>How, and why, you should add JavaScript linting to your project. With ESLint and Gulp</title>
      <dc:creator>Ash Connolly</dc:creator>
      <pubDate>Mon, 04 Mar 2024 17:36:00 +0000</pubDate>
      <link>https://dev.to/ashconnolly/how-and-why-you-should-add-javascript-linting-to-your-project-with-eslint-and-gulp-5g6j</link>
      <guid>https://dev.to/ashconnolly/how-and-why-you-should-add-javascript-linting-to-your-project-with-eslint-and-gulp-5g6j</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published &lt;a href="https://ashconnolly.com/blog/how-to-add-javascript-linting" rel="noopener noreferrer"&gt;here&lt;/a&gt;, Feb 28, 2018&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://nodejs.org/en/" rel="noopener noreferrer"&gt;Node&lt;/a&gt; installed&lt;/li&gt;
&lt;li&gt;A little &lt;a href="https://gulpjs.com/" rel="noopener noreferrer"&gt;gulp&lt;/a&gt; and &lt;a href="https://www.npmjs.com/" rel="noopener noreferrer"&gt;npm&lt;/a&gt; knowledge is beneficial, but not required&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some people prefer to see the code first, so if you would like to download a working demo, the files &lt;a href="https://ashconnolly.com/blog/eslint-tutorial-files.zip" rel="noopener noreferrer"&gt;can be found here&lt;/a&gt; (be sure to run &lt;code&gt;npm i&lt;/code&gt; to install the dependencies).&lt;/p&gt;

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

&lt;p&gt;Linting is the process of checking your code for potential errors. Linting tools usually allow you to specify a set of rules to check your code against. These rules can vary from general code layout, like maximum line length and code indentation, to how you declare functions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why lint?
&lt;/h2&gt;

&lt;p&gt;Linters help you to write standardised code to ensure quality, minimise errors and increase readability. This is helpful when working in teams to ensure all developers are writing code in the same way. In day-to-day work, if developers are working with various files that have a consistent layout, it makes the code easier to read, which means developers can work faster, saving time. Linters also offer performance benefits in highlighting inefficient or unused code. Naturally we want the best user experience for our customers and keeping the code as efficient and lightweight as possible to reduce page load time is a big part of that.&lt;/p&gt;

&lt;h2&gt;
  
  
  ESLint
&lt;/h2&gt;

&lt;p&gt;Some of the most popular JavaScript linting tools are ESLint, JSHint, JSLint and JSCS. We're going to be using ESLint. It’s very flexible, easy to use and has the best ES6 support, which will be helpful if we introduce more modern JavaScript (that will be transpiled for older browsers using &lt;a href="https://babeljs.io/" rel="noopener noreferrer"&gt;https://babeljs.io/&lt;/a&gt;). All rules for ESLint can be found here: &lt;a href="https://eslint.org/docs/rules/" rel="noopener noreferrer"&gt;https://eslint.org/docs/rules/&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A great starting point – Airbnb JavaScript Style Guide
&lt;/h2&gt;

&lt;p&gt;Instead of writing our own exhaustive list of JavaScript rules, we can use a ruleset defined by the developers at Airbnb, and then adjust it to suit our preferences. The &lt;a href="https://github.com/airbnb/javascript" rel="noopener noreferrer"&gt;Airbnb JavaScript Style Guide&lt;/a&gt; is well known among JavaScript developers and used by some big companies: Lonely Planet, National Geographic and Sainsburys to name a few. It’s a great place to start.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using ESLint with Gulp
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Note: Over recent years &lt;a href="https://webpack.js.org/" rel="noopener noreferrer"&gt;Webpack&lt;/a&gt; has become a more popular choice than Gulp due the increase of JavaScript applications which require a more configurable build system. However, if that flexibility isn’t needed Gulp is still great for many projects.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We could install ESLint globally and run it from the command line using the command &lt;code&gt;eslint&lt;/code&gt;. However, in this tutorial we are going to be using ESLint in a gulp project and that means we can install ESLint, and all necessary dependencies, locally. This is beneficial for other people on the project as all dependencies are kept neatly inside the project (listed in the &lt;code&gt;package.json&lt;/code&gt;) and won’t require any extra work or global installations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing our dependencies
&lt;/h2&gt;

&lt;p&gt;If you don’t yet have gulp installed, in terminal navigate to the root of your project folder and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install gulp --save-dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the &lt;code&gt;--save-dev&lt;/code&gt; will add the package to your &lt;code&gt;package.json&lt;/code&gt; as development dependencies.&lt;/p&gt;

&lt;p&gt;Here are the ESLint dependencies we are going to install:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;eslint – the ESLint tool&lt;/li&gt;
&lt;li&gt;gulp-eslint – the gulp plugin for ESLint&lt;/li&gt;
&lt;li&gt;eslint-config-airbnb – the Airbnb ESLint configuration (rule set)&lt;/li&gt;
&lt;li&gt;eslint-plugin-react – a plugin to add react-specific rules for ESLint to use&lt;/li&gt;
&lt;li&gt;eslint-plugin-import – a plugin to add linting ES2015+ (ES6+) import/export syntax&lt;/li&gt;
&lt;li&gt;eslint-plugin-jsx-a11y – a plugin to check accessibility of JSX elements (react)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To install all of these run (again from the root of your project folder):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install gulp gulp-eslint eslint-config-airbnb eslint eslint-plugin-react eslint-plugin-import eslint-plugin-jsx-a11y --save-dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Adding an ESLint configuration file
&lt;/h2&gt;

&lt;p&gt;We now need to add an ESLint configuration file, which will tell our linting process what standards and rules our code needs to meet. We could have a file named &lt;code&gt;.eslintrc&lt;/code&gt; in the root of our user folder, which would set global default linting rules. Instead, we will have an &lt;code&gt;.eslintrc&lt;/code&gt; file in the root of our project folder to set rules for this individual project.&lt;/p&gt;

&lt;p&gt;To create the file, in terminal go to the root of your project and run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;touch .eslintrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create the file and we can add our rules to it. Note this file begins with a full stop so might not be visible in mac finder or windows explorer but should be visible in your code editor/IDE.&lt;/p&gt;

&lt;p&gt;Open up the file and add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"env"&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;"es6"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"browser"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"jquery"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&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;"extends"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"airbnb"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"rules"&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="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;This will set our linting up to work with ES6, the browser, node, jQuery and use Airbnb’s configuration/ruleset. We can add extra rules that will override those in the Airbnb ruleset in the rules object. For example, if you would rather indent using tabs (you reckless animal), your rules would look like:&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="nl"&gt;"rules"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"indent"&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="s2"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tab"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;View more rules here: &lt;a href="https://eslint.org/docs/rules/" rel="noopener noreferrer"&gt;https://eslint.org/docs/rules/&lt;/a&gt;&lt;br&gt;
You can specify error, warn, or off to choose how a rule should be flagged or if it's disabled entirely.&lt;/p&gt;
&lt;h2&gt;
  
  
  Adding a gulp ESLint task
&lt;/h2&gt;

&lt;p&gt;Now we have ESLint installed and our rules ready, we need to add our gulp task and dependencies to our &lt;code&gt;gulpfile.js&lt;/code&gt; which will run our linting. In your gulp file you will need the following:&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;var&lt;/span&gt; &lt;span class="nx"&gt;gulp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gulp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;eslint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gulp-eslint&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;gulp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eslint&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;gulp&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;src&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./exampleCode.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="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;eslint&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;eslint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;eslint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;failAfterError&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;Be sure to link the src to your JavaScript file, or lint all the JS files in a directory using globbing - &lt;code&gt;return gulp.src(‘./folder-path/**/*.js’)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now if we run &lt;code&gt;gulp eslint&lt;/code&gt; from the command line it should highlight our issues. For example, if our &lt;code&gt;exampleCode.js&lt;/code&gt; file contained:&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;function&lt;/span&gt; &lt;span class="nf"&gt;exampleFunction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;testObject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Ash Connolly&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Sheffield&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;testObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;, &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;testObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;exampleFunction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;...it would return the following errors:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/Ash/sites/eslint-tutorial $gulp eslint
[15:37:42] Using gulpfile ~/Ash/sites/eslint-tutorial/gulpfile.js
[15:37:42] Starting 'eslint'...
[15:37:43]
/Users/Ash/Ash/sites/eslint-tutorial/exampleCode.js
  2:1   error  Expected indentation of 2 spaces but found 4    indent
  2:5   error  Unexpected var, use let or const instead        no-var
  3:1   error  Expected indentation of 4 spaces but found 8    indent
  3:9   error  Unnecessarily quoted property 'name' found      quote-props
  3:16  error  Strings must use singlequote                    quotes
  3:16  error  Missing space before value for key 'name'       key-spacing
  4:1   error  Expected indentation of 4 spaces but found 8    indent
  4:9   error  Unnecessarily quoted property 'location' found  quote-props
  4:20  error  Missing space before value for key 'location'   key-spacing
  4:20  error  Strings must use singlequote                    quotes
  4:31  error  Missing trailing comma                          comma-dangle
  5:1   error  Expected indentation of 2 spaces but found 4    indent
  6:1   error  Expected indentation of 2 spaces but found 4    indent
  6:12  error  Unexpected string concatenation                 prefer-template

✖ 14 problems (14 errors, 0 warnings)
  14 errors, 0 warnings potentially fixable with the `--fix` option.

[15:37:43] 'eslint' errored after 1.48 s
[15:37:43] ESLintError in plugin 'gulp-eslint'
Message:
    Failed with 14 errors
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can see parts of our code that don’t align with the rules.&lt;/p&gt;

&lt;h2&gt;
  
  
  ⚡️ The magical fix ️️⚡️
&lt;/h2&gt;

&lt;p&gt;One of the great things about ESLint is that it can &lt;strong&gt;fix our code for us&lt;/strong&gt;!&lt;br&gt;
To do this we need to create a new task that will both lint and fix the code.&lt;/p&gt;

&lt;p&gt;First of all we need to install an npm module called &lt;code&gt;gulp-if&lt;/code&gt; which allows to us to check if ESLint has fixed the file, before we update the file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install gulp-if --save-dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now in our gulp file we need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add the new gulp-if dependency&lt;/li&gt;
&lt;li&gt;Add a new function to check if ESLint has fixed the file&lt;/li&gt;
&lt;li&gt;And then add our new task that both lints and fixes the file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our entire gulp file will now look like this:&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;var&lt;/span&gt; &lt;span class="nx"&gt;gulp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gulp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;eslint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gulp-eslint&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;gulpIf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gulp-if&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// new dependency added&lt;/span&gt;

&lt;span class="nx"&gt;gulp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eslint&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;gulp&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;src&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./exampleCode.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="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;eslint&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;eslint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;eslint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;failAfterError&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// new function added to check if ESLint has run the fix&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eslint&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eslint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fixed&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// new lint and fix task&lt;/span&gt;
&lt;span class="nx"&gt;gulp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eslint-fix&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;gulp&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;src&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./exampleCode.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="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nf"&gt;eslint&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;fix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;eslint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="c1"&gt;// if running fix - replace existing file with fixed one&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;gulpIf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isFixed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;gulp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;eslint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;failAfterError&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 if we run &lt;code&gt;gulp eslint-fix&lt;/code&gt; we should get the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/Ash/sites/eslint-tutorial $gulp eslint-fix
[15:38:52] Using gulpfile ~/Ash/sites/eslint-tutorial/gulpfile.js
[15:38:52] Starting 'eslint-fix'...
[15:38:54] Finished 'eslint-fix' after 1.51 s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can see that all of our previous problems have been removed and the contents or our &lt;code&gt;exampleCode.js&lt;/code&gt; file has been updated in various ways.&lt;/p&gt;

&lt;p&gt;Before:&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;function&lt;/span&gt; &lt;span class="nf"&gt;exampleFunction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;testObject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Ash Connolly&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Sheffield&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;testObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;, &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;testObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;exampleFunction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After:&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;function&lt;/span&gt; &lt;span class="nf"&gt;exampleFunction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;testObject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Ash Connolly&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Sheffield&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;testObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&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;testObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&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="nf"&gt;exampleFunction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Changes made:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All indentation has been updated&lt;/li&gt;
&lt;li&gt;Var changed to ES6 const&lt;/li&gt;
&lt;li&gt;Unnecessary quoting of object property removed&lt;/li&gt;
&lt;li&gt;Double quotes changed to single in object values&lt;/li&gt;
&lt;li&gt;Space before object values added&lt;/li&gt;
&lt;li&gt;Added trailing comma for last object property&lt;/li&gt;
&lt;li&gt;Return string has been changed to an ES6* template literal.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And that's it! All our linting is working and it can fix our code for us! 😀&lt;br&gt;
When running the fix you should be confident that you understand the issues and changes made after running the fix to ensure that your JS behaves as expected.&lt;/p&gt;

&lt;p&gt;* Please note the last change involves converting a JavaScript string to an ES6 JavaScript template literal, which as an ES6 feature, is not supported in all browsers. To enable use of ES6 JavaScript in older browsers you will need to transpile it using &lt;a href="https://babeljs.io/" rel="noopener noreferrer"&gt;https://babeljs.io/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you would like to download a working demo containing all the code in this tutorial &lt;a href="https://ashconnolly.com/blog/eslint-tutorial-files.zip" rel="noopener noreferrer"&gt;please click here&lt;/a&gt; (be sure to run &lt;code&gt;npm i&lt;/code&gt; to install the dependencies).&lt;/p&gt;
&lt;h2&gt;
  
  
  Advanced example
&lt;/h2&gt;

&lt;p&gt;If you would like to see a more advanced gulp task where we can pass options via the command line, we can use the advanced example below (note this requires you to install a new dependency by running &lt;code&gt;npm i yargs --save-dev&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;var&lt;/span&gt; &lt;span class="nx"&gt;gulp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gulp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;eslint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gulp-eslint&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;gulpIf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gulp-if&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;argv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;yargs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;argv&lt;/span&gt;

&lt;span class="nx"&gt;gulp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eslint&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./exampleCode.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;fixCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fix&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;gulp&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;src&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;base&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nf"&gt;eslint&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;fix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fixCode&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="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;eslint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;gulpIf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isFixed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;gulp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;eslint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;failAfterError&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;We can now pass ESLint a specific file to lint, if we don’t it will use the default target in the gulp task, currently set to &lt;code&gt;./exampleCode.js&lt;/code&gt;. We can also set a flag to fix the file using &lt;code&gt;--fix&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here is a list of example commands you could pass to the &lt;code&gt;eslint&lt;/code&gt; gulp task:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gulp eslint                                      // lint default target(s)
gulp eslint --fix                                // lint + fix all default target(s)
gulp eslint --file ./folder/filename.js          // lint supplied file
gulp eslint --file ./folder/filename.js --fix    // lint + fix supplied file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enjoy, and happy linting! 😀&lt;/p&gt;

&lt;p&gt;If you like React, Next.js or front end development in general, feel free to follow and say hi on Twitter &lt;a href="https://ashconnolly.com/twitter" rel="noopener noreferrer"&gt;@AshConnolly_&lt;/a&gt;! 👋 🙂&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>The benefits of ☠️ skeleton screens / content placeholders and how to make them</title>
      <dc:creator>Ash Connolly</dc:creator>
      <pubDate>Mon, 27 Sep 2021 14:18:33 +0000</pubDate>
      <link>https://dev.to/ashconnolly/the-benefits-of-skeleton-screens-content-placeholders-and-how-to-make-them-4obg</link>
      <guid>https://dev.to/ashconnolly/the-benefits-of-skeleton-screens-content-placeholders-and-how-to-make-them-4obg</guid>
      <description>&lt;h2&gt;
  
  
  What are they?
&lt;/h2&gt;

&lt;p&gt;Skeleton screens are a way of communicating to the user that content is loading. They go by many names: content placeholders, interface previews, skeleton patterns, to name a few. It’s likely you’ll have seen them before, as they’re used by some big companies like Slack, Facebook and Medium.&lt;/p&gt;

&lt;p&gt;Facebook skeleton screen (credit to &lt;a href="https://css-tricks.com/building-skeleton-screens-css-custom-properties/" rel="noopener noreferrer"&gt;css-tricks&lt;/a&gt;):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Feq91nsqto3arab3pfxaw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Feq91nsqto3arab3pfxaw.png" alt="Facebook skeleton screen" width="655" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Slack skeleton screen:&lt;br&gt;
&lt;a href="https://media2.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%2Fc3qpizpbzar6ug9uyw5o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fc3qpizpbzar6ug9uyw5o.png" alt="Slack skeleton screen" width="800" height="483"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Medium skeleton screen:&lt;br&gt;
&lt;a href="https://media2.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%2Fblwrbroykoshu36hm13b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fblwrbroykoshu36hm13b.png" alt="Medium skeleton screen" width="800" height="687"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;They aren’t exactly a new thing, &lt;a href="https://twitter.com/lukew" rel="noopener noreferrer"&gt;Luke Wroblewski&lt;/a&gt; &lt;a href="https://www.lukew.com/ff/entry.asp?1797" rel="noopener noreferrer"&gt;introduced the concept&lt;/a&gt; during the development of his Polar app (now acquired by Google) all the way back in 2013. They're now seeing more widespread adoption and for good reason.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why use them?
&lt;/h2&gt;

&lt;p&gt;When content is loading, either on page load or after an interaction, it's important to communicate this to the user in an appropriate way. Skeleton screens give us the opportunity to indicate the type of content that's loading, which helps increase the perceived performance of our interface:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Perceived performance is a measure of how fast something feels to the user. The idea is that users are more patient and will think of a system as faster if they know what's going on and can anticipate content before it's actually there. It's a lot about managing expectations and keeping the user informed."&lt;br&gt;&lt;br&gt;
— &lt;a href="https://css-tricks.com/building-skeleton-screens-css-custom-properties/" rel="noopener noreferrer"&gt;Max Böck&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It also gives a much smoother transition when the skeleton screen is removed and the content is shown.&lt;/p&gt;

&lt;p&gt;What about good old progress indicators?&lt;br&gt;
We could use a progress indicator (like a spinner) to show this. However, after years of use, users are all too familiar and frustrated with progress indicators:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"With the introduction of these progress indicators, we had made people watch the clock. As a result, time went slower and so did our app."&lt;br&gt;&lt;br&gt;
— &lt;a href="https://www.lukew.com/ff/entry.asp?1797" rel="noopener noreferrer"&gt;Luke Wroblewski&lt;/a&gt;, &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It's also quite a jarring experience to see a small progress indicator replaced by a large chunk of content.&lt;/p&gt;
&lt;h2&gt;
  
  
  Creating the skeleton screens
&lt;/h2&gt;

&lt;p&gt;When animating web elements, it's important to prioritise performance. The last thing you want is for your skeleton screens to cause unnecessary load on your device, slowing down your webpage and creating a &lt;a href="http://jankfree.org/" rel="noopener noreferrer"&gt;janky&lt;/a&gt; experience for the user.&lt;/p&gt;

&lt;p&gt;I had three simple requirements when creating them to ensure high performance and flexibility in use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Have as few animating elements as possible&lt;/li&gt;
&lt;li&gt;Only use &lt;a href="https://www.smashingmagazine.com/2016/12/gpu-animation-doing-it-right/" rel="noopener noreferrer"&gt;GPU-based animations&lt;/a&gt;, like &lt;code&gt;translate&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Use modifiers classes to affect the height and repetition of elements so that these skeleton screens are customisable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To have as few animating elements as possible, there’s a small bit of visual trickery going on. We only have one element animating, then we overlay white lines to make it appear as if there are many elements being animated. In the example below the overlay can be toggled on and off:&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/ashconnolly/embed/VXeKBV/?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;To reduce the markup, the overlays are created using linear gradients. This ensures that they will repeat endlessly, regardless of the height of the component. This means if we want a skeleton screen to have more repetition, for example showing eight lines instead of four, we can simply change its height using a modifier class:&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/ashconnolly/embed/EEPqag?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;This makes the components scalable and flexible without the need for extra, repetitive DOM elements.&lt;/p&gt;

&lt;h2&gt;
  
  
  More skeleton screens for more scenarios
&lt;/h2&gt;

&lt;p&gt;As mentioned earlier, skeleton screens should indicate the type of content that's loading. This means we’ll likely need several skeleton screens to represent the various types of content:&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/ashconnolly/embed/XEXvoa?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;I won’t dive into the code, but it can all be seen in the codepen above. It utilises several &lt;code&gt;SCSS&lt;/code&gt; variables and mixins to make customising it as easy as possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  A final performance check
&lt;/h2&gt;

&lt;p&gt;It’s a good idea to check the skeleton screens are as performant as can be to ensure the best user experience. Thankfully Chrome Developer Tools makes this ver easy with its frame-rate meter found in Render Settings (&lt;a href="https://developer.chrome.com/devtools/docs/rendering-settings" rel="noopener noreferrer"&gt;click here&lt;/a&gt; for instructions).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fyky3jfxbhxiaqf20n8io.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fyky3jfxbhxiaqf20n8io.gif" alt="gif of chrome frame rate showing 60 fps" width="626" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, our frame rate is a fairly consistent 60fps. This means our skeleton screens are performing well and not negatively impacting the page.&lt;/p&gt;

&lt;p&gt;And there we have it. We now have in place lightweight, performant, and flexible skeleton screens to help create a better user experience.&lt;/p&gt;

&lt;p&gt;If you like React, Next.js and front end development, feel free to follow me and say hi on &lt;a href="https://ashconnolly.com/twitter" rel="noopener noreferrer"&gt;twitter.com/AshConnolly_&lt;/a&gt;! 👋 😃&lt;/p&gt;

&lt;p&gt;Stunning cover photo by &lt;a href="https://unsplash.com/@szmigieldesign" rel="noopener noreferrer"&gt;Lukasz Szmigiel on Unsplash!&lt;/a&gt;&lt;/p&gt;

</description>
      <category>html</category>
      <category>css</category>
      <category>beginners</category>
      <category>ux</category>
    </item>
    <item>
      <title>Prevent "window is not defined" Errors With a useClientSide() Custom Hook</title>
      <dc:creator>Ash Connolly</dc:creator>
      <pubDate>Mon, 27 Sep 2021 11:09:41 +0000</pubDate>
      <link>https://dev.to/ashconnolly/prevent-window-is-not-defined-errors-with-a-useclientside-custom-hook-20f8</link>
      <guid>https://dev.to/ashconnolly/prevent-window-is-not-defined-errors-with-a-useclientside-custom-hook-20f8</guid>
      <description>&lt;p&gt;&lt;strong&gt;TLDR:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There is no &lt;code&gt;window&lt;/code&gt; object on the server - trying to access the &lt;code&gt;window&lt;/code&gt; object will thrown an error in server side rendered code, and in Node.js based development environments&lt;/li&gt;
&lt;li&gt;You can access &lt;code&gt;window&lt;/code&gt; in a &lt;code&gt;useEffect&lt;/code&gt; hook, as &lt;code&gt;uesEffect&lt;/code&gt; only runs on the client&lt;/li&gt;
&lt;li&gt;We want to avoid having to repeat this &lt;code&gt;useEffect&lt;/code&gt; logic in every component that needs to access &lt;code&gt;window&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Instead we can move this logic into a custom react hook to keep everything super tidy! 🎉&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The finished &lt;code&gt;useClientSide()&lt;/code&gt; hook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useClientSide&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;func&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;useEffect&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="nf"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;func&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="nx"&gt;func&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;value&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;getUserAgent&lt;/span&gt; &lt;span class="o"&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="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userAgent&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Example&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userAgent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useClientSide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;getUserAgent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;userAgent&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;userAgent&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&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;Heres a &lt;a href="https://stackblitz.com/edit/useclientside-hook?file=pages%2Findex.js" rel="noopener noreferrer"&gt;stackblitz⚡ Next.js demo&lt;/a&gt;. &lt;/p&gt;

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

&lt;p&gt;When trying to access window with react frameworks like Next.js you might run into issues when trying to access the window object and see the following error: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fdawxjxnxxv94b6rqex6m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fdawxjxnxxv94b6rqex6m.png" alt="window is not defined error" width="513" height="119"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is because somewhere in your app window is trying to be accessed from the server, where it does not exist. &lt;/p&gt;

&lt;p&gt;In Next.js this could be because we're trying to access &lt;code&gt;window&lt;/code&gt; on a page that uses &lt;a href="https://nextjs.org/docs/basic-features/data-fetching#getserversideprops-server-side-rendering" rel="noopener noreferrer"&gt;getServerSideProps&lt;/a&gt;, which makes the page a server side rendered (SSR).&lt;/p&gt;

&lt;p&gt;You might think:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"But my app is static, with no server side rendering, why am I getting Server errors??"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Most development environments are created by running a local Node.js server (Next.js does this). And as Node.js runs on the server, there is no &lt;code&gt;window&lt;/code&gt; object&lt;/p&gt;

&lt;h2&gt;
  
  
  Example Problem: Device Detection
&lt;/h2&gt;

&lt;p&gt;Say if you had a button, and on a touch device you want it to say &lt;strong&gt;"Tap here"&lt;/strong&gt;, otherwise it would say &lt;strong&gt;"Click here"&lt;/strong&gt;, you could check the &lt;code&gt;window&lt;/code&gt; object for &lt;code&gt;navigator.userAgent&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;This would tell us what device type they're on, like Android or IOS, and we could infer if it's a touch device. There are other ways to check touch devices, but for the purposes of this tutorial, we'll do it this way.&lt;/p&gt;

&lt;p&gt;You could approach it like this for client side rendered apps:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isTouchDevice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ua&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userAgent&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ua&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/Android|webOS|iPhone|iPad|iPod|BlackBerry|BB10|PlayBook|IEMobile|Opera Mini/i&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Example&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isTouch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;isTouchDevice&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isTouch&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Tap here!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Click here!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&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;Note: I won't show the code for &lt;code&gt;isTouchDevice()&lt;/code&gt; again, just to keep the code examples clearer. Just remember it returns &lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt;! :)&lt;/p&gt;

&lt;p&gt;Here we are getting the &lt;code&gt;window.navigator.userAgent&lt;/code&gt; and then passing it into our function and checking if it contains any identifiers for touch devices, if it does return &lt;code&gt;true&lt;/code&gt;, otherwise return &lt;code&gt;false&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;However, this code will cause the &lt;code&gt;window is not defined&lt;/code&gt; error, as our local dev environment is running on a server, where there is no window object! &lt;/p&gt;

&lt;h2&gt;
  
  
  A Common, But Not Ideal Solution 🙅‍♂️
&lt;/h2&gt;

&lt;p&gt;We could check if window is not defined by adding this line at the top of any function that tries to access window:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;undefined&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note you cannot do &lt;code&gt;window === undefined&lt;/code&gt; as this assume would &lt;code&gt;window&lt;/code&gt; is declared, but has no value. When actually, &lt;code&gt;window&lt;/code&gt; hasn't been declared at all. This is the difference between:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;undefined&lt;/code&gt;: a variable that is declared but not initialised or defined (aka not given a value)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;not defined&lt;/code&gt;: a variable that has not been declared at all &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using &lt;code&gt;typeof window === 'undefined'&lt;/code&gt; is far from ideal and can cause rendering issues as explained in this brilliant in-depth article by &lt;a class="mentioned-user" href="https://dev.to/joshwcomeau"&gt;@joshwcomeau&lt;/a&gt;: &lt;a href="https://www.joshwcomeau.com/react/the-perils-of-rehydration/" rel="noopener noreferrer"&gt;The Perils Of Rehydration&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution: Only Reference Window On The Client 👍
&lt;/h2&gt;

&lt;p&gt;We can do this by running our &lt;code&gt;isTouchDevice()&lt;/code&gt; function inside a &lt;code&gt;useEffect&lt;/code&gt;, which only runs on the client when the component mounts.&lt;/p&gt;

&lt;p&gt;We can also store the return value of &lt;code&gt;isTouchDevice()&lt;/code&gt; in state by using &lt;code&gt;useState&lt;/code&gt;. Storing it in state means that it's value is preserved during re-renders.&lt;/p&gt;

&lt;p&gt;Here's a working example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&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;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isTouchDevice&lt;/span&gt; &lt;span class="o"&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="c1"&gt;// returns true or false, see code above&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Example&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isTouch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setisTouch&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&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="nf"&gt;setisTouch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;isTouchDevice&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isTouch&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Tap here!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Click here!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&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;Once the component mounts (which only happens on the client) the function is run and the state of &lt;code&gt;isTouch&lt;/code&gt; is updated to a &lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt; value, which causes our button to show the correct messaging.&lt;/p&gt;

&lt;p&gt;🤔 But having to do this every time you want to use the &lt;code&gt;isTouchDevice&lt;/code&gt; function is really a hassle and will lead to lots of needless repetition of &lt;code&gt;useEffect()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;What would be much neater is a custom react hook that obfuscates all of this logic, allowing us to do something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Example&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isTouch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useIsTouchDevice&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isTouch&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Tap here!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Click here!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&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;That would help make things easier, but something else would be better...&lt;/p&gt;

&lt;h2&gt;
  
  
  A Step Further: Making a &lt;code&gt;useClientSide()&lt;/code&gt; Hook! 🔥
&lt;/h2&gt;

&lt;p&gt;What would be even better than a &lt;code&gt;useIsTouchDevice()&lt;/code&gt; hook? A flexible, generalized custom hook that could take any function as an argument, and only run that function on the client side: a &lt;code&gt;useClientSide()&lt;/code&gt; hook! 😃&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useClientSide&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;func&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;useEffect&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="nf"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;func&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="nx"&gt;func&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;value&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;getUserAgent&lt;/span&gt; &lt;span class="o"&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="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userAgent&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Example&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userAgent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useClientSide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;getUserAgent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;userAgent&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;userAgent&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&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;What this custom hook is doing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;taking a function as an argument&lt;/li&gt;
&lt;li&gt;calling that function in a &lt;code&gt;useEffect&lt;/code&gt; hook (which is only done on the client)&lt;/li&gt;
&lt;li&gt;saving what is returned by that function to the local state of the &lt;code&gt;useClientSide()&lt;/code&gt; hook&lt;/li&gt;
&lt;li&gt;then returning that local state value &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now let's use it with our &lt;code&gt;isTouchDevice()&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&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;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isTouchDevice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ua&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userAgent&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ua&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/Android|webOS|iPhone|iPad|iPod|BlackBerry|BB10|PlayBook|IEMobile|Opera Mini/i&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&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;useClientSide&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;func&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;useEffect&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="nf"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;func&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="nx"&gt;func&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;value&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Example&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isTouch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useClientSide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isTouchDevice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isTouch&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Tap here!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Click here!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&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;Heres a &lt;a href="https://stackblitz.com/edit/useclientside-hook?file=pages%2Findex.js" rel="noopener noreferrer"&gt;stackblitz⚡ Next.js demo&lt;/a&gt;.  &lt;/p&gt;

&lt;p&gt;If you want to check the &lt;code&gt;isTouch&lt;/code&gt; is working as expected, just simulate a mobile device using your browser's dev tools. Like &lt;a href="https://developer.chrome.com/docs/devtools/device-mode/" rel="noopener noreferrer"&gt;device mode&lt;/a&gt; in chrome.&lt;/p&gt;

&lt;h2&gt;
  
  
  Done!
&lt;/h2&gt;

&lt;p&gt;There we go! All working! We have a useful, reusable custom hook that allows use to run any client specific code easily! 😃 🎉&lt;/p&gt;

&lt;p&gt;I built this hook while building &lt;a href="http://episoderatings.com" rel="noopener noreferrer"&gt;episoderatings.com&lt;/a&gt; (a way to view episode ratings in a graph), to help me easily detect touch devices and display specific messaging! &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fpmu59cj5jrtxau33zu3z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fpmu59cj5jrtxau33zu3z.png" alt="episode ratings" width="602" height="593"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you like React, Next.js and front end development, feel free to follow me and say hi on &lt;a href="https://ashconnolly.com/twitter" rel="noopener noreferrer"&gt;twitter.com/AshConnolly_&lt;/a&gt;! 👋 🙂&lt;/p&gt;

&lt;p&gt;Stunning cover photo by &lt;a href="https://unsplash.com/photos/dEOC8M_lmxI" rel="noopener noreferrer"&gt;Spencer Watson on Unsplash!&lt;/a&gt;&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>react</category>
      <category>javascript</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How To Quickly Add Cypress To Your Next.js App</title>
      <dc:creator>Ash Connolly</dc:creator>
      <pubDate>Mon, 31 May 2021 11:14:32 +0000</pubDate>
      <link>https://dev.to/ashconnolly/how-to-quickly-add-cypress-to-your-next-js-app-2oc6</link>
      <guid>https://dev.to/ashconnolly/how-to-quickly-add-cypress-to-your-next-js-app-2oc6</guid>
      <description>&lt;p&gt;Pssst... you might also like this guide on adding Jest to your Next.js App. Combined with Cypress, it's a great setup! 😃&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/ashconnolly" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&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%2Fuser%2Fprofile_image%2F204950%2Fac281f92-162f-4f59-91bf-2fbcd762187d.jpeg" alt="ashconnolly"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/ashconnolly/how-to-quickly-add-jest-to-your-next-js-app-1h32" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;How To Quickly Add Jest To Your Next.js App&lt;/h2&gt;
      &lt;h3&gt;Ash Connolly ・ May 30 '21&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#nextjs&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#react&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#beginners&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#javascript&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Why use Cypress for end to end / integration testing?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Writing Cypress tests are easy and feel intuitive&lt;/li&gt;
&lt;li&gt;Good developer experience with quick setup&lt;/li&gt;
&lt;li&gt;The tests resemble how apps are used, not how they are implemented, which means they don't need changing even if you refactor your whole app!&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Adding Cypress
&lt;/h1&gt;

&lt;h3&gt;
  
  
  Install the dependencies
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;yarn: &lt;code&gt;yarn add cypress start-server-and-test --dev&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;npm: &lt;code&gt;npm install cypress start-server-and-test --save-dev&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;start-server-and-test&lt;/code&gt; will allow us to run our app locally before starting Cypress.&lt;/p&gt;

&lt;p&gt;Now we need to open Cypress for the first time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;yarn: &lt;code&gt;yarn run cypress open&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;npm: &lt;code&gt;npx cypress open&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This will add a bunch of folders to the root of your app:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;cypress/fixtures → these are our mock server response&lt;/li&gt;
&lt;li&gt;cypress/integration → these our UI tests&lt;/li&gt;
&lt;li&gt;cypress/plugins → these are, you guessed it, cypress plugins!&lt;/li&gt;
&lt;li&gt;cypress/supports → these are reusable functions to use in our tests&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This will also have added a bunch of helpful example tests in &lt;code&gt;cypress/integration/examples&lt;/code&gt; too!&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding scripts
&lt;/h3&gt;

&lt;p&gt;Now we need to add some scripts to our &lt;code&gt;package.json&lt;/code&gt; so we can run cypress. &lt;/p&gt;

&lt;p&gt;What we could do open two terminal windows... &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In one we would run our app locally using &lt;code&gt;yarn dev&lt;/code&gt; or &lt;code&gt;yarn start&lt;/code&gt; (depending on your setup). &lt;/li&gt;
&lt;li&gt;And in the other terminal run the cypress tests against our local app.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But that's not ideal. Instead we want to be able to run a single command that will do both of these for us. This will make running the tests in a release pipeline (like jenkins, circle CI, or github actions etc) easier to do.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; I use &lt;code&gt;yarn dev&lt;/code&gt; to run my app locally (as it's a next.js app) on port &lt;code&gt;3000&lt;/code&gt;. if you use a different command (like &lt;code&gt;start&lt;/code&gt;) or a different port, be sure to change it in the scrips below.&lt;/p&gt;

&lt;p&gt;Add the following scripts (the ones starting with &lt;code&gt;cy&lt;/code&gt;) to your package.json:&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;dev&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;next dev&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;cy:open-only&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;cypress open&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;cy:run-only&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;cypress run&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;cy:open&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;start-server-and-test dev 3000 cy:open-only&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;cy:run&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;start-server-and-test dev 3000 cy:run-only&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;Remember, the &lt;code&gt;start-server-and-test&lt;/code&gt; command will allow us to run our app locally before starting Cypress.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;cy:open-only&lt;/code&gt; will open the cypress GUI&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cy:run-only&lt;/code&gt; will run cypress tests&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cy:open&lt;/code&gt; will run &lt;code&gt;dev&lt;/code&gt; to run our app locally, and then run &lt;code&gt;cy:open-only&lt;/code&gt; to open the cypress GUI.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cy:run&lt;/code&gt; will run &lt;code&gt;dev&lt;/code&gt; to run our app locally, and then run &lt;code&gt;cy:run-only&lt;/code&gt; to run the cypress tests in the terminal.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first two commands on their own will not work unless your app is running. Which is why we have the last two commands, which will run our app locally, then run the tests, without the need to run our app in a separate terminal.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding our first test
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Add a test file to &lt;code&gt;./cypress/integration/&lt;/code&gt; called &lt;code&gt;app.spec.js&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;App&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should load our app and show content&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;http://localhost:3000&amp;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;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Welcome to Next.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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Be sure to update the &lt;code&gt;cy.contains&lt;/code&gt; to reference some text found on your homepage. I'm doing this in a brand new Next.js app, so I'm checking for &lt;code&gt;Welcome to Next.js!&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now if we run:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;yarn: &lt;code&gt;yarn cy:run&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;npm: &lt;code&gt;npm run cy:run&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We will see our tests running in the terminal!:&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%2Fbxrdng8mg95zjnkzi5ko.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%2Fbxrdng8mg95zjnkzi5ko.png" alt="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bxrdng8mg95zjnkzi5ko.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can also open the Cypress GUI and see our tests run in a browser: Then we'll open cypress&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;yarn: &lt;code&gt;yarn cy:open&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;npm: &lt;code&gt;npm run cy:open&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And we should see our Cypress testing window, showing all available tests:&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%2Fwlaf9613vrs25x98bx5e.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%2Fwlaf9613vrs25x98bx5e.png" alt="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wlaf9613vrs25x98bx5e.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note: I have collapsed the folder called &lt;code&gt;examples&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Click the &lt;code&gt;app.spec.js&lt;/code&gt; and it will pop open a browser, navigate to your app, and run our tests against it!&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%2Fbmzh57hqtfyixikwu5yc.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%2Fbmzh57hqtfyixikwu5yc.png" alt="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bmzh57hqtfyixikwu5yc.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Done!
&lt;/h2&gt;

&lt;p&gt;And that's it! We have added Cypress to our Next.js app! 🎉 😃 &lt;/p&gt;

&lt;p&gt;Now we can write end-to-end tests for all of our user journeys! For further learning on Cypress, I highly recommend the "Cypress in a Nutshell" video by &lt;a href="https://dev.to/amirrustam"&gt;Amir Rustamzadeh&lt;/a&gt; (Head of Developer Experience at Cypress). It's a very practical and concise watch!&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/LcGHiFnBh3Y"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;If you're interested in hearing more tips about React, Next.js, and JavaScript, feel free to &lt;a href="http://ashconnolly.com/twitter" rel="noopener noreferrer"&gt;follow me on twitter&lt;/a&gt;! 😃&lt;/p&gt;

&lt;p&gt;Stunning cover photo by &lt;a href="https://unsplash.com/@sir_jarvis?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Matthew on Unsplash!&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>beginners</category>
      <category>javascript</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>How To Quickly Add Jest To Your Next.js App</title>
      <dc:creator>Ash Connolly</dc:creator>
      <pubDate>Sun, 30 May 2021 18:22:05 +0000</pubDate>
      <link>https://dev.to/ashconnolly/how-to-quickly-add-jest-to-your-next-js-app-1h32</link>
      <guid>https://dev.to/ashconnolly/how-to-quickly-add-jest-to-your-next-js-app-1h32</guid>
      <description>&lt;p&gt;Pssst.. you might also like this guide on adding Cypress to your Next.js App. Combined with Jest, it's a great setup! &lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/ashconnolly" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&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%2Fuser%2Fprofile_image%2F204950%2Fac281f92-162f-4f59-91bf-2fbcd762187d.jpeg" alt="ashconnolly"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/ashconnolly/how-to-add-jest-to-your-next-js-app-2a3p" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;How To Quickly Add Cypress To Your Next.js App (deprecated)&lt;/h2&gt;
      &lt;h3&gt;Ash Connolly ・ May 30 '21&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#nextjs&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#javascript&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#beginners&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#react&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;h1&gt;
  
  
  Adding Jest
&lt;/h1&gt;

&lt;p&gt;Add the jest dependency:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;yarn: &lt;code&gt;yarn add jest --dev&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;npm: &lt;code&gt;npm install jest --save-dev&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Add a &lt;code&gt;jest&lt;/code&gt; script to your package.json so that we can run jest against our test files:&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="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;"jest"&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"&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;Add a test file anywhere in your app. For now lets call it &lt;code&gt;example.test.js&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&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;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sum()&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should return 5 if given 2 and 3 &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&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 if we run &lt;code&gt;yarn jest&lt;/code&gt; or &lt;code&gt;npm run jest&lt;/code&gt; we'll see the test is found, it runs, and passes! ✅&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%2Fe2balbg5gh2itomof04a.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%2Fe2balbg5gh2itomof04a.png" alt="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e2balbg5gh2itomof04a.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Jest with Cypress
&lt;/h2&gt;

&lt;p&gt;If you're using Cypress, we need to add our own &lt;code&gt;jest.config.js&lt;/code&gt; file to tell Cypress to ignore our cypress tests. Otherwise Jest will pick them up and try to run jest on the files and cause an error. This is because Jest is set up to run tests on files that end in &lt;code&gt;spec.js&lt;/code&gt; or &lt;code&gt;test.js&lt;/code&gt; and Cypress tests end in &lt;code&gt;spec.js&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&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="c1"&gt;// An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader&lt;/span&gt;
  &lt;span class="na"&gt;modulePathIgnorePatterns&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="s1"&gt;./cypress&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;ul&gt;
&lt;li&gt;You can also setup a jest config file using &lt;code&gt;npx jest --init&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Done!
&lt;/h2&gt;

&lt;p&gt;And that's it! We have added Jest to our Next.js app! 🎉 😃 &lt;/p&gt;

&lt;p&gt;Now we can unit test all of our JS logic / helper functions! For more details on how to write tests, be sure to check the &lt;a href="https://jestjs.io/docs/using-matchers" rel="noopener noreferrer"&gt;Jest Docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you're interested in hearing more tips about React, Next.js, and JavaScript, feel free to &lt;a href="http://ashconnolly.com/twitter" rel="noopener noreferrer"&gt;follow me on twitter&lt;/a&gt;!😃&lt;/p&gt;

&lt;p&gt;Epic cover photo by &lt;a href="https://unsplash.com/@kensmithdesign?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Ken Smith on Unsplash!&lt;/a&gt;&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>react</category>
      <category>beginners</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
