changeset 2577:67fd664e2612

Translated "Using node modules with njs" into Russian.
author Yaroslav Zhuravlev <yar@nginx.com>
date Thu, 06 Aug 2020 14:49:00 +0100
parents 4c8d0b37932d
children fafb7767c128
files xml/ru/GNUmakefile xml/ru/docs/njs/index.xml xml/ru/docs/njs/node_modules.xml
diffstat 3 files changed, 157 insertions(+), 153 deletions(-) [+]
line wrap: on
line diff
--- a/xml/ru/GNUmakefile
+++ b/xml/ru/GNUmakefile
@@ -112,6 +112,7 @@ REFS =									\
 		njs/examples						\
 		njs/install						\
 		njs/reference						\
+		njs/node_modules					\
 		njs/typescript						\
 
 TOP =									\
--- a/xml/ru/docs/njs/index.xml
+++ b/xml/ru/docs/njs/index.xml
@@ -89,7 +89,7 @@ ngx_stream_js_module</link>
 </listitem>
 
 <listitem>
-<link doc="node_modules.xml">Использование модулей Node.js в njs</link>
+<link doc="node_modules.xml"/>
 </listitem>
 
 </list>
copy from xml/en/docs/njs/node_modules.xml
copy to xml/ru/docs/njs/node_modules.xml
--- a/xml/en/docs/njs/node_modules.xml
+++ b/xml/ru/docs/njs/node_modules.xml
@@ -6,90 +6,90 @@
 
 <!DOCTYPE article SYSTEM "../../../../dtd/article.dtd">
 
-<article name="Using node modules with njs"
-        link="/en/docs/njs/node_modules.html"
+<article name="Использование модулей Node.js в njs"
+        link="/ru/docs/njs/node_modules.html"
         lang="en"
         rev="4">
 
 <section id="intro">
 
 <para>
-Often, a developer wants to use 3rd-party code,
-usually available as a library of some kind.
-In the JavaScript world, the concept of a module is relatively new,
-so there was no standard until recently.
-Many platforms (browsers) still don't support modules, which makes code
-reuse harder.
-This article describes ways to reuse
-<link url="https://nodejs.org/">Node.js</link> code in njs.
+Часто разработчику приходится использовать сторонний код и,
+как правило, такой код доступен в виде библиотеки.
+В JavaScript концепция модулей является новой и
+до недавнего времени не была стандартизированa.
+До сих пор множество платформ или браузеров не поддерживают модули,
+по этой причине практически невозможно повторно использовать код.
+В данной статье приводятся способы повторного использования
+кода в njs при помощи <link url="https://nodejs.org/">Node.js</link>.
 </para>
 
 <note>
-Examples in this article use features that appeared in
+В примерах статьи используется функциональность
 <link doc="index.xml">njs</link>
 <link doc="changes.xml" id="njs0.3.8">0.3.8</link>
 </note>
 
 <para>
-There is a number of issues
-that may arise when 3rd-party code is added to njs:
+При добавлении стороннего кода в njs
+может возникнуть несколько проблем:
 
 <list type="bullet">
 
 <listitem>
-Multiple files that reference each other and their dependencies
+большое количество файлов, ссылающихся друг на друга, и их зависимости
 </listitem>
 
 <listitem>
-Platform-specific APIs
+платформозависимые API
 </listitem>
 
 <listitem>
-Modern standard language constructions
+языковые конструкции нового стандарта
 </listitem>
 
 </list>
 </para>
 
 <para>
-The good news is that such problems are not something new or specific to njs.
-JavaScript developers face them daily
-when trying to support multiple disparate platforms
-with very different properties.
-There are instruments designed to resolve the above-mentioned issues.
+Однако это не является чем-то новым или специфичным для njs.
+Разработчикам JavaScript приходится часто иметь дело с подобными случаями,
+например при поддержке нескольких несхожих платформ
+с разными свойствами.
+Данные проблемы можно разрешить при помощи следующих инструментов:
 
 <list type="bullet">
 
 <listitem>
