DEV Community

Cover image for Using Fission with Elm - Part 2: Integrating Fission into the Elm project
Matt "Verge" Virgin for XetiCode LLC

Posted on

Using Fission with Elm - Part 2: Integrating Fission into the Elm project

Prelude

This is part of a three-part series. In part one, I demonstrated how to use Vite to manage an Elm application. In part two (this article), I will show you how to integrate Fission into the project from part one. Part three will walk you through how to refactor the project for Fission authentication and Fission Drive.

The Github repository associated with this article can be found here:
https://github.com/xeticode/fission-with-elm-demos/tree/Part-2


Intro

Welcome to round two! The time has come to upgrade our project from part one! The upgrade will connect the application to Fission, which I will introduce to you in a short moment. Before the introduction, I want to point out why Fission is a tool of the future. Fission uses a distributed system to store data. To one up that, Fission built a file system in the distributed system and protects it with military grade encryption. That means you can have a whole file system saved and protected across a whole network (in this case, the internet) rather than just on a remote machine or your own. And for app development, it means no need to worry about server maintenance or scaling. Anyways, I am getting ahead of myself. Without further ado, I present to you the InterPlanetary File System (IPFS) and, of course, Fission.

Enter IPFS…

In short, the “IPFS is a distributed system for storing and accessing files, websites, applications, and data” (for more information, see IPFS). No more need for centralized servers! Have you ever heard of blockchain? It uses a similar technical approach: peer-to-peer networking using content addressing. Say goodbye to centralized servers!

Enter Fission…

To add to my pre-introduction, Fission is built on top of the IPFS, and implements a layer of military grade encryption. I know I mentioned this before, but it deserves more attention. Fission created a file system called Webnative File System (Wnfs). It has a huge advantage over cloud storage in that it resides in a distributed system rather than centralized servers, meaning it is backed up on a vast network of machines and not at the data centers of some tech company.

Fission developed the Webnative SDK to interact with Fission services. Since we are working with an Elm application, we will use the Webnative-elm module for Elm (see Webnative-Elm). Using this wrapper allows us to maximize our Elm code and minimize the JavaScript for the project.


The Walkthrough

NOTE: This article assumes you have completed the project as described in part 1. If you have not completed that project, please go back and follow the steps in part 1 to complete it or download the part 1 reference project. See Fission with Elm, Part 1: Using Vite to manage Elm applications for both options.

Installing Webnative dependencies

To start things off, we will need to install Webnative to our node modules and elm.json file. To do this, run the following commands in the terminal from the root directory of the project:

npm install --save-dev webnative webnative-elm
npx elm-json install fission-suite/webnative-elm
Enter fullscreen mode Exit fullscreen mode

These commands do the following:

  • npm install webnative webnative-elm will install both webnative and webnative-elm libraries to the project (check package.json for the new additions).
  • npx elm-json install fission-suite/webnative-elm will install the Elm dependency of the fission-suite/webnative-elm module (check elm.json for the new addition). This module is a wrapper, written in Elm, for Webnative.

Modifying js/index.js

This is pretty simple.

At the top of the file, add these two lines:

import * as webnative from webnative
import * as webnativeElm from webnative-elm
Enter fullscreen mode Exit fullscreen mode

And after the const app = Elm.Main.init({}); line, add these two lines:

webnative.setup.debug({enabled:true});
webnativeElm.setup({app, webnative});
Enter fullscreen mode Exit fullscreen mode

Here is a quick breakdown of the new lines:

  • webnative.setup.debug({enabled:true}); toggles on the debug mode. If enabled, the debug mode will output Webnative-related messages to the Console tab in the Developer Tools window. Toggle debug mode with this window open and you will easily see the difference.
  • webnativeElm.setup({app, webnative}); initiates the webnative-elm wrapper, taking the initialized Elm application and the Webnative SDK connection as parameters.

Modifying src/Main.elm

Ports

Elm ports are how an Elm application can communicate with JavaScript, or the “outside world” as I like to call it (for an in-depth explanation of Elm ports, see Elm Ports). The current state of the Main.elm file does not permit the use of ports. To change this, we need to change the file from a standard module to a port module. On line 1 of Main.elm, add port before module. We can now use ports in this Elm file! Let’s add some!
Normally, Elm ports require two ends: one Elm, and one in JavaScript. What makes this situation “abby”-normal (if you know, you know) is that this application is only concerned with interacting with Fission. The webnative-elm wrapper handles the JavaScript end of the Webnative-related ports. The wrapper has also consolidated all of the ports we may need into two ports: one for all Webnative requests, and one for all Webnative responses.
The Webnative SDK requires two ports: one for requests, and one for responses. Add these two lines just after the import block at the top of the file in Main.elm to satisfy the requirement:

port webnativeRequest : Webnative.Request -> Cmd msg
port webnativeResponse : (Webnative.Response -> msg) -> Sub msg 
Enter fullscreen mode Exit fullscreen mode

Once you have them added, you will notice the red squiggles under Webnative.Request and Webnative.Response. This is because we have yet to import Webnative to the file. Add:

