Seo en Laravel - Optimizando los archivos JavaScript en un blog

Video thumbnail

Te voy dando un poquito mis consideraciones sobre el uso de JavaScript y optimización en un proyecto en Laravel, pero puedes aplicar estos pasos a otros tipos de proyectos web. 

El primer punto que quiero revisar es el bendito JavaScript, que me parece increíble, pero prácticamente no tengo casi nada cargando. Aun así, sí tengo algunas integraciones activas, como con Facebook y con Google Tag Manager, ADS que se cargan en la web pero NO SON NECESARIOS para que la web funcione,  y esto es un factor clave, ya que, lo podemos cargar DESPUES, pasado un tiempo prudencial.

Crítica a la integración de YouTube en webs

También tengo integrado YouTube. Y esto me parece increíble: que ellos mismos critiquen una integración que ellos proveen, es decir, la de YouTube. Tú entras a su plataforma, le das a compartir, colocas el iframe, y se supone que debería estar optimizado para que pase sus propias pruebas... pero no. Así que, bueno, toca inventárselas por ahí.

Entonces, quiero analizar qué JavaScript está cargando en mi página. Para ello, me dirijo a la sección de herramientas del desarrollador, específicamente a la pestaña de Network, y filtro por .js. Al recargar la página, puedo ver claramente los scripts cargados, y veremos que el de JS es una parte CRITICA, ya que carga demasiados recursos, rentalizando la carga de toda la web.

Identificación de mis JavaScript

En este punto, tenemos claro los scripts que no forman parte de la web, como los de pixel de Facebook o el ADS de Google, también conocemos otros recursos como el de Youtube que aunque no forman parte de la web, si son necesarios para tener un recurso más interesante.

Lo siguiente que buscamos, es que podemos optimizar de nuestros propios  archivos JS. En este caso, son dos:

  • highlight.js
  • blog.js

Optimizar nuestros archivos

Estos dos son de mi autoría. Ya esto es una mejora, porque antes tenía todo en un solo archivo, el famoso blog.js. Este incluía de todo. En base a recomendaciones, decidí dividirlos en módulos más pequeños.

También estoy eliminando dependencias que ya no necesito. Por ejemplo, Axios: en el blog solo hago unas pocas peticiones, y he migrado la mayoría a fetch. Puede que todavía quede algo por allí, pero poco a poco estoy ordenando todo.

Reemplazo de Axios y otros scripts

Ya eliminé Axios por completo. También consideré quitar Alpine, pero pesa tan poco que por ahora lo voy a dejar.

Otro script que estoy evaluando es el del plugin de highlight.js. Este es fundamental para mí, ya que da formato al código en los artículos. Aunque no tengo un ejemplo aquí visible, básicamente lo que hace es detectar bloques pre y aplicarles un formato visual, separándolos por tokens para estilizar el código.

Organización del código y carga condicional

Lo que estoy haciendo es organizar el código mejor. Por ejemplo, tengo el highlight.js dividido: su CSS está en el layout principal, y el JS lo cargo solo cuando es necesario, bajo una condición específica. Esa lógica te la explicaré en un próximo video.

El archivo blog.js ahora solo contiene las funciones mínimas: búsquedas y peticiones locales. Tiene menos de 300 líneas y planeo optimizarlo aún más. Solo conserva lo esencial.

Los Iframe de Youtube SON UN VENENO en el SEO de tu Blog, Como corregirlo?

Video thumbnail

Cómo Pasé de un Rendimiento de 37 a 100 en PageSpeed: El Problema del <iframe>
En este y en los próximos videos te voy a hablar un poco de cómo pasé de tener un rendimiento de 37 en mis publicaciones, a simplemente alcanzar 100. Lo cual, sinceramente, aún me sorprende bastante, ya que todavía tengo algunas cositas que corregir. Por lo tanto, aunque la métrica ahora sea perfecta, el sitio no lo es del todo. Aún tengo detalles por mejorar, como lo tengo anotado por aquí, pero en fin... te voy a ir comentando de todo un poco.

En este primer video, quiero enfocarme únicamente en el bendito <iframe> de YouTube, que ha sido un verdadero veneno para el rendimiento.

El Dilema del Video Incrustado en el Blog

Si tú tienes un blog, seguramente ya te han comentado que debes compartir tanto texto como video, sobre todo si haces contenido mixto. Es decir, creas un video y luego haces un artículo, o viceversa. Lo ideal es que ambos se presenten en la misma publicación: el video arriba y el texto abajo. De esta forma estás potenciando tu contenido al ofrecer dos formatos distintos.

