Assets not loading when deploying to Heroku

Hi there! I have deployed this (after forking) to Heroku, but for some reason, none of the assets are loading. I’m fairly new to the language and I have a feeling that maybe some environmental variable might be misconfigured or something?

The front page loads perfectly fine, but not as intended. I went to check the developer tools and realized that it was doing a GET call from localhost, which I don’t believe is right?

GET http://localhost:43751/css/app-b358ab485f4965187a0366829058b5e7.css?vsn=d net::ERR_CONNECTION_REFUSED

GET http://localhost:43751/js/app-47ffdb6029e02e02cf2f5c4f4e2c7e4e.js?vsn=d net::ERR_CONNECTION_REFUSED

localhost:43751/images/til-logo-144x144-866373717b4dc8f05b886baaf7abae3b.png?vsn=d:1 

GET http://localhost:43751/images/til-logo-144x144-866373717b4dc8f05b886baaf7abae3b.png?vsn=d net::ERR_CONNECTION_REFUSED

Error while trying to use the following icon from the Manifest: http://localhost:43751/images/til-logo-144x144-866373717b4dc8f05b886baaf7abae3b.png?vsn=d (Download error or resource isn't a valid image)

Not sure if the config needs to be changed here: tilex/config.exs at master · hashrocket/tilex · GitHub since this is where I find localhost only existing or if it needs to be added to the Heroku config vars, but I have inputted in the SECRET_KEY_BASE on Heroku.

The dyno is using: web MIX_ENV=prod mix phx.server and made sure it’s pointing to my app.
Sorry if I’m not providing all the information needed, so please let me know if I’m missing something.

Hey there!

Just a quick note: Usually people prefer building a Release first and deploying that instead of installing Elixir and mix and then using mix phx.server. Check out the docs on Releases here:

To address your immediate issue, did you make sure to a) install and build your assets (npm run deploy --prefix ./assets) and b) compile your assets with mix phx.digest?

I also recommend you take a look at the Deployment Guide from Phoenix:
https://hexdocs.pm/phoenix/deployment.html

In case the issue is actually related to the generation of absolute URLs: You might have to change the URL configuration from

config :tilex, TilexWeb.Endpoint,
  url: [host: "localhost"],

to something like

config :tilex, TilexWeb.Endpoint,
  url: [host: "example.com", scheme: :https],

(see Phoenix.Endpoint — Phoenix v1.5.7)

1 Like

Thanks for a quick response! I’ll definitely check out the docs you mentioned and I guess I just got too hasty with deploying :sweat_smile:

To address your immediate issue, did you make sure to a) install and build your assets (npm run deploy --prefix ./assets ) and b) compile your assets with mix phx.digest ?

I went and a heroku run on it and refreshed the page and the end result was still the same. I also changed localhost to point to the Heroku project as well to no avail. What I’ve noticed comparing my app to original project is that (checking the Sources via developer tools here) the scripts load (e.g. analytics.js, app.js, etc.) but my project doesn’t contain that. The main thing I see under sources are just an index file that’s still somehow referencing localhost and a manifest.json file.

The prod config expects to find the host’s name in a HOST environment variable, are you setting that in your Heroku config?

Yep! I’ve replaced HOST with my Heroku app url. The issue is just that none of html/css files load properly

What buildpack are you using (and what version of it)? It sounds like you might be missing https://github.com/gjaldon/heroku-buildpack-phoenix-static which is usually used in addition to GitHub - HashNuke/heroku-buildpack-elixir: Heroku Buildpack for Elixir with nitro boost

I’m not entirely sure what versions they are specifically, but from here tilex/app.json at master · hashrocket/tilex · GitHub I had copy-pasted those to URLs to Heroku buildpack config so I assume that’s right?

Just for note, this is the Heroku app I’m trying to work with: https://stoiven-til.herokuapp.com/

Hmm, the assets such as the CSS are loading fine for me and if you are using those buildpacks should be good. This is what I see on that site:

Yea! I ended up getting it working this morning so what timing hah.

I had to add the URL under here

static_url =
  System.get_env("EDGE_URL")
  |> Kernel.||(System.get_env("HOST"))
  |> Kernel.||("https://stoiven-til.herokuapp.com")
  |> URI.parse()
  |> Map.from_struct()

Which I’m not entirely sure why yet. On the other hand, still running into another issue (well I guess this is different from the main issue, so maybe might need to make another post?)

The permalink and raw buttons don’t work for posts. One leads to an error page and the other leads to a crashed site (spouting HTTP ERROR 500), respectively. Not sure why the edit works fine tho (as an admin) and as well as the channel.

I’m looking at the heroku logs and getting this when hitting permalink:

