Node — одна из самых известных платформ для разработки приложений, работающая на движке V8 и выполняющая код JavaScript вне веб-браузера. Несмотря на популярность и интересные функции, такие как асинхронное или неблокирующее поведение, Nodejs не так быстр по сравнению с языками или фреймворками, такими как Go и Rust.

С другой стороны, Rust — это строго типизированный и компилируемый язык с отличными функциями, такими как замыкание и анонимные функции, богатая стандартная библиотека (std), сильные типы, полиморфизм, фантастическая система сборки и менеджер пакетов Cargo. . Rust также является безопасным для памяти языком, поскольку он выполняет проверку памяти при компиляции. Со всеми этими положительными сторонами Rust вы когда-нибудь задумывались, можете ли вы писать JavaScript, но с такой же безопасностью типов и памяти, как Rust? Вот где Неон вступает в игру. Neon позволяет писать JavaScript на Rust.

Что такое неон

Neon — это библиотека и набор инструментов для встраивания Rust в ваши приложения и библиотеки Node.js. Neon позволяет вам писать безопасные для типов и памяти, безотказные нативные модули Node, которые гарантируют параллелизм Rust с безопасностью потоков.

Преимущества использования неона

Помимо памяти и безопасности типов, есть и другие причины, по которым вам следует использовать Rust Embedded в Node.

  • Параллельное программирование и потоки
  • Производительность
  • Доступ к родным библиотекам ОС
  • Доступ к экосистеме Rust через Cargo

Neon также предоставляет интерфейс командной строки и рабочий процесс, связанный с соглашениями, которые избавляют от хлопот создания собственных модулей Node.

Изучение неонового API

Давайте изучим Neon API и посмотрим, как мы можем написать собственный модуль узла с помощью Rust. Во-первых, давайте посмотрим на типы дескрипторов Howlet.

  • JsValue находится на вершине иерархии типов и может ссылаться на любое значение JavaScript.
  • JsObject находится на вершине иерархии типов объектов. Все типы объектов реализуют трейт Object, который позволяет получать и устанавливать свойства. Такие типы, как JsFunction, JsArray, JsDate и JsError, попадают в этот раздел.
  • JsNumber, JsBoolean, JsString, JsNull и JsUndefined являются встроенными Типы данных JavaScript, не являющиеся объектными типами (примитивные типы)

Далее переходим к файлу точки входа src/lib.rs. Он будет состоять из основной функции, которая имеет специальную неоновую аннотацию под названием #[neon::main], которая выполняется при загрузке модуля (инициализация в модуле Neon). Вы можете переименовать функцию, если хотите, пока сохраняете эту аннотацию. Это будет точка входа вашего модуля.

#[neon::main]
fn main(mut cx: ModuleContext) -> NeonResult<()> {
    cx.export_function("hello", hello)?;
    Ok(())
}
fn hello(mut cx: FunctionContext) -> JsResult<JsString> {
    Ok(cx.string("hello node"))
}

Функция hello, экспортируемая методом main, принимает аргумент с именем FunctionContext (который предоставляет функции Neon доступ к среде выполнения JavaScript) и возвращает строку JavaScript. Вы можете заметить, что все функции Neon возвращаются с типом под названиемJsResult, потому что все функции Neon потенциально могут генерировать исключение JavaScript.

Создайте модуль Nodejs

Давайте погрузимся в Neon, создав модуль узла. В этом примере давайте создадим модуль, который предоставляет функции для создания области фигур (квадрат, круг, треугольник и т. д.). Но прежде чем мы начнем, у нас есть некоторые предварительные условия, и вам нужна последняя версия или LTS-версия Nodejs и Rust (визуальные инструменты сборки студии, если вы используете Windows). После установки всех необходимых компонентов приступим к инициализации проекта.

npm init neon neon-area

Приведенная выше команда инициализирует проект файлами Cargo.toml и package.json, которые содержат сведения о пакете (зависимости, сведения о модулях) для Rust и Nodejs. Вы заметите, что в корне проекта появится новый каталог с именем src/,который состоит из файла с именем lib.rs, где все волшебство происходит с Rust.

Этот src/lib.rs изначально будет выглядеть так.

use neon::prelude::*;
fn hello(mut cx: FunctionContext) -> JsResult<JsString> {
  Ok(cx.string("hello"))
}
#[neon::main]
fn main(mut cx: ModuleContext) -> NeonResult<()> {
 cx.export_function("hello", hello)?;
 Ok(())
}

В приведенном выше коде вы будете экспортировать функцию, которая возвращает строку (в javaScript) как свойство модуля с именем hello, а позже вы сможете получить к нему доступ через JavaScript, импортировав модуль. Чтобы сначала создать модуль узла, вы должны создать приведенный выше код, используя следующую команду.

npm run build -- --release

Это скомпилирует ваш код Rust и создаст собственный модуль узла в корне вашего проекта с именем index.node. Эти файлы .node являются надстройками Node (бинарными модулями), и вы должны иметь возможность использовать для них require() с JavaScript для доступа к модулю.

const {hello} = require("./index.node");
console.log(hello()); // logs "hello" to the console

Теперь давайте перейдем к созданию нашего модуля области с помощью Neon. Во-первых, давайте создадим структуру с именем Area и перейдем к реализации этих методов.

struct Area {
 pub pi: f64,
}
impl Area {
 
 fn circle(&self, radius: f64) -> f64 {
   return 2.00 * self.pi * radius;
 }
 fn squar(&self, length: f64, width: f64) -> f64 {
   return length * width;
 }
 fn traingle(&self, length: f64, width: f64, height: f64) -> f64 {
  let s: f64 = (length + width + height) / 2.0;
  let area: f64 = s * (s - length) * (s - width) * (s - height);
  return area.sqrt();
 }
 fn pentagon(&self, length: f64) -> f64 {
  return ((f64::sqrt(5.00 * (5.00 + (2.00 * f64::sqrt(5.00))))) /   4.00) * (length * length);
 }
 fn hexagon(&self, length: f64) -> f64 {
  return (3.00 * f64::sqrt(3.00)) / 2.00 * length;
 }
 fn trapezium(&self, length: f64, base: f64, height: f64) -> f64 {
  return (length * base) / 2.00 * height;
 }
}

Теперь давайте экспортируем эти функции как модуль через метод main. Давайте посмотрим на окончательный код для файла src/lib.rc.

Теперь пришло время снова собрать модуль и использовать сгенерированный модуль в приложении JavaScript.

Выполнение приведенного выше кода приведет к чему-то подобному в терминале.

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

Заключение

Neon — один из лучших способов написания собственных узловых модулей из-за типа и безопасности памяти, обеспечиваемых Rust. Neon также предоставляет цикл событий JavaScript для планирования асинхронных событий, поэтому вы можете выполнять дорогостоящие или длительные вычисления в фоновом потоке, не блокируя поток JavaScript. У Neon есть хорошее и активное сообщество в slack, где вы можете делиться опытом и учиться у сообщества неонов. Вы можете делать больше интересных вещей с Neon, обязательно просмотрите их документацию для получения дополнительной информации. Наконец, спасибо, что нашли время, чтобы прочитать это. Я хотел бы видеть ваши вопросы и комментарии ниже.

Ваше здоровье!

Узнать больше