Published on

JavaScript Toolset

Authors

The internet is full of awesome lists for JavaScript and other languages.

But I have found that keeping a list for yourself can be better as it is a list of tools you have used and would use again - you have experience and context using the tool.

This page is a living document of my list of tools that I use when working with JavaScript as well as the example usage of these tools (where applicable). As it is a living document the tools here are by no means exhaustive and will get updated if/when I find a better alternative or ways to use them.

Toolset

Backend

AreaNameUsage
DBSequelizeUsage
ServerExpress GeneratorUsage
WebsocketswsUsage
WebsocketswscatUsage

Frontend

AreaSubareaNameUsage
ComponentsReact::Scaffoldingcreate-react-appUsage

Front and Backend

AreaNameUsage
TranspilerBabelUsage
Test RunnerMochaUsage
Code StylePrettierUsage
Prettier Code Formatter for VS CodeUsage

Sequelize

Back to top

Install the cli by running:

yarn global add sequelize-cli
First Time Usage

Back to top

In the root of your project run:

sequelize init

Install the required dependencies

# If you are using sqlite3 as your DB otherwise install the appropriate package
yarn add sqlite3
yarn add sequelize
yarn add sequelize-cli

Update the config in the generated config folder (in my case I am using sqlite3 but update to reflect the DB you use):

{
  "development": {
    "dialect": "sqlite",
    "storage": "./app.db"
  },
  "test": {
    "dialect": "sqlite",
    "storage": "./app.db"
  },
  "production": {
    "dialect": "sqlite",
    "storage": "./app.db"
  }
}

Update each respective environment to have the correct details.

Update your .gitignore to ignore your DB file (only because in this case we are using sqlite3):

# ...
# DB
app.db
Generate Schemas, Seeds and Migrations

Back to top

From the root of the project that has sequelize in run:

sequelize model:generate --name YourTableName --attributes attributeName1:text,attributeName2:bigint
  • This generates the model and migration for that model
  • Possible datatype can be found here.
  • Unfortunately you cannot specify column constraints here
    • You have to specify constraints in the generated model migration after running the above command.
      • Possible contraints can be found here.
sequelize seed:generate --name demo-yourTableName
  • This generates a seed file that you will need to populate with seed data

Example seed file:

'use strict'

module.exports = {
  up: (queryInterface, Sequelize) => {
    return queryInterface.bulkInsert(
      'Products',
      [
        {
          name: 'Dog food',
          price: 10.2,
          createdAt: new Date().toDateString(), //this field was added to the table for you by sequelize, you still need to explicitly define it
          updatedAt: new Date().toDateString(), //this field was added to the table for you by sequelize, you still need to explicitly define it
        },
      ],
      {}
    )
  },

  down: (queryInterface, Sequelize) => {
    return queryInterface.bulkDelete('Products', {
      [Sequelize.Op.and]: [{ name: 'Dog food' }, { price: 10.2 }],
    })
  },
}
  • Possible operators can be found here.

To run migration and seeds:

sequelize db:migrate
sequelize db:seed:all
  • If you get a validation error it means one or more constraints in your seed is wrong
    • One common mistake I make is leaving out createdAt and updatedAt in my seed scripts

If you need to specify custom paths for your sequelize config, migrations, seeders and models you can do that by creating a .sequelizerc file in the root of your project as described here here. For example if I have all my source code in a folder in the root of my project called src then my .sequelizerc file would look as follows:

const path = require('path')

module.exports = {
  config: path.resolve('src', 'config', 'config.json'),
  'models-path': path.resolve('src', 'models'),
  'seeders-path': path.resolve('src', 'seeders'),
  'migrations-path': path.resolve('src', 'migrations'),
}

Express Generator

Back to top

First Time Usage

Back to top

yarn global add express-generator
Generate Scaffolding

Back to top

express --view=hbs nameOfFolderForServer
  • nameOfFolderForServer: is the name of the folder that the generator will create for you with the scaffolding inside

Create React App

Back to top

npx create-react-app nameOfApp
Setting Up Absolute Imports

