The Web UI
A ReactJS based Web UI to speak to a MakeHaus Node JS application. The application is intended and tested to be served by the web server baked into makehaus-js. For development purposes, the application is served by the bootstrapping web server (more details on the development workflow given below).
develop branch is the default development branch.
Cloning And Initial Setup
Clone the repository and from the working directory execute
https://github.com/makeproaudio/glue-react-browser.git npm i
This will pull all necessary dependencies as defined in
package.json into the
A few files are produced by the bootstrapper. Only relevant files used in development are mentioned below
node_modules/ public/ index.html manifest.json worker.js src/ components/ layout/ mpa-custom-ui-widgets/ mpa-material-ui-widgets/ mpa-widget-interface/ style/ App.js index.js serviceWorker.js style-helper.js package.json
Typical Development Workflow
create-react-app, a default development server is provided so that any change you make in sources is immediately deployed and reflected in the development server. To run the development server, enter:
This should launch the application on port 3000 unless another application uses that port. The development server’s caching is not 100% reliable, therefore it is recommended to adopt the following measures in your development setup. Ensure to revert before making a new build:
- Work in incognito mode
- Disable the service worker - Refer to
public/index.htmlfor comments on how to do this.
- The React toolchain does not have a direct breakpoint debugger interaction with VSCode. The recommendation is to add
console.log()to trace application flow.
Making A Minified Build
To create a new deployment build, ensure that you have reverted any steps you may have taken to ease your development workflow. Execute the following command:
npm run build
This will output a minified version of the web application into a new folder called
build in the root working directory folder. If the
build folder existed earlier, a fresh build will replace its contents.
Deploying To makehaus-js
Copy the contents of the
build folder and paste it into the
webapp folder of makehaus-js.
- ReactJS as the front end library
- FlexBox for css based layouting
- MaterialUI as the standard widget library
- socket.io for network communication over websockets. Socket IO allows topic based event driven communication.
- serviceworker.js for Progressive Web App capabilities
Notes and Caveats
- At the time of writing the application, react 16 was the latest version.
- create-react-app was used to bootstrap the react project.
- Widgets have been implemented using MaterialUI but are not limited to MaterialUI. It is perfectly valid to implement widgets with a different library.
- socket.io was chosen as the standard network communication library for its simplicity and performance.
- Some package dependencies inside package.json can be pruned as they are probably not being used at the moment.
- The dockerfile that you find inside the repository was a good to have feature and is not necessary in developing the application. It may not be in a valid state.
The most important components in the application are:
- Connection To Server
- Widget Interface
- Widget Helper and Implementations
Connection To Server
To load the application, the Host URL must be known. This Host URL is determined by the web server baked into makehaus-js and the web app port you supply to your makehaus-js application at the time of initialization. By default, the web app port is 3000.
Once you navigate to the Host URL, you’ll be asked to enter the makehaus websocket port used for communicating to makehaus . By default, the websocket server port is 8001.
For more details on default ports and makehaus-js configuration, refer to the makehaus-js documentation.
After setting up your port correctly, your makehaus-js layout will be transferred to the web application.
The entry point of the web application is
Refer to comments in
App.js for application flow.
Once the initial handshake is over and layout data has been received by the web application, the Layouter takes over. It is the responsibility of the components in
/src/components/layout to layout the json received from the server. This is a simple html/css driven implementation.
The Web UI is primarily server driven and relies on events being transmitted from the server to change its own state. The “
rx” topic is a fast lane for communication specifically oriented towards widgets.
The heavy lifting of the code is done by the Widget component in
/src/components/mpa-widget-interface/widget.jsx. Refer to comments in this file for application flow.
For the web application, a
Widget is a network abstraction layer over the different types of widgets that MakeHaus supports. A
Widget can change its type, therefore the
Widget component tunes into
TYPECHANGE messages coming from the server on the “
Depending on the widget metadata as received by the server, the
Widget component spawns instances of standard MPA Widget Interface components. These Widget Interface components are standardized and can be found in the
Here is a detailed explanation for the Slider MPA Widget Interface component located at
The entry point is the
componentDidMount() function. Here, a handler is registered on the “
rx” topic to receive any necessary updates from the server. The different events that may come in from the server are:
TOUCH- the corresponding hardware widget was touched
VALUE- the value of the widget was updated
COLOR- a color change was triggered on the widget
CONTEXT- the context label of the widget was updated
LABEL- the main label of the widget was updated
TYPECHANGE- the min/max/values of the widget was updated.
Note that the
TYPECHANGE here does not have the same meaning as the
TYPECHANGE for the base
Not every Widget may support each and every one of these events. Each MPA Widget Interface then chooses to do whatever it pleases with the event.
render() function is where the actual UI implementation of the Widget is rendered.
Widget Helper and Implementations
The ideology of this architecture is to keep the MPA Widget Interface decoupled from the UI Widget implementation. Currently, most of the UI Widget implementations make use of the Material UI library. However, in the future, if we wish to change from Material UI to another library, the MPA Widget interfaces provide the flexibility to do so without altering the core network communication between the web application and the server.
The UI Widget implementations can be found in the following packages:
Supporting A New Widget
Support a new Widget may mean one of two different things:
- Are you supporting a new UI implementation of an existing MPA Widget Interface
- Are you building a new MPA Widget Interface from scratch?
To create a new UI implementation of an existing MPA Widget Interface, check off the following items:
- Create a new component for the UI Widget. If you’re implementing a new Material UI based widget, place it under
src/components/mpa-material-ui-widgetsotherwise if it’s a custom widget, place it under
src/components/mpa-custom-ui-widgets. As a convention, if you’re implementing a new widget from an existing baseline UI library, create a new folder under
- Let’s assume you’d like to replace the existing UI Button with a different Button. In the
src/components/mpa-widget-interface/button.jsx, replace the
returnsection to return your new component that you’ve just created.
- For any property of the component that is rendered by a server change(eg. color, label, context, min, max, etc) make sure you reference the correct state property variable of the MPA Widget Interface defined in the constructor in the component that you return in the
To create a new MPA Widget Interface, check off the following items:
- Create a new component for the MPA Widget Interface and place it under
- In the
constructor()function of the new MPA Widget Interface, destructure the props that you want to get from metadata.stack and pass these initial values to the state of the component.
- In the
componentWillUnmount()function of the new MPA Widget Interface, ensure to deregister to the “
rx” topic from the socket to avoid memory leaks.
- In the
componentDidMount()function of the new MPA Widget Interface, register a new handler on the “
rx” topic and implement the events you wish to listen to. The list of events is specified in the Slider example mentioned above.
- In the
render()function of the new MPA Widget Interface, return the UI Widget Implementation you wish to render. Refer to the section above for details on how to create a new UI Widget implementation.
- Inside the
src/components/mpa-widget-interface/widget.jsx, navigate to the
widgetForMetaproperty and add a new condition which catches the name of the widget you send from the server.
- In the return section of the new conditional clause, return the new MPA Widget Interface you created wrapped inside a div tag.
Reporting Widget Events To The Server
For certain widgets, you may wish to send event callbacks from the UI widget to the server. An example of this can be found in the
handleClick() function of the
Button component under
src/components/mpa-widget-interface/button.jsx.The topic used here is called “
socket.emit() is the method to send data to the server. There is no specific structure to the data that you pass to the server on the “
tx” topic, so take sufficient caution to implement the data format appropriately on the server.
Progressive Web App Support
PWAs allow a web application to be run in a native sandbox inside supported mobile browsers without having to install an application via the native application store. Although PWAs are a huge box, the MakeHaus Web UI uses minimal features of PWAs. The relevant files to modify are
src/serviceWorker.js. The setup required for making an application a PWA is a one time task and the only relevant changes to be made are in the
manifest.json file, which contains metadata regarding what the application name should be, the icon to be displayed, the splash screen, theming on the splash screen, orientation etc. All other files shouldn’t be touched unless a new PWA feature is needed to be implemented.
- Network Discovery: To truly make the application mobile, create a react native wrapper which can do basic discovery of makehaus-js web servers in the network. This will save the user from having to navigate to the Host URL. The UI application can continue to be shown using a WebView widget.
- Layouter New Feature: Currently, only Rows are supported from the server. If Columns are also to be implemented, the Layouter will need to be modified to become a matrix.
- New Widgets: Label / Heading, Text Input Field
- Code Cleanup: Add a prettier config file to implement a standard code formatter
- Code Cleanup: Map all events from the server to a standardized enum
- Code Cleanup: Replace React Class Components with pure function components.
- Code Cleanup: Replace socket.io with useSocket hooks
- Code Cleanup: Create custom React hooks to implement events in MPA Widget Interface components. In that case, the componentDidMount() function can be split to more atomic functions such as onColor, onLabel, onContext etc.