Deep Dive Into Modern Web Development
- part0 Fundamentals of Web apps
- part1 Introduction to React
- part2 Communicating with server
- part3 Programming a server with NodeJS and Express
- part4 Testing Express servers, user administration
- part5 Testing React apps
- part6 State management with Redux
- part7 React router, custom hooks, styling app with CSS and webpack
- part8 GraphQL
- part9 TypeScript
- part10 React Native
- part11 CI/CD
npx create-react-app myapp {. | myApp}
cd my-app
npm start
- Thymeleaf used along with Java Spring
- ECMAScript6-ES6
- JS Arrow function expressions
- create-react-app
- the React-library
- React-component
- Babel
- XML
- Props It is possible to pass data to components using so called props.
- JSbin
- ECMAScript compatibility table
- Install JSON Server
- Using Concurrently with json-server and your React App
- React Filter
npm install -g json-server
- Run JSON Server on your app
npx json-server --port 3001 --watch db.json
- Install json-server as a development dependency (only used during development) by executing the command:
npm install json-server --save-dev
and making a small addition to the scripts part of the package.json file:
"server": "json-server -p3001 --watch db.json"
After install j-son server and backend as dependencies in our project.
npm i -D json-server backend
In package.json
"dev": "concurrently \"npm run start\" \"npm run json-server\""
-
Promise based HTTP client for the browser and node.js Execute command at the root of the project:
npm install axios
Axios is now included among the other dependencies: in package.json in section dependencies
Debugging Full Stack applications may seem tricky at first. Soon our application will also have a database in addition to the frontend and backend, and there will be many potential areas for bugs in the application.
When the application "does not work", we have to first figure out where the problem actually occurs. It's very common for the problem to exist in a place where you didn't expect it to, and it can take minutes, hours, or even days before you find the source of the problem.
The key is to be systemic. Since the problem can exist anywhere, you must question everything, and eliminate all possibilities one by one. Logging to the console, Postman, debuggers, and experience will help.
When bugs occur, the worst of all possible strategies is to continue writing code. It will guarantee that your code will soon have even more bugs, and debugging them will be even more difficult. The stop and fix principle from Toyota Production Systems is very effective in this situation as well.
Construire une culture d'arrêt pour résoudre le problème, pour obtenir la bonne qualité du premier coup
La méthode Jidoka consiste à arrêter le travail dès qu'un problème survient pour éviter de produire des éléments défectueux. Il s'agit ainsi de « construire la qualité dans le produit, en détectant les anomalies dans le processus
- In Js Toutes les valeurs sont vraies sauf si elles sont définies comme fausses (c'est-à-dire, à l'exception de faux, 0, -0, 0n, "", null, undefined et NaN).
//Truthy
if (true)
if ({})
if ([])
if (42)
if ("0")
if ("false")
if (new Date())
if (-42)
if (12n)
if (3.14)
if (-3.14)
if (Infinity)
if (-Infinity)
- Mozilla's JavaScript Guide
- A re-introduction to JavaScript (JS tutorial)
- You-Dont-Know-JS
- javascript.info
- Destructuring
- JS Refactor plugin for VS Code that automatically changes short form arrow functions into their longer form, and vice versa.
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals
- Template literals
- Spread syntax
- npm script
- Higher-order functions
- Map
- Reduce basics
- Index as a key is an anti-pattern
- Simplify your JavaScript – Use .map(), .reduce(), and .filter()
- Representational State Transfer (REST)
- Status Code Definitions
- Same origin policy and CORS
- Same-origin policy
- CORS
Fast, unopinionated, minimalist web framework for node.
Express est une infrastructure d'applications Web Node.js minimaliste et flexible qui fournit un ensemble de fonctionnalités robuste pour les applications Web et mobiles. route-parameters
npm install express
On node app
const express = require('express')
const app = express()
app.use(express.json());
Error Handling refers to how Express catches and processes errors that occur both synchronously and asynchronously. Express comes with a default error handler so you don’t need to write your own to get started
https://github.com/davidbanham/express-async-errors
npm install express-async-errors --save
HTTP request logger middleware for node.js
- morgan
- cors CORS is a node.js package for providing a Connect/Express middleware that can be used to enable CORS with various options.
- Getting Started on Heroku with Node.js Heroku is a platform as a service (PaaS) that enables developers to build, run, and operate applications entirely in the cloud.
sudo npm install -g heroku
heroku --version
- Add a file called Procfile to the project's root to tell Heroku how to start the application.
web: npm start
Heroku manages app deployments with Git, the popular version control system. You definitely don’t need to be a Git expert to deploy code to Heroku, but it’s helpful to learn the basics.
cd myapp
git init
Initialized empty Git repository in .git/
git add .
git commit -m "My first commit"
Created initial commit 5df2d09: My first commit
44 files changed, 8393 insertions(+), 0 deletions(-)
create mode 100644 README
create mode 100644 Procfile
create mode 100644 app/controllers/source_file
...
heroku create
Creating app... done, ⬢ thawing-inlet-61413
https://thawing-inlet-61413.herokuapp.com/ | https://git.heroku.com/thawing-inlet-61413.git
tell you the difference between your branch and the remote one.
git remote -v
heroku https://git.heroku.com/thawing-inlet-61413.git (fetch)
heroku https://git.heroku.com/thawing-inlet-61413.git (push)
git remmote add heroku https://git.heroku.com/infinite-sierra-55116.git
git branch -u heroku/master
Generally, you will add a git remote for your Heroku app during the Heroku app creation process, i.e. heroku create
. However, if you are working on an existing app and want to add git remotes to enable manual deploys, the following commands may be useful.
Note that on Heroku, you must always use master
as the destination branch on the remote. If you want to deploy a different branch, you can use the syntax local_branch:destination_branch
seen below (in this example, we push the local staging
branch to the master
branch on heroku.
$ git remote add staging https://git.heroku.com/staging-app.git
$ git push staging staging:master
In some cases, your local branch may be missing some commits that were already deployed to Heroku, resulting in an error. If you are very sure you want to proceed, add the --force
(-f
) flag.
$ git push staging staging:master -f
By convention, the remote name "heroku" is typically used for the production application.
$ git remote add heroku https://git.heroku.com/app.git
$ git push heroku master
As @voke points out, you can alternatively use a Heroku CLI command to add your remote. However, it looks like this will always use the default remote name heroku
for the remote. If you would like to use a different name for your remote, see the "Rename a remote" section below.
$ heroku git:remote -a staging-app
Edit: Thanks to @nruth for pointing out you can supply a remote name to this command with the -r
flag.
$ heroku git:remote -a staging-app -r staging
As @Saworieza points out, all of the examples above use the https protocol for connecting to the remotes, but it is also possible to connect via ssh.
$ git remote add staging git@heroku.com:staging-app.git
$ git remote add heroku git@heroku.com:app.git
The -v
is the flag for "verbose" and includes the remote URL in addition to the remote name.
$ git remote -v
$ git remote rename heroku staging
If you have already created https remotes and want to switch them to use ssh, the following command can be used. This command can also be used to change the target URL without changing the protocol
$ git remote set-url staging git@heroku.com:staging-app.git
$ git remote set-url heroku https://git.heroku.com/production-app.git
*Static To serve static files such as images, CSS files, and JavaScript files, use the express.static built-in middleware function in Express.
-
On application you can use instruction
debugger
console.log('props value is', props)
console.log('props value is' + props)
The most important snippet is the one for the console.log() command, for example clog. This can be created like so:
{
"console.log": {
"prefix": "clog",
"body": [
"console.log('$1')",
],
"description": "Log output to console"
}
}
Changes on the frontend have caused it to no longer work in development mode (when started with command npm start), as the connection to the backend does not work.
Mongoose is a MongoDB object modeling tool designed to work in an asynchronous environment. Mongoose supports both promises and callbacks.
npm install mongoose
We will use MongoDB which is a so-called document database.
Document databases differ from relational databases in how they organize data as well as the query languages they support. Document databases are usually categorized under the NoSQL umbrella term.
Read now the chapters on collections and documents from the MongoDB manual to get a basic idea on how a document database stores data.
-
Connection NB: Please note the password is the password created for the database user, not your MongoDB Atlas password. Also, if you created password with special characters, then you'll need to URL encode that password.
-
Schema
After establishing the connection to the database, we define the schema for a note and the matching model:
const noteSchema = new mongoose.Schema({
content: String,
date: Date,
important: Boolean,
})
const Note = mongoose.model('Note', noteSchema)
- Creating and saving objects
Next, the application creates a new note object with the help of the Note model:
const note = new Note({
content: 'HTML is Easy',
date: new Date(),
important: false,
})
One smarter way of validating the format of the data before it is stored in the database, is to use the validation functionality available in Mongoose.We can define specific validation rules for each field in the schema:
npm install --save mongoose-unique-validator --legacy-peer-deps
const schema = new Schema({
name: {
type: String,
required: true
}
});
const Cat = db.model('Cat', schema);
// This cat has no name :(
const cat = new Cat();
cat.save(function(error) {
assert.equal(error.errors['name'].message,
'Path `name` is required.');
error = cat.validateSync();
assert.equal(error.errors['name'].message,
'Path `name` is required.');
});
Other example
var mongoose = require('mongoose');
var uniqueValidator = require('mongoose-unique-validator');
// Define your schema as normal.
var userSchema = mongoose.Schema({
username: { type: String, required: true, unique: true },
email: { type: String, index: true, unique: true, required: true },
password: { type: String, required: true }
}
);
NB: On update operations, mongoose validators are off by default. Read the documentation to determine how to enable them.
function setRunValidators() {
this.setOptions({ runValidators: true });
}
mongoose.plugin(schema => {
schema.pre('update', setRunValidators);
});
// Apply the uniqueValidator plugin to userSchema.
userSchema.plugin(uniqueValidator);
// Pre hook for findOneAndUpdate
personSchema.pre('findOneAndUpdate', function(next) {
this.options.runValidators = true;
next();
});
Before we move onto the next part, we will take a look at an important tool called lint. Wikipedia says the following about lint:
Generically, lint or a linter is any tool that detects and flags errors in programming languages, including stylistic errors. The term lint-like behavior is sometimes applied to the process of flagging suspicious language usage. Lint-like tools generally perform static analysis of source code.
In compiled statically typed languages like Java, IDEs like NetBeans can point out errors in the code, even ones that are more than just compile errors. Additional tools for performing static analysis like checkstyle, can be used for expanding the capabilities of the IDE to also point out problems related to style, like indentation.
In the JavaScript universe, the current leading tool for static analysis aka. "linting" is ESlint.
Let's install ESlint as a development dependency to the backend project with the command:
npm install eslint --save-dev
After this we can initialize a default ESlint configuration with the command:
node_modules/.bin/eslint --init
The configuration will be saved in the .eslintrc.js file:
module.exports = {
"env": {
"browser": true,
"es2021": true
},
"extends": [
"eslint:recommended",
"plugin:react/recommended"
],
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": 12,
"sourceType": "module"
},
"plugins": [
"react"
],
"rules": {
}
};
Let's immediately change the rule concerning indentation, so that the indentation level is two spaces.
"indent": [
"error",
2
],
Inspecting and validating a file like index.js can be done with the following command:
node_modules/.bin/eslint index.js
It is recommended to create a separate npm script for linting:
{
// ...
"scripts": {
"start": "node index.js",
"dev": "nodemon index.js",
// ...
"lint": "eslint ."
},
// ...
}
Now the npm run lint command will check every file in the project.
Also the files in the build directory get checked when the command is run. We do not want this to happen, and we can accomplish this by creating an .eslintignore file in the project's root with the following contents:
Let's not fix these issues just yet.
A better alternative to executing the linter from the command line is to configure a eslint-plugin to the editor, that runs the linter continuously. By using the plugin you will see errors in your code immediately. You can find more information about the Visual Studio ESLint plugin here.
This makes errors easy to spot and fix right away.
ESlint has a vast array of rules that are easy to take into use by editing the .eslintrc.js file.
Let's add the eqeqeq rule that warns us, if equality is checked with anything but the triple equals operator. The rule is added under the rules field in the configuration file.
{
// ...
'rules': {
// ...
'eqeqeq': 'error',
},
}
While we're at it, let's make a few other changes to the rules.
Let's prevent unnecessary trailing spaces at the ends of lines, let's require that there is always a space before and after curly braces, and let's also demand a consistent use of whitespaces in the function parameters of arrow functions.
//On .eslintrc.js
{
// ...
'rules': {
// ...
'eqeqeq': 'error',
'no-trailing-spaces': 'error',
'object-curly-spacing': [
'error', 'always'
],
'arrow-spacing': [
'error', { 'before': true, 'after': true }
]
},
}
Our default configuration takes a bunch of predetermined rules into use from eslint:recommended:
'extends': 'eslint:recommended',
This includes a rule that warns about console.log commands. Disabling a rule can be accomplished by defining its "value" as 0 in the configuration file. Let's do this for the no-console rule in the meantime.
{
// ...
'rules': {
// ...
'eqeqeq': 'error',
'no-trailing-spaces': 'error',
'object-curly-spacing': [
'error', 'always'
],
'arrow-spacing': [
'error', { 'before': true, 'after': true }
],
'no-console': 0 },
}
NB when you make changes to the .eslintrc.js file, it is recommended to run the linter from the command line. This will verify that the configuration file is correctly formatted:
If there is something wrong in your configuration file, the lint plugin can behave quite erratically.
Many companies define coding standards that are enforced throughout the organization through the ESlint configuration file. It is not recommended to keep reinventing the wheel over and over again, and it can be a good idea to adopt a ready-made configuration from someone else's project into yours. Recently many projects have adopted the Airbnb Javascript style guide by taking Airbnb's ESlint configuration into use.
Jest est un framework de test JavaScript de qualité qui met l'accent sur la simplicité.
Il fonctionne avec les projets utilisant : Babel, TypeScript, Node, React, Angular, Vue et plus encore !
npm install --save-dev jest
Another way of running a single test (or describe block) is to specify the name of the test to be run with the -t flag:
npm test -- -t 'when list has only one blog, equals the likes of that'
A modern JavaScript utility library delivering modularity, performance & extras.
cross-env makes it so you can have a single command without worrying about setting or using the environment variable properly for the platform. Just set it like you would if it's running on a POSIX system, and cross-env will take care of setting it properly.
npm install --save-dev cross-env
The motivation with this module is to provide a high-level abstraction for testing HTTP, while still allowing you to drop down to the lower-level API provided by superagent.
npm install supertest --save-dev
To change your testEnvironment
to Node.js, add testEnvironment
to your jest.config.js
file:
module.exports = {
testEnvironment: 'node'
};
npm test -- tests/note_api.test.js
npm test -- -t "a specific note is within the returned notes"
npm test -- -t 'notes'
Instructions for creating snippets can be found here.
Useful, ready-made snippets can also be found as VS Code plugins, in the marketplace.
You can get the command-line parameters from the process.argv variable.
npm install -g npm
You need for node_module
npm install react-scripts --save
npm cache verify && rm -rf node_modules/ && npm i
or
npm i --legacy-peer-deps
or
npm update --force
Node applicaiton: We can update the dependencies of the project with the command:
npm update
Node applicaiton: Likewise, if we start working on the project on another computer, we can install all up-to-date dependencies of the project defined in package.json with the command:
npm install
Unfortunately, npm doesn't integrate natively any upgrade tool. So to do it, you need to install a new global dependency. And here is a good one: npm-check. You can use it by running the following:
npm install -g npm-check
And then, in your repository : npm-check -u (-u options activate the interactive update).
npm-check -u
Concurrently Run multiple commands concurrently. Like npm run watch-js & npm run watch-less but better.
- The tool is written in Node.js, but you can use it to run any commands.
npm install -g concurrently
- or if you are using it from npm scripts:
npm install concurrently --save
Debugging is also possible with the Chrome developer console by starting your application with the command:
node --inspect index.js
You can access the debugger by clicking the green icon - the node logo - that appears in the Chrome developer console:
// Install nodemon globally with Node JS
npm install nodemon -g
npm install --save-dev nodemon
// On package.json in "scripts" section add
"dev": "nodemon -L index.js", -A signaler
Dotenv is a zero-dependency module that loads environment variables from a .env file into process.env. Storing configuration in the environment separate from code is based on The Twelve-Factor App methodology.
# with npm
npm install dotenv
# or with Yarn
yarn add dotenv
As early as possible in your application, require and configure dotenv.
require('dotenv').config()
Create a .env file in the root directory of your project. Add environment-specific variables on new lines in the form of NAME=VALUE. For example:
DB_HOST=localhost
DB_USER=root
DB_PASS=s1mpl3
process.env now has the keys and values you defined in your .env file.
const db = require('db')
db.connect({
host: process.env.DB_HOST,
username: process.env.DB_USER,
password: process.env.DB_PASS
})
For creating a new React app with all the necessary librairies.
npx create-react-app {name of app}
Comprehensive date library
https://github.com/date-fns/date-fns
Dead simple Object schema validation
https://github.com/jquense/yup
Forms without tears
https://github.com/formium/formik
like nodemon but for ts
https://github.com/wclr/ts-node-dev
ts-node is a TypeScript execution engine and REPL for Node.js.
https://github.com/TypeStrong/ts-node
javascript with types.
https://github.com/microsoft/TypeScript
The JavaScript reference implementation for GraphQL, a query language for APIs created by Facebook.
https://github.com/graphql/graphql-js
Apollo Client is a fully-featured caching GraphQL client with integrations for React
https://github.com/apollographql/apollo-client
Apollo Server is a community-maintained open-source GraphQL server.
https://github.com/apollographql/apollo-server
Allow to create a local database with json extension for simulate a backend rapidly.
https://github.com/typicode/json-server
Allow to make HTTP request easly.
https://github.com/axios/axios
backend library for simplify http request routing and middleware configuration
https://github.com/expressjs/express
Provide autorefresh when a backend file is modified
https://github.com/remy/nodemon
Allow cross-origin requests for node backend
https://github.com/expressjs/cors
High level API to communicate with a MongoDB database.
https://github.com/Automattic/mongoose
Facilitate the use of environnement variable in .env files.
https://github.com/motdotla/dotenv
Linter that throw errors when the code doesn't respect standards.
https://github.com/eslint/eslint
Jest is a javascript testing framework.
https://github.com/facebook/jest
Sometimes windows prompt crash when we pass out variable environment. Crossenv car resolve that issue.
https://github.com/kentcdodds/cross-env
Supertest is a testing framework for HTTP requests.
https://github.com/visionmedia/supertest
This library allow us to get rid of the try/catch block in async/await blocks.
https://github.com/davidbanham/express-async-errors
Bcrypt is a library for hashing passwords.
https://github.com/kelektiv/node.bcrypt.js
This is an extension of mongoose to add a unique validator on fields before insert.
https://github.com/blakehaswell/mongoose-unique-validator
Permit to generate jsonwebtoken in order to verify authentification
https://github.com/auth0/node-jsonwebtoken
Prop-types is a tool that allow us to add some rules when receiving props inside a React child component.
https://github.com/facebook/prop-types
Disable the relative eslint errors due to jest non-standard syntax
https://github.com/jest-community/eslint-plugin-jest
Suite of tools that encourage the tests in React apps
https://github.com/testing-library/react-testing-library
Cypress is an EndToEnd library in order to test complete application with front-end and back-end.
https://github.com/cypress-io/cypress
Disable the relative eslint errors due to cypress non-standard syntax
https://github.com/cypress-io/eslint-plugin-cypress
Redux permit to save states at the root of the application with the concept of stores
https://github.com/reduxjs/redux
Deepfreeze make sure that our reducer is an immutable function.
https://github.com/substack/deep-freeze
React-redux simplify the bindings between React and Redux withe the use of Dispatcher and Selector.
https://github.com/reduxjs/react-redux
This library coupled with ReduxDevTools, permit to follow every acions made on the application and simplify debugging.
https://github.com/zalmoxisus/redux-devtools-extension
This library allow to execute asynchronous dispatch with redux stores.
https://github.com/reduxjs/redux-thunk
React-router-dom provides React components for manage the history and navigation on the front end of the application with Router, Link, Switch...
https://github.com/ReactTraining/react-router
Styled-components allow us to create our own custom html components with tagged template literals.
https://github.com/styled-components/styled-components
A utility-first CSS framework for rapidly building custom user interfaces.
https://github.com/tailwindlabs/tailwindcss
Love this CSS framework
https://github.com/Semantic-Org/Semantic-UI-React
generate unique key
https://github.com/uuidjs/uuid
Web application that can host web application for free if it's personnal development.
Web application that permit to host MongoDB database.
https://www.mongodb.com/fr-fr/cloud/atlas
Website that reference all library that are typescript typed
Tool that permit to see the HTTP Post request made with apollo-client
Expo Snack is an online editor for React Native JSFiddle CodePen
Public url for testing
We need to create a .env file at the root of the projet and add this two environnement variable.
CHOKIDAR_USEPOLLING=true
FAST_REFRESH=false
Put the project inside the wsl directory that can be accessible with \wsl$ variable inside Windows environement.
Cypress doesn't launch and don't give us any errors. We need to first download an XServer for windows, for example : https://github.com/ArcticaProject/vcxsrv and configure the shortcut target with -ac arguments.
C:/{pathtoexecutable}/xlaunch.exe -ac
When Xlaunch is launched, we need to tick the "Disable access control" box.
Next we need to export the DISPLAY environement variable with the wsl2 ip thanks to this script.
# set DISPLAY variable to the IP automatically assigned to WSL2
export DISPLAY=$(cat /etc/resolv.conf | grep nameserver | awk '{print $2; exit;}'):0.0
After that we start the dbus service with this command
# Automatically start D-Bus to allow communication with Cypress GUI app
sudo /etc/init.d/dbus start &> /dev/null
Ressources: https://gist.github.com/bergmannjg/461958db03c6ae41a66d264ae6504ade#install-tools-in-windows
Ressource: https://stackoverflow.com/a/65295027/11631534 Here's the full steps I found worked for LAN development between my mobile and expo running in WSL2 (Ubuntu 20 on Windows 10 20H2):
- One time at the start: open Expo ports inbound in Windows Firewall Windows firewall should be on, and it should block inbound attempts by default. The following will open the Expo ports 19000–19006, inbound, but only on a network that you have configured as "private" (that's the -Profile Private part): (powershell as Admin)
New-NetFireWallRule -Profile Private -DisplayName 'Expo ports for LAN development' `
-Direction Inbound -LocalPort 19000-19006 -Action Allow -Protocol TCP
(You can check it after with Get-NetFirewallRule |Where-Object {$_.DisplayName -Match "Expo.*"})
- Point portproxy to WSL; Re-run "Each time WSL has a new IP address" (I'm not sure yet how often the WSL IP address changes, but I suspect only a reboot would)
I saw stuff on the web, including other answers here, saying portproxy to connectaddress=127.0.0.1 but it did not work for me (WSL2, Windows 10 20H2). I can't say why others found it worked, I can only say that repeated testing confirmed for me that 127.0.0.1 did not work, but the WSL IP address did work.
So here's a reusable command to auto set the connectaddress to the right WSL address: (powershell — just for the easy inline Trim() — as Admin)
netsh interface portproxy add v4tov4 listenport=19000 listenaddress=0.0.0.0 `
connectport=19000 connectaddress=$($(wsl hostname -I).Trim());
netsh interface portproxy add v4tov4 listenport=19001 listenaddress=0.0.0.0 `
connectport=19001 connectaddress=$($(wsl hostname -I).Trim());
- Point Metro to your dev machine LAN IP Address; Re-run inside WSL "Each time dev host has a new IP address" This is the one that probably changes most often. Your laptop local network IP certainly changes when you change networks (e.g. home/office) — and can change at other times too.
Fortunately it's also pastable / aliasable: WSL2 shell
export REACT_NATIVE_PACKAGER_HOSTNAME=$(netsh.exe interface ip show address "Wi-Fi" | grep 'Adresse IP' | sed -r "s/[^0-9.]//g")
echo Meteor will use dev machine IP address: $REACT_NATIVE_PACKAGER_HOSTNAME (If your dev box doesn't change LAN often, you might get away with setting REACT_NATIVE_PACKAGER_HOSTNAME in your .bashrc / .zshrc)
I "wish I didn't have to re-run things and it could all be automated", but that same laziness makes me happy to at least have commands 2 and 3 able to simple "rerun" and consistently get Expo LAN mode working for my WSL2-hosted Expo dev mode.