1. 程式人生 > >This single-page web app can edit itself

This single-page web app can edit itself

This single-page web app can edit itself

How to create a self-editing, (im)mutable web profile, and have fun doing it

What we’ll be building in this tutorial… a decentralized, editable profile app.

The official IPFS Javascript library has undergone several major updates recently that make it even better for building decentralized web-apps and DWeb sites. With the advent of

IPNS support in , app developers can now support ‘mutable’ IPFS content and near real-time updates. This means we can start to build interactions with DWeb technologies that provide the same (or better!) experience that users have come to expect from most Web2 technologies! As you probably already know, a positive Dweb user experience is a big part of our focus at
Textile
, so any time we see an opportunity to test out new tools that can help us make this happen, we get excited.

To get a taste for what IPNS in the browser can bring, we thought it might be fun to build a simple profile app, something akin to an about.me page or similar. While we’re building this app, we’ll use

Knockout to simplify our user interface using a model-view view-model (MVVM) pattern . For those who wan to skip ahead to the end, you can clone and play around with the full working app right away, for the rest of you, let’s get started…

Getting started

Like many of our previous posts, we’ll start by cloning Textile’s handy-dandy ipfs app template.

While you’re at it, go ahead and grab this IPFS getter module, which makes it easy to use promises when creating a new IPFS peer/node in the browser. You can save it in your projects src directory and call it something like ipfs-promise.js.

Ok, with the project cloned and our new file ready to go, the only other thing you’ll want to do is yarn install the required modules, and then yarn watch your code so we can start building and testing our app.

yarn install
yarn watch

Once your project is built, the watch command will ‘watch’ for changes and update your compiled bundle as needed (we’re using ). So you should fire up http://localhost:8000 in your browser and refresh that page along the way each time you make any changes to your code. You can also check out this previous tutorial where we cover some of the required modules and development tools we’ll be using in today’s post. Ok, enough setup, let’s get building…

Let’s get building

We’ll start pretty basic, adding only minimal functionality to get us going. So our main.js file gets some minor updates:

Which is essentially just starting up an IPFS peer in the browser, querying for our peer’s id, comparing this with the user id from the url’s query string (that’s how we’ll view other peoples’ profiles, via a user parameter), and console.loging some information. Easy. The app page itself will look pretty much empty, save for a few ‘branding’ bits if you’ve left those in. So that’s great, and hopefully you’re seeing something like this in your browser’s Javascript console:

Viewing profile for Qm… from peer with id Qm…
Viewing own profile, editing will be enabled!

So now, let’s begin designing our profile app!

The View

We’ll start by defining our view. Since we’re developing our web-app with Knockout, our view is defined via our index.html file. Here’s the basic structure:

If you take a look at the main div, you’ll see we have components for our profile image, profile information such as first and last name, etc. We also include a section for work with a list of jobs, as well as a section for a bio write-up, and even social media links. Just for fun, we’ve included some external links to font awesome css assets, just to mix in some ‘centralized’ bits and pieces. You could, of course, include these within your app’s bundle if you wanted, at the expense of a slightly larger bundle size. While you’re at it, you might as well create a style.css file and stick this stuff in it to make things look nice and ‘profile-like’.

The Data Model

With that in mind, we then turn to our data model. For this example, we’ll be using the user-profile data model from our previous tutorial on building a simple decentralized RESTful endpoint with IPFS/IPNS. This is just a simple JSON-based structure with fields for name, work, social media, etc. If you really wanted to get fancy, you could do something like a formalized json-schema based structure, but I leave that as an exercise for the reader. For now, here’s the default structure, which we’ll provide to our app as an importable object (import { defaultProfile } from "./default-profile.js”):

In our code, we’re going to assume that the user either already has this JSON doc published to their IPNS hash, or they’re going to create one using our app. Once we get going, most of our app functionality will go into modifying and republishing this data.

The View Model

Which finally brings us to our view model. This is where we link our user-profile data model (default-profile.js) to our previously defined profile view structure (index.html). We’re going to take advantage of Knockout and the very nice mapping plugin, which gives us a straightforward way to map plain ol’ Javascript objects into a view model with the appropriate observables ready to go. This is awesome, because it really means we’re only adding a few lines to the bottom of our init function in main.js:

// Setup a viewModel based on our JSON structure
const viewModel = ko.mapping.fromJS(defaultProfile)
// Add an 'extra' observable for when we're loading
viewModel.state = {}
viewModel.state.loading = ko.observable(true)
viewModel.state.editing = ko.observable(false)
// Apply the viewModel bindings
ko.applyBindings(viewModel)

But before we save this and reload our page, we’ll also want to create our view’s bindings, so that our view model can actually update our view for us! For that, we return to our index.html file, and add various data-bind properties to bind our view elements to our model via our view-model. You should really check out the Knockout docs for an explanation for all of this fancy binding stuff, but suffice to say, this is how we map our users’ profile information to their profile page. Here’s what the body div from index.html should look like now:

Each view element is mapped in some way, shape, or form to part of our data model. For example, we’ll display a loading spinner if loading is true (and hide the rest). Conversely, for each element in our work array, we’ll display the text for the job title and employer. Any time these elements are updated, our view-model will automatically take care of the changes for us… slick! Alright, after all that, let’s check out our handy work…

Check it out

Here’s what we have so far…

Not all that exciting, so you can change your initial loading bool to false for now, and you’ll likely see something like this:

Simple profile app… but something’s missing