-Multiple files that reference each other, and their dependencies
+Большое количество файлов, ссылающихся друг на друга, и их зависимости
 <para>
-This can be solved by merging all the interdependent code into a single file.
-Tools like
-<link url="http://browserify.org/">browserify</link> or
-<link url="https://webpack.js.org/">webpack</link>
-accept an entire project and produce a single file containing
-your code and all the dependencies.
+Решение: слияние всего независимого кода в один файл.
+Для этих целей могут использоваться утилиты
+<link url="http://browserify.org/">browserify</link> или
+<link url="https://webpack.js.org/">webpack</link>,
+позволяющие преобразовать проект в один файл, содержащий
+код и все зависимости.
 </para>
 </listitem>
 
 <listitem>
-Platform-specific APIs
+Платформозависимые API
 <para>
-You can use multiple libraries that implement such APIs
-in a platform-agnostic manner (at the expense of performance, though).
-Particular features can also be implemented using the
-<link url="https://polyfill.io/v3/">polyfill</link> approach.
+Решение: использование библиотек, реализующих подобные API
+в платформонезависимом режиме, однако в ущерб производительности.
+Определённая функциональность может быть также реализована при помощи
+<link url="https://polyfill.io/v3/">polyfill</link>.
 </para>
 </listitem>
 
 <listitem>
-Modern standard language constructions
+Языковые конструкции нового стандарта
 <para>
-Such code can be transpiled:
-this means performing a number of transformations
-that rewrite newer language features in accordance with an older standard.
-For example, <link url="https://babeljs.io/"> babel</link> project
-can be used to this purpose.
+Решение: трансплирование кода&mdash;
+ряд преобразований,
+заменяющих новые функции языка в соответствии со старым стандартом.
+Для этих целей может использоваться
+<link url="https://babeljs.io/"> babel</link>.
 </para>
 </listitem>
 
@@ -97,19 +97,20 @@ can be used to this purpose.
 </para>
 
 <para>
-In this guide, we will use two relatively large npm-hosted libraries:
+В статье также используются две относительно большие
+библиотеки на основе npm:
 
 <list type="bullet">
 
 <listitem>
 <link url="https://www.npmjs.com/package/protobufjs">protobufjs</link>&mdash;
-a library for creating and parsing protobuf messages used by the
-<link url="https://grpc.io/">gRPC</link> protocol
+библиотека для создания и парсинга protobuf-сообщений, используемая
+протоколом <link url="https://grpc.io/">gRPC</link>
 </listitem>
 
 <listitem>
 <link url="https://www.npmjs.com/package/dns-packet">dns-packet</link>&mdash;
-a library for processing DNS protocol packets
+библиотека для обработки пакетов протокола DNS
 </listitem>
 
 </list>
@@ -118,19 +119,20 @@ a library for processing DNS protocol pa
 </section>
 
 
-<section id="environment" name="Environment">
+<section id="environment" name="Окружение">
 
 <para>
 <note>
-This document mostly employs a generic approach
-and avoids specific best practice advices concerning Node.js
-and JavaScript.
-Make sure to consult the corresponding package's manual
-before following the steps suggested here.
+В статье описываются общие принципы работы
+и не ставится цель описания подробных сценариев работы с Node.js
+и JavaScript.
+Перед выполнением команд
+необходимо ознакомиться с документацией соответствующих пакетов.
 </note>
-First (assuming Node.js is installed and operational), let's create an
-empty project and install some dependencies;
-the commands below assume we are in the working directory:
+Сначала, предварительно установив и запустив Node.js, необходимо создать
+пустой проект и установить зависимости;
+для выполнения нижеперечисленных команд необходимо
+находиться в рабочем каталоге:
 <example>
 $ mkdir my_project &amp;&amp; cd my_project
 $ npx license choose_your_license_here > LICENSE
@@ -162,30 +164,30 @@ EOF
 <section id="protobuf" name="Protobufjs">
 
 <para>
