Sådan skriver du en produktionsklar Node- og Express-app

Projektstrukturering

Da jeg begyndte at opbygge Node & Express-applikationer, vidste jeg ikke, hvor vigtigt det var at strukturere din applikation. Express kommer ikke med strenge regler eller retningslinjer for vedligeholdelse af projektstrukturen.

Du er fri til at bruge enhver struktur, du ønsker. Når din codebase vokser, har du en lang routehåndterer. Dette gør din kode vanskelig at forstå, og den indeholder potentielle fejl.

Hvis du arbejder for en opstart, har du det meste af tiden ikke tid til at refractere dit projekt eller modulere det. Du kan ende med en endeløs løkke med bug fixing og patch.

Over tid, mens jeg arbejdede med både små teams og store teams, indså jeg, hvilken slags struktur der kunne vokse med dit projekt og stadig være let at vedligeholde.

Model View-controller

MVC-mønsteret hjælper med hurtig og parallel udvikling. For eksempel kan en udvikler arbejde på visningen, mens en anden kan arbejde på at skabe forretningslogikken i controlleren.

Lad os se på et eksempel på en simpel bruger CRUD-applikation.

project/ controllers/ users.js util/ plugin.js middlewares/ auth.js models/ user.js routes/ user.js router.js public/ js/ css/ img/ views/ users/ index.jade tests/ users/ create-user-test.js update-user-test.js get-user-test.js .gitignore app.js package.json
  • controllere: Definer dine apprutehåndterere og forretningslogik
  • util: Skriver hjælpefunktioner / hjælperfunktioner her, som kan bruges af alle controllere. For eksempel kan du skrive en funktion som mergeTwoArrays(arr1, arr2).
  • middlewares: Du kan skrive middlewares for at fortolke alle indgående anmodninger, før du går til rutehåndteringen. For eksempel,

    router.post('/login', auth, controller.login)hvor auther en middleware-funktion defineret i middlewares/auth.js.

  • modeller: også en slags middleware mellem din controller og databasen. Du kan definere et skema og foretage en validering, før du skriver til databasen. For eksempel kan du bruge en ORM som Mongoose, der kommer med gode funktioner og metoder til brug i selve skemaet
  • ruter: Definer dine appruter med HTTP-metoder. For eksempel kan du definere alt relateret til brugeren.
router.post('/users/create', controller.create) router.put('/users/:userId', controller.update) router.get('/users', controller.getAll)
  • offentlig: Gem statiske billeder i /img, tilpassede JavaScript-filer og CSS/css
  • visninger: Indeholder skabeloner, der skal gengives af serveren.
  • tests: Her kan du skrive alle enhedstest eller acceptstest til API-serveren.
  • app.js: Fungerer som hovedfilen til projektet, hvor du initialiserer appen og andre elementer i projektet.
  • package.json: Plejer afhængighederne, de scripts, der skal køres med npmkommandoen, og versionen af ​​dit projekt.

Undtagelser og fejlhåndtering

Dette er et af de vigtigste aspekter at tænke på, når du opretter et projekt med ethvert sprog. Lad os se, hvordan vi håndterer fejl og undtagelser yndefuldt i en Express-app.

Brug af løfter

En af fordelene ved at bruge løfter frem for tilbagekald er, at de kan håndtere implicitte eller eksplicitte undtagelser / fejl i asynkrone kodeblokke såvel som for synkron kode, der er defineret i .then(), et tilbagekald til løfte

Bare tilføj .catch(next)i slutningen af ​​løftet kæden. For eksempel:

