Mapear Activos
AssetMapper no es gran cosa. Seguro que se viste genial y tiene buenos movimientos de baile, pero en realidad es bastante sencillo. Tiene dos características principales.
Característica número uno: configuramos "rutas" -como el directorio assets/ - y hace públicos los archivos que contiene.
Veámoslo en acción. Si te has descargado el código del curso, deberías tener un directoriotutorial/ con un importante archivo penguin.png en su interior. Cópialo. Dentro de assets/, podemos organizar las cosas como queramos. Así que vamos a crear un directorioimages/ y a transportar allí a nuestro pingüino.
Ahora, recuerda, sin la magia de AssetMapper, los únicos archivos a los que nuestro navegador debería poder acceder son los que están dentro del directorio public/. Así que debería ser imposible añadir una etiqueta img que cargue nuestro pingüino. Pero... es posible.
Utilizando la "ruta lógica
Dirígete a, qué tal, templates/base.html.twig. En cualquier lugar -iré por encima del bloquebody - añade un img con src="{{ asset() }}" pasándole la ruta a nuestro archivo relativa al directorio assets/. Así que images/penguin.png.
| // ... lines 1 - 20 | |
| <body class="bg-gray-800 text-white"> | |
| // ... lines 22 - 49 | |
| <img src="{{ asset('images/penguin.png') }}"> | |
| // ... lines 51 - 69 | |
| </body> | |
| // ... lines 71 - 72 |
Ya está. Esto se conoce como la "ruta lógica" al activo. Como hemos apuntado AssetMapper al directorio assets/, podemos referirnos a cosas dentro de él a través de su ruta relativa a esa raíz.
Y hay una forma estupenda de ver todos los activos que están en las rutas de AssetMapper yendo al terminal y ejecutando:
php bin/console debug:asset
¡Genial! En primer lugar, en la parte superior, muestra las rutas de AssetMapper, incluido el directorio assets/. Este proyecto también tiene instalado Pagerfanta. Y ya estamos viendo cómo los bundles pueden añadir sus propias rutas AssetMapper para que sus propios archivos estén disponibles públicamente. Esto no será importante para nosotros, pero podríamos dirigir el navegador a cualquier archivo dentro de ese directorio del bundle.
A continuación, vemos nuestro archivo de imagen, nuestro archivo CSS y nuestro archivo JavaScript. Estas son sus rutas en el sistema de archivos y estas son sus rutas lógicas.
Nombres de archivo versionados
La cuestión es que, utilizando la función asset() y la ruta lógica a un activo, cuando actualizamos... ¡funciona! ¡Woh! Y si inspeccionamos el elemento, ¡mira la URL! ¡Contiene un hash de versión en el medio! En realidad voy a ver la fuente de la página... es un poco más fácil de ver.
Así que no sólo penguin.png está disponible públicamente, sino que la ruta no es sólopenguin.png: contiene un hash de versión. Si modificáramos el archivo fuente penguin.png-por ejemplo, poniéndole una pajarita chula- el hash de la versión cambiaría automáticamente, obligando a cualquiera que utilizara nuestro sitio a descargar el archivo nuevo. ¡Booya!
Así es como se carga app.css En la parte superior, la etiqueta de enlace utilizaasset('styles/app.css'), que es la ruta lógica en AssetMapper a ese archivo. Y así también sale con un bonito nombre de archivo versionado.
¿Cómo se hacen públicos los archivos?
Vale, pero ¿cómo funciona esto? Si eres como yo, querrás saber cómo se hacen las salchichas. Bueno, en el entorno dev, funciona gracias a un oyente de eventos del núcleo... básicamente un elegante controlador interno de Symfony.
Por ejemplo, cuando el navegador carga esta imagen, esa petición pasa por Symfony. Ve que estamos intentando cargar /assets/images/penguin-versionhash.png, encuentra el archivo fuente y lo sirve.
¡Podemos probarlo! En la pestaña principal, haz clic en cualquier icono de la barra de herramientas de depuración web para entrar en el perfilador y, a continuación, haz clic en "Últimas 10" para ver las 10 peticiones más recientes a través de Symfony. Y ahí está: la petición que sirvió la imagen del pingüino. Adorable.
En producción, cargar nuestros archivos a través de Symfony no sería lo suficientemente rápido. Así que, en su lugar, durante el despliegue, ejecutarás un nuevo comando de consola:
php bin/console asset-map:compile
Hablaremos más sobre el despliegue más adelante. ¡Pero esto es realmente genial! Copia cada archivo de cada ruta AssetMapper en el directorio public/assets/ utilizando su nombre de archivo versionado. Y ya está.
De repente, este archivo ya no está siendo servido por Symfony: ¡estamos viendo un archivo real, físico! En public/assets/, ¡sí! Podemos ver los archivos finales en todo su esplendor.
Pero... mientras desarrollamos, elimina ese directorio para que todo siga cargándose dinámicamente.
Trasladar los favicons a AssetMapper
Y ya que estamos aquí, ¿ves esos favicons dentro del directorio public/? Estamos enlazando con ellos en la parte superior de base.html.twig. Eso funciona perfectamente: la funciónasset() puede seguir haciendo referencia a cosas dentro del directorio public/.
| // ... lines 1 - 2 | |
| <head> | |
| // ... lines 4 - 7 | |
| <link rel="apple-touch-icon" sizes="180x180" href="{{ asset('apple-touch-icon.png') }}"> | |
| <link rel="icon" type="image/png" sizes="32x32" href="{{ asset('favicon-32x32.png') }}"> | |
| <link rel="icon" type="image/png" sizes="16x16" href="{{ asset('favicon-16x16.png') }}"> | |
| // ... lines 11 - 19 | |
| </head> | |
| // ... lines 21 - 72 |
Pero... ¡sin apenas trabajo, podemos añadirles el versionado libre de activos! Paso 1: muévelos al directorio assets/images/. Paso 2: añade a cada ruta el prefijoimages/ para obtener su ruta lógica.
Y... así de fácil, seguimos viendo el favicon aquí arriba... pero lo que es más importante, si vemos el código fuente de la página, ¡ahora están versionados!
A continuación, profundicemos un poco más en los archivos CSS. Por ejemplo, ¿cómo podemos referirnos a imágenes de fondo desde dentro de CSS... si el nombre final del archivo está versionado?
10 Comments
I've been using asset mapper while developing a small website and I encountered a problem when using it together with LiipImagineBundle to resize my images. When running in the dev environment, LiipImagineBundle can't find the images because of the additional hash that asset mapper adds to the file name.
My assets are in an
assetsdirectory in the project root.The generated path from asset mapper is
assets/img/my_image-kNM.png. But because I am running indevenv, this "aliased" file does not really exist. LiipImagine however requires the file to exists in the file system and can't find it.One way to fix this is by running
asset-map:compileso the actual files exist in thepublic/assetsdirectory. But I want to stay flexible while still developing and don't want to have to remember that I need to compile my asset map.I modified the
liip_imagine.yamlconfig and added the following lines so that Liip can find my assets and also stopped using theasset("...")twig function. I basically just let LiipImagine figure out where to load the images from.Is there an easier way to use asset mapper together with LiipImagine? It feels like right now they are fighting with each other.
Hey @Stefan-G
Sorry for my late reply. You've hit an interesting edge case. I see a few options:
1) Do what you did, but add that config only for the
devenvironment2) Run
symfony console asset-map:compile --watchand keep it running3) A more robust solution: create your own loader service. You could "decorate" the main service
Liip\ImagineBundle\Binary\Loader\LoaderInterfaceand remove the hash part from the filename before processing it.Cheers!
There is a problem with asset mapper in production enviroment with uploaded files since it requires the compile option to be run.
For example, if your app allows users to upload images, but they are private images, so you store them in assets, and then it works great when in dev, but in prod it doesnt work because compile is not being run after every image upload.
That makes asset mapper incompatible with uploaded images from vich uploader bundle, etc?
Hey @MarkR
Sorry for our super late reply. Somehow we never saw this question
The files/images you store inside your private assets directory are meant for static files of your application, not files uploaded by users. The uploads should be stored in a public directory (you can add authorization rules so only file owners can actually access them)
I hope it helps. Cheers!
How can I include an image (e.g., an icon like assets/images/icon.png) in Symfony AssetMapper without applying versioning to it?
Hey @ahmedbhs ,
Hm, I wonder what's the reason behind avoiding using hash for that icon? Hash is always a good idea, no downsides at all and it makes your deploys more robust.
But if you really need that - I think you just should stop handling that image via AssetMapper then. Just put that image somewhere in the public/ dir and reference it with
{{ asset() }}. IIRC it should build the correct path w/o the hash. Because you can't use versioning for some assets only, it's a global strategy, you either use it in AssetMapper or not at all.I hope that helps!
Cheers!
no more build system? :D mind is blown!
When running debug:asset it explodes!
It is likely to do with me experimenting with Symfony 7.
I can't find any info on it and am not sure right now if this is a showstopper.
I wonder if this rings any bell and if you have any super magic counterspell to this error.
Tnx!
Hey @Sjoerd-N!
Upgrade
symfony/asset-mapperto the absolute latest version. A bug was introduced in 7.0.4 and should be fixed in 7.0.5.Cheers!
Hi, nice to find that symfony goes back, abandoning once and for all the prebuilt js in favor of assets, among other things that of assets is a very old (not bad) concept used by an excellent framework (I won't name names) considered minor compared to symfony. Does this method promise to become the best way to deal with css and js or is it just an alternative? Thanks
Hey @pasquale_pellicani!
I'm pretty happy too - it's really nice to work with :)
I can't say for sure. My best guess right now is that we, for the next few years, will have 2 paths. The "build" systems are now so widely used, that I think it will take time for people to realize that they don't need it. And, build systems WILL still exist forever, at the very least, to handle things like JSX, Vue, etc. The challenge over the next 12 months will be to (A) continue improving the DX for asset mapper (we have some work to do on 6.4 for this, especially related to making CSS nicer to use I think) and (B) reminding people this exists and it's excellent! It also helps that we're leveraging "web standards" (e.g. importmaps, ECMAScript code).
Anyway, we'll see. But there is nothing preventing this method from becoming the main way of handling things for non-SPA sites.
Cheers!
"Houston: no signs of life"
Start the conversation!