-The library provides a parser
-for the <literal>.proto</literal> interface definitions
-and a code generator for message parsing and generation.
+Библиотека предоставляет парсер
+для определения интерфейса <literal>.proto</literal>,
+а также генератор кода для парсинга и генерации сообщений.
 </para>
 
 <para>
-In this example, we will use the
+В данном примере используется
+файл
 <link url="https://github.com/grpc/grpc/blob/master/examples/protos/helloworld.proto">helloworld.proto</link>
-file
-from the gRPC examples.
-Our goal is to create two messages:
-<literal>HelloRequest</literal> and
+из примеров gRPC.
+Целью является создание двух сообщений:
+<literal>HelloRequest</literal> и
 <literal>HelloResponse</literal>.
-We will use the
-<link url="https://github.com/protobufjs/protobuf.js/blob/master/README.md#reflection-vs-static-code">static</link>
-mode of protobufjs instead of dynamically generating classes, because
-njs doesn't support adding new functions dynamically
-due to security considerations.
+Также используется
+<link url="https://github.com/protobufjs/protobuf.js/blob/master/README.md#reflection-vs-static-code">статический</link>
+режим protobufjs вместо динамически генерируемых классов, так как
+njs не поддерживает динамическое добавление новых функций
+из соображений безопасности.
 </para>
 
 <para>
-Next, the library is installed and
-the JavaScript code implementing message marshalling
-is generated from the protocol definition:
+Затем устанавливается библиотека,
+из определения протокола генерируется код JavaScript,
+реализующий маршалинг сообщений:
 <example>
 $ npm install protobufjs
 $ npx pbjs -t static-module helloworld.proto > static.js
@@ -193,33 +195,33 @@ is generated from the protocol definitio
 </para>
 
 <para>
-Thus, the <literal>static.js</literal> file becomes our new dependency,
-storing all the code we need to implement message processing.
-The <literal>set_buffer()</literal> function contains code that uses the
-library to create a buffer with the serialized
-<literal>HelloRequest</literal> message.
-The code resides in the <literal>code.js</literal> file:
+Таким образом файл <literal>static.js</literal> становится новой зависимостью,
+хранящей необходимый код для реализации обработки сообщений.
+Функция <literal>set_buffer()</literal> содержит код, использующий
+библиотеку для создания буфера с сериализованным
+сообщением <literal>HelloRequest</literal>.
+Код находится в файле <literal>code.js</literal>:
 <example>
 var pb = require('./static.js');
 
