Mercurial > hg > nginx-site
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. +Решение: трансплирование кода— +ряд преобразований, +заменяющих новые функции языка в соответствии со старым стандартом. +Для этих целей может использоваться +<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>— -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>— -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 && 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 & 0xFF000000) >>> 24; // length: uint32 in network byte order + frame[0] = 0; // флаг 'compressed' + frame[1] = (n & 0xFF000000) >>> 24; // длина: uint32 в сетевом порядке байт frame[2] = (n & 0x00FF0000) >>> 16; frame[3] = (n & 0x0000FF00) >>> 8; frame[4] = (n & 0x000000FF) >>> 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-кода, который предполагается запускать в браузере, +то есть сразу после загрузки. +Однако необходимо получить другой результат— +экспортируемую функцию, на которую +можно сослаться из конфигурации 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 & 0xFF000000) >>> 24; // length: uint32 in network byte order + frame[0] = 0; // флаг 'compressed' + frame[1] = (n & 0xFF000000) >>> 24; // длина: uint32 в сетевом порядке байт frame[2] = (n & 0x00FF0000) >>> 16; frame[3] = (n & 0x0000FF00) >>> 8; frame[4] = (n & 0x000000FF) >>> 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 < 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] << 24) + (head[2] << 16) + (head[3] << 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>