Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Optimización y perfiles

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $12.00

With a Subscription, click any sentence in the script to jump to that part of the video!

Login Subscribe

En lugar de decirte que el sitio es rápido, ¡vamos a probarlo! En Chrome, hay una herramienta llamada "Lighthouse", que también puedes conseguir para algunos otros navegadores. Ejecútala sólo para el rendimiento y selecciona "Analizar carga de página".

Esta es la mejor manera de ver si tienes algún problema de rendimiento en el frontend. Es probable que nuestra puntuación sea bastante alta -simplemente porque nuestro sitio es pequeño y rápido-, pero podemos utilizar el informe para detectar algunos posibles problemas. Y... ¡sí! Obtuvimos un 98 ¡sin sistema de construcción! Es asombroso. Pero podemos hacerlo aún mejor.

Eliminar los recursos que bloquean el renderizado

Si nos desplazamos hacia abajo, podemos ver dónde están nuestras áreas problemáticas. La primera es "Eliminar recursos que bloquean la renderización", que apunta a nuestro archivo de fuentes. Gran parte de lo que vamos a hablar no tiene nada que ver con AssetMapper: se trata simplemente del rendimiento del frontend en general. Si abres templates/base.html.twig, tenemos una etiqueta <link> que apunta a este archivo de fuentes.

... lines 1 - 2
<head>
... lines 4 - 11
{% block stylesheets %}
... line 13
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/inter@5.0.3/index.min.css">
... line 15
{% endblock %}
... lines 17 - 21
</head>
... lines 23 - 72

