# HG changeset patch # User Yaroslav Zhuravlev # Date 1596721618 -3600 # Node ID 4c8d0b37932dadde7ed16898fa9ce29ba69cb7ce # Parent 2839ad72d8ef9d054e1471ed358bd6b1288b2833 Corrected syntax and style of "Using node modules with njs". diff --git a/xml/en/docs/njs/node_modules.xml b/xml/en/docs/njs/node_modules.xml --- a/xml/en/docs/njs/node_modules.xml +++ b/xml/en/docs/njs/node_modules.xml @@ -9,20 +9,19 @@
+ rev="4"> -
+
-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. +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. -The njs does not (yet) support modules, too. -This article describes ways to overcome this limitation, using the -Node.js ecosystem as an example. +This article describes ways to reuse +Node.js code in njs. @@ -32,30 +31,32 @@ Examples in this article use features th -There is a number of issues that may arise when 3rd-party code is added to njs: +There is a number of issues +that may arise when 3rd-party code is added to njs: -Multiple files that reference each other, and their -dependencies + +Multiple files that reference each other and their dependencies + -Platform-specific APIs + +Platform-specific APIs + -Modern standard language constructions + +Modern standard language constructions + - -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. +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. - - - @@ -74,8 +75,8 @@ your code and all the dependencies. Platform-specific APIs -You can use multiple libraries that implement such APIs in a platform-agnostic -manner (at the expense of performance, though). +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 polyfill approach. @@ -84,57 +85,52 @@ Particular features can also be implemen Modern standard language constructions -Such code can be transpiled: this means performing a number of transformations +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, babel project can -be used to this purpose. +For example, babel project +can be used to this purpose. - - In this guide, we will use two relatively large npm-hosted libraries: -protobufjs - +protobufjs— a library for creating and parsing protobuf messages used by the -gRPC protocol. - +gRPC protocol -dns-packet - -a library for processing DNS protocol packets. +dns-packet— +a library for processing DNS protocol packets -
+
- -This document mostly employs a generic approach and AVOIDS specific best -practice advices concerning Node.js and the rapidly evolving JavaScript -ecosystem. -Make sure to consult the corresponding package's manual BEFORE following the -steps suggested here. +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. - First (assuming Node.js is installed and operational), let's create an -empty project and install some dependencies; the commands below assume we're -in the working directory: - +empty project and install some dependencies; +the commands below assume we are in the working directory: $ mkdir my_project && cd my_project $ npx license choose_your_license_here > LICENSE @@ -162,44 +158,47 @@ EOF
+
-The library provides a parser for the .proto interface -definitions and a code generator for message parsing and generation. +The library provides a parser +for the .proto interface definitions +and a code generator for message parsing and generation. In this example, we will use the helloworld.proto -file from the gRPC examples. -Our goal is to create two messages: HelloRequest and +file +from the gRPC examples. +Our goal is to create two messages: +HelloRequest and HelloResponse. We will use the static mode of protobufjs instead of dynamically generating classes, because -njs doesn't support adding new functions dynamically due to security -considerations. +njs doesn't support adding new functions dynamically +due to security considerations. -Next, the library is installed and javascript code implementing -message marshalling is generated from the protocol definition: +Next, the library is installed and +the JavaScript code implementing message marshalling +is generated from the protocol definition: $ npm install protobufjs $ npx pbjs -t static-module helloworld.proto > static.js - -Thus, the static.js file becomes our new dependency, storing -all the code we need to implement message processing. +Thus, the static.js file becomes our new dependency, +storing all the code we need to implement message processing. The set_buffer() function contains code that uses the -library to create a buffer with the serialized HelloRequest -message. +library to create a buffer with the serialized +HelloRequest message. The code resides in the code.js file: - var pb = require('./static.js'); @@ -220,7 +219,7 @@ function set_buffer(pb) var frame = new Uint8Array(5 + buffer.length); frame[0] = 0; // 'compressed' flag - frame[1] = (n & 0xFF000000) >>> 24; // length: uint32 in network order + frame[1] = (n & 0xFF000000) >>> 24; // length: uint32 in network byte order frame[2] = (n & 0x00FF0000) >>> 16; frame[3] = (n & 0x0000FF00) >>> 8; frame[4] = (n & 0x000000FF) >>> 0; @@ -236,7 +235,6 @@ var frame = set_buffer(pb); To ensure it works, we execute the code using node: - $ node ./code.js Uint8Array [ @@ -245,10 +243,8 @@ Uint8Array [ 116, 114, 105, 110, 103 ] - You can see that this got us a properly encoded gRPC frame. Now let's run it with njs: - $ njs ./code.js Thrown: @@ -266,18 +262,17 @@ or other similar tool. An attempt to process our existing code.js file will result -in a bunch of JS code that is supposed to run in a browser, i.e. immediately -upon loading. +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. - -In this guide, we use njs cli in all examples for the sake of simplicity. +In this guide, we use +njs cli in all examples for the sake of simplicity. In real life, you will be using nginx njs module to run your code. - @@ -292,13 +287,12 @@ the library. -Next, we process it with browserify to get all dependencies into a single file: +Next, we process it with browserify +to get all dependencies into a single file: $ npx browserify load.js -o bundle.js -d - -The result is huge file that contains all our dependencies: - +The result is a huge file that contains all our dependencies: (function(){function...... ... @@ -306,10 +300,8 @@ The result is huge file that contains al },{"protobufjs/minimal":9}]},{},[1]) //# sourceMappingURL.............. - To get final "njs_bundle.js" file we concatenate "bundle.js" and the following code: - // Example usage of protobuf library: prepare a buffer to send function set_buffer(pb) @@ -328,7 +320,7 @@ function set_buffer(pb) var frame = new Uint8Array(5 + buffer.length); frame[0] = 0; // 'compressed' flag - frame[1] = (n & 0xFF000000) >>> 24; // length: uint32 in network order + frame[1] = (n & 0xFF000000) >>> 24; // length: uint32 in network byte order frame[2] = (n & 0x00FF0000) >>> 16; frame[3] = (n & 0x0000FF00) >>> 8; frame[4] = (n & 0x000000FF) >>> 0; @@ -348,7 +340,6 @@ function setbuf() var frame = setbuf(); console.log(frame); - Let's run the file using node to make sure things still work: $ node ./njs_bundle.js @@ -358,14 +349,11 @@ Uint8Array [ 116, 114, 105, 110, 103 ] - Now let's proceed further with njs: - $ /njs ./njs_bundle.js Uint8Array [0,0,0,0,12,10,10,84,101,115,116,83,116,114,105,110,103] - 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: @@ -374,9 +362,7 @@ if (global.njs) { return String.bytesFrom(frame) } - Finally, we got it working: - $ njs ./njs_bundle.js |hexdump -C 00000000 00 00 00 00 0c 0a 0a 54 65 73 74 53 74 72 69 6e |.......TestStrin| @@ -418,6 +404,7 @@ function parse_msg(pb, msg)
+
@@ -435,7 +422,6 @@ Additional node packages are needed: $ npm install buffer $ npm install dns-packet - The configuration file, webpack.config.js: const path = require('path'); @@ -470,31 +456,23 @@ module.exports = { Note we are using "production" mode. In this mode webpack does not use "eval" construction not supported by njs. - The referenced load.js file is our entry point: global.dns = require('dns-packet') global.Buffer = require('buffer/').Buffer - We start the same way, by producing a single file for the libraries: - $ npx browserify load.js -o bundle.js -d - Next, we process the file with webpack, which itself invokes babel: - $ npx webpack --config webpack.config.js - This command produces the dist/wp_out.js file, which is a transpiled version of bundle.js. - We need to concatenate it with code.js that stores our code: - function set_buffer(dnsPacket) { @@ -512,23 +490,18 @@ function set_buffer(dnsPacket) return buf; } - 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 "dist" directory: - $ cat dist/wp_out.js code.js > njs_dns_bundle.js - Let's call our code at the end of a file: var b = setbuf(1); console.log(b); - And execute it using node: - $ node ./njs_dns_bundle_final.js Buffer [Uint8Array] [ @@ -538,7 +511,6 @@ Buffer [Uint8Array] [ 0, 1, 0, 1 ] - Make sure this works as expected, and then run it with njs: $ njs ./njs_dns_bundle_final.js @@ -563,7 +535,6 @@ function parse_response(buf) // expected name is 'google.com', according to our request above } -