Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Module dependency not detected a compile time #10037

Closed
kipcole9 opened this issue May 15, 2020 · 5 comments
Closed

Module dependency not detected a compile time #10037

kipcole9 opened this issue May 15, 2020 · 5 comments

Comments

@kipcole9
Copy link
Contributor

kipcole9 commented May 15, 2020

I'm not certain if this is a bug or working as expected. If the latter then my apologies for the report.

Environment

  • Elixir 1.10.3 and master, erlang 22.3.3
  • Operating system: macOS Catalina

Current behavior

A module referenced in a Plug configuration is not compiled at compile time in :test. In this test repo, the following error occurs

Code example

defmodule DemoWeb.Router do
  use DemoWeb, :router

  pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_flash
    plug :protect_from_forgery
    plug :put_secure_browser_headers
  end

  pipeline :api do
    plug :accepts, ["json"]
  end

  pipeline :localized do
    plug Cldr.Plug.SetLocale,
      apps: [:cldr, :gettext],
      cldr: Demo.Cldr,  # <-- Error occurs because this module is not compiled when the plug definition is compiled in prod and test
      from: [:query, :accept_language]
  end
  ...

Reproduce the error

% MIX_ENV=test mix compile
...
==> ex_cldr_units
Compiling 8 files (.ex)
Generated ex_cldr_units app
==> demo
Compiling 16 files (.ex)

== Compilation error in file lib/demo_web/router.ex ==
** (Cldr.UnknownBackendError) The backend Demo.Cldr is not known or not a backend module.
    (ex_cldr 2.14.0) lib/cldr/plug/plug_set_locale.ex:426: Cldr.Plug.SetLocale.validate_cldr/2
    (ex_cldr 2.14.0) lib/cldr/plug/plug_set_locale.ex:119: Cldr.Plug.SetLocale.init/1
...

The error does not occur in :dev mode, presumably because Plug.init/1 is called at runtime where as in :prod and :test its called at compile time.

Workaround

requireing the module forces compilation order.

defmodule DemoWeb.Router do
  use DemoWeb, :router
  require Demo.Cldr  # <---- requiring the module forces compilation order
  ...
end
% MIX_ENV=test mix compile
Compiling 16 files (.ex)

16:56:00.929 [info]  Downloaded locale "de"
Generating Demo.Cldr for 4 locales named ["de", "en", "en-001", "root"] with a default locale named "de"
Generated demo app

Expected behavior

The compiler detects the module dependency and compiles it.

@wojtekmach
Copy link
Member

I wonder if it's because config :phoenix, :plug_init_mode, :runtime (https://github.com/syfgkjasdkn/cldr-demo/blob/master/config/dev.exs#L59)

@kipcole9
Copy link
Contributor Author

I just updated the notes to reflect it works fine in :dev, its in :test that this occurs (and probably in :prod) due to the different runtime versus compile time execution of Plug.init/1 as you note.

@josevalim
Copy link
Member

josevalim commented May 15, 2020 via email

@kipcole9
Copy link
Contributor Author

kipcole9 commented May 15, 2020

José, you are right, I'm only calling Code.ensure_loaded/1. No problem at all to change to Code.ensure_compiled/2 if you think thats appropriate (I try to avoid it given that suggestion in the docs). But given the compile-time behaviour it makes sense.

FWIW here's the current code:

    defp validate_app_and_scope!(app, module) when not is_nil(app) and is_atom(module) do
      cond do
        app in @app_options && Code.ensure_loaded?(module) ->
          :ok

        app in @app_options ->
          raise ArgumentError, "Backend module #{inspect(module)} is unavailable"

        true ->
          raise ArgumentError, "App #{inspect(app)} is unknown"
      end
    end

@josevalim
Copy link
Member

You do want to avoid it but given you are trying to verify it at compile-time, then at least on this case you shouldn't. Closing this for now but feel free to follow up if you have questions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

3 participants