Kako napisati Node i Express aplikaciju spremnu za produkciju

Strukturiranje projekata

Kad sam počeo izrađivati ​​Node & Express aplikacije, nisam znao koliko je važno strukturirati vašu aplikaciju. Express ne dolazi sa strogim pravilima ili smjernicama za održavanje strukture projekta.

Možete slobodno koristiti bilo koju strukturu koju želite. Kada vaša baza kodova naraste, na kraju imate duge routerukovatelje. Zbog toga je vaš kôd teško razumjeti i sadrži potencijalne pogreške.

Ako radite za startup, većinu vremena nećete imati vremena za prelamanje vašeg projekta ili modularizaciju. Možete završiti s beskrajnom petljom ispravljanja i ispravljanja programskih pogrešaka.

Tijekom vremena, radeći i s malim i s velikim timovima, shvatio sam kakvu strukturu možete rasti s vašim projektom i koju je i dalje lako održavati.

Model View Controller

MVC obrazac pomaže u brzom i paralelnom razvoju. Na primjer, jedan programer može raditi na prikazu, dok drugi može raditi na stvaranju poslovne logike u kontroleru.

Pogledajmo primjer jednostavne korisničke CRUD aplikacije.

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
  • kontroleri: definirajte rukovatelje ruta aplikacija i poslovnu logiku
  • util: Ovdje zapisuje uslužne / pomoćne funkcije koje mogu koristiti bilo koji kontrolori. Na primjer, možete napisati funkciju poput mergeTwoArrays(arr1, arr2).
  • middlewares: Možete napisati middlewares da biste protumačili sve dolazne zahtjeve prije prelaska na rukovatelj rutom. Na primjer,

    router.post('/login', auth, controller.login)gdje authje funkcija međuopreme definirana u middlewares/auth.js.

  • modeli: također vrsta posredničkog softvera između vašeg kontrolera i baze podataka. Možete definirati shemu i izvršiti provjeru prije pisanja u bazu podataka. Na primjer, možete koristiti ORM poput Mongoosea koji dolazi s izvrsnim značajkama i metodama za upotrebu u samoj shemi
  • rute: Definirajte rute aplikacije pomoću HTTP metoda. Na primjer, možete definirati sve što se odnosi na korisnika.
router.post('/users/create', controller.create) router.put('/users/:userId', controller.update) router.get('/users', controller.getAll)
  • javno: pohranite statične slike u /img, prilagođene JavaScript datoteke i CSS/css
  • pogledi: Sadrži predloške koje poslužitelj generira.
  • testovi: Ovdje možete napisati sve jedinične testove ili testove prihvaćanja za API poslužitelj.
  • app.js: Djeluje kao glavna datoteka projekta u kojoj inicijalizirate aplikaciju i ostale elemente projekta.
  • package.json: Vodi računa o ovisnostima, skriptama koje se pokreću s npmnaredbom i verziji vašeg projekta.

Iznimke i rukovanje pogreškama

Ovo je jedan od najvažnijih aspekata o kojem treba razmišljati prilikom stvaranja bilo kojeg projekta na bilo kojem jeziku. Pogledajmo kako se elegantno nositi s pogreškama i iznimkama u Express aplikaciji.

Koristeći se obećanjima

Jedna od prednosti korištenja obećanja u odnosu na povratne pozive je da se oni mogu nositi s implicitnim ili eksplicitnim iznimkama / pogreškama u blokovima asinkronog koda, kao i za sinkroni kod definiran u .then(), povratnom pozivu obećanja

Samo dodajte .catch(next)na kraju lanca obećanja. Na primjer:

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) })

Koristeći try-catch

Try-catch je tradicionalni način hvatanja iznimaka u asinkronom kodu.

Pogledajmo primjer s mogućnošću dobivanja iznimke:

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') } }) })

Izbjegavajte upotrebu sinkronog koda

Sinkroni kod također poznat i kao blokirni kod, jer blokira izvršenje dok se ne izvrše.

Stoga izbjegavajte korištenje sinkronih funkcija ili metoda koje bi mogle potrajati milisekunde ili mikrosekunde. Za web mjesto s velikim prometom to će se složiti i može dovesti do velike latencije ili vremena odgovora na zahtjeve za API.

Nemojte ih posebno koristiti u proizvodnji :)

Mnogi moduli Node.js dolaze s obje metode .synci .asyncmetodama, pa zato koristite async u proizvodnji.

Ali, ako i dalje želite koristiti sinkroni API, koristite --trace-sync-iozastavicu naredbenog retka. Ispisat će upozorenje i trag steka kad god vaša aplikacija koristi sinkroni API.

Više o osnovama postupanja s pogreškama potražite u:

  • Rukovanje pogreškama u Node.js
  • Izgradnja robusnih aplikacija čvorova: rukovanje pogreškama (StrongLoop blog)
Ono što ne biste smjeli je osluškivati uncaughtExceptiondogađaj koji se emitira kad se iznimka mjehuri sve do povratne petlje događaja. Njegova upotreba uglavnom nije poželjna.

Prijavljivanje pravilno

Zapisivanje je neophodno za uklanjanje pogrešaka i aktivnosti aplikacija. Koristi se uglavnom u razvojne svrhe. Koristimo console.logi, console.errorali to su sinkrone funkcije.

U svrhu otklanjanja pogrešaka

Možete koristiti modul poput otklanjanja pogrešaka. Ovaj vam modul omogućuje upotrebu varijable okruženja DEBUG za kontrolu onoga na što se poruke za otklanjanje pogrešaka šalju console.err(), ako ih ima.

Za aktivnosti u aplikaciji

Jedan od načina je upisivanje u bazu podataka.

Pogledajte kako sam koristio mongoose dodatke za reviziju svoje aplikacije.

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.

However, rather than using this module directly, it’s far better to use one of the many tools out there that do it for you automatically. For example node-pm or cluster-service.

Using PM2

For pm2 you can use cluster directly through a command. For example,

# 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 

If you encounter any problems, feel free to get in touch or comment below.

I would be happy to help :)

Don’t hesitate to clap if you considered this a worthwhile read!

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

Originally published at 101node.io on September 30, 2018.