Ruta de los activos en archivos CSS en Symfony 2

101

Problema

Tengo un archivo CSS con algunas rutas (para imágenes, fuentes, etc. url(..)).

Mi estructura de ruta es así:

...
+-src/
| +-MyCompany/
|   +-MyBundle/
|     +-Resources/
|       +-assets/
|         +-css/
|           +-stylesheets...
+-web/
| +-images/
|   +-images...
...

Quiero hacer referencia a mis imágenes en la hoja de estilo.

Primera solucion

Cambié todas las rutas en el archivo CSS a rutas absolutas. Esto no es una solución, ya que la aplicación también debería (¡y tiene que hacerlo!) Estar trabajando en un subdirectorio.

Segunda solución

Utilice Assetic con filter="cssrewrite".

Así que cambié todas mis rutas en mi archivo CSS a

url("../../../../../../web/images/myimage.png")

para representar la ruta real desde mi directorio de recursos al /web/imagesdirectorio. Esto no funciona, ya que cssrewrite produce el siguiente código:

url("../../Resources/assets/")

que obviamente es el camino equivocado.

Después de assetic:dumpcrear esta ruta, que sigue siendo incorrecta:

url("../../../web/images/myimage.png")

El código de ramita de Assetic:

{% stylesheets
    '@MyCompanyMyBundle/Resources/assets/css/*.css'
    filter="cssrewrite"
%}
<link rel="stylesheet" href="{{ asset_url }}" />
{% endstylesheets %}

Solución actual (tercera)

Dado que todos los archivos CSS terminan /web/css/stylexyz.css, cambié todas las rutas en el archivo CSS para que sean relativas:

url("../images/myimage.png")

Esta (mala) solución funciona, excepto en el deventorno: la ruta CSS es /app_dev.php/css/stylexyz.cssy, por lo tanto, la ruta de la imagen resultante de esto es /app_dev.php/images/myimage.png, lo que da como resultado un NotFoundHttpException.

¿Existe una solución mejor y que funcione?

apfelbox
fuente
1
Publiqué
¿Esto realmente resuelve el problema con las rutas al usarlo app_dev.php?
apfelbox

Respuestas:

194

Me he encontrado con el mismo problema.

En breve:

  • Dispuesto a tener CSS original en un directorio "interno" (Resources / assets / css / a.css)
  • Dispuesto a tener las imágenes en el directorio "público" (Resources / public / images / devil.png)
  • Deseando que la ramita tome ese CSS, lo recompila en web / css / a.css y haz que apunte la imagen en /web/bundles/mynicebundle/images/devil.png

He hecho una prueba con TODAS las combinaciones posibles (sensatas) de lo siguiente:

  • @notation, notación relativa
  • Analizar con cssrewrite, sin él
  • Fondo de imagen CSS vs etiqueta <img> directa src = a la misma imagen que CSS
  • CSS analizado con assetic y también sin analizar con salida directa assetic
  • Y todo esto multiplicado probando un "directorio público" (as Resources/public/css) con el CSS y un directorio "privado" (as Resources/assets/css).

Esto me dio un total de 14 combinaciones en la misma ramita, y esta ruta se lanzó desde

  • "/app_dev.php/"
  • "/app.php/"
  • y "/"

dando así 14 x 3 = 42 pruebas.

Además, todo esto ha sido probado trabajando en un subdirectorio, por lo que no hay forma de engañar al dar URL absolutas porque simplemente no funcionarían.

Las pruebas fueron dos imágenes sin nombre y luego divs nombrados de 'a' a 'f' para el CSS construido DESDE la carpeta pública y nombrados 'g a' l 'para los construidos a partir de la ruta interna.

Observé lo siguiente:

Solo 3 de las 14 pruebas se mostraron adecuadamente en las tres URL. Y NINGUNO era de la carpeta "interna" (Recursos / activos). Era un requisito previo tener el CSS PUBLIC de repuesto y luego compilar con assetic FROM allí.

