JavaScript Tools I use in 2020

Submitted by Jeff on

While I don't think the tools I am using will change yearly, I figured it would be good to put the year to get a time perspective down the road. This is the year I started to use NPM and NodeJS to put my JavaScript into a package to help manage the code. I did a bit of research and tried to find things similar to the tools and metrics that I use in PHP.  Another criteria is to be able to bundle and compress my code to make loading easier and faster. So here is what I have, I am going to show some of the shorter configurations here then I will show in more detail in other articles as need later.

To start we need a task runner. On the PHP side I use Ant as it is compatible with the CI platform Jenkins. For the JavaScript it won't directly be interacting with the CI so I found Grunt. Grunt is one of a few JavaScript task runners. This one looked like it had some following and had some plugins for tools that I wanted to use. The configuration is an exported function that you define a configuration in a JSON format. It seemed to be able to build my packages as I needed. To install can use this package:

npm --save install grunt

This will install Grunt in the production side of the NPM package as we will need that for the when you install the production version of your package.

The next package that I installed is Complexity. It checks the complexity of the code, so if you have functions with a lot of if statements it will flag those as something that needs to be changed. This is similar to phpmd the mess detector, but more focused on complexity.

npm --save install grunt-complexity

We need this in the production list of packages because Grunt loads all of the utilities even if they are not used in a task. So pretty much all of the grunt-* packages will need to be install in production. Here is what we will be adding to the Grunt script:

    complexity: {
      generic: {
        src: ['src/*.js'],
        options: {
          breakOnErrors: true,
          //jsLintXML: false,
          checkstyleXML: 'build/logs/checkstyle.xml',
          pmdXML: 'build/logs/pmd.xml',
          errorsOnly: false,
          cyclomatic: 10, //[3, 7, 12],
          halstead: 20, //[8, 13, 20],
          //maintainability: 100,
          hideComplexFunctions: false,
          broadcast: false
        }
      }
    }

Most of what you see is that it looks at all of the .js files in src, to search subdirectories you need 'src/**/*.js'. I put all of the reports into a build directory to be pulled by the CI. I still have some playing to do with this, but what I changed from the default help move the project forward until I can learn more.

Next is a package that will help make my code look pretty in a standard way. The package is elint

npm --save-dev install eslint eslint-config-google

This will install the eslint package and add the standard that you want to use for your code. Since Google seems to be heading some of the JavaScript advances I figured they would be good to model my code after. So the code will have the same format that Google uses. Here is what I put into the eslintrc.json file which can be used in the command line or the Grunt script.

{
    "env": {
        "browser": true,
        "es6": true
    },
    "extends": [
        "google"
    ],
    "globals": {
        "Atomics": "readonly",
        "SharedArrayBuffer": "readonly"
    },
    "parserOptions": {
        "ecmaVersion": 2018,
        "sourceType": "module"
    },
    "rules": {
        "max-len": [
            "error",
            {
                "code": 80,
                "ignorePattern": "/.*(\/.*)*/"
            }
        ]
    }
}

Speaking of Grunt we need to install the extension of Grunt that allows us to use ESLint in a task. Which we need to add to the production side of the package.

npm --save install grunt-eslint

Here is what I put into the Grunt script.

    eslint: {
      options: {
        configFile: 'eslintrc.json'
      },
      target: ['src/*.js']
    },

The next tool that I installed is jscpd. This package will search your code for duplicate code. As it is bad practice to have code that does the exact same thing in multiple areas. As it makes it easier to update in one spot than multiples.  For the install I will install the grunt plugin on the production side of the NPM package and the main package on the development side of the NPM package.

npm --save install grunt-jscpd
npm --save-dev install jscpd

Here is what I put into the grunt configuration, I have it output a report for the Jenkins CI when it is a build other wise it outputs the information to the screen if I run the cli task.

    jscpd: {
      cli: {
        path: 'src/'
      },
      build: {
        output: 'build/logs/jscpd-report.xml',
        path: 'src/'
      }
    },

In the jscpd.json is where I put the details of jscpd on where to look and where to output. This file might not be needed if you don't run jscpd without grunt.

{
    "path": "src/",
    "reporters": ["xml"],
    "output": "build/logs"
}

In the Jenkins CI I have documentation generated from jsdoc. Which looks for comments in your code to generate information about your code. It reads what I have seen as pretty standard comment annotations to augment the information. With this I just install the grunt package in the production side of NPM.

npm --save install grunt-jsdoc

In the grunt configuration I have the below task setup.

    jsdoc: {
      dist: {
        src: ['src/*/*.js'],
        options: {
          destination: 'build/api'
        }
      }
    },

The bundler that I am using is webpack. I pick it as it seemed to have a good layout and seemed to do what I needed. For this I needed to install a few loaders and some other plugins to get webpack to do what I needed. There is enough here for another article that I will try and write later. Here is what I have installed and some of the plugins I have used. There is some redundancy here, because I am still learning on what to use. 

npm --save install grunt-webpack webpack webpack-cli mini-css-extract-plugin css-loader file-loader worker-loader babel-minify-webpack-plugin optimize-css-assets-webpack-plugin

After building a couple configs that I will share later on how to build when I figure it out I add the below tasks. Note the watch task, which allows webpack to watch for changes in the code to regenerate the bundles automatically.

    webpack: {
      dev: webpackDevConfig,
      watch: Object.assign({ watch: true }, webpackDevConfig[0]),
      prod: webpackProdConfig
    }

For testing my code I went to Karma and Jasmine. This is another thing I am going to look into writing a separate article on as there is a lot involved with Karma and Jasmine. They also have some pretty decent documentation. I have installed most of it in the development side of the the NPM package just the grunt plugin and the main package are on the production side.

npm --save install grunt-karma karma
npm --save-dev install karma-cli karma-jasmine karma-jasmine-html karma-chrome-launcher karma-firefox-launcher karma-webpack karma-coverage karma-coverage-istanbul-instrumenter karma-coverage-istanbul-reporter instanbul-instrumenter-loader

Here is the grunt task for Karma. As you can see I have added a watch task that will allow Karma to watch files as they change to rerun the tests on the code. Not as helpful as the webpack version, but can be useful from time to time.

karma: {
  unit: {
    configFile: 'karma.conf.js'
  },
  watch: {
    configFile: 'karma.conf.js',
    autoWatch: true,
    singleRun: false
  }
}, 

With both the webpack and the karma tasks having a watch function you need a way to run both of them at the same time from the same . To do that you install the grunt plugin concurrent. It will let you run tasks at the same time.

npm --save install grunt-concurrent

Here is how you set it up in grunt. 

    concurrent: {
      watch: {
        tasks: ['webpack:watch', 'karma:watch'],
        options: {
          logConcurrentOutput: true
        }
      }
    },

 The last tool that I have is puppteer. Puppeteer can be used in integration tests to make sure things work in the browser. It can also be used for screenshots of you application. I am currently using it for the latter, as I haven't figured out coverage yet in puppeteer. This is one I will write an article on as there were a few quirks on getting some of my screenshots to work.

npm --save-dev install puppeteer

These are the tools that I am currently working with. I might update this article as I learn things or change things. This is at least a starting point and some ideas on what to use.

Taxonomy