Back to top

  • Ensure you are running a new enough version of Create React App (older versions do not support this).
  • In the root of the project (the same level as the package.json file) create a file called jsconfig.json
  • In that file add the following contents:
{
  "compilerOptions": {
    "baseUrl": "src"
  },
  "include": ["src"]
}

It is recommended that top level directories in the src folder should be changed to start with upper case to differentiate your project's internal dependencies from those you imported from npm.

With the above setting in place we can take the following:

import Loader from '../../Components/Loader'

And change it to the following:

import Loader from 'Components/Loader'

Babel

Back to top

Note: If you are doing this in React and you are using create-react-app, babel has already been setup for you.

Minimal Setup - Backend (NodeJS)

Back to top

Install requirements in project:

yarn add -D nodemon @babel/core @babel/node @babel/preset-env @babel/cli

Create the .babelrc file:

touch .babelrc

A Basic Babelrc

{
  "presets": ["@babel/preset-env"]
}

Update your package.json run script (the script you use while deving):

...
  "scripts": {
    "start": "nodemon --exec babel-node src/your-main-file.js",
    "build": "babel src --out-dir dist",
    "serve": "yarn run build && node dist/your-main-file.js"
  },
...
Building and Running One JS File

Back to top

First install @babel/node if it is not already installed:

yarn add -D @babel/node

To use it for example from an npm script write something like:

babel-node --presets @babel/env ./path/to/file/in/your/project.js

And in a package.json file it would look like this:

...
"scripts": {
  "run-single-file": "babel-node --presets @babel/env ./path/to/file/in/your/project.js"
},
...

babel-node is meant to behave like babel-cli but does not 100%. To be safe make the single file you are running pull in as few dependencies as possible.

Setting up Mocha and Chai With Babel Support

Back to top

Install the required dependencies:

yarn add -D @babel/register mocha chai
# This is needed for: import 'regenerator-runtime/runtime';
#   and: import 'core-js/stable';
#   you need this to use async in tests
yarn add core-js/stable

Add the below script to your package.json file:

...
"scripts": {
...
    "test": "mocha --require @babel/register 'src/**/**spec.js'"
}
...

Now add your tests anywhere inside of src or its sub-directories as long as they end in .spec.js.

As you are using Mocha to run these files you automatically have access to a number of function for example a simple test file looks as follows:

import { expect } from 'chai'
import 'core-js/stable'
import 'regenerator-runtime/runtime'

after(() => {
  // put any code you want run at the end of all test suites like for example closing DB connections
})

describe('Describe your test suite', () => {
  it('should do whatever you are testing', async () => {
    // ...
    expect(someCondition).to.eql(expectedValue)
    // ...
  })
})

Prettier

Back to top

Install prettier:

yarn add -D prettier

Create a .prettierrc file:

touch .prettierrc

An example of an RC file looks as follows:

{
  "semi": false,
  "singleQuote": true
}

Possible RC options can be found here.

Most editors have plugins that can be installed that look for your rc file and use that to format your code.

Websockets

Back to top

Install the dependency:

yarn add ws
wscat

Back to top

Install the dependency:

npm install -g wscat

Usage:

wscat -c ws://localhost:3001

In the above the server:

  • Is running locally in this case.
  • Is running on port 3001.
Express Setup

Back to top

import express from 'express'
import WebSocket from 'ws'
import http from 'http'

const app = express()

const server = http.createServer(app)

// wss => web socket server
const wss = new WebSocket.Server({ server })

wss.on('connection', (ws) => {
  //this gets hit when the ws connection is first established
  ws.on('message', (message) => {
    //this is hit when the ws receives a message
    // handle message here
    const detail = JSON.parse(message)

    if (detail && detail.type === 'topic-you-expose') {
      ws.clients.forEach((client) => {
        if (client != ws && client.readyState === WebSocket.OPEN) {
          client.send(detail.payload)
        }
      })
    }
  })
})

server.listen(process.env.PORT || 3001, () => {
  console.log(
    `Server running on: [http://your-host:${server.address().port}] and [ws://your-host:${
      server.address().port
    }]`
  )
})
NodeJS Client Setup

Back to top

import WebSocket from 'ws';

// WebSocket client => wsc
const wsc = new WebSocket('ws:localhost:3001');

...
//we need to now send a message to our server
wsc.send(messageToSend);
...