Embed Node-RED into mean express on the same port in an iframe

I got it to actually work after putting all the following right at the beginning of app.js in the express demo:

var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');

var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');

var RED = require("node-red");
var http = require('http');
var embeddedStart = require('node-red-embedded-start');

var app = express();
var server = http.createServer(app);

// Create the settings object - see default settings.js file for other options
var settings = {
    httpAdminRoot:"/red",
    httpNodeRoot: "/api",
    userDir:"/home/nol/.nodered/",
    functionGlobalContext: { }    // enables global context
};

// Initialise the runtime with a server and settings
RED.init(server,settings);

// Serve the editor UI from /red
app.use(settings.httpAdminRoot,RED.httpAdmin);

// Serve the http nodes UI from /api
app.use(settings.httpNodeRoot,RED.httpNode);

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');

app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', indexRouter);
app.use('/users', usersRouter);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  next(createError(404));
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

app.set("view options", {layout: false});
app.use(express.static(__dirname + '/public'));
app.get('/', function(req, res){
    res.render('/views/home.html');
});

module.exports = {app: app, RED: RED};

and all the following in the bin/www

#!/usr/bin/env node

/**
 * Module dependencies.
 */

var app = require('../app');
var debug = require('debug')('myapp:server');
var http = require('http');
var express = require("express");
var RED = require("node-red");
var embeddedStart = require('node-red-embedded-start');

// I know it looks weird lol
var app = app.app;

/**
 * Get port from environment and store in Express.
 */

var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);

/**
 * Create HTTP server.
 */

var server = http.createServer(app);

/**
 * Listen on provided port, on all network interfaces.
 */

server.listen(port);
server.on('error', onError);
server.on('listening', onListening);

/**
 * Normalize a port into a number, string, or false.
 */

function normalizePort(val) {
  var port = parseInt(val, 10);

  if (isNaN(port)) {
    // named pipe
    return val;
  }

  if (port >= 0) {
    // port number
    return port;
  }

  return false;
}

/**
 * Event listener for HTTP server "error" event.
 */

app.use(express.static('public'));

function onError(error) {
  if (error.syscall !== 'listen') {
    throw error;
  }

  var bind = typeof port === 'string'
    ? 'Pipe ' + port
    : 'Port ' + port;

  // handle specific listen errors with friendly messages
  switch (error.code) {
    case 'EACCES':
      console.error(bind + ' requires elevated privileges');
      process.exit(1);
      break;
    case 'EADDRINUSE':
      console.error(bind + ' is already in use');
      process.exit(1);
      break;
    default:
      throw error;
  }
}

/**
 * Event listener for HTTP server "listening" event.
 */

function onListening() {
  var addr = server.address();
  var bind = typeof addr === 'string'
    ? 'pipe ' + addr
    : 'port ' + addr.port;
  debug('Listening on ' + bind);
}

// Start the runtime
RED.start().then(embeddedStart(RED, 5)).then((result) => {
    // result is whatever RED.start() resolved to
    // RED.nodes.getFlows() etc are now ready to use
    console.log(RED.nodes.getFlows());
}).catch((err) => {
    if (/^timed out/.test(err.message)) {
        // embeddedStart() timed out
        // the value that RED.start() resolved to is available as err.result
    }
});

and here the log ( versions etc should be the same from when it didnt work because all I changed was where I put some app.use statements


"C:\Program Files\JetBrains\WebStorm 2018.1.4\bin\runnerw.exe" "C:\Program Files\nodejs\node.exe" "C:\Program Files\nodejs\node_modules\npm\bin\npm-cli.js" start

> myapp@0.0.0 start C:\Users\Zeus.Bower\Documents\Repositories\myapp
> node ./bin/www
[Function: route] [Function: use] [Function: path] [Function: enabled] [Function: render] [Function: route] [Function: route] [Function: route]
15 Jun 07:23:40 - [info] 

Welcome to Node-RED
===================

15 Jun 07:23:40 - [info] Node-RED version: v0.18.7
15 Jun 07:23:40 - [info] Node.js  version: v10.3.0
15 Jun 07:23:40 - [info] Windows_NT 10.0.17134 x64 LE
15 Jun 07:23:41 - [info] Loading palette nodes
15 Jun 07:23:43 - [warn] ------------------------------------------------------
15 Jun 07:23:43 - [warn] [node-red/rpi-gpio] Info : Ignoring Raspberry Pi specific node
15 Jun 07:23:43 - [warn] [node-red/tail] Not currently supported on Windows.
15 Jun 07:23:43 - [warn] ------------------------------------------------------
15 Jun 07:23:43 - [info] User directory : /home/nol/.nodered/
15 Jun 07:23:43 - [warn] Projects disabled : set editorTheme.projects.enabled=true to enable
15 Jun 07:23:43 - [info] Flows file     : \home\nol\.nodered\flows_nb-zbower.json
15 Jun 07:23:43 - [warn] 

---------------------------------------------------------------------
Your flow credentials file is encrypted using a system-generated key.

If the system-generated key is lost for any reason, your credentials
file will not be recoverable, you will have to delete it and re-enter
your credentials.

You should set your own key using the 'credentialSecret' option in
your settings file. Node-RED will then re-encrypt your credentials
file using your chosen key the next time you deploy a change.
---------------------------------------------------------------------

15 Jun 07:23:43 - [info] Starting flows
15 Jun 07:23:43 - [info] Started flows

So now I have it working in an iframe in the express demo app ( didnt get it to work in the mean stack angular components yet but that should be doable after seeing it can actually work) but Im now gettig this error and RED loses immediately connection in the iframe and cant reconnect ( lost connection to server).

red.min.js:16 WebSocket connection to 'ws://localhost:3000/red/comms' failed: Connection closed before receiving a handshake response

with the /home/nol/.node-red… no I dont but does it cause problems in the app?

thanks again for your help you two have been amazing already!!

P.S. if ive made any dummy mistakes or ugly stuff like app.app please forgive me as ive been 10h non stop on this just yesterday and my brain stopped working properly at some point :sweat_smile: