在config.exs
或dev.exs/prod.exs/test.exs
中使用第三方模块时,似乎加载和编译凤凰中的配置文件的方式存在问题。
示例:要为JWT身份验证设置Guardian,我尝试在config.exs
中使用JOSE.JWK
模块进行JWK创建/加载。我可以使用iex -S mix phoenix.server
在控制台中使用该模块。它当然是作为依赖项安装的。我得到的错误是
** (Mix.Config.LoadError) could not load config config/config.exs
** (UndefinedFunctionError) undefined function JOSE.JWK.from_file/2 (module JOSE.JWK is not available)
这是我的config.exs
中的代码# Configure Guardian for JWT Authentication
config :guardian, Guardian,
allowed_algos: ["HS512"], # optional
verify_module: Guardian.JWT, # optional
issuer: "MyApp",
ttl: { 30, :days },
verify_issuer: true, # optional
secret_key: System.get_env("GUARDIAN_KEY_PASSPHRASE") |> JOSE.JWK.from_file(System.get_env("GUARDIAN_KEY_FILE")),
serializer: MyApp.GuardianSerializer
当我在匿名函数中包含对JOSE.JWK.from_file/2
的调用时,它会起作用。但是当然Guardian.config(:secret_key)的值是匿名函数本身而不是它的返回值:
# Configure Guardian for JWT Authentication
config :guardian, Guardian,
allowed_algos: ["HS512"], # optional
verify_module: Guardian.JWT, # optional
issuer: "MyApp",
ttl: { 30, :days },
verify_issuer: true, # optional
secret_key: fn -> System.get_env("GUARDIAN_KEY_PASSPHRASE") |> JOSE.JWK.from_file(System.get_env("GUARDIAN_KEY_FILE")) end,
serializer: MyApp.GuardianSerializer
这个例子没问题,因为Guardian接受了这个配置值的函数。但我可以想象这可能是一个问题的其他情况。
这是有目的的限制吗?我错过了什么吗?有办法解决这个问题吗?
答案 0 :(得分:17)
由于在编译依赖项之前评估了配置,因此无法使用配置中依赖项的代码。
原因很简单:配置可能会改变编译依赖项的方式。您需要先决定要做什么 - 编译以评估配置。已经决定首先评估配置,因为通过配置操作编译比使用依赖关系配置其他应用程序更有用(和频繁) - 最常见的配置只是原始数据。
答案 1 :(得分:2)
如果您在运行mix之前首先编译一个位于elixirc_paths
之外的模块,并且它在elixir搜索路径中,它会找到它。只需Whatever.foo(:bar)
将预编译作为混合任务包装起来会更有意义,并且在调用第三方dep之前调用mix以确保config deps是最新的。
如果在评估config之前有预配置混合挂钩和/或config/lib
预编译,那将会很有帮助。否则,即使使用import_config
并且不允许模块化和干掉代码,配置也会增长并变成令人厌恶的代码堆。
另一个问题是,有一个最小的混合任务,只需加载你的应用程序就可以获取值并将它们写入stdout,然后使用一个端口将它们带到其他地方(Rails在这些地方执行此操作)。
答案 2 :(得分:0)
事实证明,使用档案可以使用Mix执行此操作。
它们需要手动安装,但可以使用单独的Mix项目mix archive.build
轻松构建。
它们的局限性在于归档项目不能拥有自己的依赖项。
有关详细信息,请参阅文档。 https://hexdocs.pm/mix/Mix.Tasks.Archive.Build.html#content