-// Example usage of protobuf library: prepare a buffer to send
+// Пример использования библиотеки protobuf: подготовка буфера к отправке
 function set_buffer(pb)
 {
-    // set fields of gRPC payload
+    // назначение полей gRPC payload
     var payload = { name: "TestString" };
 
-    // create an object
+    // создание объекта
     var message = pb.helloworld.HelloRequest.create(payload);
 
-    // serialize object to buffer
+    // сериализация объекта в буфер
     var buffer = pb.helloworld.HelloRequest.encode(message).finish();
 
     var n = buffer.length;
 
     var frame = new Uint8Array(5 + buffer.length);
 
-    frame[0] = 0;                        // 'compressed' flag
-    frame[1] = (n &amp; 0xFF000000) &gt;&gt;&gt; 24;  // length: uint32 in network byte order
+    frame[0] = 0;                        // флаг 'compressed'
+    frame[1] = (n &amp; 0xFF000000) &gt;&gt;&gt; 24;  // длина: uint32 в сетевом порядке байт
     frame[2] = (n &amp; 0x00FF0000) &gt;&gt;&gt; 16;
     frame[3] = (n &amp; 0x0000FF00) &gt;&gt;&gt;  8;
     frame[4] = (n &amp; 0x000000FF) &gt;&gt;&gt;  0;
@@ -234,7 +236,7 @@ var frame = set_buffer(pb);
 </para>
 
 <para>
-To ensure it works, we execute the code using node:
+Для проверки работоспособности необходимо выполнить код при помощи node:
 <example>
 $ node ./code.js
 Uint8Array [
@@ -243,8 +245,8 @@ Uint8Array [
   116, 114, 105, 110, 103
 ]
 </example>
-You can see that this got us a properly encoded <literal>gRPC</literal> frame.
-Now let's run it with njs:
+Результатом является закодированный фрейм <literal>gRPC</literal>.
+Теперь фрейм можно запустить с njs:
 <example>
 $ njs ./code.js
 Thrown:
@@ -255,44 +257,44 @@ Error: Cannot find module "./static.js"
 </para>
 
 <para>
-Modules are not supported, so we've received an exception.
-To overcome this issue, let's use <literal>browserify</literal>
-or other similar tool.
+Так как модули не поддерживаются, то операция завершается получением исключения.
+В этом случае можно использовать утилиту <literal>browserify</literal>
+или другую подобную утилиту.
 </para>
 
 <para>
-An attempt to process our existing <literal>code.js</literal> file will result
-in a bunch of JS code that is supposed to run in a browser,
-i.e. immediately upon loading.
-This isn't something we actually want.
-Instead, we want to have an exported function that
-can be referenced from the nginx configuration.
-This requires some wrapper code.
+Попытка обработки файла <literal>code.js</literal> завершится
+большим количеством JS-кода, который предполагается запускать в браузере,
+то есть сразу после загрузки.
+Однако необходимо получить другой результат&mdash;
+экспортируемую функцию, на которую
+можно сослаться из конфигурации nginx.
+Для этого потребуется создание кода-обёртки.
 <note>
-In this guide, we use
-njs <link doc="cli.xml">cli</link> in all examples for the sake of simplicity.
-In real life, you will be using nginx njs module to run your code.
+В целях упрощения в примерах данной статьи
+используется <link doc="cli.xml">интерфейс комадной строки</link> njs.
+На практике для запуска кода обычно используется njs-модуль для nginx.
 </note>
 </para>
 
 <para>
-The <literal>load.js</literal> file contains the library-loading code that
-stores its handle in the global namespace:
+Файл <literal>load.js</literal> содержит код, загружающий библиотеку,
+храняющую дескриптор в глобальном пространстве имён:
 <example>
 global.hello = require('./static.js');
 </example>
-This code will be replaced with merged content.
-Our code will be using the "<literal>global.hello</literal>" handle to access
-the library.
+Данный код будет заменён объединённым содержимым.
+Код будет использовать дескриптор "<literal>global.hello</literal>" для доступа
+к библиотеке.
 </para>
 
 <para>
-Next, we process it with <literal>browserify</literal>
-to get all dependencies into a single file:
+Затем для получения всех зависимостей в один файл
+код обрабатыается утилитой <literal>browserify</literal>:
 <example>
 $ npx browserify load.js -o bundle.js -d
 </example>
-The result is a huge file that contains all our dependencies:
+В результате генерируется объёмный файл, содержащий все зависимости:
 <example>
 (function(){function......
 ...
@@ -300,27 +302,27 @@ The result is a huge file that contains 
 },{"protobufjs/minimal":9}]},{},[1])
 //# sourceMappingURL..............
 </example>
-To get final "<literal>njs_bundle.js</literal>" file we concatenate
-"<literal>bundle.js</literal>" and the following code:
+Для получения результирующего файла "<literal>njs_bundle.js</literal>"
+необходимо объединить "<literal>bundle.js</literal>" и следующий код:
 <example>