Request: GET /posts/zdugo1ftmi-using-tail-to-capture-logs
2021-02-22T21:25:04.573534+00:00 app[web.1]: ** (exit) an exception was raised:
2021-02-22T21:25:04.573535+00:00 app[web.1]: ** (FunctionClauseError) no function clause matching in URI.parse/1
2021-02-22T21:25:04.573535+00:00 app[web.1]: (elixir) lib/uri.ex:451: URI.parse(nil)
2021-02-22T21:25:04.573536+00:00 app[web.1]: (elixir) lib/uri.ex:577: URI.merge/2
2021-02-22T21:25:04.573537+00:00 app[web.1]: (tilex) lib/tilex_web/controllers/post_controller.ex:216: TilexWeb.PostController.assign_post_canonical_url/2
2021-02-22T21:25:04.573537+00:00 app[web.1]: (tilex) lib/tilex_web/controllers/post_controller.ex:59: TilexWeb.PostController.show/2
2021-02-22T21:25:04.573538+00:00 app[web.1]: (tilex) lib/tilex_web/controllers/post_controller.ex:1: TilexWeb.PostController.action/2
2021-02-22T21:25:04.573538+00:00 app[web.1]: (tilex) lib/tilex_web/controllers/post_controller.ex:1: TilexWeb.PostController.phoenix_controller_pipeline/2
2021-02-22T21:25:04.573539+00:00 app[web.1]: (tilex) lib/tilex_web/endpoint.ex:1: TilexWeb.Endpoint.instrument/4
2021-02-22T21:25:04.573539+00:00 app[web.1]: (phoenix) lib/phoenix/router.ex:288: Phoenix.Router.__call__/2
2021-02-22T21:25:04.884880+00:00 app[web.1]: 21:25:04.878 request_id=dd3a8e3d-beaa-4920-9a6c-525897c84940 [info] GET /phoenix/live_reload/frame
2021-02-22T21:25:04.885634+00:00 app[web.1]: 21:25:04.878 request_id=dd3a8e3d-beaa-4920-9a6c-525897c84940 [info] Sent 404 in 164µs

And this for raw

2021-02-22T21:26:24.976988+00:00 app[web.1]: Server: stoiven-til.herokuapp.com:80 (http)
2021-02-22T21:26:24.976989+00:00 app[web.1]: Request: GET /posts/zdugo1ftmi-using-tail-to-capture-logs.md
2021-02-22T21:26:24.976989+00:00 app[web.1]: ** (exit) an exception was raised:
2021-02-22T21:26:24.976990+00:00 app[web.1]: ** (FunctionClauseError) no function clause matching in Plug.Conn.resp/3

I did mix phx.routes and it seems like everything is put in place? Not sure why it’s not working.

developer_post_path  GET     /api/developer_posts.json              TilexWeb.Api.DeveloperPostController :index
          feed_path  GET     /rss                                   TilexWeb.FeedController :index
         pixel_path  GET     /pixel                                 TilexWeb.PixelController :index
          post_path  POST    /posts/:slug/like.json                 TilexWeb.PostController :like
          post_path  POST    /posts/:slug/unlike.json               TilexWeb.PostController :unlike
          auth_path  GET     /admin                                 TilexWeb.AuthController :index
          auth_path  DELETE  /auth/logout                           TilexWeb.AuthController :delete
          auth_path  GET     /auth/:provider                        TilexWeb.AuthController :request
          auth_path  GET     /auth/:provider/callback               TilexWeb.AuthController :callback
          auth_path  POST    /auth/:provider/callback               TilexWeb.AuthController :callback
         stats_path  GET     /statistics                            TilexWeb.StatsController :index
         stats_path  GET     /developer/statistics                  TilexWeb.StatsController :developer
       sitemap_path  GET     /sitemap.xml                           TilexWeb.SitemapController :index
  web_manifest_path  GET     /manifest.json                         TilexWeb.WebManifestController :index
          post_path  GET     /random                                TilexWeb.PostController :random
     developer_path  GET     /authors/:name                         TilexWeb.DeveloperController :show
     developer_path  GET     /profile/edit                          TilexWeb.DeveloperController :edit
     developer_path  PUT     /profile/edit                          TilexWeb.DeveloperController :update
          post_path  GET     /                                      TilexWeb.PostController :index
          post_path  GET     /posts                                 TilexWeb.PostController :index
          post_path  GET     /posts/:titled_slug/edit               TilexWeb.PostController :edit
          post_path  GET     /posts/new                             TilexWeb.PostController :new
          post_path  GET     /posts/:titled_slug                    TilexWeb.PostController :show
          post_path  POST    /posts                                 TilexWeb.PostController :create
          post_path  PATCH   /posts/:titled_slug                    TilexWeb.PostController :update
                     PUT     /posts/:titled_slug                    TilexWeb.PostController :update
          post_path  DELETE  /posts/:titled_slug                    TilexWeb.PostController :delete
       channel_path  GET     /:name                                 TilexWeb.ChannelController :show
          websocket  WS      /socket/websocket                      TilexWeb.UserSocket
           longpoll  GET     /socket/longpoll                       TilexWeb.UserSocket
           longpoll  POST    /socket/longpoll                       TilexWeb.UserSocket

Generally I would probably write this something more like:

base = System.get_env("EDGE_URL") || System.get_env("HOST") || "https://stoiven-til.herokuapp.com"
static_url =
  URI.parse(base)
  |> Map.from_struct()

But calling Map.from_struct on a %URI{} seems highly atypical. Usually I would call to_string on the %URI{} to get out a plan URL (e.g. "https://stoiven-til.herokuapp.com"), but if you wanted that in this case you would not even need URI.parse unless you’re using it for validation. Can you show how you’re using static_url?

For the other issues I think you should post a new topic, and make sure to include the implementation of the controllers (along with the exceptions).

1 Like

The error here appears to be a missing canonical_domain:

which is set in config/config.exs:

This suggests to me that HOST is not set correctly in the environment.

2 Likes

Well what did ya know…I should def be reading more :sweat_smile:. I appreciate the help! I got it up and running now!

1 Like