Як написати готовий до використання додаток Node і Express

Структурування проекту

Коли я починав створювати програми Node & 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.

  • models: також свого роду проміжне програмне забезпечення між вашим контролером та базою даних. Ви можете визначити схему та виконати певну перевірку перед записом у базу даних. Наприклад, ви можете використовувати ORM, такий як Mongoose, який має чудові функції та методи для використання в самій схемі
  • маршрути: Визначте маршрути додатків методами HTTP. Наприклад, ви можете визначити все, що стосується користувача.
router.post('/users/create', controller.create) router.put('/users/:userId', controller.update) router.get('/users', controller.getAll)
  • public: зберігайте статичні зображення у /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.