Making A Lightning Web App: Part 3

Making a Lightning Fast UI with WebSockets

William O'Beirne
4 min readJun 7, 2019

Hey, this is part 3 of a 5 part series on building a Lightning app. If you haven’t read parts 1 & 2, you might want to start from the beginning.

Our app as we left it in part 2 of the tutorial series is now a fully functioning Lightning web app, but it’s far from the polished result we’re aiming for. It relies on polling the server for updates, and makes the page refresh when we make a post. So we’re going to speed things up by replacing some of our traditional calls with Web Sockets.

WebSockets and Lightning make a great pair, as the ability to make small and frequent payments needs small and frequent messages to be sent back and forth between the client and the server. If you’re not familiar with how sockets work, I suggest doing a bit of light reading before we get started. But don’t worry, the concept is extremely simple once you see how it works, and I’ll try to explain along the way.

Getting Started: Clone the (new) Project

Yet again, we’ll start with cloning a further iteration of the project. If you want to keep any changes you made to the first part, feel free to manually add the new code.

# Run this if you don't already have the repository
git clone https://github.com/wbobeirne/lightning-app-tutorial.git
cd lightning-app-tutorial
git checkout part-3

# Run this inside the repository directory if you already had it
git fetch origin
git checkout part-3

Also yet again, you’ll need to install the dependencies we need. We didn’t add too many this go-around, but adding web sockets to our API has necessitated a few more:

npm install

Let’s move on to the code!

The Code

We haven’t added any new files here, we’ve just altered some of the previous ones to use websockets instead. Let’s start with the server:

server/index.ts

We’ve added a new websocket endpoint here using the express-ws module. Unlike GET, POST, PUT, or DELETE requests that return information once as a part of an HTTP request, websocket endpoints open a persistent connection to the server that allow us to pass data back and forth. In this case though, we'll only be passing information down to the client, and otherwise continue using HTTP requests for everything else.

The first thing we do is grab all of our existing posts, and feed them through the socket. Each post is sent as a “message” of JSON encoded data. We then setup an event listener for new posts, and when they’re made, we send a message as they come in. This’ll make our application update in real time!

The final bits are just websocket house-keeping. We ping the client every 10 seconds just to keep the connection going, as some clients and servers will automatically close off sockets that haven’t sent message for a bit. And once the connection is closed, we’ll stop trying to send new posts through it.

And that’s it for changes to our server! Onto the client:

client/App.tsx

It looks like a lot of code, but much of it is component state boilerplate. We’ve now made our App component the central store of posts data by using its component state, and passing it down as props so that our other components can be much simpler.

As soon as our App component mounts, it’ll open a websocket by calling this.connect() in componentDidMount. It saves incoming posts to component state, and passes them to the Posts and PostForm components as props. If there are any errors in the connection, we can save that too and display an error message along with a button to call the connect method again.

While our Posts component is now so simple that it's only a render function, our PostsForm component has been changed a bit to handle the data now coming in from props:

client/components/PostsForm.tsx

We’ve replaced our previous methodology of polling to server to see if our post has been accepted. Now we check every time our component changes in componentDidUpdate due to new props being passed, and see if the pendingPost is in the array of posts we get from props. If it is, we just reset the form to its initial state so that the user can start posting again.

The Result

With that out of the way, we can fire the project up again with npm run dev and check out our new and improved Lightning app:

And that’s it for our websocket implementation! You should check out all of the components to see the changes I didn’t cover in detail, and play around a bit yourself to see how much better it works.

Next up for part 4, we’ll be integrating WebLN into our app to allow for a slicker payment experience, as well as message signatures and verification for our posts.

--

--