Packages

Phoenix Plug to proxy assets served by the webpack dev server

Current section

3 Versions

Jump to

Compare versions

4 files changed
+63 additions
-27 deletions
  @@ -1,4 +1,6 @@
1 1 # WebpackStatic
2 + [![Build Status](https://travis-ci.org/jmartin84/WebpackStaticPlug.svg?branch=master)](https://travis-ci.org/jmartin84/WebpackStaticPlug)
3 +
2 4 Phoenix plug to proxy a locally running instance of the webpack dev server.<br />
3 5 This plug will only serve assets when the env parameter has the value of `:dev`.<br />
4 6 Phoenix will be allowed a chance to resolve any assets not resolved by webpack.<br />
  @@ -27,4 +27,4 @@
27 27 {<<"optional">>,false},
28 28 {<<"repository">>,<<"hexpm">>},
29 29 {<<"requirement">>,<<"~> 1.0">>}]]}.
30 - {<<"version">>,<<"0.1.1">>}.
30 + {<<"version">>,<<"0.2.0">>}.
  @@ -18,7 +18,6 @@ defmodule WebpackStatic.Plug do
18 18
19 19 $ mix deps.get
20 20
21 -
22 21 ## Usage
23 22 Add WebpackStatic.Plug as a plug in the phoenix project's endpoint.
24 23
  @@ -42,43 +41,56 @@ defmodule WebpackStatic.Plug do
