Hello there,
I have the following scenario:
I have a library my_lib
that is used in my_app
. my_lib
has a configuration file option that accepts a list of modules. Based on the list of modules provided, a Plug
is generated.
The config in my_app
is defined like this:
config :my_lib,
modules: [MyApp.Plugs.Plug1, MyApp.Plugs.Plug2]
The code in my_lib
looks like this:
modules = Application.get_env(:my_lib, :modules)
for module <- modules do
quote do
forward "/module/#{unquote module}", to: unquote(module)
end
end
This compiles, but a request to /module/Elixir.MyApp.Plugs.Plug1
just yields a 404 error. Interestingly, I also get a warning in VS Code in the for
line, that modules
cannot be iterated since it is nil
, which to my understanding cannot be the case since I defined a default value of []
for it the mix.exs
file of my_lib
(I can also certainly confirm that it is not nil
, since logging it prints the expected value).
def application do
[
mod: {MyLib.Application, []},
env: [modules: []]
]
end
At this point I assumed that I either made an error in my meta-programming or since my_lib
is compiled before my_app
, that its modules are simply not yet available.
According to the documentation Code.ensure_compiled/1
would be a good candidate to wait for the compilation of these modules. So I added a call to this function and printed out its results, which were quite baffling to me:
modules = Application.get_env(:my_lib, :modules)
for module <- modules do
compiled = Code.ensure_compiled(module)
IO.puts("ensure_compiled #{inspect module} -> #{inspect compiled}")
# = ensure_compiled MyApp.Plugs.Plug1 -> {:error, :nofile}
# = ensure_compiled MyApp.Plugs.Plug2 -> {:error, :nofile}
quote do
forward "/module/#{unquote module}", to: unquote(module)
end
end
Apparently these modules do not exist at all. However, calling this function directly in IEx, the call resolves successfully:
iex(1)> Code.ensure_loaded MyApp.Plugs.Plug1
{:module, MyApp.Plugs.Plug1}
If I had to take another guess the module resolution fails since my_lib
is looking for a source file in its own lib
folder and does not take other applications (my_app
) into account.
- Is there any way to use modules of the “parent” app during compilation? If so, how would I go about that?
- What did I do wrong that Plug did not throw an error or return a 500, but just silently ignore my module (well, or just works for that matter )?
- Did I set the default config value incorrectly? It seems to work when executing, but since VS Code (using the elixir-ls extension) complains about it, I guess there must be something not quite right with it.
Thank you for your time! I realize that this is quite the wall of text