Setup Simple Web UI for Node.js App in Seconds
Tags: node, react
Published: 2024-01-17 14:08:43

I have plenty of small projects written in Node.js, and most of the time, **I would like to but won't** setup web UI for those projects because that would introduce new frontend & backend code which would look bloated comparing to the core code of the projects themselves.

There is a good solution for some of those cases - [ink](https://github.com/vadimdemedes/ink). With ink, I can implement text-based UI with knowledge of React, which is neat but there are still some caveats for my usages:

- **It's not daemon friendly.** E.g., ink app within pm2 would not look pretty. If I want to daemonize the app, I basically lose the UI capability other than log streams.
- **It's not mobile friendly.** To access the app from a mobile device, I have to SSH connect the server and wish the UI won't mess up with my screen size.

## BackPage

Web UI would still be my first choice if it got a lower price tag. And here comes the [BackPage](https://github.com/vilicvane/backpage).

```tsx
import {BackPage} from 'backpage';
import React from 'react';

const page = new BackPage();

page.render(<div>Hello BackPage!</div>);

page.guide(); // Prints URL.
```

And you immediately get this:

![BackPage rendering a Hello message](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j1nsn877qzufimpydogp.png)

BackPage renders the React element and streams live changes to browser using `WebSocket`. But the drawback is obvious: it does not support common user interactions.

## Form-based Interactions

However, it supports simple form-based action which should be more than enough for its use cases as a complementary to log streams.

```tsx
import React, {useState} from 'react';

import {ActionButton, BackPage} from 'backpage';

const page = new BackPage();

const App = () => {
  const [started, setStarted] = useState(false);

  return (
    <>
      <div>{started ? 'Started' : 'Stopped'}</div>
      <ActionButton action={() => setStarted(true)}>Start</ActionButton>
      <ActionButton action={() => setStarted(false)}>Stop</ActionButton>
    </>
  );
};

page.render(<App />);

page.guide();
```

And this is what you get:

![BackPage rendering Start and Stop action buttons](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p9cajp4vwxtd6fmdnmym.gif)

To receive inputs from the browser, you can use `Form` element:

```tsx
page.render(
  <Form action={data => console.info(data)}>
    <input name="foo" />
    <button type="submit">submit</button>
    <button type="reset">reset</button>
  </Form>,
);
```

> `ActionButton` is actually a button wrapped within a `Form`.

## Browser Notifications

You can also send notifications to the browser and optionally fallback to something like a webhook, if the notification not getting clicked within the timeout:

```tsx
const page = new BackPage({
  notify: {
    fallback() {
      return 'https://webhook/...',
    },
  },
});

page.notify({
  title: 'Hello BackPage!',
  body: 'Click me or your webhook will get fired!',
});
```

The result (don't forget to allow notification for the relevant origin in browser):

![BackPage notification popping out](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fi7em5beegeebh23xd8t.gif)

## Public URL

For cases that accessing BackPage via the internet is needed, the simplest way is to use the minimal [BackPage "Cloud"](https://backpage.cloud) which doesn't even have a public UI (and yes, its private "dashboard" is served by BackPage itself). And the only thing you need to add is a random UUID as token:

```tsx
import {BackPage, getPersistentToken} from 'backpage';

const page = new BackPage({
  token: getPersistentToken(),
});
```

You can also use the `randomUUID()` function provided by Node.js core `crypto` module if you want a new URL every time.

## Conclusion

BackPage makes simple web UI for Node.js app with limited needs for interaction easy. You may use BackPage to quickly setup web UI for small Node.js app, or even dashboard for Node.js backend.

As [BackPage](https://github.com/vilicvane/backpage) is still in its early stage, please consider starring the project if you found it potentially useful. ❤

If you have any problem or question against BackPage, please file an issue or leave a comment. I am always a quick responder when I am awake.

> And yes, it's named after FrontPage. Even the logo is copied from FrontPage.