Пошаговое руководство для понимания основных концепций и создания первого расширения

Это сообщение в блоге написано Мариано Моретти, энтузиастом Node.js, активным членом сообщества JavaScript в La Plata и талантливым разработчиком в NaNLABS. Вы можете подписаться на него в Twitter @btomoretti и подписаться на @LaPlataJS, чтобы узнать больше об этом местном сообществе JavaScript в Аргентине. Эта статья впервые появилась в NaNLABS здесь.

Если вы читаете на испанском языке, вы можете прочитать этот пост на испанском здесь: Extensiones Nativas: ¿dónde empezar?

В этой статье мы поговорим о наиболее важных концепциях разработки собственных расширений для Node.js. Позже я покажу, как создать наше первое собственное расширение на практическом примере. И, наконец, я оставлю несколько ссылок, чтобы узнать об этом больше.

ОСНОВЫ, ЧТОБЫ НАЧАТЬ РАБОТУ С НАТУРАЛЬНЫМИ РАСШИРЕНИЯМИ

Проще говоря, мы можем сказать, что собственное расширение - это набор реализованной логики C ++, которая может быть вызвана из кода JavaScript.

На этом этапе нам интересно выяснить, как работает NodeJS и какие части в нем задействованы. Важно знать, почему мы можем говорить о двух языках (JavaScript и C ++) в контексте NodeJS.

Я люблю объяснять это так:

  • JavaScript: это язык программирования.
  • V8: это движок, который запускает наш код JavaScript.
  • Libuv: это библиотека C, которая обеспечивает асинхронное выполнение.

Теперь, где мы можем разместить собственные расширения? Я выберу действие записи / чтения диска в качестве примера, чтобы объяснить это. Ни JavaScript, ни V8 не предоставляют нам доступа к диску. Libuv обеспечивает асинхронное выполнение. Но с NodeJS мы можем писать / читать на диск, верно? Что ж, это тот момент, когда нативные расширения вступают в игру. Модуль fs реализован с использованием C ++ (у него есть доступ к диску) и в конечном итоге предоставляет методы (например, writeFile и readFile), которые можно вызывать из JavaScript.

Как только мы это узнаем, мы можем начать делать наши первые шаги в нативных расширениях. Поговорим о необходимых нам инструментах.

БАЗОВЫЙ ИНСТРУМЕНТ ДЛЯ ПОСТРОЕНИЯ НАТУРАЛЬНОГО РАСШИРЕНИЯ

BINDING.GYP ФАЙЛ

Этот файл позволяет нам указать, как нам нужно скомпилировать собственное расширение. Одна из основных вещей, которую нам нужно определить, - это файлы, которые будут скомпилированы, и то, как мы будем называть окончательный двоичный файл. Он имеет структуру, подобную JSON, и ключи для его настройки - это источники и цель.

NODE-GYP

Это инструмент, который позволяет нам скомпилировать собственное расширение. Он реализован в Node.js и связан с npm, поэтому мы можем просто запустить npm install, и это скомпилирует наше собственное расширение. Когда мы запускаем npm install, он обнаруживает наш файл binding.gyp, включенный в нашу корневую папку, и затем начинает компилировать.

Кроме того, это позволяет нам делать релизные (по умолчанию) или отладочные сборки. В результате двоичный файл с расширением .node будет создан внутри папки выпуска или отладки, в зависимости от того, как он был настроен.

ВЯЗКИ

Это пакет Node.js, который позволяет нам экспортировать собственное расширение. Он отвечает за поиск в папке сборки или выпуска.

N-API

Именно C API позволяет нам полностью абстрактно взаимодействовать с нашим движком. Для меня это результат эволюции, которая пытается перенести узел на разные архитектуры.

N-API обеспечивает стабильность и совместимость между различными версиями узлов. То есть, если мое собственное расширение скомпилировано для узла 8.1, мне не нужно компилировать его снова для узла 8.6 или 9.3. Таким образом, облегчая жизнь сопровождающим и участникам.

На данный момент N-API переведен на стабильную версию с Node.js v10. Скоро в 8 он будет стабильным, а в 6 - экспериментальным.

