dwyl / app

Clear your mind. Organise your life. Ignore distractions. Focus on what matters.
http://dwyl.github.io/app/
147 stars 22 forks source link

SPIKE: `Elm PWA` - Basic Offline Support #254

Open nelsonic opened 4 years ago

nelsonic commented 4 years ago

How much use is a "keep track of all the things" App that doesn't work offline? offline We hypothesize that an App meant to help people capture everything on their mind and get stuff done must work offline.

With this in mind, we need to do a Spike1 to explore using Elm for a Progressive Web App (PWA).

We can only test "offline support" by having some sort of "online" functionality thankfully we already have the "online" counterpart in the form of the capture workflow in dwyl/app-mvp-phoenix

Objectives

Todo

The PWA does not have to use Elm UI, but it would be a good "bonus level" to attempt to use it. See: https://github.com/dwyl/learn-elm/issues/145

We have collected a few useful links on Elm PWAs https://github.com/dwyl/learn-elm/issues/54 including a complete application: https://github.com/rl-king/elm-hnpwa We should be able to get started quite quickly by combining the work done in our dwyl/app-mvp-phoenix with this https://github.com/opvasger/elm-pwa by following this guide: https://github.com/dwyl/learn-elm/issues/54#issuecomment-558550433

Constraints

1https://en.wikipedia.org/wiki/Spike_(software_development)

SimonLab commented 4 years ago

Add new Elm project to Phoenix

image

We should now have a elm.json file and a src folder in assets where our Elm code will be added

Compile Elm to js using Webpack

Phoenix is already using Webpack to create one javascript containing all the code imported in assets/js/app.js

