Phoenix and Riot.js – trying to use the less javascript i can – ELIXIR PART III

Javascript and phoenix

Intro

While developing a modern web app, soon or later, you have to deal with javascript, in order to give your users better experiences and to avoid useless page reload and so on.

The radical choice is to use one of popular javascript framework to manage all front end stuffs with a spa app. This way you can totally decouple front end and back end and get some real amazing results, but you have to write a ton of code,often writing some features twice, one for the client and one for the server.

This time my goal is to learn at my best a new language and e new framework that claim to have built into it a lot of features that gaves the same good user experience of spa apps, with a lot less lines of code.
I mean phoenix channels, presences, sockets and so on, so i’d like to use the less javascript I can, without refuse to have an acceptable user experience.

The solution i found is Riot.js v3, which is by far lighter than most popular frameworks – polymer is 6 times heavier, angular much more, it’s component based and has a well written and complete documentation.

Here is a brief description about i integrated it into phoenix in order to make an heavy use of it’s capabilities.

Setup

Phoenix1.4 use Webpack 4 to manage static assets (prior versions used brunch, here a guide about), and it has defaults good enough to let you add 3rd party libraries available and ready to use with little or no effort.

All you have to do is to create a js folder under your asset/static path into the _web app to contains the libraries you want to use, and because of Riot.js needs also, at least, a file per component, i added into /assets/static/js/tags directory to contain them.

Webpack will copy them all into priv/static folder of your web app, ready to be served at usual urls.

So the struct fo that part of the app will something similar to:

nagger_web$ tree -d 1 -L 1 assets/
assets/
├── css
├── js
├── node_modules
├── static
│   ├── images
│   └── js
│       └── tags
└── vendor

Then i copied into js folder the riot+compiler.min.js file, the only file needed by Riot to compile at runtime the components, and added it’s reference into the base app template, app.html.eex becouse i’m planning to use Riot every time i need some dom manipulation, in thisway it will be available everywhere.

I added superagent too, becouse it’s very practical when you have to deal with asyncronous ajax requests but you want to keep your code clean and readable.

The lines added are:

<script src="https://polyfill.io/v3/polyfill.min.js?features=Array.from,Promise,Symbol,Object.setPrototypeOf,Object.getOwnPropertySymbols"></script>
<script src="https://cdn.jsdelivr.net/npm/superagent"></script>
<script src="<%= Routes.static_path(@conn, "/js/riot_compiler.min.js") %>"></script>

And voilà, Riot is available everywhere ;-D

Just be sure to add these lines into the <head> tag of the page, this way their functions will be available into all your template when rendered.

Now i want to test if it’s really working, so i created the simplest riot tag ever and saved it as hello-world.tag into the assets/static/js/tags folder

<hello-world>
  <h3>Hello World from { opts.from }!!!</h3>
  <script>
    console.log('All fine...');
  </script>
</hello-world>

And added to my templates/pags/index.html.eex templates the three lines of code that should make it rendered on the DOM.

<div class="row">
  <script src="<%= Routes.static_path(@conn, "/js/tags/hello-world.tag") %>" type="riot/tag"></script>

  <hello-world from="Sergio"></hello-world>
  <script>
      riot.mount('*');
  </script>
</div>

And launched the server with usual command:

$mix phx.server

in order to verify if everything is working as expected, aaand…

Enjoy!!

Build foundations for complex Phoenix Web App using –umbrella option – ELIXIR part II

So, as maybe you get here, i’m playing with Phoenix framework trying to learn how to do web development in Elixir the hard way – i mean bumping my head against any single aspect of both the language and the framework.

And what’s best then have a good practice to start your projects?

This is what i get till now for Phoenix.

Usually a good start in building your new app is to split the original idea into smaller units, each with a single responsibility to carry on. This way it’s easier to maintain and to integrate with new features.
Phoenix give the opportunity to organize the modules under what is called an “umbrella”.

Let’s we have a look on it using mix commands and some lines of code.

The app in my mind is a web page from where you can block some category of people you don’t like on twitter, using their twitter preferencies, in order to nag them – ex. all Trump followers – so i’ll call it nagthem.

  • Creating the app:
$ mix phx.new nagthem --umbrella

