Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
  1. Generate phoenix app
$ mix phx.new phx_react
Fetch and install dependencies? [Yn] y
  1. Generate react app in the assets directory
cd ./phx_react/assets

npx create-react-app my-app
cd my-app
  1. Prepare a scripts folder
# ./phx_react/assets/my-app/scripts
mkdir ./scripts
touch ./scripts/cp_build_to_phoenix
chmod +x ./scripts/cp_build_to_phoenix
  1. Add this script ./scripts/cp_build_to_phoenix
# ./phx_react/assets/my-app/scripts/cp_build_to_phoenix

#!/bin/bash
# cd into ./scripts directory
cd "$(dirname "$0")"
# Copy JS bundle to my-app static assets dir
cp -r ../build/static ../../../priv/static/
cp ../build/*.json  \
    ../build/*.ico  \
    ../build/*.json \
    ../build/*.js   \
    ../../../priv/static/
  1. Edit the build command in my-app's package.json
// ./phx_react/assets/my-app/package.json
{
  "scripts": {
    "build": "react-scripts build && bash ./scripts/cp_build_to_pheonix"
  }
}

Now, if you run this command from the terminal

# from ./phx_react/assets/my-app
yarn build

The priv/static folder of your phoenix app will look like this:

# ./phx_react/priv/static/
$ tree ./priv/static/
./priv/static/
├── asset-manifest.json
├── css
│ ├── app.css
│ └── app.css.map
├── favicon.ico
├── images
│ └── phoenix.png
├── js
│ ├── app.js
│ └── app.js.map
├── manifest.json
├── robots.txt
├── service-worker.js
└── static
├── css
│ ├── main.c17080f1.css
│ └── main.c17080f1.css.map
├── js
│ ├── main.a285be49.js
│ └── main.a285be49.js.map
└── media
└── logo.5d5d9eef.svg
7 directories, 15 files

The react app is in the static/static folder (a bit redundant but bear with me).

The last part is to make phoenix render it!

You will need some information within the asset-manifest.json for that.

  1. Create a new view helper file:
# lib/phx_react_web/views/view_helpers.ex

# Either Jason.decode or Poison.decode depending on which lib you're using.

defmodule PhxReactWeb.ViewHelpers do
  def read_json_file(filename) do
    with {:ok, body} <- File.read(filename),
    {:ok, json} <- Poison.decode(body), do: {:ok, json}
  end
end
  1. Include this module in phx_react_web.ex
# lib/phx_react_web.ex

defmodule PhxReactWeb do
  # ...
  def view do
    quote do
      # ...
      import PhxReactWeb.ViewHelpers
    end
  end
end
  1. In your layout specify the bundle's src
<%
  {:ok, manifest} = read_json_file("priv/static/asset-manifest.json")
  main_js  = "/" <> manifest["main.js"]
  main_css = "/" <> manifest["main.css"]
%>
<!DOCTYPE html>
<html lang="en">
  <head>
    <!-- ... -->
    <link rel="manifest" href="<%= static_path(@conn, "/static/asset-manifest.json") %>">
    <link rel="stylesheet" href="<%= static_path(@conn, main_css) %>">
  </head>

  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <script src="<%= static_path(@conn, main_js) %>"></script>
  </body>
</html>
  1. Last but not least, add the static/static folder to the directory of statically served assets
defmodule PhxReactWeb.Endpoint do
  # ...
  plug Plug.Static,
    at: "/", from: :phx_react, gzip: false,
    only: ~w(static css fonts images js favicon.ico robots.txt)
    #          ^ --- add this.
    # ...
end
  1. Profit!

You may want to add another script to automatically build your react app from your phoenix app.

$ mkdir ./phx_react/assets/scripts/scripts
$ touch ./phx_react/assets/scripts/scripts/build

Then:

# ./phx_react/assets/scripts/build

#!/bin/bash

# cd into script directory
cd "$(dirname "$0")"

# Build my-app app
cd ../my-app && yarn build

Then add this to the deploy command in ./phx_react/assets/package.json

// ./phx_react/assets/package.json
{
  // ...
  "scripts": {
    "deploy": "brunch build --production && bash ./scripts/build",
    // ...
  },
  // ...
}

Then from ./phx_react/assets:

# ./phx_react/assets
yarn deploy
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.