router.post('/create', (req, res, next) => { User.create(req.body) // function to store user data in db .then(result => { // do something with result return result }) .then(user => res.json(user)) .catch(next) })

Brug try-catch

Try-catch er en traditionel måde at fange undtagelser på asynkron kode.

Lad os se på et eksempel med mulighed for at få en undtagelse:

router.get('/search', (req, res) => { setImmediate(() => { const jsonStr = req.query.params try { const jsonObj = JSON.parse(jsonStr) res.send('Success') } catch (e) { res.status(400).send('Invalid JSON string') } }) })

Undgå at bruge synkron kode

Synkron kode, også kendt som blokeringskode, fordi den blokerer udførelsen, indtil de udføres.

Så undgå at bruge synkrone funktioner eller metoder, der kan tage millisekunder eller mikrosekunder. For et websted med høj trafik vil det sammensættes og kan føre til høj latenstid eller svartid for API-anmodningerne.

Brug dem ikke i produktionen især :)

Mange Node.js-moduler leveres med begge .syncog .asyncmetoder, så brug async i produktionen.

Men hvis du stadig vil bruge en synkron API, skal du bruge --trace-sync-iokommandolinjeflag. Det udskriver en advarsel og et stakspor, når din applikation bruger en synkron API.

For mere om de grundlæggende fejlhåndtering, se:

  • Fejlhåndtering i Node.js
  • Bygning af robuste knudeprogrammer: Fejlhåndtering (StrongLoop-blog)
Hvad du ikke skal gøre er at lytte til uncaughtExceptionbegivenheden, der udsendes, når en undtagelse bobler helt tilbage til begivenhedssløjfen. Brug foretrækkes generelt ikke.

Logger korrekt

Logning er afgørende for fejlfinding og appaktivitet. Det bruges hovedsageligt til udviklingsformål. Vi bruger console.logog console.errormen disse er synkrone funktioner.

Til fejlfindingsformål

Du kan bruge et modul som debug. Dette modul giver dig mulighed for at bruge DEBUG-miljøvariablen til at kontrollere, hvilke fejlretningsmeddelelser der sendes til console.err(), hvis nogen.

Til appaktivitet

En måde er at skrive dem til databasen.

Tjek hvordan jeg brugte mangoose-plugins til at foretage revision af min ansøgning.

Another way is to write to a file OR use a logging library like Winston or Bunyan. For a detailed comparison of these two libraries, see the StrongLoop blog post Comparing Winston and Bunyan Node.js Logging.

require(“./../../../../../../”) mess

There are different workarounds for this problem.

If you find any module getting popular and if it has logical independence from the application, you can convert it to private npm module and use it like any other module in package.json.

OR

const path = require('path'); const HOMEDIR = path.join(__dirname,'..','..');

where __dirname is the built-in variable that names the directory that contains the current file, and .. ,..is the requisite number of steps up the directory tree to reach the root of the project.

From there it is simply:

const foo = require(path.join(HOMEDIR,'lib','foo')); const bar = require(path.join(HOMEDIR,'lib','foo','bar'));

to load an arbitrary file within the project.

Let me know in the comment below if you have better ideas :)

Set NODE_ENV to “production”

The NODE_ENV environment variable specifies the environment in which an application is running (usually, development or production). One of the simplest things you can do to improve performance is to set NODE_ENVto “production.”

Setting NODE_ENV to “production” makes Express:

  • Cache view templates.
  • Cache CSS files generated from CSS extensions.
  • Generate less verbose error messages.

Tests indicate that just doing this can improve app performance by a factor of three!

Using Process Manager

For production, you should not simply use node app.j — if your app crashes, it will be offline until you restart it.

The most popular process managers for Node are:

  • StrongLoop Process Manager
  • PM2
  • Forever

I personally use PM2.

For a feature-by-feature comparison of the three process managers, see //strong-pm.io/compare/. For a more detailed introduction to all three, see Process managers for Express apps.

Run your app in a cluster

In a multi-core system, you can increase the performance of a Node app by many times by launching a cluster of processes.

A cluster runs multiple instances of the app, ideally one instance on each CPU core. This distributes the load and tasks among the instances.

Using Node’s cluster module

Clustering is made possible with Node’s cluster module. This enables a master process to spawn worker processes. It distributes incoming connections among the workers.

Men i stedet for at bruge dette modul direkte, er det langt bedre at bruge et af de mange værktøjer derude, der gør det automatisk for dig. For eksempel node-pm eller cluster-service.

Brug af PM2

Til pm2 kan du bruge klynge direkte gennem en kommando. For eksempel,

# Start 4 worker processes pm2 start app.js -i 4 # Auto-detect number of available CPUs and start that many worker processes pm2 start app.js -i max 

Hvis du støder på problemer, er du velkommen til at kontakte eller kommentere nedenfor.

Jeg hjælper gerne :)

Tøv ikke med at klappe, hvis du betragter dette som en god læsning!

Referencer: //expressjs.com/en/advanced/best-practice-performance.html

Oprindeligt offentliggjort på 101node.io den 30. september 2018.