Grails layoutResources equivalente para asset-Pipeline
asset pipeline grails 3 (4)
Estoy intentando configurar un diseño de SiteMesh en grids v2.3.1 utilizando el plug-in de la tubería de activos (v1.0.4), pero no estoy seguro de cómo manejar la inclusión de los recursos de javascript en una ubicación específica de mi plantilla (como lo haría usando r: layoutResources si usa el plugin de recursos ).
Diseño de ejemplo (grails-app / views / layouts / test.gsp):
<html>
<head>
<title><g:layoutTitle/></title>
<g:layoutHead/>
</head>
<body>
<div class="thecontent">
<g:layoutBody/>
</div>
<asset:javascript src="application.js"/>
<!-- WANT DECORATED PAGE RESOURCES TO BE INCLUDED HERE -->
</body>
</html>
Ejemplo gsp (grails-app / views / test.gsp):
<html>
<head>
<meta name="layout" content="test"/>
<title>The Title</title>
<asset:stylesheet src="thispageonly.css"/>
</head>
<body>
<div id="helloworld">
Hello World
</div>
<asset:javascript src="thispageonly.js"/>
</body>
</html>
La página decorada resultante (haciendo caso omiso de bundling de activos / tuberías / etc) funciona para stylesheet (ya que está en cabeza) pero falla para javascript:
<html>
<head>
<meta name="layout" content="test"/>
<title>The Title</title>
<link rel="stylesheet" href="/assets/thispageonly.css?compile=false"/>
</head>
<body>
<div class="thecontent">
<div id="helloworld">
Hello World
</div>
<!-- *** NOT WHERE I WANT THIS *** -->
<script src="/assets/thispageonly.js?compile=false" type="text/javascript"></script>
</div>
<script src="/assets/application.js?compile=false" type="text/javascript"></script>
</body>
</html>
Actualmente, la única forma en que puedo hacer que esto funcione es usar g: applyLayout yg: pageProperty:
<!-- grails-app/views/layouts/test2.gsp -->
<html>
<head>
<title><g:layoutTitle/></title>
<g:layoutHead/>
</head>
<body>
<div class="thecontent">
<g:layoutBody/>
</div>
<asset:javascript src="application.js"/>
<g:pageProperty name="page.javascript"/>
</body>
</html>
<!-- grails-app/views/test2.gsp -->
<g:applyLayout name="test2">
<html>
<head>
<title>The Title</title>
<asset:stylesheet src="thispageonly.css"/>
</head>
<body>
<div id="helloworld">
Hello World
</div>
<content tag="javascript">
<asset:javascript src="thispageonly.js"/>
</content>
</body>
</html>
</g:applyLayout>
Pero esta desviación de la metaetiqueta parece demasiado complicada (además, no estoy seguro de si la documentación mal documentada de g: pageProperty será compatible como está en futuras actualizaciones). ¿Cuál es la mejor manera a largo plazo de hacer esto?
El uso de sitemesh para controlar la colocación de objetos es totalmente un caso de uso válido. Sitemesh no va a ningún lado y realmente lo uso para controlar el contenedor secundario y la herencia de diseño. No tenía sentido duplicar este control de flujo integrado en el complemento de la tubería de activos.
Otro truco que es bastante útil es usar las <g:layoutHead/>
y <g:layoutBody/>
, que también son bastante útiles.
Si esto demuestra ser un problema, en el futuro, podemos considerar proporcionar un modo que tenga este comportamiento. Déjame saber cómo van las cosas con asset-Pipeline y si surgen problemas como este, no dudes en abrir un ticket en github. Aparentemente, también tengo que vigilar el desbordamiento de la pila :)
IGNORE ESTA RESPUESTA, vea el comentario a continuación del creador de la asset-pipeline
sobre cómo esto ya existe en el complemento de la tubería de <asset:script>
como <asset:script>
.
ANTIGUA RESPUESTA:
Sitemesh me duele la cabeza y, por lo que puedo decir, la solución que usa las etiquetas g:layoutHead
y g:layoutBody
no es algo que le permita recopilar varios fragmentos de JavaScript diferentes y emitirlos en un solo bloque.
La aplicación en la que recientemente comencé a trabajar apalancaba bastante la etiqueta r:script
, y la usaba varias veces en una sola página gsp (en varias plantillas incluidas).
Cómo planeo resolver esto en mi aplicación es con un taglib que hace más o menos lo que hizo la etiqueta r:script
. Reúna cualquier fragmento de javascript diferido y emítelo donde el usuario pida que se emita.
Aquí hay un taglib de muestra que puede hacer esto:
class DeferTagLib {
static namespace = ''defer''
static defaultEncodeAs = [emitScript: ''raw''] // we actually want to inject javascript :)
private static JAVASCRIPT_DEFER_PROPERTY = "__defer__javascript"
protected String removeJavascript() {
try {
return getJavascript()
} finally {
getRequest().removeAttribute(JAVASCRIPT_DEFER_PROPERTY)
}
}
protected String getJavascript() {
return getRequest().getAttribute(JAVASCRIPT_DEFER_PROPERTY)
}
protected void appendJavascript(String javascript) {
String currentValue = getJavascript() ?: ""
getRequest().setAttribute(JAVASCRIPT_DEFER_PROPERTY, currentValue + javascript)
}
// For gathering script tags in your gsp files and emitting them in the footer of the layout
// A replacement for the r:script tag that came with Resources, but is not in the asset-pipeline plugin
def script = { attrs, body ->
appendJavascript(body())
}
// Used in the layout to emit all the script that has been deferred so far in the footer of the page
// A replacement for the <r:layoutResources/> tag that emitted javascript in the footer
// (the 2nd time it was called, kind of confusing...)
def emitScript = { attrs ->
out << "<script>${removeJavascript()}</script>"
}
}
Luego, en mis páginas / fragmentos gsp, puedo reemplazar cualquier llamada anterior a r:script
con defer:script
:
<defer:script>
// this is before
</defer:script>
... maybe another template that''s included ...
<defer:script>
alert("foo!");
</defer:script>
... later
<defer:script>
// after
</defer:script>
Y en mi diseño, en la parte inferior puedo hacer esto
<html>
<head>
.... shared head stuff ....
<g:layoutHead/>
</head>
<body>
.... body stuff before layout
<g:layoutBody/>
.... other body stuff after layout
<defer:emitScript/>
</body>
</html>
Eso terminará creando una sección después de que el cuerpo se vea como
... the actual body from the gsp
<script>
// this is before ...
alert("foo!");
// after
</script>
</body>
</html>
FYI: Esto funciona bien para mí, aunque es un poco feo.
<!-- grails-app/views/layouts/test2.gsp -->
<html>
<head>
<title><g:layoutTitle/></title>
<g:layoutHead/>
</head>
<body>
<div class="thecontent">
<g:layoutBody/>
</div>
<asset:javascript src="application.js"/>
<asset:deferredScripts/>
</body>
</html>
<!-- grails-app/views/test2.gsp -->
<g:applyLayout name="test2">
<html>
<head>
<title>The Title</title>
<asset:stylesheet src="thispageonly.css"/>
</head>
<body>
<div id="helloworld">
Hello World
</div>
<asset:script src="${assetPath(src: ''thispageonly.js'')}" type="text/javascript" />
</body>
</html>
</g:applyLayout>
No estoy seguro acerca de su requerimiento En mi proyecto, necesitaba mover todos los archivos de JavaScript a pie de página. Moví la etiqueta de "recursos de diseño" de Encabezado a pie de página y funcionó bien.
<footer class="clear">
<r:layoutResources>
</footer>