42 41 require Poison
43 42
44 43 @doc false
45 - def init([port, webpack_assets, env, manifest_path]) do
46 - [port, webpack_assets, env, manifest_path]
44 + def init(args) do
45 + List.keysort(args, 0)
47 46 end
48 47
49 48 @doc false
50 49 def call(conn, [
51 - {:port, port},
52 - {:webpack_assets, assets},
53 50 {:env, env},
54 - {:manifest_path, manifest_path}
51 + {:manifest_path, manifest_path},
52 + {:port, port},
53 + {:webpack_assets, assets}
55 54 ]) do
56 55 if env == :dev do
57 56 manifest_task = Task.async(fn -> get_manifest(manifest_path, port) end)
58 - serve_asset(conn, port, assets, Task.await(manifest_task))
57 + manifest = Task.await(manifest_task)
58 +
59 + case manifest do
60 + {:error, message} -> raise message
61 + {:ok, manifest} -> serve_asset(conn, port, assets, manifest)
62 + nil -> serve_asset(conn, port, assets, nil)
63 + end
59 64 else
60 65 conn
61 66 end
62 67 end
63 68
64 - defp get_manifest(path, port) do
69 + defp get_manifest(path, port) when is_binary(path) do
65 70 url =
66 71 "http://localhost:#{port}"
67 72 |> URI.merge(path)
68 73 |> URI.to_string()
69 74
70 - case Http.get(url, headers: [Accept: "application/json"]) do
71 - %HTTPotion.Response{status_code: code} when code == 400 ->
72 - raise "404 could not find: #{url}"
75 + response = Http.get(url, headers: [Accept: "application/json"])
76 +
77 + case response do
78 + %HTTPotion.Response{status_code: code} when code == 404 ->
79 + {:error, "Error: could not find manifest located at #{url}"}
80 +
81 + %HTTPotion.Response{body: body, status_code: code} when code >= 400 ->
82 + {:error, "Error: fetching manifest, status:#{code} body:#{body}"}
73 83
74 84 %HTTPotion.Response{body: body} ->
75 - Poison.decode!(body)
85 + Poison.decode(body)
76 86
77 87 %HTTPotion.ErrorResponse{message: message} ->
78 - raise "Error fetching manifest: #{message}"
88 + {:error, "Error: fetching manifest: #{message}"}
79 89 end
80 90 end
81 91
92 + defp get_manifest(_, _), do: nil
93 +
82 94 defp serve_asset(
83 95 conn = %Plug.Conn{
84 96 path_info: [uri, file_name],
  @@ -93,7 +105,7 @@ defmodule WebpackStatic.Plug do
93 105 actual_path =
94 106 case manifest do
95 107 %{^requested_path => value} -> value
96 - _ -> file_name
108 + _ -> requested_path
97 109 end
98 110
99 111 url =
  @@ -113,7 +125,13 @@ defmodule WebpackStatic.Plug do
113 125 headers: req_headers
114 126 )
115 127
116 - receive_response(conn)
128 + response = receive_response(conn)
129 +
130 + case response do
131 + {:not_found, conn} -> conn
132 + {:error, message} -> raise message
133 + {:ok, conn} -> Conn.halt(conn)
134 + end
117 135 else
118 136 conn
119 137 end
  @@ -126,28 +144,40 @@ defmodule WebpackStatic.Plug do
126 144 %HTTPotion.AsyncChunk{chunk: chunk} ->
127 145 case Conn.chunk(conn, chunk) do
128 146 {:ok, conn} -> receive_response(conn)
129 - {:error, reason} -> raise reason
147 + {:error, reason} -> {:error, "Error fetching webpack resource: #{reason}"}
130 148 end
131 149
132 150 %HTTPotion.AsyncHeaders{status_code: status} when status == 404 ->
133 - conn
151 + {:not_found, conn}
134 152
135 - %HTTPotion.AsyncHeaders{headers: %HTTPotion.Headers{hdrs: headers}} ->
153 + %HTTPotion.AsyncHeaders{
154 + status_code: code,
155 + headers: %HTTPotion.Headers{
156 + hdrs: headers
157 + }
158 + }
159 + when code < 400 ->
136 160 headers
137 161 |> Map.to_list()
138 162 |> Enum.reduce(conn, fn {key, value}, acc ->
139 163 Conn.put_resp_header(acc, key, value)
140 164 end)
141 - |> Conn.send_chunked(200)
165 + |> Conn.send_chunked(code)
142 166 |> receive_response()
143 167
144 168 %HTTPotion.AsyncEnd{} ->
145 - Conn.halt(conn)
169 + {:ok, conn}
146 170
147 171 %HTTPotion.ErrorResponse{message: message} ->
148 - raise "Error fetching webpack resource: #{message}"
172 + {:error, "Error fetching webpack resource: #{message}"}
173 +
174 + %HTTPotion.AsyncHeaders{
175 + status_code: code
176 + }
177 + when code >= 400 ->
178 + {:error, "Webpack responded with error code: #{code}"}
149 179 after
150 - 15_000 -> raise "Error fetching webpack resource: Timeout exceeded"
180 + 15_000 -> {:error, "Error fetching webpack resource: Timeout exceeded"}
151 181 end
152 182 end
153 183 end
  @@ -5,7 +5,7 @@ defmodule WebpackStatic.MixProject do
5 5 def project do
6 6 [
7 7 app: :webpack_static_plug,
8 - version: "0.1.1",
8 + version: "0.2.0",
9 9 elixir: "~> 1.6",
10 10 start_permanent: Mix.env() == :prod,
11 11 deps: deps(),
  @@ -13,8 +13,9 @@ defmodule WebpackStatic.MixProject do
13 13 source_url: "https://github.com/jmartin84/WebpackStaticPlug",
14 14 description: "Phoenix Plug to proxy assets served by the webpack dev server",
15 15 package: package(),
16 - docs: [main: "WebpackStatic.Plug",
17 - extras: ["README.md"]]
16 + docs: [main: "WebpackStatic.Plug", extras: ["README.md"]],
17 + test_coverage: [tool: ExCoveralls],
18 + preferred_cli_env: ["coveralls": :test, "coveralls.detail": :test, "coveralls.post": :test, "coveralls.html": :test]
18 19 ]
19 20 end
20 21
  @@ -39,8 +40,11 @@ defmodule WebpackStatic.MixProject do
39 40 {:httpotion, "~> 3.1.0"},
40 41 {:poison, "~> 3.1"},
41 42 {:plug, "~> 1.0"},
43 + {:dialyzex, "~> 1.1.0", only: :dev},
42 44 {:credo, "~> 0.9.1", only: [:dev, :test], runtime: false},
43 - {:ex_doc, "~> 0.16", only: :dev, runtime: false}
45 + {:bypass, "~> 0.8", only: :test},
46 + {:ex_doc, "~> 0.16", only: :dev, runtime: false},
47 + {:excoveralls, "~> 0.8", only: :test}
44 48 # {:dep_from_hexpm, "~> 0.3.0"},
45 49 # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"},
46 50 ]