Hasta ahí, todo bien.
El problema viene cuando decides incrustar el video directamente con el <iframe> de YouTube, que es una verdadera porquería en términos de rendimiento.

Ese fue el cáncer que tenía en mi blog, así que quiero hablarte un poco sobre eso.

El Video que No es un Video

Fíjate que donde debería estar el video, no parece un reproductor normal de YouTube. Y es que no es un video real: lo que ves es simplemente una imagen estática. Esta imagen puede ser la misma miniatura del video que está en YouTube o una optimizada que subí directamente al blog.

En mi caso, prefiero usar la imagen local porque está en formato WebP, que es el que me exige PageSpeed. Curiosamente, YouTube te devuelve un JPG como miniatura, y luego Google te dice que deberías usar WebP. Irónico, ¿no?

Carga del Video Bajo Demanda

Entonces, ¿qué pasa cuando haces clic sobre esa imagen?
Ahí es cuando se carga el video real de YouTube, bajo demanda. Desde el punto de vista del usuario, esto es excelente porque la página carga más rápido, pero… hay un detalle importante.

Cuando haces esto, Google y otros motores de búsqueda ya no detectan el video como contenido enriquecido, porque técnicamente lo que estás mostrando al principio es solo un enlace disfrazado.

Solución con Etiquetas de Datos Estructurados

Para resolver esto, utilizo una técnica interesante. Aun cuando el video no está incrustado directamente con <iframe>, le indico a Google que ese video forma parte del contenido mediante un bloque de datos estructurados en formato JSON-LD.

En el código fuente, puedes ver que uso un script donde especifico datos como:

  • Título del video
  • Descripción (la misma que la del post)
  • Fecha de publicación
  • Nombre del autor (en mi caso, yo mismo o “Desarrollo Libre”)
  • Logo del canal
  • URL del video en YouTube
const jsonLd = {
                    "@context": "https://schema.org",
                    "@type": "VideoObject",
                    "name": @json($post->title),
                    "description": @json($post->description ?? 'Resumen del contenido del video'),
                    "thumbnailUrl": image ??  `https://img.youtube.com/vi/${videoId}/hqdefault.jpg`,
                    "uploadDate": "{{ \Carbon\Carbon::parse($post->date)->toAtomString() }}",
                    "embedUrl": `https://www.youtube.com/embed/${videoId}`,
                    "publisher": {
                        "@type": "Organization",
                        "name": "Desarrollo Libre",
                        "logo": {
                            "@type": "ImageObject",
                            "url": @json(asset('images/logo/logo.png'))
                        }
                    }
                };

Y todo esto lo armo una sola vez, cuando la página se carga por primera vez.

Alternativas: Plugins Ligthweight para YouTube

Otra opción que evalué fue usar plugins como lite-youtube-embed, que carga el video 224 veces más rápido, según su documentación.

El problema es que te casas con una sintaxis específica del plugin, como por ejemplo:

<lite-youtube videoid="TuIDDeVideo"></lite-youtube>

Y eso es justo lo que yo no quería. Prefiero mantener el contenido como lo hace todo el mundo —usando <iframe>— para luego procesarlo internamente. Pero si tú quieres ir por la vía del plugin, también es válido.

TRUCAZO para el SEO en Laravel, Carga Diferida y Pre Render del contenido

Video thumbnail

Te explicaba cómo pasé de un puntaje de 50 a 73 en PageSpeed, simplemente cambiando el bendito iframe de YouTube. Esto era lo que tenía inicialmente, y fíjate que cuando lo cambio, ya tengo aquí 73. Ahora voy a continuar la explicación desde ese punto y mostrarte cómo llegué hasta los 100, con los cambios que realicé.

Aprovecho también para comentarte que este material formará parte de un curso que voy a crear más adelante. Actualmente estoy trabajando en mi tienda en línea —a la fecha de grabación—, pero luego haré otro curso sobre cómo crear un blog bien optimizado, explicando todos estos detalles y algunas cosas más.

Optimización: ¿Qué fue lo que cambié?

Mejorar la accesibilidad, title, alt y derivados

Aquí puedes ver nuevamente el 73. A partir de ahí, el resto de los cambios se centraron en hacer la carga más eficiente. Eso incluía cosas como mejorar la accesibilidad, por ejemplo, colocando atributos especiales a los botones para indicar su función. Esto sirve especialmente para lectores de pantalla, como los que usan personas con discapacidad visual, para que entiendan qué hace cada botón:

