Webpack Hot-Reloading with Phoenix
January 14, 2016
this is just a reminder without proper comments...
Steps to enable Webpack + hot-reloding in Phoenix:
- Router: add routes for webpack controller (proxy)
if Mix.env == :dev do
scope "/static", Front do
pipe_through :api
get "/:req", WebPackController, :hot_update
end
end
- Webpack Proxy Controller (web/controllers/web_pack_controller.ex)
defmodule Front.WebPackController do
use Phoenix.Controller
@webpack_url "http://localhost:3000/static/"
def hot_update(conn, params) do
req = Map.get(params, "req")
res = HTTPoison.get! @webpack_url <> req
text conn, res.body
end
end
- Endpoint: adjust static Plug to include webpack
plug Plug.Static,
at: "/", from: :back, gzip: false,
only: ~w(css fonts images js webpack favicon.ico robots.txt)
- Config: dev.exs - configure watchers:
webpack_args = [Path.expand("assets/node_modules/.bin/webpack-dev-server"),
"--port=3000",
"--history-api-fallback",
"--hot",
"--progress",
"--inline",
"--colors",
"--stdin", ## so it will stop, when stdin from phoenix is closed
## requires https://github.com/webpack/webpack-dev-server/pull/352/files --> stdin, so probably >= 1.14.2
]
if IEx.started?, do: webpack_args = List.delete(webpack_args, "--progress")
config :front, Front.Endpoint,
http: [port: 4000],
debug_errors: true,
code_reloader: true,
check_origin: false,
root: Path.expand("..", __DIR__) <> "/assets", #we need to be in the assets folder...
watchers: [
"node": webpack_args,
]
- Mix: add task for asset digesting (lib/mix/tasks.ex)
defmodule Mix.Tasks.MyApp.Digest do
use Mix.Task
def run(args) do
Mix.Shell.IO.cmd "cd assets && npm run build"
:ok = Mix.Tasks.Phoenix.Digest.run(args)
end
end
in mix.exs
defp aliases do
[
....#
"phoenix.digest": ["my_app.digest"]
]
end
# add :httpoison to be started
defp applications(:dev) do
[:httpoison] + applications(:prod)
end
defp applications(_) do
[....]
end
- Views
- layout_view.ex
defmodule Front.LayoutView do
use Front.Web, :view
def styles_bundle(conn) do
make_path(conn, "vendor_styles-bundle.js")
end
def js_bundle(conn) do
make_path(conn, "js-bundle.js")
end
# enables hot-reloadable URLs in development
defp make_path(conn, asset) do
if Mix.env == :dev do
"http://localhost:3000/static/" <> asset
else
Front.Router.Helpers.static_path(conn, "/webpack/" <> asset)
end
end
end
templates: - use helpers in layout
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="">
<title>Front - React</title>
<script src="<%= styles_bundle(@conn) %>"></script>
</head>
<body>
<div id="root" class="container">
</div> <!-- /container -->
<script src='<%= js_bundle(@conn) %>'></script>
</body>
</html>
Gotchas:
Error: ENOENT: no such file or directory, open '.../node_modules/webpack-dev-server/client/live.bundle.js'
at Error (native)
cd node_modules/webpack-dev-server && npm run-script prepublish