Estos son los resultados:

  1. Resultado lanzado con /app_dev.php/ Resultado lanzado con /app_dev.php/

  2. Resultado lanzado con /app.php/ Resultado lanzado con /app.php/

  3. Resultado lanzado con / ingrese la descripción de la imagen aquí

Entonces ... SOLAMENTE - La segunda imagen - Div B - Div C son las sintaxis permitidas.

Aquí está el código TWIG:

<html>
    <head>
            {% stylesheets 'bundles/commondirty/css_original/container.css' filter="cssrewrite" %}
                <link href="{{ asset_url }}" rel="stylesheet" type="text/css" />
            {% endstylesheets %}

    {# First Row: ABCDEF #}

            <link href="{{ '../bundles/commondirty/css_original/a.css' }}" rel="stylesheet" type="text/css" />
            <link href="{{ asset( 'bundles/commondirty/css_original/b.css' ) }}" rel="stylesheet" type="text/css" />

            {% stylesheets 'bundles/commondirty/css_original/c.css' filter="cssrewrite" %}
                <link href="{{ asset_url }}" rel="stylesheet" type="text/css" />
            {% endstylesheets %}

            {% stylesheets 'bundles/commondirty/css_original/d.css' %}
                <link href="{{ asset_url }}" rel="stylesheet" type="text/css" />
            {% endstylesheets %}

            {% stylesheets '@CommonDirtyBundle/Resources/public/css_original/e.css' filter="cssrewrite" %}
                <link href="{{ asset_url }}" rel="stylesheet" type="text/css" />
            {% endstylesheets %}

            {% stylesheets '@CommonDirtyBundle/Resources/public/css_original/f.css' %}
                <link href="{{ asset_url }}" rel="stylesheet" type="text/css" />
            {% endstylesheets %}

    {# First Row: GHIJKL #}

            <link href="{{ '../../src/Common/DirtyBundle/Resources/assets/css/g.css' }}" rel="stylesheet" type="text/css" />
            <link href="{{ asset( '../src/Common/DirtyBundle/Resources/assets/css/h.css' ) }}" rel="stylesheet" type="text/css" />

            {% stylesheets '../src/Common/DirtyBundle/Resources/assets/css/i.css' filter="cssrewrite" %}
                <link href="{{ asset_url }}" rel="stylesheet" type="text/css" />
            {% endstylesheets %}

            {% stylesheets '../src/Common/DirtyBundle/Resources/assets/css/j.css' %}
                <link href="{{ asset_url }}" rel="stylesheet" type="text/css" />
            {% endstylesheets %}

            {% stylesheets '@CommonDirtyBundle/Resources/assets/css/k.css' filter="cssrewrite" %}
                <link href="{{ asset_url }}" rel="stylesheet" type="text/css" />
            {% endstylesheets %}

            {% stylesheets '@CommonDirtyBundle/Resources/assets/css/l.css' %}
                <link href="{{ asset_url }}" rel="stylesheet" type="text/css" />
            {% endstylesheets %}

    </head>
    <body>
        <div class="container">
            <p>
                <img alt="Devil" src="../bundles/commondirty/images/devil.png">
                <img alt="Devil" src="{{ asset('bundles/commondirty/images/devil.png') }}">
            </p>
            <p>
                <div class="a">
                    A
                </div>
                <div class="b">
                    B
                </div>
                <div class="c">
                    C
                </div>
                <div class="d">
                    D
                </div>
                <div class="e">
                    E
                </div>
                <div class="f">
                    F
                </div>
            </p>
            <p>
                <div class="g">
                    G
                </div>
                <div class="h">
                    H
                </div>
                <div class="i">
                    I
                </div>
                <div class="j">
                    J
                </div>
                <div class="k">
                    K
                </div>
                <div class="l">
                    L
                </div>
            </p>
        </div>
    </body>
</html>

El container.css:

div.container
{
    border: 1px solid red;
    padding: 0px;
}

div.container img, div.container div 
{
    border: 1px solid green;
    padding: 5px;
    margin: 5px;
    width: 64px;
    height: 64px;
    display: inline-block;
    vertical-align: top;
}

Y a.css, b.css, c.css, etc: todos idénticos, solo cambiando el color y el selector de CSS.

.a
{
    background: red url('../images/devil.png');
}

La estructura de "directorios" es:

Directorios Directorios

Todo esto vino, porque no quería que los archivos originales individuales se expusieran al público, especialmente si quería jugar con el filtro "menos" o "sass" o similar ... No quería que se publicaran mis "originales", solo los compilado uno.

Pero hay buenas noticias . Si no desea tener el "CSS de repuesto" en los directorios públicos ... no lo instale con --symlink, sino haciendo una copia. Una vez que "assetic" ha creado el CSS compuesto, puede BORRAR el CSS original del sistema de archivos y dejar las imágenes:

Proceso de compilación Proceso de compilación

Tenga en cuenta que hago esto por el --env=prodmedio ambiente.

Solo algunos pensamientos finales:

  • Este comportamiento deseado se puede lograr teniendo las imágenes en el directorio "público" en Git o Mercurial y el "css" en el directorio "activos". Es decir, en lugar de tenerlos en "público" como se muestra en los directorios, imagina a, b, c ... residiendo en los "activos" en lugar de "público", que tu instalador / implementador (probablemente un script Bash ) para poner el CSS temporalmente dentro del directorio "público" antes de que assets:installse ejecute, luego assets:install, luego assetic:dump, y luego automatizar la eliminación de CSS del directorio público después de que assetic:dumpse haya ejecutado. Esto lograría EXACTAMENTE el comportamiento deseado en la pregunta.

  • Otra solución (desconocida si es posible) sería explorar si "assets: install" solo puede tomar "public" como fuente o también podría tomar "assets" como fuente para publicar. Eso ayudaría cuando se instala con la --symlinkopción al desarrollar.

  • Además, si vamos a realizar un script para eliminarlos del directorio "público", entonces, desaparece la necesidad de almacenarlos en un directorio separado ("activos"). Pueden vivir dentro de "público" en nuestro sistema de control de versiones, ya que se eliminarán cuando se implementen al público. Esto también permite el --symlinkuso.

PERO DE TODOS MODOS, PRECAUCIÓN AHORA: Como ahora los originales ya no están allí ( rm -Rf), solo hay dos soluciones, no tres. El div activo "B" ya no funciona ya que era una llamada de activo () asumiendo que existía el activo original. Sólo funcionará "C" (el compilado).

Entonces ... SOLO HAY UN GANADOR FINAL: Div "C" permite EXACTAMENTE lo que se pidió en el tema: Para ser compilado, respetar el camino a las imágenes y no exponer la fuente original al público.

El ganador es C

El ganador es C

Xavi Montero
fuente
3
Enlaces a las imágenes de la publicación anterior: 1) Resultado lanzado con /app_dev.php/ , 2) Resultado lanzado con /app.php/ link , 3) resultado lanzado con / link , 4) Enlace de directorios , 5) Enlace de proceso de compilación , 6) ¿Quién es el enlace
Xavi Montero
1
Y si desea agregar una imagen de otro paquete, en lugar de usar, background-image: url('../images/devil.png');use estobackground-image: url('../../../bundles/frontendlayout/images/devil.png');
Xavi Montero
1
También funciona combinando "cssrewrite" con "menos":{% stylesheets filter="cssrewrite,less" "bundles/frontendlayout/less/layout.less" %} <link href="{{ asset_url }}" rel="stylesheet" type="text/css" /> {% endstylesheets %}
Xavi Montero
1
Esto se indica en la documentación de Symfony. Ver aquí
Noah Duncan
17