-// Example usage of protobuf library: prepare a buffer to send
+// Пример использования библиотеки protobuf: подготовка буфера к отправке
 function set_buffer(pb)
 {
-    // set fields of gRPC payload
+    // назначение полей gRPC payload
     var payload = { name: "TestString" };
 
-    // create an object
+    // создание объекта
     var message = pb.helloworld.HelloRequest.create(payload);
 
-    // serialize object to buffer
+    // сериализация объекта в буфер
     var buffer = pb.helloworld.HelloRequest.encode(message).finish();
 
     var n = buffer.length;
 
     var frame = new Uint8Array(5 + buffer.length);
 
-    frame[0] = 0;                        // 'compressed' flag
-    frame[1] = (n &amp; 0xFF000000) &gt;&gt;&gt; 24;  // length: uint32 in network byte order
+    frame[0] = 0;                        // флаг 'compressed'
+    frame[1] = (n &amp; 0xFF000000) &gt;&gt;&gt; 24;  // длина: uint32 в сетевом порядке байт
     frame[2] = (n &amp; 0x00FF0000) &gt;&gt;&gt; 16;
     frame[3] = (n &amp; 0x0000FF00) &gt;&gt;&gt;  8;
     frame[4] = (n &amp; 0x000000FF) &gt;&gt;&gt;  0;
@@ -330,17 +332,17 @@ function set_buffer(pb)
     return frame;
 }
 
-// functions to be called from outside
+// функции, вызываемые снаружи
 function setbuf()
 {
     return set_buffer(global.hello);
 }
 
-// call the code
+// вызов кода
 var frame = setbuf();
 console.log(frame);
 </example>
-Let's run the file using node to make sure things still work:
+Для проверки работоспособности необходимо запустить файл при помощи node:
 <example>
 $ node ./njs_bundle.js
 Uint8Array [
@@ -349,42 +351,42 @@ Uint8Array [
   116, 114, 105, 110, 103
 ]
 </example>
-Now let's proceed further with njs:
+Дальнейшие шаги выполняются при помощи njs:
 <example>
 $ /njs ./njs_bundle.js
 Uint8Array [0,0,0,0,12,10,10,84,101,115,116,83,116,114,105,110,103]
 </example>
-The last thing will be to use njs-specific API to convert
-array into byte string, so it could be usable by nginx module.
-We can add the following snippet before the last line:
+Теперь необходимо задействовать njs API для преобразования
+массива в байтовую строку для дальнейшего использования модулем nginx.
+Данный код необходимо добавить перед последней строкой:
 <example>
 if (global.njs) {
     return String.bytesFrom(frame)
 }
 </example>
-Finally, we got it working:
+Проверка работоспособности:
 <example>
 $ njs ./njs_bundle.js |hexdump -C
 00000000  00 00 00 00 0c 0a 0a 54  65 73 74 53 74 72 69 6e  |.......TestStrin|
 00000010  67 0a                                             |g.|
 00000012
 </example>
-This is the intended result.
-Response parsing can be implemented similarly:
+Экспортируемая функция получена.
+Парсинг ответа может быть сделан аналогичным способом:
 <example>
 function parse_msg(pb, msg)
 {
-    // convert byte string into integer array
+    // преобразование байтовой строки в массив целых чисел
     var bytes = msg.split('').map(v=>v.charCodeAt(0));
 
     if (bytes.length &lt; 5) {
         throw 'message too short';
     }
 
-    // first 5 bytes is gRPC frame (compression + length)
+    // первые 5 байт являются фреймом gRPC (сжатие + длина)
     var head = bytes.splice(0, 5);
 
-    // ensure we have proper message length
+    // проверка правильной длины сообщения
     var len = (head[1] &lt;&lt; 24)
               + (head[2] &lt;&lt; 16)
               + (head[3] &lt;&lt; 8)
@@ -394,7 +396,7 @@ function parse_msg(pb, msg)
         throw 'header length mismatch';
     }
 
-    // invoke protobufjs to decode message
+    // вызов protobufjs для декодирования сообщения
     var response = pb.helloworld.HelloReply.decode(bytes);
 
     console.log('Reply is:' + response.message);
@@ -405,24 +407,25 @@ function parse_msg(pb, msg)
 </section>
 
 
-<section id="dnspacket" name="DNS-packet">
+<section id="dnspacket" name="Пакет DNS">
 
 <para>
-This example uses a library for generation and parsing of DNS packets.
-This a case worth considering because the library and its dependencies
-use modern language constructions not yet supported by njs.
-In turn, this requires from us an extra step: transpiling the source code.
+В примере используется библиотека для создания и парсинга пакетов DNS.
+Эта библиотека, а также её зависимости,
+использует современные языковые конструкции, не поддерживаемые в njs.
+Для поддержки таких конструкций
+потребуется дополнительный шаг: транспилирование исходного кода.
 </para>
 
 <para>
-Additional node packages are needed:
+Необходимо установить дополнительные пакеты node:
 <example>
 $ npm install @babel/core @babel/cli @babel/preset-env babel-loader
 $ npm install webpack webpack-cli
 $ npm install buffer
 $ npm install dns-packet
 </example>
-The configuration file, webpack.config.js:
+Файл конфигурации webpack.config.js:
 <example>
 const path = require('path');
 
@@ -453,26 +456,26 @@ module.exports = {
     }
 };
 </example>
