Как да напиша готово за производство приложение Node и Express

Структуриране на проекти

Когато започнах да изграждам Node & Express приложения, не знаех колко е важно да структурирам вашето приложение. Express не идва със строги правила или насоки за поддържане на структурата на проекта.

Можете свободно да използвате каквато и да е структура. Когато вашата кодова база расте, в крайна сметка имате дълги routeманипулатори. Това прави кода ви труден за разбиране и съдържа потенциални грешки.

Ако работите за стартиране, през повечето време няма да имате време да пречупите проекта си или да го модулирате. Можете да завършите с безкраен цикъл за отстраняване на грешки и корекции.

С течение на времето, докато работех както с малки екипи, така и с големи екипи, разбрах каква структура може да се развие с вашия проект и все пак да бъде лесна за поддръжка.

Контролер за изглед на модел

Моделът MVC помага за бързо и паралелно развитие. Например, един разработчик може да работи върху изгледа, докато друг може да работи върху създаването на бизнес логика в контролера.

Нека да разгледаме пример за просто потребителско CRUD приложение.

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
  • контролери: Определете манипулаторите на маршрута на приложението и бизнес логиката
  • util: Написва тук помощни / помощни функции, които могат да се използват от всеки контролер. Например можете да напишете функция като mergeTwoArrays(arr1, arr2).
  • middlewares: Можете да пишете middlewares, за да интерпретирате всички входящи заявки, преди да преминете към манипулатора на маршрута. Например,

    router.post('/login', auth, controller.login)където authе функцията на междинния софтуер, дефинирана в middlewares/auth.js.

  • модели: също вид междинен софтуер между вашия контролер и базата данни. Можете да дефинирате схема и да извършите някои проверки, преди да запишете в базата данни. Например можете да използвате ORM като Mongoose, който се предлага със страхотни функции и методи за използване в самата схема
  • маршрути: Определете маршрутите на приложението си с HTTP методи. Например можете да дефинирате всичко, свързано с потребителя.
router.post('/users/create', controller.create) router.put('/users/:userId', controller.update) router.get('/users', controller.getAll)
  • публично: Съхранявайте статични изображения в /img, персонализирани JavaScript файлове и CSS/css
  • изгледи: Съдържа шаблони, които трябва да бъдат изобразени от сървъра.
  • тестове: Тук можете да напишете всички модулни тестове или тестове за приемане за API сървъра.
  • app.js: Действа като основен файл на проекта, където инициализирате приложението и другите елементи на проекта.
  • package.json: Грижи се за зависимостите, скриптовете, които да се изпълняват с npmкомандата, и версията на вашия проект.

Изключения и обработка на грешки

Това е един от най-важните аспекти, върху които трябва да помислите, когато създавате всеки проект с който и да е език. Нека да видим как да обработваме елегантно грешки и изключения в приложението Express.

Използване на обещания

Едно от предимствата на използването на обещания пред обратно извикване е, че те могат да се справят с неявни или явни изключения / грешки в асинхронни кодови блокове, както и за синхронен код, дефиниран в .then(), обещание за обратно извикване

Просто добавете .catch(next)в края на веригата за обещания. Например:

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

Използване на try-catch

Try-catch е традиционен начин за улавяне на изключения в асинхронен код.

Нека да разгледаме един пример с възможност за получаване на изключение:

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

Избягвайте да използвате синхронен код

Синхронен код, известен също като блокиращ код, тъй като блокира изпълнението, докато те бъдат изпълнени.

Затова избягвайте да използвате синхронни функции или методи, които могат да отнемат милисекунди или микросекунди. За уебсайт с голям трафик той ще се състави и може да доведе до висока латентност или време за реакция на заявките за API.

Не ги използвайте в производството особено :)

Много модули Node.js се предлагат и с двете, .syncи с .asyncметодите, така че използвайте async в производството.

Но ако все пак искате да използвате синхронен API, използвайте --trace-sync-ioфлага на командния ред. Той ще отпечатва предупреждение и проследяване на стека, когато вашето приложение използва синхронен API.

За повече информация относно основите на обработката на грешки вижте:

  • Обработка на грешки в Node.js
  • Изграждане на здрави приложения на възли: Обработка на грешки (StrongLoop блог)
Това, което не трябва да правите, е да слушате uncaughtExceptionсъбитието, излъчено, когато едно изключение мехурче по целия път обратно до цикъла на събитието. Използването му обикновено не е за предпочитане.

Правилно регистриране

Регистрацията е от съществено значение за отстраняване на грешки и активност в приложенията. Използва се предимно за целите на развитието. Ние използваме console.logи, console.errorно това са синхронни функции.

С цел отстраняване на грешки

Можете да използвате модул като отстраняване на грешки. Този модул ви позволява да използвате променливата на средата DEBUG, за да контролирате до какво се изпращат съобщения за отстраняване на грешки console.err(), ако има такива.

За активност в приложението

Един от начините е да ги запишете в базата данни.

Вижте как използвах приставки за мангуста, за да направя одит на моето приложение.

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.