import Webnative
Enter fullscreen mode Exit fullscreen mode

to the import block at the top of the file.

Adding Permissions

Every Fission-based application requires a set of defined permissions to initialize the application.
There are three functions we will add to our project to define these permissions: appPermissions, fsPermissions, and permissions.

appPermissions will return a record with fields indicating the name of the application and the creator of the application. Add the following just after the Webnative ports in Main.elm:

appPermissions : Webnative.AppPermissions
appPermissions =
    { creator = "Trillian"
    , name = "fission-with-elm"
    }
Enter fullscreen mode Exit fullscreen mode

This is what Fission will use to create a file path within the Wnfs to the files produced by this application (i.e. Apps/Trillian/fission-with-elm/). Feel free to change the creator field to your own username if you so desire.

fsPermissions will return a record with fields indicating what public and private parts of the Wnfs for which the application will request access (“fs” stands for File System here). Add the following a couple of lines after appPermissions, but before type alias Flags:

fsPermissions : Webnative.FileSystemPermissions
fsPermissions = 
    { public =
            { directories = []
        , files = []
            }
    , private = 
            { directories = []
            , files = []
            }
    }
Enter fullscreen mode Exit fullscreen mode

This application is not asking to access any parts of the Wnfs external to this application, so the lists will remain empty.

permissions the icing on the cake. This will return a record with two fields: app and fs. These correspond to the two previous code blocks we talked about. Add the following a couple of lines after fsPermissions, but before type alias Flags:

permissions : Webnative.Permissions
permissions =
    { app = Just appPermissions
    , fs = Just fsPermissions
    }
Enter fullscreen mode Exit fullscreen mode

We will pass this, our newly defined permissions, through the webnativeRequest port in the next step.

The init and subscriptions functions

init

The only difference here is changing the Cmd msg from Cmd.none to a command that will initialize the application as a Webnative application. The new init function should look like this:

init : Flags -> Url.Url -> Navigation.Key -> (Model, Cmd Msg)
init {} url key =
    ( Model
    , permissions
        |> Webnative.init
        |> webnativeRequest
    )
Enter fullscreen mode Exit fullscreen mode

Here is a quick explanation of the new command:

  • permissions was previously defined in the walkthrough. It indicates both the name and creator of the application and contains a list of Wnfs access requests.
  • Webnative.init is a function of webnative-elm that will load a user's Wenative File System, if said user is authenticated.
  • webnativeRequest is our port for our Webnative related requests. subscriptions We now need to subscribe to webnativeResponse so the response will be properly handled and not left by the wayside. In the subscriptions function, change Sub.none to:
webnativeResponse GotWebnativeResponse
Enter fullscreen mode Exit fullscreen mode

This will set the application to watch our webnativeResponse port for any changes. GotWebnativeResponse is a Msg variant we will add in a few moments and will be where we handle the response.

Adding a variant to the Msg and updating the update function

Msg

At this point, we have only two Msg variants: UrlChanged Url.Url and LinkClicked Browser.UrlRequest. To handle the webnativeResponse, we need to add the GotWebnativeResponse variant. Add the new variant to the Msg so that it looks like this:

type Msg 
    = UrlChanged Url.Url
    | LinkClicked Browser.UrlRequest
    | GotWebnativeResponse Webnative.Response
Enter fullscreen mode Exit fullscreen mode

This new variant will allow us to dictate how to handle each response the application receives from webnativeResponse. Our friendly red squiggles should now be present on our update function. This is because our new Msg variant is a new branch the case statement in our update function needs to handle. The only problem? We have yet to add the branch to the case statement. This exemplifies one of the beauties of Elm, it forces us to handle each defined potential outcome or branch of whatever it is that is the subject of a case statement. Super helpful if you are, at times, forgetful 😉 Let us now add the new branch to update.

update

That being said, as much as we may enjoy the red squiggles, they need to go. Add the following branch to the update function's case statement:

GotWebnativeResponse response ->
    (model, Cmd.none)
Enter fullscreen mode Exit fullscreen mode

This will satisfy the Elm compiler, but it needs to be noted that this state of the GotWebnativeResponse branch does not handle anything. It is currently a dead end for the Webnative response, and for the time being, it will stay that way. The reason for this decision is that adding the proper logic to this branch fits beautifully with what is covered in part three of this series: authentication and interacting with the Wnfs. So be sure to check out part three!


The Ending

Before its over: See that it works

So far we have done all this work, but have yet to visually see any of that work in our app. If you have not done so already, get your dev server running. Once you have the app running, open the Developer Tools window in your browser, and go to the Console tab. You should see the following message in the list of messages:

[vite-plugin-elm] ports. webnativeRequest.subscribe called
Enter fullscreen mode Exit fullscreen mode

This indicates that our application is listening to the webnativeRequest port! Visually, it is not much, but internally this is very important.

Adieu

And there you have it! The application has been upgraded with Fission integration. In this article, I showed you how to build upon what we made in the first article. In the third article, we will see the culmination as functionality is added to the project. If you wish to learn more about Fission or the Webntive-Elm module, check out these links:

Top comments (0)