El filtro cssrewrite no es compatible con la notación @bundle por ahora. Entonces tienes dos opciones:

  • Referencia a los archivos CSS en la carpeta web (después: console assets:install --symlink web)

    {% stylesheets '/bundles/myCompany/css/*." filter="cssrewrite" %}
  • Utilice el filtro cssembed para incrustar imágenes en el CSS de esta manera.

    {% stylesheets '@MyCompanyMyBundle/Resources/assets/css/*.css' filter="cssembed" %}
Jeremymarc
fuente
Gracias por tu comentario. La segunda solución suena bastante bien si solo tiene imágenes bastante pequeñas. Sin embargo, no me sentiría cómodo poniendo más de 100k imágenes en el archivo CSS.
apfelbox
9

Publicaré lo que me funcionó, gracias a @ xavi-montero.

Pon tu CSS en el Resource/public/cssdirectorio de tu paquete y tus imágenes en digamos Resource/public/img.

Cambie las rutas aséticas al formulario 'bundles/mybundle/css/*.css', en su diseño.

En config.yml, agregue la regla css_rewritea assetic:

assetic:
    filters:
        cssrewrite:
            apply_to: "\.css$"

Ahora instale los activos y compile con assetic:

$ rm -r app/cache/* # just in case
$ php app/console assets:install --symlink
$ php app/console assetic:dump --env=prod

Esto es lo suficientemente bueno para el cuadro de desarrollo y --symlinkes útil, por lo que no tiene que reinstalar sus activos (por ejemplo, agrega una nueva imagen) cuando ingresa app_dev.php.

Para el servidor de producción, acabo de eliminar la opción '--symlink' (en mi script de implementación) y agregué este comando al final:

$ rm -r web/bundles/*/css web/bundles/*/js # all this is already compiled, we don't need the originals

Todo esta hecho. Con esto, puede usar rutas como esta en sus archivos .css:../img/picture.jpeg

ChocoDesarrollador
fuente
5

Tuve el mismo problema y solo intenté usar lo siguiente como solución. Parece funcionar hasta ahora. Incluso puede crear una plantilla ficticia que solo contenga referencias a todos esos activos estáticos.

{% stylesheets
    output='assets/fonts/glyphicons-halflings-regular.ttf'
    'bundles/bootstrap/fonts/glyphicons-halflings-regular.ttf'
%}{% endstylesheets %}

Observe la omisión de cualquier resultado, lo que significa que no aparece nada en la plantilla. Cuando ejecuto assetic: dump, los archivos se copian en la ubicación deseada y el css incluye el trabajo como se esperaba.

Cowlby
fuente
1
Puede usar una entrada de configuración para un activo con nombre y no es necesario que la incluya en las plantillas. Se volcará de
venimus
3

Si puede ayudar a alguien, hemos tenido muchos problemas con Assetic y ahora estamos haciendo lo siguiente en el modo de desarrollo:

  • Configurado como en Dumping Asset Files en Dev Environmen, así config_dev.ymlque hemos comentado:

    #assetic:
    #    use_controller: true

    Y en routing_dev.yml

    #_assetic:
    #    resource: .
    #    type:     assetic
  • Especifique la URL como absoluta desde la raíz web. Por ejemplo, background-image: url("/bundles/core/dynatree/skins/skin/vline.gif");Nota: nuestra raíz web vhost apunta a web/.

  • Sin uso de filtro cssrewrite

usuario1041440
fuente
3
Esta es una solución válida, pero sólo si nunca van a servir los archivos de un subdirectorio, por ejemplo: http://example.org/sub/.
apfelbox
1

A menudo administro el complemento css / js con el compositor que lo instala bajo el proveedor. Los enlazo simbólicamente al directorio web / bundles, lo que permite al compositor actualizar los paquetes según sea necesario.

ejemplo:

1 - enlace simbólico una vez (use el comando fromweb / bundles /

ln -sf vendor/select2/select2/dist/ select2

2 - use el activo donde sea necesario, en la plantilla de ramitas:

{{ asset('bundles/select2/css/fileinput.css) }}

Saludos.

Jean-Luc Barat
fuente