Current section
3 Versions
Jump to
Current section
3 Versions
Compare versions
4
files changed
+63
additions
-27
deletions
| @@ -1,4 +1,6 @@ | |
| 1 1 | # WebpackStatic |
| 2 | + [](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 | ] |