Ze Chen

Towards Modernization (I): Front-End Techniques

Project and License

Initialize a Project

npm init -y
git init && git branch -m main

License

Create a file LICENSE and copy from a template, e.g. MIT or ISC.

Other Information

The following entries may be filled in package.json

"description": "A description",
"main": "./build/src/index.js",
"files": [
    "build/**/*"
],
"repository": {
    "type": "git",
    "url": "git+https://github.com/user/repo.git"
},
"license": "ISC",
"author": {
    "name": "Your Name",
    "email": "Your Email",
    "url": "Your URL"
},
"engines": {
    "node": ">=12.0"
},
"keywords": [
    "something"
],
"bugs": {
    "url": "https://github.com/user/repo/issues"
},
"homepage": "https://github.com/user/repo#readme",

Version Control

Husky

husky ensures that tests, lint, etc. are done before git commit. See installation procedure.

npx husky-init && npm install

Commitizen

commitizen generates the commit message upon each commit. Install via

npm install --save-dev commitizen

Then run

npx commitizen init cz-conventional-changelog --save-dev --save-exact

Install husky following the instruction here. Then integrate commitizen with husky by adding the following entry in package.json

"husky": {
  "hooks": {
    "prepare-commit-msg": "exec < /dev/tty && git cz --hook || true"
  }
}

Run npx cz to commit.

Run npx cz --retry to retry a failed commit.

Semantic Release

Install via

npm install --save-dev semantic-release

In package.json we need the following entry

"repository": {
    "type": "git",
    "url": "git+https://github.com/username/repo.git"
}

In .releaserc.json put

{
    "branches": ["main"],
    "plugins": [
        ["@semantic-release/npm", {
            "npmPublish": false
        }]
    ]
}

Note that we need to git push for once to make sure that the branch exists in the remote repo.

Then we could run semantic release

npx semantic-release --no-ci # --dry-run

semantic-release works also with Nx. See nx-semantic-release-demo.

Language

Typescript

Install with

npm install typescript --save-dev

Generate tsconfig.json

npx tsc --init

Add the following entry to package.json

"scripts": {
  "typecheck": "tsc --noEmit"
}

I decided to postpone the configuration until we set up Nx.

TS-Node

Install with

npm install -D typescript

Then we could execute .ts files directly

npx ts-node foo.ts

@types/node

Install with

npm install -D @types/node

See What is @types/node package in NodeJs?.

Code Style

Prettier

Format the code, e.g. trailing semicolons.

See here for set-up.

Install and configure with

npm install --save-dev --save-exact prettier
echo {}> .prettierrc.json

Add the following to .prettierignore

# Ignore artifacts:
build
coverage

Since we will be using lint-staged later, we don't have to worry about .prettierignore yet.

Run npx prettier --write . to format files.

Run npx prettier --check . to check files.

Remember to enable prettier in the editor (see Editor Integration).

ESLint

It's the recommended practice to let Prettier handle formatting and ESLint for non-formatting issues (See What's the difference between prettier-eslint, eslint-plugin-prettier and eslint-config-prettier?).

Install using

npm install eslint --save-dev

Then interactively configure eslint using

npm init @eslint/config

See a comparison of different style guides.

Remember to enable ESLint in the editor (see Editor Integration).

We may also need the following for ESLint to work correctly

extends: [
    "plugin:import/typescript", 'prettier'
]

rules: {
    'import/extensions': ['error', 'never']
},

ESLint With Prettier

To handle conflicting rules of ESLint with Prettier, we install eslint-config-prettier using (see GitHub: eslint-config-prettier)

npm install --save-dev eslint-config-prettier

Then we edit the following in *.eslintrc.*

{
  "extends": [
    "some-other-config-you-use",
    "prettier"
  ]
}

Make sure to put "prettier" last, so it gets the chance to override other configs.

It is debatable whether one should run Prettier as if it was a linter rule. Packages like eslint-plugin-prettier do that job. However, based on the discussion in Integrating with Linters, we don't use this plugin.

ESLint Plugins

ESLint-Node

Install with

npm install --save-dev eslint-plugin-node

Then in .eslintrc.js add (see eslint-plugin-node)

extends: [
    "plugin:node/recommended",
]

However, I had not enabled this plugin yet because it has some problems when working with TypeScript (ECMAScript to be specific).

Lint-Staged

Make sure that Prettier and ESLint are both installed before installing lint-staged.

For Prettier and ESLint to automatically run upon git commit, we install lint-staged via (see lint-staged)

npx mrm@2 lint-staged

It may match only *.js files. Edit the lint-staged entry in package.json so that it covers *.ts as well.

EsLint automatically finds .eslintrc in the directory of the file to be linted, see Configuration Files.

Documentation

Typedoc

Install with

npm install -D typedoc

