Static Analysis with ESLint and LWC
Tags: webdev
Published: 2022-02-03 15:22:59

As we [learned in our last post](https://dev.to/salesforcedevs/writing-clean-and-consistent-code-with-static-analysis-using-pmd-and-apex-nn3), static analysis is useful in various situations, whether that’s keeping a codebase consistent, catching potential performance issues, or rewriting code to be more idiomatic. In our previous post, we used PMD to analyze Apex code. In this post, however, we’ll consider how to analyze another Salesforce programming environment: Lighting Web Components.

Salesforce developed [Lightning Web Components](https://lwc.dev/) (LWC) as a fast, enterprise-grade wrapper around vanilla [web components](https://developer.mozilla.org/en-US/docs/Web/Web_Components). LWC is built on the same HTML, CSS, and JavaScript that powers the web, so any analyzer for those languages can be applied here.


In this post, we’ll integrate [ESLint](https://eslint.org/) with your LWC project. We’ll also learn how to integrate ESLint with your editor and your CI system, just like we did with PMD.


### Prerequisites

Before getting started, you should have a relatively recent version of [Node](https://nodejs.org/en/) installed. Some familiarity with JavaScript can also help, but it’s not essential. We’ll also be using [VS Code](https://code.visualstudio.com/) for this tutorial.

We’ll start by cloning our sample LWC project from this Git repository:  [https://github.com/gjtorikian/sfdc-linting](https://github.com/gjtorikian/sfdc-lintingdreamhouse-sfdx.git)

This repository is a forked copy of [the dreamhouse-lwc project](https://github.com/trailheadapps/dreamhouse-lwc), except it has (intentionally) introduced some errors. We’ll use this to demonstrate how ESLint works.

Run `npm install` to download the project’s dependencies. ESLint is among them, but you’re also getting [LWC specific ESLint plugins](https://github.com/salesforce/eslint-plugin-lwc). We’ll go into more details on these below!


### Integrating ESLint

The custom LWC components in this repo are stored in the `force-app/main/default/lwc` directory. When you open this up, you’ll see several directories, each representing a single component, with their own HTML and JavaScript files.

Since JavaScript is an interpreted—rather than compiled—language, there’s no inherent way to validate whether a code path is correct until it’s executed. With Apex, Kotlin, C, or other compiled languages, a compiler steps in to ensure that all of your code adheres to the language’s grammatical rules. With JavaScript, Ruby, Python, or other interpreted languages, you often won’t know whether something is valid until a user encounters it.

This is why a static analyzer is _crucial_ for these interpreted languages. To demonstrate their power, let’s run ESLint and see what happens. For this project, ESLint has already been configured as [an npm script](https://docs.npmjs.com/cli/v6/using-npm/scripts), so we don’t need to do any configuration to run it. In the directory where you cloned your project, type this line at the command prompt:


```
npm run lint
```

You should see the following output:

```
> dreamhouse-lwc@1.0.0 lint
> eslint **/{lwc,aura}/**/*.js


dreamhouse-lwc/force-app/main/default/lwc/daysOnMarket/daysOnMarket.js
  39:22  error  Parsing error: Unexpected token, expected "(" (39:22)

dreamhouse-lwc/force-app/main/default/lwc/propertyTile/propertyTile.js
  7:15  error  'selectedEvent' is assigned a value but never used  no-unused-vars

✖ 2 problems (2 errors, 0 warnings)
```


The second error is similar to what we saw in our Apex project: a variable was created, but unused. However, the first error is much more nefarious. If you open the `daysOnMarket/daysOnMarket.js` file and navigate to line 39, you’ll notice that the final conditional is incorrectly marked as <code>else if</code></strong>, when it should simply be <strong><code>else</code></strong>:


```
if (this.daysOnMarket < MAX_DAYS_NORMAL_STATUS) {
  this.status = 'normal'
} else if (this.daysOnMarket < MAX_DAYS_WARNING_STATUS) {
  this.status = 'warning'
} else if {
  this.status = 'alert'
}
```


Catching this kind of error in a unit test is not guaranteed. This is the kind of subtle JavaScript bug that a static analyzer is perfectly designed for capturing and reporting on. 

ESLint rule configuration is similar to that of PMD. The main difference is that ESLint uses JSON notation instead of XML. Open the file at `force-app/main/default/lwc/.eslintrc.json` to see how these rules are defined. Right at the top, you’ll see a line that reads:


```
"extends": ["@salesforce/eslint-config-lwc/recommended", "prettier"],
```


Here, our ruleset is extending the `@salesforce/eslint-config-lwc` package we installed earlier. Our project also has the option of adding new rules or inheriting from any other npm package which has ESLint rules configured.

 
### Integrating ESLint in VS Code

Rather than running ESLint on the command line, let’s integrate it directly into the editor. This allows us to get immediate feedback on the code as it’s being written, without switching back and forth between the terminal. 

There’s [a plugin for VS Code that brings ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) right into the editor. When you visit that page and click **Install**, this downloads and installs the plugin to your editor.

Return to the `daysOnMarket.js` file. You’ll notice that the previously offending `else if` line now has a red, squiggly line underneath it. If you place your mouse cursor over it, a dialog box pops open that shows the error message from ESLint:


![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qpmvq0phaxx2qgze2o7q.png)


### Integrating ESLint in CI

At this point, you’ve seen how ESLint runs across your entire project and how it can be applied to individual files in your editor. The final location for integrating ESLint exists within your CI test suite. Just as your test suite fully tests your application’s logic, your static analyzer should also run across your code to identify any potential errors or issues.

Since ESLint is a dependency installed through npm, your CI servers don’t need any additional configuration to support it. If you’re using GitHub Actions, you can just add a separate step in your actions YAML file to run the program, just as you do on the command line: 


```
name: CI
on: push
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: Install modules
      run: npm install
    - name: Run ESLint
      Run: npm run lint
```


If you’re not using GitHub actions, you can simply run ESLint within a script:

```
#!/bin/sh

set -e

npm run lint
```


Since ESLint fails with a non-zero status, running this script will mark your CI as a failure, too, if there are any issues.


### Conclusion

In this series, we’ve taken a broad look at how static analysis helps keep your code clean, consistent, and effective. Static analysis can help catch those smaller problems that might get overlooked in a code review, making it an ideal component in your software development toolchain. By integrating a tool such as ESLint into your CI test suite, you can be sure that future changes won’t introduce any undesirable effects.

For learning more about working with LWC, Salesforce has [Trailhead badges](https://trailhead.salesforce.com/en/search?keywords=lwc) on various topics. The [ESLint website](https://eslint.org/docs/about/) also provides some more information on the philosophy and goals of the project. If you’d like to explore more about how to bring Salesforce together with VS Code, there’s [a whole suite of tools](https://marketplace.visualstudio.com/items?itemName=salesforce.salesforcedx-vscode) that can be installed as plugins to make writing code much easier!