Los botones no tienen nombres accesibles
A continuación se indican consejos para mejorar la semántica de los controles de tu aplicación. Estos consejos pueden mejorar la experiencia de los usuarios de tecnologías de asistencia, como los lectores de pantalla.

<button aria-label="Cerrar ventana">
   <svg><!-- ícono de cerrar --></svg>
</button>

También hice ajustes en las imágenes, asegurándome de colocar el atributo alt con una descripción adecuada. Y algo muy importante: respetar la jerarquía de encabezados. Si colocas un H1, el siguiente debe ser un H2, luego H3, y así sucesivamente. No deberías pasar de un H1 a un H3 directamente, porque se rompe la lógica del contenido. Eso era uno de los detalles que me estaban observando.

Optimizar recursos bloqueantes

Además, optimicé la respuesta del servidor. Aunque el cambio del iframe ayudó mucho, también empecé a remover todo el JavaScript innecesario. Había cosas cargándose desde el dashboard, sin sentido. Todo eso lo eliminé.

Reducción de JavaScript y código más limpio

El JavaScript que estaba cargando afectaba bastante. Aquí puedes ver lo que me estaba tomando el iframe de YouTube: una barbaridad. Y todos estos pequeños cambios afectan directamente cómo se renderiza la página.

A medida que resuelves esos problemas, la carga mejora, el servidor responde más rápido, y todo se procesa con más eficiencia. Por eso, haciendo pocos cambios estratégicos, la web evolucionó bastante.

El problema del DOM excesivo

Uno de los aspectos que también me señalaba Google era el tamaño excesivo del DOM. Esto es porque, por ejemplo, en mi contenido tengo dos tipos principales: uno con el video de YouTube y su transcripción, y otro con los cursos.

Cuando abres un curso, el documento es largo porque contiene todas las secciones del curso con su descripción. Es decir, coloco toda esa estructura dentro del HTML para que Google entienda qué hace cada cosa. Por eso el DOM es tan largo.

Esto viene directamente de mi plataforma de cursos, donde cada sección tiene sus clases. Simplemente copié esa estructura a la publicación del blog. Así que, aunque sea largo, tiene sentido y es contenido útil.

Problemas de formato y accesibilidad

Hay algunos detalles visuales que también debo mejorar. Por ejemplo, algunos contrastes son muy fuertes. Le coloqué un fondo más oscuro, pero tal vez es demasiado. También debo reorganizar el listado para que los posts recientes aparezcan primero.

Y algo curioso: cuando utilizo las imágenes de YouTube, estas devuelven un JPG, no un WebP, que es lo que Google prefiere. Y eso que si tú subes una imagen a YouTube y haces clic derecho para descargarla, muchas veces obtienes un WebP. No sé por qué no lo hacen por defecto... parece que lo hacen a propósito para complicarnos la vida.

Reducción de JavaScript: más a fondo
Volviendo a los aspectos clave: reducir JavaScript fue esencial. También cuidar los nombres y atributos. Por ejemplo, las imágenes deben tener su atributo alt, y los botones deben tener su aria-label, que ni conocía, pero que sirve para indicar qué hace cada botón.

Lo que más me importa explicarte es cómo dejé todo lo más natural posible. Si una publicación tiene un video de YouTube, simplemente coloco el iframe y listo.

Código fuente y Highlight.js

Este blog es para programadores, así que obviamente hay partes de código. Estoy trabajando en paralelo con los libros, que tienen mucho código. Para eso uso highlight.js, que estiliza el código y lo muestra bonito.

El problema es que cuando tienes un libro con 300 páginas, el plugin se vuelve pesado. En algún punto deja de funcionar o se ralentiza mucho. Eso también afecta la carga de la página.

Por eso hice algo clave: procesar el contenido una sola vez y guardarlo en un campo llamado final_content. Eso significa que el Highlight.js solo se ejecuta una vez, y luego ya no se necesita. Así me ahorro toda la carga del plugin.

Alpine.js y scripts mínimos

Otra parte que optimicé fue la carga de scripts. Uso Alpine.js para el menú hamburguesa y botones de compartir. Pero aunque pesa poco (unos 8KB), decidí también retrasar su carga.

¿Qué es lo mínimo que necesita cargar mi web? El CSS, sin duda. El HTML solo no basta. También el CSS del plugin que estiliza el código. A Google no le gustan los cambios bruscos de estilo, por eso ese CSS debe ir cargado desde el principio.

Acepto recibir anuncios de interes sobre este Blog.

Hablamos sobre la importancia de tener presente cuales son los JS (y otros recursos) que se estar cangando en la web que quieres posicionar en Google.

- Andrés Cruz

In english