Setting Up Single Page JavaScript in Phoenix with Brunch

Andrew Baker
3 min readOct 2, 2017

--

I am a Phoenix / JS build noob and could not find a clear explanation of how to create single page JS for Phoenix anywhere online, so I decided to make this quick how to.

In this tutorial I will be working with Phoenix 1.3 and Brunch 2.10.9.

By default Phoenix is set up to use the Brunch build tool to assemble all of your JS in the /assets/js folder into a file at /priv/static/js/app.js. Files must be “imported” in the /assets/js/app.js file in order to make it into the final assembled version. This is because the Brunch build tool is performing some preprocessing over the JS files to determine what should be written to the JS output file.

Making a new JS file

Step 1: Create seperate JS folders

Lets say we want to make a new JS file called “home.js” and we only want this file to be loaded on the home page. First thing is to create a new folder and JS file for this page specific JS. Your assets directory should look like this.

Next up we need some JS to import into the home.js file. Add this line to home.js:

import socket from "./homeSocket"

then create a new file at /assets/home/homeSocket.js and add the following boilerplate Phoenix code

import {Socket} from "phoenix"let homeSocket = new Socket("/socket", {params: {token: window.userToken}})homeSocket.connect()let channel = homeSocket.channel("home:lobby", {})channel.join()
.receive("ok", resp => {
console.log("Joined successfully", resp) })
.receive("error", resp => { console.log("Unable to join", resp) })
export default homeSocket

also to reduce confusion, lets go into /assets/js/app.js and reduce it to only the following line

import "phoenix_html"

Step 2: Updating Your Brunch Configs

All of the brunch build process is controlled by a file at /assets/brunch-config.js. Much of my confusion came from navigating this file. There are 3 seperate lines you need to change to get this new home.js file built.

Change the JoinTo block to the following:

joinTo: {
"js/app.js": /^(js|node_modules)/,
"js/home.js": /^(home|node_modules)/
}

This tells Brunch what files to add to the build of each specific end file. Note we use a regex to find the files and also must include the OR node_modules option. You need this since even an empty brunch build uses some node_modules.

Change the Paths block to this:

paths: {
// Dependencies and current project directories to watch
watched: ["home", "static", "css", "js", "vendor"],
// Where to compile files to
public: "../priv/static"
},

We added the “home” directory to the list of watched paths. You need this tell brunch that home is something that should be checked for files to build.

Finally change the modules block to this:

modules: {
autoRequire: {
"js/app.js": ["js/app"],
"js/home.js": ["home/home"]
}
},

This was the most confusing part for me, but brunch needs to know which file to auto execute in the resulting build file. If you do not include this all the JS is included in your site but nothing happens. We are telling Brunch that the resulting file at /priv/static/js/home.js should auto execute the code we wrote in /assets/home/home.js. Since we put an import statement in that file it will include the homeSocket file as well.

Step 3: Build files

In the command line navigate to your /assets file and run

brunch build

If you get a “no brunch found” error, install brunch globally with

npm install -g brunch

and then try again.

Step 4: Add newly built JS to your page

Now that we have this built “home.js” file, we can add it to any template we like using this line

<script src="<%= static_path(@conn, "/js/home.js") %>"></script>

Note that the app.js file is included in /templates/layout/app.html.eex so it is automatically included in all pages. By adding the home.js script to individual templates, we can control which JS loads on an individual page.

Wrap Up

I don’t claim to be an expert in the use of these tools. These instructions may very well break best practices or other code conventions. I could not find any other tutorial on how to simply get page specific JS working in Phoenix 1.3 so I figured out the simplest way I could find.

--

--