There is a specific webpack loader for Elm: https://github.com/elm-community/elm-webpack-loader that we can use in our Phoenix project to compile and bundle the Elm application

      {
        test: /\.elm$/,
        exclude: [/elm-stuff/, /node_modules/],
        use: {
          loader: 'elm-webpack-loader',
          options: {
            optimize: true
          }
        }

Create the Elm application

To test that Elm is working well with Phoenix and webpack we can create a simple application:

main = text "This is Elm text!"

- Import the Elm application in `/assets/js/app.js`:

```js
// import Elm application
import { Elm } from "../src/Main.elm";

var app = Elm.Main.init({
  node: document.getElementById('elm-app')
})
SimonLab commented 4 years ago

Now that we have mange to embed and Elm application with Phoenix the next step is to make the application more "usable".

SimonLab commented 4 years ago

So mixing "normal" Phoenix template and a SPA Elm is a bit more tedious to implement. My first idea was to have a specific javascript file for the SPA Elm and to not bundle it in app.js. However it doesn't seems possible to create multiple output with webpack. We could manually create the spa js file with elm make however this doesn't feel the right way to do this and to not using webpack.

However if we are going to use Elm for most of the feature I think we could use it for all the front end including authentication. Phoenix will only now be used to create the API. I think this might be the way to go and try to avoid rendering Phoenix templates

SimonLab commented 4 years ago

At the end It seems possible to create multiple outputs file with Webpack: https://webpack.js.org/concepts/output/#multiple-entry-points using the [name] placeholder. So we should be able to create a specific js file for the elm application and add to to the specific endpoint and keep the rest of the application using Phoenix template. I still feel that having a more distinct structure might be easier to manage, for example we could have the Elixir Phoenix API on one application and the Elm SPA in another place (repo?). Having a distinct API from the frontend will also allow us to let developers create their own frontend/apps

nelsonic commented 4 years ago

Hi @SimonLab, are you following a particular blog post or tutorial for getting Phoenix and Elm to work together? e.g: https://blog.ispirata.com/get-started-with-elm-0-19-and-phoenix-1-4-291beebb350b or https://teamgaslight.com/blog/a-starter-project-with-goodies-phoenix-1-dot-4-elm-0-dot-19-and-parcel If so, please share the links that you are following. Other people have attempted to tackle this challenge before, so we should be sharing links and describing where they work or don't work.

Our objective with this spike is just to test the creation of an Elm PWA that sends data to a Phoenix backend. That requires one API endpoint in the Phoenix App e.g: https://github.com/dwyl/app-mvp-phoenix/issues/53 We only the most basic of Elm app initialisation and compilation (covered in the links shared above). As noted in https://github.com/dwyl/learn-elm/issues/54#issuecomment-564295695 the create-elm-app utility creates a PWA out of the box. So that's what we should be using unless there is a compelling reason not to use it. 💭

As for the eventual architecture of the App we are building. We will be adopting exactly the same approach as every other SaaS App:

  1. Server-side rendered home/landing page describing the benefits of the App e.g: https://trello.com
  2. Server-side Authentication with Google and Email+Password e.g: https://trello.com/signup
  3. Once the person has successfully authenticated boot into a Full Page SPA that is 100% Elm. Here we can render the index.html.eex on the server and include the Flags in the template, and the immediately boot into Elm (with Flags) on the Client.
  4. All communication with the Phoenix Backend should be done over HTTPS using Http.request for example /api/new to create a new "capture" item.
  5. Presence (see: #255) will be added for viewing the availability of Team Mates.

The trickiest part of all this is getting the Phoenix Session from the Backend into the Elm App. If you decide to work on that, please open a separate issue, it's way beyond the scope of this SPIKE.

If you have implementation questions that require clarification, please ask them before diving in to avoid wasting time. Please ensure you have read the Books mentioned above both Jeremy and Richard cover most of the ground necessary for this SPIKE and the ELM PWA thread https://github.com/dwyl/learn-elm/issues/54#issuecomment-558550433 has much relevant detail too.

If you had read the Elm PWA thread on learn-elm you would not have needed to use elm init because create-elm-app creates all the files needed ... then it would just be a case of following one of the Phoenix 1.4 + Elm 0.19 tutorials for wiring up the WebPack config and 90% of the setup work would be done.

Please ask more questions and share more links as you are going. 👍

SimonLab commented 4 years ago

Hi @SimonLab, are you following a particular blog post or tutorial for getting Phoenix and Elm to work together?

So yes I've been looking at https://blog.ispirata.com/get-started-with-elm-0-19-and-phoenix-1-4-291beebb350b and also checked How I've added Elm to Club Soda. Since CS Phoenix is now using Webpack to bundle javascript code together. The blog post doesn't explain how webpack works with Elm so I've explained on the comment above the main concepts and how Elm is compiled and bundle to the main app.js file.

As noted in dwyl/learn-elm#54 (comment) the create-elm-app utility creates a PWA out of the box. So that's what we should be using unless there is a compelling reason not to use it.

My goal by creating the Elm with elm init instead of using the npm package create-elm-app is to understand all the steps for creating a PWA. create-elm-app code is a great reference and it will help me to implement some PWA features but I prefer to keep the application as simple as possible at the begining. Once I feel I understand all the steps we can then use the boilerplate outside of this spike

The trickiest part of all this is getting the Phoenix Session from the Backend into the Elm App. If you decide to work on that, please open a separate issue, it's way beyond the scope of this SPIKE.

I've also add a look at how to use sessions with Elm and I think https://github.com/rtfeldman/elm-spa-example is doing authentication. I'll create another issue to investigate/learn how to do this :+1:

I've spent some time yesterday thinking on how to use Navigation. As we are going to use mostly Elm on frontend I think we will need to use Browser.application "Create an application that manages Url changes." This type of Elm application are a bit more complicated to setup as compare to Browser.element (which is used in the blog :arrow_up: and by create-elm-app). However for the spike itsel as we only want to test the capture test with PWA we can have an Elm application nested and we don't have to worry about navigation for now. Once the PWA is working I can comeback to test Elm navigation. Hope this explain a bit more my thinking from yesterday. Working on https://github.com/dwyl/app-mvp-phoenix/issues/55

SimonLab commented 4 years ago

A basic Elm application is now on https://github.com/dwyl/elm-pwa-example/tree/gh-pages and hosted with Github pages: https://dwyl.github.io/elm-pwa-example/

The Elm app allow a user to create a new capture. The data is saved with the API defined and hosted on https://dwylapp.herokuapp.com/

The service worker on the application allow us at the moment to have the capture page available offline. This can be tested on Chrome with the Application tab: image

nelsonic commented 4 years ago

@SimonLab it would be really good to get this PR https://github.com/dwyl/app-mvp-phoenix/pull/52 finished so that we can close the Milestone: https://github.com/dwyl/app/milestone/4 💭 Maybe worth taking a look at this early next week after your move.

SimonLab commented 4 years ago

Working on this issue at the moment and I want to come back to a few points I've blocked on:

As mention on the comment above I've manage to create an Elm application which is also a PWA. The goal of this issue is to see if we can embed the elm application in Phoenix.

SimonLab commented 4 years ago

Concerning the first point, the Browser.application function:

image

This function creates the Elm web application however it will replace all the existing Phoenix endpoints and can't coexist with the other Phoenix views. This means that if we have a welcome page or a login page rendered with Phoenix these pages will be replaced by the Elm application which is not ideal. We can use instead the Browser.element function which create only some part of an html page with Elm. However this function doesn't provide any navigation management tool and Phoenix will be still used for routing. In this case I think it is better to just use Phoenix templating and to avoid embedding Elm inside a Phoenix view.

Concerning creating a PWA with Phoenix, I have managed to register a service worker however the configuration of the manifest.json file is not obvious and I still haven't found a simple solution (I've tried to apply some suggestions from https://stackoverflow.com/questions/45534076/site-cannot-be-installed-no-matching-service-worker-detected)

image

However I have manage previously to create an Elm PWA application, see https://github.com/dwyl/elm-pwa-example without using Phoenix.

To resume, I don't think using Elm to create a full application combine with a few Phoenix pages is the right way to go. If we want later on to add PWA to the application my choice would be to only use Phoenix to create the API, then using Elm on its own to create the UI/UX and PWA features. The API can be used later on by other tools to create the UI, for example Flutter.