- Published on
JavaScript Toolset
- Authors
- Name
- Yair Mark
- @yairmark
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
Area | Name | Usage |
---|---|---|
DB | Sequelize | Usage |
Server | Express Generator | Usage |
Websockets | ws | Usage |
Websockets | wscat | Usage |
Frontend
Area | Subarea | Name | Usage |
---|---|---|---|
Components | React::Scaffolding | create-react-app | Usage |
Front and Backend
Area | Name | Usage |
---|---|---|
Transpiler | Babel | Usage |
Test Runner | Mocha | Usage |
Code Style | Prettier | Usage |
Prettier Code Formatter for VS Code | Usage |
Sequelize
Install the cli by running:
yarn global add sequelize-cli
First Time Usage
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
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.
- You have to specify constraints in the generated model migration after running the above command.
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
andupdatedAt
in my seed scripts
- One common mistake I make is leaving out
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
First Time Usage
yarn global add express-generator
Generate Scaffolding
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
npx create-react-app nameOfApp
Setting Up Absolute Imports
- 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 calledjsconfig.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
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)
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
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
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
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
Install the dependency:
yarn add ws
wscat
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
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
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);
...