Add to the root dir a file typedoc.json with

{
  "out": "doc",
  "theme": "default"
}

Generate doc with (e.g. in an Nx workspace)

typedoc --tsconfig libs/data/tsconfig.lib.json --out docs/data libs/data/src/index.ts

See Add possibility to generating documentation for non component libraries.

Paradigm

Immer

Remark: another option is using immutable. However, we don't bother using it since Redux Toolkit uses immer.

Ramda

A functional programming library. See ramda.

RxJS

See RxJS. Library for observables.

Testing

Jest

Install with

npm install --save-dev jest

Add the following entry to package.json

{
  "scripts": {
    "test": "jest --coverage",
    "test:watch": "jest --watch"
  }
}

We may start a test using

npm t

For a tutorial, see Getting Started.

If husky is installed, tests will run automatically upon git commit.

To generate coverage report, run

npx jest --coverage

TS-Jest

Install with

npm i -D ts-jest @types/jest

Create config file with

npx ts-jest config:init

Edit jest.config.js

module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'node',
  testMatch: ['**/test/**/*.spec.ts'],
  collectCoverageFrom: [
    '<rootDir>/src/**/*.ts',
    '!<rootDir>/src/types/**/*.ts',
  ],
  globals: {
    'ts-jest': {
      diagnostics: false,
    },
  },
};

ESLint With Jest

See eslint-plugin-jest for installation and configuration. In .eslintrc.js we need

env: {
    'jest/globals': true,
}

plugins: ['jest'],

See How to use ESLint with Jest.

Testing Library

Cypress

Cypress is for e2e test.

Front-End

React

Redux

Redux Toolkits uses immer, making states immutable.

i18next

Styling

Tailwindcss

Install the dev-dependencies first

npm install -D tailwindcss postcss autoprefixer vite

Then init at the component lib directory e.g. libs/ui with

npx tailwindcss init -p

Styled-Components

Interaction

Three.js

React-Spring

@use-gesture/react

Cytoscape

See react-cytoscapejs.

Transpiling and Bundling

For a brief introduction, see Setup react with webpack and babel.

Babel

Transpiles your scripts.

Webpack

Bundles your scripts.

Back-End and Integration

Next.js

To let Next.js work with Nest one may try Next + Nest: Working together or NestJS + React (Next.js) in One MVC Repo for Rapid Prototyping. However, I don't deploy these techniques since I am gonna use Nx.

Next.js comes with webpack and babel, customization of which could be found here.

Nx

Create an Nx workspace

npx create-nx-workspace

Install Nx CLI

npm install -g nx

To run multiple tasks, run

nx run-many --target=serve --projects=api,html --parallel
Storybook With Nx
npm install -D @nrwl/storybook
nx g @nrwl/react:storybook-configuration project-name
nx run project-name:storybook
Note on Nx

Graphql

Prisma

Nexus

Nest

Install with

npm i -g @nestjs/cli

Then we could start a new project by

nest new project-name

This will pop up an interactive setup program.

A Collection of Terminologies
  • SOLID principles:
    • The single-responsibility principle: "There should never be more than one reason for a class to change." In other words, every class should have only one responsibility.
    • The open–closed principle: "Software entities ... should be open for extension, but closed for modification."
    • The Liskov substitution principle: "Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it." See also design by contract.
    • The interface segregation principle: "Many client-specific interfaces are better than one general-purpose interface."
    • The dependency inversion principle: "Depend upon abstractions, [not] concretions."
  • DTO: Data transfer object.
  • CRUD: Create, Read, Update, Delete.
  • IoC: inversion of control.
Controller

Create a controller using

nest g controller controller-name
Service

Create a service using

nest g service service-name
Module

Create a module using

nest g module module-name
CRUD Resource

Create a resource using

nest g resource users 

This will pop up an interactive creator. Controllers, modules, services, and DTOs are automatically generated.

MongoDB

Authentication

Passport

Using With NestJS

Install with

npm i @nestjs/passport passport passport-local
npm install -D @types/passport-local

OAuth

OpenId

Deploy

Nginx

For a basic config see Next.js + API on same server.

Docker

To have docker alpine image node:alpine run with Next.js we may need the following

RUN apk add --no-cache libc6-compat

Moreover we need (for compiling)

RUN apk add --no-cache --virtual .gyp \
        python3 \
        make \
        g++
RUN npm i
RUN npx nx run-many --target=build --projects=api,front --prod
RUN apk del .gyp

AWS Elastic Beanstalk

To deploy apps to AWS Elastic Bean, See @How to Deploy a NestJS app to AWS Elastic Beanstalk (with added HTTPS and CI/CD).

2022/1/22 16:24:10

0%

Uploaded successfully.

0%

Uploaded successfully.


0%

Uploaded successfully.

0%

Uploaded successfully.