Cuando tu sitio ve una etiqueta `, la descarga antes de renderizar la página. Así que básicamente congela el renderizado de la página hasta que finaliza la descarga.

Pero esto es interesante. Abre ese archivo... y tomemos una versión no minificada. Tiene un montón de posibles fuentes. Así es como funciona: nuestro navegador descarga este archivo inmediatamente... pero los archivos de fuentes en sí no se descargarán hasta que y a menos que utilicemos esta fuente. Además, font-display: swap le dice al navegador:

Oye, no pasa nada por renderizar un texto que se supone que utiliza esta fuente, aunque la fuente aún no se ha descargado. Puedes utilizar primero la fuente predeterminada del sistema, mostrar el texto, terminar de descargar este archivo de fuente, y luego utilizarlo.

Esencialmente, este archivo CSS está escrito de forma que todos estos archivos de fuentes se descargarán perezosamente. El problema, que en realidad no es un gran problema, es que, en este punto, nuestro navegador sólo ve un archivo CSS y piensa:

Necesito descargar ese archivo CSS ahora mismo y no puedo renderizar la página hasta que ¡hasta que termine!

Una vez que por fin ve el contenido CSS, descubre que hay un montón de archivos de fuentes que puede descargar perezosamente.

Así pues, los archivos CSS son recursos que bloquean la renderización... lo que normalmente es genial, porque no queremos que la página se renderice sin estilo durante medio segundo antes de que se descargue el CSS. Pero este archivo en concreto es curioso porque es un recurso que "bloquea la renderización"... pero no contiene nada crítico.

Si nos preocupamos lo suficiente como para eliminar este recurso que bloquea la renderización, podemos moverlo a app.css. Empieza copiando este archivo... o en realidad sólo las fuentes que necesitamos: muchas de ellas son para idiomas que no estamos utilizando. Yo copiaré las dos fuentes latinas... aunque es probable que ni siquiera necesitemos esta de extensión latina. A continuación, borra este archivo CSS por completo, ve a assets/styles/app.css, y pégalo. No son URL reales... así que copia la URL... pégala, quita el index.css... y debería estar bien. Vuelve a copiar la URL... y haz lo mismo aquí abajo.

... lines 1 - 4
/* inter-latin-ext-wght-normal */
@font-face {
font-family: 'Inter Variable';
font-style: normal;
font-display: swap;
font-weight: 100 900;
src: url(https://cdn.jsdelivr.net/npm/@fontsource-variable/inter@5.0.3/files/inter-latin-ext-wght-normal.woff2) format('woff2-variations');
unicode-range: U+0100-02AF,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1E00-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF;
}
/* inter-latin-wght-normal */
@font-face {
font-family: 'Inter Variable';
font-style: normal;
font-display: swap;
font-weight: 100 900;
src: url(https://cdn.jsdelivr.net/npm/@fontsource-variable/inter@5.0.3/files/inter-latin-wght-normal.woff2) format('woff2-variations');
unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
... lines 24 - 37

Perfecto. Esto añade cierta complejidad a nuestro código a cambio de una pequeña ganancia, así que yo diría que es una prioridad menor. Tenemos básicamente la misma cantidad de CSS que antes, pero hemos eliminado un pequeño recurso de bloqueo innecesario.

El otro fallo que tenemos es similar. Es para FontAwesome - concretamente, este archivo JavaScript. También está en base.html.twig. Como esta etiqueta <script> no tiene defer ni async, también bloqueará la renderización de la página. Si queremos, podemos añadirle defer, que dice:

Comienza a descargar esto inmediatamente, pero no bloquees la página mientras está terminando.

... lines 1 - 2
<head>
... lines 4 - 16
{% block javascripts %}
... line 18
<script defer src="https://kit.fontawesome.com/5a377fab5b.js" crossorigin="anonymous"></script>
{% endblock %}
</head>
... lines 22 - 71

Como esto es para fuentes FontAwesome, en el peor de los casos la página se carga y nuestros iconos de fuentes aparecen un momento después.

¡Perfilar de nuevo!

Bien, ahora que hemos cambiado un par de cosas, vamos a probarlo. Para ahorrar tiempo de redistribución, volveré a mi sitio local y ejecutaré Lighthouse de nuevo. "Analizar carga de página"... haz esto un poco más grande, y... ¡fantástico! ¡Estamos obteniendo 100 localmente!

Pero si miras aquí abajo... todavía tenemos algunas oportunidades de mejora. Vemos "Servir imágenes en formatos next gen", que es algo bueno para comprobar más adelante, pero que no está relacionado con Symfony ni con AssetMapper. Esto de "Evitar servir JavaScript heredado a navegadores modernos" creo que se refiere al shim importmap: el código que hace que el mapa de importación funcione en todos los navegadores. Es pequeño y necesario, así que no es gran cosa.

Evitar encadenar peticiones críticas

Pero debajo vemos "Evitar encadenar peticiones críticas". Este es probablemente el punto más importante de esta lista.

Esto es lo que ocurre. Como puedes ver, primero descarga el HTML. Una vez que lo hace, se da cuenta de que necesita descargar este archivo CSS. Una vez que descarga el archivo CSS, se da cuenta de que necesita descargar este archivo de fuentes. ¿Ves el problema? En lugar de saber -desde el principio- que los necesita y descargarlos todos a la vez en paralelo, nuestro navegador los va descubriendo poco a poco. En última instancia, esto significa que este archivo de fuentes tardará más en cargarse porque no puede empezar a descargarlo hasta que descargue otros archivos.

¿Cómo podemos solucionar esto? Precargando. Hablemos de este importante tema a continuación.

Leave a comment!

0
Login or Register to join the conversation
Cat in space

"Houston: no signs of life"
Start the conversation!

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": ">=8.1",
        "ext-ctype": "*",
        "ext-iconv": "*",
        "babdev/pagerfanta-bundle": "^4.0", // v4.2.0
        "doctrine/doctrine-bundle": "^2.7", // 2.10.0
        "doctrine/doctrine-migrations-bundle": "^3.2", // 3.2.4
        "doctrine/orm": "^2.12", // 2.15.2
        "knplabs/knp-time-bundle": "^1.18", // v1.20.0
        "pagerfanta/doctrine-orm-adapter": "^4.0", // v4.1.0
        "pagerfanta/twig": "^4.0", // v4.1.0
        "stof/doctrine-extensions-bundle": "^1.7", // v1.7.1
        "symfony/asset": "6.3.*", // v6.3.0
        "symfony/asset-mapper": "6.3.*", // v6.3.0
        "symfony/console": "6.3.*", // v6.3.0
        "symfony/dotenv": "6.3.*", // v6.3.0
        "symfony/flex": "^2", // v2.3.1
        "symfony/framework-bundle": "6.3.*", // v6.3.0
        "symfony/http-client": "6.3.*", // v6.3.0
        "symfony/monolog-bundle": "^3.0", // v3.8.0
        "symfony/proxy-manager-bridge": "6.3.*", // v6.3.0
        "symfony/runtime": "6.3.*", // v6.3.0
        "symfony/stimulus-bundle": "^2.9", // v2.9.1
        "symfony/twig-bundle": "6.3.*", // v6.3.0
        "symfony/ux-turbo": "^2.9", // v2.9.1
        "symfony/web-link": "6.3.*", // v6.3.0
        "symfony/yaml": "6.3.*", // v6.3.0
        "twig/extra-bundle": "^2.12|^3.0", // v3.6.1
        "twig/twig": "^2.12|^3.0" // v3.6.1
    },
    "require-dev": {
        "doctrine/doctrine-fixtures-bundle": "^3.4", // 3.4.4
        "symfony/debug-bundle": "6.3.*", // v6.3.0
        "symfony/maker-bundle": "^1.41", // v1.49.0
        "symfony/stopwatch": "6.3.*", // v6.3.0
        "symfony/web-profiler-bundle": "6.3.*", // v6.3.0
        "zenstruck/foundry": "^1.21" // v1.33.0
    }
}
userVoice