NODE ADDON API

Этот модуль Node.js предоставляет нам реализацию N-API на C ++ и позволяет использовать преимущества языка.

ПЕРВЫЕ ШАГИ В МИРЕ РОДНОГО РАСШИРЕНИЯ

Примечание. В этом примере я использовал Node.js 9.3.

Чтобы начать знакомство с миром собственных расширений, мы воспользуемся классическим примером hello world. Идея состоит в том, чтобы не перегружать код лишней логикой, чтобы мы могли сосредоточиться на минимально необходимом коде.

Мы начинаем инициализировать npm, чтобы затем можно было установить наши зависимости:

npm init

Теперь, как мы уже сказали, устанавливаем наши зависимости:

npm i node-addon-api bindings

На этом этапе нам нужно создать наш файл C с нашей логикой:

Этот файл состоит из трех важных частей, которые будут объяснены снизу вверх:

  • NODE_API_MODULE (строка 14): первый аргумент - это собственное имя расширения, а второй - имя функции, которая инициализирует наше расширение.
  • Init (строка 10): это функция, которая инициализирует наше собственное расширение. В этой функции мы должны экспортировать функции, которые будут вызываться из кода JavaScript. Для этого нам нужно установить имя функции для объекта экспорта и саму функцию, которая будет вызываться. Эта функция инициализации должна возвращать объект экспорта.
  • SayHi (строка 3): эта функция будет выполняться, когда мы вызываем собственное расширение из нашего JavaScript.

Позже нам нужно создать наш файл binding.gyp, который будет содержать конфигурацию нашего собственного расширения:

Наконец, код JavaScript, который потребует наше расширение и вызовет его.

Теперь нам просто нужно скомпилировать наше расширение, запустив npm install, и запустить файл JavaScript, который используется:

Вот и все. Мы просто запускаем собственное расширение.

ЧТО У НАС БЫЛО ДО N-API?

Я считаю важным знать контекст и историю собственных расширений, поскольку это дает доступ к большому количеству документации и примеров. Идея состоит в том, чтобы N-API в конечном итоге заменил NAN. По этой причине нам следует ненадолго оглянуться на NAN.

NAN? Да, Нативная абстракция для Node.js. NAN - это библиотека C ++, которая предоставляет нам абстракцию V8, но не позволяет нам абстрагироваться от V8.
В новых выпусках NodeJS могут быть изменения V8, которые могут нарушить работу нашего собственного расширения. Использование N-API - способ избежать этой проблемы.

ДАЛЬНЕЙШИЕ ШАГИ ПО РАЗРАБОТКЕ НАТУРАЛЬНЫХ РАСШИРЕНИЙ

Как я уже сказал, знание NAN позволяет нам учиться на примерах и документации. Это хорошее дополнение к нашему процессу обучения собственному расширению.

  • Примеры NAPI можно найти здесь.
  • Примеры Node-addon-api можно найти здесь.
  • Примеры Nan можно найти здесь.
  • Еще один хороший источник - тесты здесь.
  • Чтобы узнать больше о нативных расширениях здесь.

ЗАКЛЮЧЕНИЕ

Изучение нативных расширений помогло мне понять, как работает NodeJS и как он устроен. Есть несколько сценариев, в которых мы можем их использовать, например, повышение производительности, интеграция библиотек C / C ++ или интеграция с унаследованным кодом.

Таким образом, это отличный способ узнать о внутреннем устройстве NodeJS.

Если у вас есть сомнения, оставьте комментарий, и я вам помогу. Вы также можете подписаться на меня в твиттере @btomoretti

УЧАСТИЕ В СООБЩЕСТВЕ

Я сделал этот пост для публикации в LaPlataJS. Это местное сообщество JavaScript, в котором я участвую, помогая с обсуждениями, организацией мероприятий или публикациями. Я думаю, что при любой возможности вам следует присоединиться к сообществу. Для меня это имеет много преимуществ. Вы можете узнать действительно хороших людей, поделиться идеями, узнать что-то новое, а иногда и выпить пива с друзьями.