Jugar marco 2.2.x:La ubicación de activos estáticos no funciona en producción.
-
21-12-2019 - |
Pregunta
Tener problemas para acceder a la ubicación de los activos compilados en producción.
Mi estrategia ha sido servir mis activos en "app/assets/ui" cuando están en desarrollo y "públicos" cuando están en producción. Esto se hace como se muestra a continuación en mi archivo conf/routes.
#{if(play.Play.mode.isDev())}
GET /assets/*file controllers.common.Assets.at(path="/app/assets/ui", file)
#{/}
#{else}
GET /assets/*file controllers.common.Assets.at(path="/public", file)
#{/}
Como definí asignaciones de activos fuera de "público", agregué la siguiente línea en mi Build.scala
playAssetsDirectories <+= baseDirectory / "app/assets/ui"
Como ejemplo, mis scripts se cargan condicionalmente según el entorno, como se muestra a continuación.
@if(play.Play.isDev()) {<script src="@routes.Assets.at("/app/assets/ui", "javascripts/application.js")"type="text/javascript"></script>} else {<script src="@.routes.Assets.at("/public", "javascripts/application.min.js")" type="text/javascript"></script>}
Estoy usando Grunt para mi flujo de trabajo frontend y cuando la aplicación se compila, copia los archivos de distribución a la carpeta pública de la aplicación.Inicio la aplicación en producción usando "sbt clean compile stage"
y luego ejecute la aplicación empaquetada.
Mi problema parece que las rutas todavía se refieren a la carpeta "app/assets/ui" en lugar de a la carpeta "pública" de distribución.
¿Algún consejo sobre cómo puedo depurar esto?Mi experiencia laboral es como desarrollador front-end, ¡así que soy muy nuevo en Play!y escala.
Solución
Como lo mencionó @estmatic, tu condicional en routes
no será evaluado.
Como generalmente es extremadamente útil consolidar las diferencias entre la aplicación Mode
s en archivos, te sugiero que extiendas GlobalSettings
(si aún no lo has hecho) y anula el onLoadConfig
método:
class Settings extends GlobalSettings {
override def onLoadConfig(config: Configuration, path: File, classloader: ClassLoader, mode: Mode.Mode): Configuration = {
val specificConfig:Config = // ... Use the mode param to load appropriate file
super.onLoadConfig(specificConfig, path, classloader, mode)
}
...
}
Entonces podría tener archivos con el nombre apropiado (dev.conf
y production.conf
me vienen a la mente) que contienen valores adecuados, siendo uno de ellos la base path
para que lo utilice el controlador de activos.
EDITAR resulta que hacerlo de esta manera hace que se use en routes
incómodo, aquí hay otro enfoque:
Este enfoque no utiliza un archivo de configuración por entorno, lo que significa que si algo cambia en la configuración del frontend (p. ej.ya no se sirve desde /public
) tendrás que cambiar este código y volver a implementarlo.Sin embargo, encaja bastante bien en Play 2.x:
package controllers
object EnvironmentSpecificAssets extends AssetsBuilder {
val modeToAssetsPathMap = Map(
Mode.Dev -> "/app/assets/ui",
Mode.Prod -> "/public")
lazy val modePath = modeToAssetsPathMap(Play.current.mode)
/** New single-argument `at`, determines its path from the current app mode */
def at(file:String): Action[AnyContent] = at(modePath, file)
}
El código se explica por sí mismo, el único "truco" es probablemente el lazy val
lo que significa que solo tenemos que evaluar el modo de funcionamiento actual y realizar la búsqueda en el mapa una vez.
Ahora tu routes
el archivo se ve así:
GET /assets/*file controllers.EnvironmentSpecificAssets.at(file)
Otros consejos
Playframework 2.x no admite declaraciones condicionales en el archivo de rutas.Las versiones 1.x tenían esto pero fue eliminado.
Lo que tienes en tu archivo de rutas son simplemente dos rutas con el mismo patrón de URI, /assets/file*
.Las otras líneas simplemente se ignoran como comentarios ya que comienzan con el carácter de almohadilla. #
.Creo que dado que el patrón es el mismo para ambas, la primera ruta capta todo y la segunda no hace nada.
No es exactamente lo que intentas hacer, pero creo que puedes hacer que los patrones de ruta sean un poco diferentes y debería funcionar.
GET /assets/dev/*file controllers.common.Assets.at(path="/app/assets/ui", file)
GET /assets/*file controllers.common.Assets.at(path="/public", file)