├── .gitignore ├── src ├── RED.ico ├── index.js ├── run-nodered.js └── index.html ├── package.json └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | out 3 | context 4 | home -------------------------------------------------------------------------------- /src/RED.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdkrieg/nodered-portable/HEAD/src/RED.ico -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nodered-portable", 3 | "productName": "nodered-portable", 4 | "version": "1.1.1", 5 | "description": "Node-RED: Portable Version", 6 | "homepage": "http://nodered.org", 7 | "main": "src/index.js", 8 | "scripts": { 9 | "nodered": "node ./src/run-nodered.js", 10 | "start": "electron-forge start", 11 | "package": "electron-forge package", 12 | "make": "electron-forge make", 13 | "publish": "electron-forge publish", 14 | "lint": "eslint src --color" 15 | }, 16 | "author": "Matthew Krieg", 17 | "license": "MIT", 18 | "repository": { 19 | "type": "git", 20 | "url": "https://github.com/mdkrieg/nodered-portable.git" 21 | }, 22 | "config": { 23 | "forge": { 24 | "make_targets": { 25 | "win32": [ 26 | "squirrel" 27 | ] 28 | }, 29 | "electronPackagerConfig": { 30 | "packageManager": "npm", 31 | "icon": "src/RED.ico" 32 | }, 33 | "electronWinstallerConfig": { 34 | "name": "nodered_portable" 35 | }, 36 | "electronInstallerDebian": {}, 37 | "electronInstallerRedhat": {}, 38 | "windowsStoreConfig": { 39 | "packageName": "", 40 | "name": "noderedportable" 41 | } 42 | } 43 | }, 44 | "dependencies": { 45 | "electron-compile": "^6.4.4", 46 | "electron-squirrel-startup": "^1.0.0", 47 | "node-red": "^2.1.3" 48 | }, 49 | "devDependencies": { 50 | "babel-plugin-transform-async-to-generator": "^6.24.1", 51 | "babel-preset-env": "^1.7.0", 52 | "babel-preset-react": "^6.24.1", 53 | "electron-forge": "^5.2.4", 54 | "electron-prebuilt-compile": "8.2.0", 55 | "eslint": "^3.19.0", 56 | "eslint-config-airbnb": "^15.1.0", 57 | "eslint-plugin-import": "^2.25.2", 58 | "eslint-plugin-jsx-a11y": "^5.1.1", 59 | "eslint-plugin-react": "^7.26.1" 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nodered-portable 2 | #### Node-RED Portable Version via Electron 3 | 4 | Node-RED source: https://github.com/node-red/node-red 5 | 6 | ## Download 7 | 8 | ### https://sourceforge.net/projects/nodered-portable 9 | 10 | ![nodered-portable](https://user-images.githubusercontent.com/66855036/140457489-48035e8e-ad47-43a8-b982-aa95c8ce4784.png) 11 | 12 | 13 | ## Make 14 | 15 | #### Follow these instructions if you want to build from scratch 16 | 17 | First you will need to have Node and NPM installed, to confirm: 18 | ``` 19 | \\> node -v 20 | v14.17.6 21 | \\> npm -v 22 | 6.14.15 23 | ``` 24 | (above were used for development, exact versions may not be critical) 25 | 26 | To begin, clone the repository and open it. 27 | ``` 28 | git clone https://github.com/mdkrieg/nodered-portable.git 29 | cd nodered-portable 30 | ``` 31 | Then install dependencies using NPM. 32 | ``` 33 | npm install 34 | ``` 35 | Then, if that completes successfully run the make script. 36 | ``` 37 | npm run make 38 | ``` 39 | This will save the compiled program to the "./out" directory (creating if needed). 40 | 41 | If the above fails you may need to install windows build tools using ***Administrator Prompt*** 42 | ``` 43 | npm install -g windows-build-tools 44 | ``` 45 | 46 | #### For Mac OS or Linux 47 | 48 | Currently I have only needed this for Windows but to build for other targets, research Electron Forge (https://www.electronforge.io/), and look into the following configuration in the package.json: 49 | ``` 50 | "config": { 51 | "forge": { 52 | "make_targets": { 53 | "win32": [ 54 | "squirrel" 55 | ] 56 | }, 57 | ... 58 | } 59 | ``` 60 | 61 | These are the "make_targets" listed in the default package.json: 62 | ``` 63 | "make_targets": { 64 | "win32": [ 65 | "squirrel" 66 | ], 67 | "darwin": [ 68 | "zip" 69 | ], 70 | "linux": [ 71 | "deb", 72 | "rpm" 73 | ] 74 | }, 75 | ``` 76 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | const debug = "PROD" || process.env.debug || "PROD"; 2 | 3 | import { app, BrowserWindow } from 'electron'; 4 | 5 | const nodered = require("./run-nodered.js"); 6 | nodered(); 7 | 8 | // Handle creating/removing shortcuts on Windows when installing/uninstalling. 9 | if (require('electron-squirrel-startup')) { // eslint-disable-line global-require 10 | app.quit(); 11 | } 12 | 13 | // Keep a global reference of the window object, if you don't, the window will 14 | // be closed automatically when the JavaScript object is garbage collected. 15 | let mainWindow; 16 | 17 | 18 | const createWindow = () => { 19 | // Create the browser window. 20 | mainWindow = new BrowserWindow({ 21 | width: 800, 22 | height: 600, 23 | }); 24 | mainWindow.setMenu(null); 25 | // and load the index.html of the app. 26 | mainWindow.loadURL(`file://${__dirname}/index.html`); 27 | //mainWindow.loadURL("http://localhost:8000/red"); 28 | // Open the DevTools. 29 | if(debug == "DEV") mainWindow.webContents.openDevTools(); 30 | 31 | // Emitted when the window is closed. 32 | mainWindow.on('closed', () => { 33 | // Dereference the window object, usually you would store windows 34 | // in an array if your app supports multi windows, this is the time 35 | // when you should delete the corresponding element. 36 | mainWindow = null; 37 | }); 38 | }; 39 | 40 | // This method will be called when Electron has finished 41 | // initialization and is ready to create browser windows. 42 | // Some APIs can only be used after this event occurs. 43 | app.on('ready', createWindow); 44 | 45 | // Quit when all windows are closed. 46 | app.on('window-all-closed', () => { 47 | // On OS X it is common for applications and their menu bar 48 | // to stay active until the user quits explicitly with Cmd + Q 49 | if (process.platform !== 'darwin') { 50 | app.quit(); 51 | } 52 | }); 53 | 54 | app.on('activate', () => { 55 | // On OS X it's common to re-create a window in the app when the 56 | // dock icon is clicked and there are no other windows open. 57 | if (mainWindow === null) { 58 | createWindow(); 59 | } 60 | 61 | }); 62 | 63 | // In this file you can include the rest of your app's specific main process 64 | // code. You can also put them in separate files and import them here. 65 | -------------------------------------------------------------------------------- /src/run-nodered.js: -------------------------------------------------------------------------------- 1 | module.exports = function(){ 2 | const http = require('http'); 3 | const express = require("express"); 4 | let inputs; 5 | if (require.main === module) { 6 | inputs = {}; 7 | startNodeRED(); 8 | }else{ 9 | const WebSocket = require('ws'); 10 | const WSv = new WebSocket.Server({port: 50820}); 11 | let socket; 12 | WSv.on('connection', function(s) { 13 | socket = s; 14 | // When you receive a message, send that message to every socket. 15 | socket.on('message', function(msg) { 16 | inputs = JSON.parse(msg); 17 | }); 18 | 19 | // Only start NR on websocket close 20 | socket.on('close', function() { 21 | startNodeRED(); 22 | }); 23 | }); 24 | } 25 | 26 | function startNodeRED(){ 27 | var RED = require("../node_modules/node-red"); 28 | 29 | // Create an Express app 30 | var app = express(); 31 | 32 | // Create a server 33 | var REDserver = http.createServer(app); 34 | 35 | // Create the settings object - see default settings.js file for other options 36 | var settings = { 37 | httpAdminRoot: inputs.adminPath || "/red", 38 | httpNodeRoot: inputs.nodePath || "/api", 39 | userDir:".", 40 | httpStatic:"public", 41 | contextStorage: { 42 | default: { 43 | module:"localfilesystem", 44 | config: { 45 | dir: "context" 46 | } 47 | } 48 | } 49 | }; 50 | 51 | // Initialise the runtime with a server and settings 52 | RED.init(REDserver,settings); 53 | 54 | // Add a simple route for static content served from 'public' 55 | app.use("/",express.static(settings.httpStatic)); 56 | // Serve the editor UI from /red 57 | app.use(settings.httpAdminRoot,RED.httpAdmin); 58 | // Serve the http nodes UI from /api 59 | app.use(settings.httpNodeRoot,RED.httpNode); 60 | 61 | REDserver.listen(inputs.port || 1880); 62 | 63 | // Start the runtime 64 | RED.start(); 65 | } 66 | }; 67 | if (require.main === module) { 68 | module.exports(); 69 | } -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 63 | 108 | 109 | 110 | 111 | 114 |
115 |
116 |
117 |
118 | 119 |
120 | 121 | 122 | 123 | 124 | 125 | image/svg+xml 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | --------------------------------------------------------------------------------