The workshop or CNC app has to handle all communication with the controller running the CNC machine. This includes connecting/disconnecting, sending commands and receiving responses. It has to be compatible with GRBL, one of the most popular pieces of software for hobby CNC controllers. There are other controllers (tinyG, smoothie board) that are also based on GRBL and so accept the same commands. The app has to run in the broswer and connect to the controller via a serial (usb) port.
There are two distinct ways of handling the data sent to and received from the CNC machine. The frontend can either be dumb or intelligent. For example, when executing multiple lines of Gcode it could play dumb and send them in bulk to the server and let it handle the correct send procedure. The correct sending procedure for the CNC controller is to send a Gcode command and then wait for an 'ok' response. When the response is received another command can be sent.
The alternative is an intelligent client which queues these commands and sends them individually, using the server as merely a router to the serial port. Although both would work, in my opinion then are some real advantages to using an 'intelligent' frontend. The app is essentially controlling a robotic machine in real time, and we want real time access. Queuing commands on the client allows easy interruption should something happen. We can just stop sending commands if we want. It would be more complicated to stop and resume if the server was processing and queuing the commands.
Handing the two way communication is done using websockets. Different 'events' are fired for sending/receiving data and connection attempts.
It's important to close the websocket or serialport socket when a connection fails or is reset. If not closed it will continue to take up memory. Events must also be removed to prevent duplicates and weird behaviour.
The Angular 2 framework was used to build the single page browser app. The server runs on nodejs making use of the express framework.