- Generate phoenix app
$ mix phx.new phx_react
Fetch and install dependencies? [Yn] y
- Generate react app in the
assets
directory
cd ./phx_react/assets
npx create-react-app my-app
cd my-app
- 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
- 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/
- Edit the
build
command inmy-app
'spackage.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.
- 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
- 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
- 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>
- 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
- 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