The integrated Node.js implementation in OS 8.2.x and OS 8.3.x is based on Node v10. For further documentation and usage information, consult the Node.js 10.0.0 API documentation.
Note
Node.js is not enabled for iframes or Web Workers.
Enabling Node.js
Node.js object functionality is available in BrightAuthor:connected when users specify Node.js items in Presentation Settings. Node.js objects are not available in BrightAuthor.
Node.js is enabled for individual roHtmlWidget instances by including the nodejs_enabled:true
entry in the initialization parameters of the roHtmlWidget object.
r=CreateObject("roRectangle", 0,0,1920,1080) is = { port: 3000 } config = { nodejs_enabled: true inspector_server: is brightsign_js_objects_enabled: true url: "file:///sd:/nodehello.html" } h=CreateObject("roHtmlWidget", r, config) h.Show()
Important
We do not recommend loading arbitrary websites with Node.js enabled. Some JavaScript libraries assume that Node.js is running on an instance with server-side capabilities, and they will attempt to load dependencies, causing playback to fail.
If you are using a BrightAuthor plugin to enable Node.js, you will need to set other desired parameters in the plugin, rather than with an HTML5 state. For example, if you want to enable the mouse cursor, you will need to set mouse_enabled:true
during the roHtmlWidget initialization, rather than checking the box in the HTML5 state.
Cross-Domain Security
Chromium has default security measures for preventing cross-site scripting attacks: If the URL for the roHtmlWidget instance is a remote domain, JavaScript applications from that domain cannot make HTTP requests to other domains; on the other hand, if the URL points to local storage, requests to other, remote domains are acceptable.
If you want to reference other domains in remote applications, set the websecurity
parameter to false
when initalizing the roHtmlWidget, as shown below:
r=CreateObject("roRectangle", 0,0,1920,1080) is = { port: 3000 } config = { nodejs_enabled: true inspector_server: is brightsign_js_objects_enabled: true url: "http://www.mysitehere.com" security_params: {websecurity: false} } h=CreateObject("roHtmlWidget", r, config) h.Show()
Web Storage
If you want to use JavaScript storage applications, you will need to specify a storage_path
and storage_quota
when initializaing the roHtmlWidget:
r=CreateObject("roRectangle", 0,0,1920,1080) is = { port: 3000 } config = { nodejs_enabled: true inspector_server: is brightsign_js_objects_enabled: true url: "file:///sd:/nodehello.html" storage_path: "SD:" storage_quota: 1073741824 } h=CreateObject("roHtmlWidget", r, config) h.Show()
JQuery
JQuery® requires a workaround to operate correctly with Node.js. See this page for an example.
Packaging and Delivering Node.js Applications
To deploy your Node.js application to a BrightSign player, run "npm install" on your computer. This will create the node_modules
directory. Copy this directory to the SD card along with the rest of the application.
When initialized, the BrightSign Node.js implementation seeks to the node_modules
directory relative to the loaded HTML file. Like a standard Node.js application, it then loads all modules contained in the node_modules
directory.
Note
The majority of Node.js modules contain JavaScript code only. However, some modules contain binary code. When a module containing binary parts is installed using "npm install", the binary parts are compiled for the local platform (usually Intel x64), and this code will not run on a BrightSign player. Currently, the BrightSign Node.js implementation is limited to JavaScript code only.
WebPack
The node_modules directory associated with a Node.js application may contain hundreds or thousands of unnecessary files. The webpack® bundler allows you to reduce the node_modules directory to a manageable size.
To use webpack®, you will need to place your Node.js entry-point function in a separate file (e.g. "index.js"), rather than as inline HTML. This file will contain the references to other JavaScript files and Node.js modules:
var myutils = require('./utilities'); // My utilities.js var moment = require('moment'); // A node module function main() { myutils.foo(); moment.now(); //... }
The JavaScript file containing the Node.js entry point can then be referenced in the HTML file:
<script src='./index.js'></script>
To use webpack®, attach main()
to the window object so that it can be found from the HTML file:
var myutils = require('./utilities'); // My utilities.js var moment = require('moment'); // A node module function main() { myutils.foo(); moment.now(); //... } window.main = main;
Change the HTML file so that it points to the bundled JavaScript and to window.main()
:
<script src='./bundle.js'></script> <body onload="window.main()">
To build your bundle, run the following npm steps on your computer:
npm i -D webpack webpack-cli npx webpack --mode production
Now you can publish the index.html and bundle.js files; there's no need to publish the node_modules
directory. See the sample webpack® configuration below for more information.
Device Storage Paths
To load Node.js modules and read/write files, you must first define the root directory of the device storage. The following are common root directories:
- microSD:
"storage/sd/"
- SSD:
"storage/ssd/"
- USB:
"storage/usb1/"
We recommend using the process.chdir()
call at the beginning of the script to change the process path:
var process = require("process"); process.chdir("/storage/sd");
Alternatively, if you have modules located on multiple storage drives, you can append multiple search paths to a module:
module.paths.push("/storage/sd/") module.paths.push("/storage/ssd/") module.paths.push("/storage/usb1/")
Debugging Applications
When Node.js modules are enabled, they become visible from the Chromium remote inspector, allowing you to debug applications. The console.log works like a normal web application: Output is redirected to both stderr and the remote inspector.
Downloading Large Files
If your application uses the XMLHttpRequest object to download a large file (100-200MB, depending on the player model), the player will run out of memory and the download operation will fail. The XMLHttpRequest object first downloads the whole file into memory, then creates a blob object of equal size, so memory requirements for a download are effectively double that of the file size.
For large-file downloads, we recommend using the Fetch API, which has callbacks that are fired when fragments are downloaded. Data can be appended to the disk as it arrives, so the player won't run out of memory, no matter the file size. The "download-test" HTML/JavaScript example below uses the Fetch API and the Node.js File Service module to download a file in fragments.
Note
This example is specific to BrightSign players and requires node.js runtime, enabled by use of the roHtmlWidget nodejs_enabled
flag, to write files to disk.
Node.js Examples
GitHub contains a Node.js-starter-project. This project was originally created for BrightAuthor but can also be used with BrightAuthor:connected.
Another example is the script below, which initializes an HTTP server on the BrightSign player at port 8000. When a client (for example, a desktop browser) connects to the server, it will send the model number and boot version of the player to the client. The script also displays the IP address of the connected client on the screen attached to the player.
<html> <script> function displayMessage() { // Load the http module to create an http server. var http = require('http'); // Configure our HTTP server to respond with Hello World to all requests. var server = http.createServer(function (request, response) { var device_info = new BSDeviceInfo(); response.writeHead(200, {"Content-Type": "text/plain"}); response.end("Device Information:\n" + device_info.model + "\n" + device_info.bootVersion + "\n"); var ip = request.connection.remoteAddress; document.getElementById("Ip").innerHTML+="Server responded to: "+ ip + "<br>"; console.log("Server responded to request from " + ip); }); // Listen on port 8000, IP defaults to 127.0.0.1 server.listen(8000); // Display it on brightsign browser var os = require('os'); var interfaces = os.networkInterfaces(); var addresses = []; for (var k in interfaces) { for (var k2 in interfaces[k]) { var address = interfaces[k][k2]; if (address.family === 'IPv4' && !address.internal) { addresses.push(address.address); } } } var message = "Server running at: " + addresses[0] + ":8000<br>"; document.getElementById("Ip").innerHTML+= message; // Print message on console console.log(message); } </script> <body style="background-color:red" onload="displayMessage()"> <div id = "Ip" style="font-size:60px; text-align:center;"> </div> </body> </html>
Built-in modules, such as "os" and "http", can be initialized using the require()
method. If the nodejs_enabled:true
entry is not included when initializing the roHtmlWidget object (as shown above), the require()
method will not be available.