-Note we are using "<literal>production</literal>" mode.
-In this mode webpack does not use "<literal>eval</literal>" construction
-not supported by njs.
-The referenced <literal>load.js</literal> file is our entry point:
+В данном случае используется режим "<literal>production</literal>".
+Конструкция "<literal>eval</literal>" не используется, так как
+не поддерживается njs.
+Точкой входа является файл <literal>load.js</literal>:
 <example>
 global.dns = require('dns-packet')
 global.Buffer = require('buffer/').Buffer
 </example>
-We start the same way, by producing a single file for the libraries:
+Сначала необходимо создать единый файл для библиотек, как в предыдущих примерах:
 <example>
 $ npx browserify load.js -o bundle.js -d
 </example>
-Next, we process the file with webpack, which itself invokes babel:
+Затем необходимо обработать утилитой webpack, что также запускает babel:
 <example>
 $ npx webpack --config webpack.config.js
 </example>
-This command produces the <literal>dist/wp_out.js</literal> file, which is a
-transpiled version of <literal>bundle.js</literal>.
-We need to concatenate it with <literal>code.js</literal>
-that stores our code:
+Команда создаёт файл <literal>dist/wp_out.js</literal>, являющийся
+трансплицированной версией <literal>bundle.js</literal>.
+Далее необходимо объединить этот файл с <literal>code.js</literal>,
+хранящим код:
 <example>
 function set_buffer(dnsPacket)
 {
@@ -490,18 +493,18 @@ function set_buffer(dnsPacket)
     return buf;
 }
 </example>
-Note that in this example generated code is not wrapped into function and we
-do not need to call it explicitly.
-The result is in the "<literal>dist</literal>" directory:
+В данном примере генерируемый код не обёрнут в функцию,
+явного вызова не требуется.
+Результат доступен в каталоге "<literal>dist</literal>":
 <example>
 $ cat dist/wp_out.js code.js > njs_dns_bundle.js
 </example>
-Let's call our code at the end of a file:
+Далее осуществляется вызов кода в конце файла:
 <example>
 var b = setbuf(1);
 console.log(b);
 </example>
-And execute it using node:
+И затем выполнение кода при помощи node:
 <example>
 $ node ./njs_dns_bundle_final.js
 Buffer [Uint8Array] [
@@ -511,16 +514,15 @@ Buffer [Uint8Array] [
     0,   1,   0, 1
 ]
 </example>
-Make sure this works as expected, and then run it with njs:
+Тестирование и запуск кода вместе с njs:
 <example>
 $ njs ./njs_dns_bundle_final.js
 Uint8Array [0,1,1,0,0,1,0,0,0,0,0,0,6,103,111,111,103,108,101,3,99,111,109,0,0,1,0,1]
 </example>
-
 </para>
 
 <para>
-The response can be parsed as follows:
+Ответ можно распарсить следующим способом:
 <example>
 function parse_response(buf)
 {
@@ -532,9 +534,10 @@ function parse_response(buf)
 
     var resolved_name = packet.answers[0].name;
 
-    // expected name is 'google.com', according to our request above
+    // ожидаемое имя 'google.com', согласно запросу выше
 }
 </example>
+
 </para>
 
 </section>