Using this command the following directory structure is created:

$ tree nagthem_umbrella/ -d 2 -L 1
nagthem_umbrella/
├── apps
├── _build
├── config
└── deps

As you can see the postfix “_umbrella” is added to the app name passed to the command and there is an “apps” directory.

Intuitively it will contains the app’s modules. In fact right now we will find in it the first two modules that we are used to find creating an app whithout the umbrella option:

$ tree apps/ -d 1 -L 3
apps/
├── nagthem
│   ├── lib
│   │   └── nagthem
│   ├── priv
│   │   └── repo
│   └── test
│   └── support
└── nagthem_web
├── assets
│   ├── css
│   ├── js
│   ├── node_modules
│   ├── static
│   └── vendor
├── lib
│   └── nagthem_web
├── priv
│   ├── gettext
│   └── static
└── test
├── nagthem_web
└── support

But now we have the opportunity to add what we are planning to develop in a very appropriated and ordinated way, submoduling as we need.

I mean, i’m planning to interact with twitter’s api, so i will need an api module to do this, well, after cd into apps, with the command

$mix phx.new api --app api --no-webpack --no-html --no-ecto

Phoenix create for me the right app skeleton (without the need for ecto, that is managed in the nagthem app), wich i can populate later using generators.

App struct is:

$ tree api/ -L 2
api/
├── config
│   ├── config.exs
│   ├── dev.exs
│   ├── prod.exs
│   ├── prod.secret.exs
│   └── test.exs
├── lib
│   ├── api
│   ├── api.ex
│   ├── api_web
│   └── api_web.ex
├── mix.exs
├── priv
│   └── gettext
├── README.md
└── test
├── api_web
├── support
└── test_helper.exs

No a single useless file 🙂

I can do something similar for tha admin module of my app,with command

$mix phx.new admin --app admin --no-ecto

In this case i wanted webpack and templates skeletons, so i didn’t used the –no-webpack option, and the appstruct is:

$ tree admin/ -L 2
admin/
├── assets
│   ├── css
│   ├── js
│   ├── node_modules
│   ├── package.json
│   ├── package-lock.json
│   ├── static
│   ├── vendor
│   └── webpack.config.js
├── config
│   ├── config.exs
│   ├── dev.exs
│   ├── prod.exs
│   ├── prod.secret.exs
│   └── test.exs
├── lib
│   ├── admin
│   ├── admin.ex
│   ├── admin_web
│   └── admin_web.ex
├── mix.exs
├── priv
│   ├── gettext
│   └── static
├── README.md
└── test
├── admin_web
├── support
└── test_helper.exs

And last but not least i can group under the umbrella non-Phoenix app, i mean simple Elixir app, if my module doesn’t need any “web” interaction, for example i’m going to implement authentication in this way, and so with command

$ mix new auth --app auth --sup

the lighter skeleton is used and app struct is

$ tree auth/ -L 2
auth/
├── lib
│   ├── auth
│   └── auth.ex
├── mix.exs
├── README.md
└── test
├── auth_test.exs
└── test_helper.exs

Not bad, isn’t it?

Imo this is reallya good way to start with your project, It shows you the right path, and prevents you from messing up before you even get to the heart of the matter.

Imo they could have copied some of this from Django doing such a thing since before elixir was conceived 🙂

And something similar to django urlpatterns can also be done in order to route your requests and to be sure that certain url is routed to the right module.

I manage to achive this editing the router Phoenix use as default, the one created with the nagthem_web app, and it’s pretty simple.

All you have to do is to specify where to redirect certain urls:

defmodule NaggerWeb.Router do
  use NaggerWeb, :router

  pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_flash
    plug :protect_from_forgery
    plug :put_secure_browser_headers
  end

  pipeline :api do
    plug :accepts, ["json"]
  end

  scope "/", NaggerWeb do
    pipe_through :browser

    get "/", PageController, :index
  end

  forward "/admin", AdminWeb.Router
  forward "/api", ApiWeb.Router

end

I know this isn’t the only way to achieve this, here you can fine an elegant way using subdomain, but formy need this is enough for now.

That’s all folks, for today. If i can in next weeks i’ll keep you informed into my progress with Elixir 😉

Have a good time

Sergio