About code organization in eex templates, with socket and Presence

phoenix
eex
javascript
presence
socket
Tags: #<Tag:0x00007fbcb64931b0> #<Tag:0x00007fbcb6492e90> #<Tag:0x00007fbcb6492d50> #<Tag:0x00007fbcb6492c10> #<Tag:0x00007fbcb6492ad0>

#1

I wanted to organize the use of socket and Presence in a template in my own way.
As a newbie, it seems to me that putting all the client code that deals with channels in sockets.js can convert it into a very large piece.
Especially if there are many pages that use sockets / Presence.
I do not know which is the best solution (or if this is a problem for other people), but my misunderstood functioning of js, leads me to organize the code well.

In socket.js

    import {Socket, Presence} from "phoenix"
    // Other stuff
    export {
      Presence,
      socket
    }

In app.js, instead of import socket from "./socket" at the end, I write

import {Presence, socket} from "./socket"

window.getPhoenixSocket = function () {
    return socket;
};
window.getPhoenixPresence = function () {
    return Presence;
};

And in the template eex (I know it’s not good practice to mix html and scripts) (except for the React guys!) I write the following script:

<script>
  window.onload = function () {
    let channel = getPhoenixSocket (). channel ("cute: channel", {})
    let Presence = getPhoenixPresence ();
....
// Here I can use channel and Presence for my obscure purposes
....
}
</script>

Thus the code of each page that uses socket remains in the own page and not in socket.js

As I am not entirely satisfied with this solution, I ask you, is this correct? Is not it? What would be the best way to do it?
Is there someone who has this problem?


#2

The issue is that you are mixing JavaScript styles. When you see import, you are looking at modular JavaScript. For browsers modular JavaScript is processed by bundlers like Brunch or Webpack. See Modern JavaScript Explained For Dinosaurs.

Mastering Modular JavaScript


#3

Ok, Alright, I mix styles (I do not know which). But the easy and simple solution, what is it? How would you put the code to be compatible with Brunch, easy and understandable?
Thanks


#4

You are doing the “easy and simple” thing but

I am not entirely satisfied with this solution,

because it isn’t optimal for pages that make significant use of JavaScript.

I posted a quick example here of how to convert to a modular style. In your case there is the additional challenge that you will likely need a separate bundle for each page - something that is handled by bundlers with “multiple entry points”, i.e. one bundle per entry point. There is a (Brunch) discussion about that:

However note that Phoenix 1.4 uses Webpack 4 instead of Brunch.

Technically the code that you put inside the script tags is supposed to be at the end of app.js (the page bundle) - in which case you wouldn’t need to attach getPhoenixSocket and getPhoenixPresence to the global window object.

So your challenge is to get Brunch to generate the app1.js, app2.js, etc. bundles that you need for your various pages and include them in the page templates (and remove app.js from the layout template app.html.eex).


#5

Really good answer.
Thanks


#6

Before you get too far into the weeds with Brunch you may want to consider switching to Webpack 4.

Scavenging the Phoenix 1.4 setup for 1.3.2 is described here. The Webpack configuration for multi-page-applications is documented.

Webpack will pull in any imported dependencies into the bundle as long as it knows where to look.


#7

Others interesting solutions has been published in Medium, and as @peerreynders indicates, it also uses Webpack.

And the last one i’ve found is here Diacode and the second page here