Mejora del rendimiento de los temas de Shopify (estudio de caso)

 

 

 

  • Implemente rápidamente. Implementar inteligentemente
  • ¡Registro!

  • Índice
    1. Nuestro objetivo era simple
    2. Quitar jQuery
    3. API de observador de intersección
    4. Layzcargando imágenes yobject-fit
    5. API de MatchMedia
    6. Buscando código duplicado
    7. Estadísticas de rendimiento
    8. ¿Que sigue?
      1. Recursos para desarrolladores de Shopify

    Cuando se trata de temas para grandes plataformas y CMS, los problemas heredados suelen convertirse en un cuello de botella. En este artículo, Carson Shold analiza cómo su equipo mejoró el rendimiento y la organización de sus temas de Shopify, y mejoró la mantenibilidad a lo largo del camino.

     

    La temida refactorización del código antiguo puede resultar un desafío. El código evoluciona con el tiempo con más funciones, dependencias nuevas o cambiantes, o tal vez un objetivo de mejoras de rendimiento. Al abordar una gran refactorización, ¿en qué cosas debería centrarse y qué mejoras de rendimiento puede esperar?

    He estado creando temas de Shopify durante casi una década. Cuando trabajé internamente en Shopify en 2013, los temas eran bastante simples en términos de complejidad del código. La parte más difícil fue que Shopify requería temas compatibles con IE8 y, hasta finales de 2020, IE11. Eso significaba que había una gran cantidad de JavaScript moderno que no podíamos utilizar sin polyfills, a veces considerables.

     

    Ocho años después, en 2021, los temas son infinitamente más complejos porque Shopify ha lanzado un montón de funciones nuevas (para acompañar nuestras ideas internas en Archetype Themes ). El problema es que la creación de nuevas funciones de alto rendimiento solo llegará hasta cierto punto cuando parte de su código base sea tan antiguo que tenga antiguos polyfills de IE o hacks de CSS de IE10. Nuestros temas tenían puntuaciones de velocidad bastante buenas para lo que ofrecían, pero sin duda estaban inflados.

    Nuestro objetivo era simple

    Mejor rendimiento en todos los ámbitos. Tiempo más rápido para pintar por primera vez. Menos bloqueo de JS. Menos complejidad del código.

    Llegar allí fue la parte difícil. Incluía:

    • Elimine jQuery y reescriba ~6k líneas de JS por tema en Vanilla JS
    • Elimine Manillars.js, ya que nuestras necesidades de plantillas eran demasiado pequeñas para un paquete tan grande.
    • Estandarizar el código compartido entre temas (eliminar duplicaciones)

    Alejarme de jQuery fue una bendición, pero fue un proceso largo. Afortunadamente, Tobias Ahlin tiene una guía fantástica sobre algunas de las conversiones rápidas fuera de jQuery . Mientras atravesaba estos cambios, fue el momento perfecto para repensar algunas cuestiones más básicas, como cómo estaba estructurado mi JS y cómo se inicializaban los elementos.

    Quitar jQuery

    Escribir Vanilla JS siempre pareció una quimera. Teníamos que admitir el antiguo IE, por lo que era muy fácil ignorar cualquier intento de eliminarlo. Luego, Shopify abandonó el soporte para IE 11 y las nubes se abrieron: era nuestro momento.

    ¿Por qué eliminar jQuery de todos modos? He escuchado muchos argumentos sobre esto, como que el tamaño del paquete no es tan malo en comparación con un marco como React. Bueno, jQuery no es un marco como React, por lo que es una comparación un poco inútil. jQuery es una forma de utilizar selectores similares a CSS y una sintaxis fácil de usar para desarrolladores para cosas como animaciones y solicitudes Ajax. Sobre todo, ayudó con las diferencias entre navegadores para que los desarrolladores no tuvieran que pensar en ello.

    Queríamos eliminarlo por varias razones:

    • Menos JS es bueno para el rendimiento;
    • No es necesario en los navegadores modernos;
    • El CEO de Shopify impulsó JS puro en los temas .

    Soy uno de esos desarrolladores que quedaron estancados en el pasado. Conocía jQuery por dentro y por fuera y podía lograr que lograra casi cualquier cosa que intentara. ¿Fue perfecto? No claro que no. Pero cuando miras el ciclo de vida de algunos frameworks JS que fracasaron , jQuery siempre ha sido estable y eso me resultó familiar y seguro. Eliminar nuestra dependencia de él y desenredarlo de ~6k líneas de código (para cada tema) parecía insuperable, especialmente cuando no podía estar seguro de que mis puntajes de rendimiento se beneficiarían o en qué medida.

    Nuestro enfoque fue comentar cada módulo que teníamos, eliminar jQuery y agregar lentamente cada módulo o función, uno a la vez, mientras se reescribía. Comenzamos con el archivo más simple, uno con algunas funciones y algunos selectores. Agradable y fácil, sin errores en las herramientas de desarrollo, es hora de seguir adelante.

     

    Hicimos esto uno por uno, recordando las soluciones fáciles de los primeros archivos cuando llegamos a los complejos, como refactorizar todas las características potenciales asociadas con un producto y su forma de agregar al carrito (conté, son 24 cosas únicas). . Al final, obtuvimos el producto JS de 1600 líneas de código a 1000. En el camino, encontramos mejores formas de hacer algunas cosas y volvíamos atrás y refactorizábamos según fuera necesario.

    Nos dimos cuenta de que Vanilla JS no da miedo, es simplemente una forma un poco más intencional de escribir código que jQuery. También nos dimos cuenta de que algunos códigos antiguos eran un desastre: necesitábamos organizar el JS para que fuera más modular y eliminar el código duplicado (más sobre esto a continuación). Pero antes de eso, queríamos jugar con algunos de los JS divertidos que solo habíamos usado en otros proyectos.

    API de observador de intersección

    Los temas de Shopify son poderosos porque permiten a los comerciantes mover elementos por la página como quieran. Eso significa que, como desarrollador, usted no sabe dónde está el elemento, si existe o cuántos existen.

    Para inicializar estos elementos, habíamos estado usando eventos de desplazamiento que verificaban continuamente si un elemento estaba visible en la página con esta función:

    theme.isElementVisible = function($el, threshold) { var rect = $el[0].getBoundingClientRect(); var windowHeight = window.innerHeight || document.documentElement.clientHeight; threshold = threshold ? threshold : 0; // If offsetParent is null, it means the element is entirely hidden if ($el[0].offsetParent === null) { return false; } return ( rect.bottom = (0 - (threshold / 1.5)) rect.right = 0 rect.top = (windowHeight + threshold) rect.left = (window.innerWidth || document.documentElement.clientWidth) );};

    A pesar de que estos eventos de desplazamiento estaban limitados, el navegador hacía muchos cálculos todo el tiempo. Realmente nunca se sintió demasiado lento, pero ocupó un lugar en la pila de llamadas , lo que afectó a otros JS que competían por la prioridad. Ojalá hubiéramos investigado más el rendimiento de esta actualización específicamente porque creo que es responsable de muchas de las mejoras en el tiempo de interacción y el tiempo total de bloqueo que verá a continuación.

    Llega la API Intersection Observer . Ahora que no era necesario el soporte para IE11, estaba muy feliz de poder utilizarlo por completo. En resumen, es una forma asincrónica de saber cuándo un elemento está visible en la ventana. No más mediciones lentas ni eventos de desplazamiento.

    Para inicializar un elemento cuando está visible, usamos algo tan simple como esto:

    theme.initWhenVisible({ element: document.querySelector('div'), callback: myCallback});

    Todo el JS requerido para el elemento se manejará dentro myCallback, evitando que haga nada hasta que sea visible.

     

    Esto configura un observador para ese elemento y luego elimina el observador una vez que es visible. Siempre es bueno limpiar lo que ensucia, incluso si cree que no habría mucho impacto sin ello. Si hay una devolución de llamada, la ejecutamos y nuestro módulo está listo para funcionar.

    theme.initWhenVisible = function(options) { var threshold = options.threshold ? options.threshold : 0; var observer = new IntersectionObserver((entries, observer) = { entries.forEach(entry = { if (entry.isIntersecting) { if (typeof options.callback === 'function') { options.callback(); observer.unobserve(entry.target); } } }); }, {rootMargin: '0px 0px '+ threshold +'px 0px'}); observer.observe(options.element);};

    También puedes pasar un umbral para inicializar el elemento antes de que esté en la pantalla, lo que puede ser útil si deseas precargar algo como la API de mapas de Google ligeramente antes de que el elemento sea visible para que esté listo cuando lo esté.

    Layzcargando imágenes yobject-fit

    Usamos lazysizes para cargar nuestras imágenes de forma diferida. Tiene algunos complementos útiles para cargar también imágenes de fondo, pero requiere mucho más marcado en su elemento. Si bien los complementos son bastante pequeños, es una cosa más que se elimina fácilmente con CSS puro.

    Usar object-fitCSS significaba que podíamos colocar una imagen como una imagen de fondo, pero como un imgelemento y obtener todos los beneficios de la carga diferida normal sin JS adicional. El beneficio real de esto es que estamos un paso más cerca de utilizar la carga diferida del navegador nativo (que no admite imágenes de fondo). Aún tendremos que cargar lazysizes como alternativa cuando el enfoque nativo no sea compatible , pero eso significa eliminar una dependencia completa. Mejores grifos de cocina

    scriptif ('loading' in HTMLImageElement.prototype) { // Browser supports `loading`} else { // Fetch and initialize lazysizes}/script

    API de MatchMedia

    En el pasado, usábamos enquire.js para saber cuándo cambiaban los puntos de interrupción. Esto se usa al cambiar el tamaño de los elementos, cambiar los argumentos de un módulo para escritorio versus móvil, o simplemente para mostrar/ocultar elementos que no se pueden usar con CSS.

    En lugar de depender de otro paquete, una vez más podemos optar por una solución nativa en matchMedia .

    var query = 'screen and (max-width:769px)';var isSmall = matchMedia(query).matches;matchMedia(query).addListener(function(mql) { if (mql.matches) { isSmall = true; document.dispatchEvent(new CustomEvent('matchSmall')); } else { isSmall = true; document.dispatchEvent(new CustomEvent('unmatchSmall')); } });

    Con solo unas pocas líneas de código, podemos escuchar cambios en los puntos de interrupción y cambiar una variable útil que se usa en otros lugares y desencadenar un evento personalizado que módulos específicos pueden escuchar.

    document.addEventListener('matchSmall', function() { // destroy desktop-only features // initialize mobile-friendly JS});

    Buscando código duplicado

    Como mencioné al principio, poco a poco habíamos ido incorporando funciones a nuestros temas durante años. No pasó mucho tiempo para que se crearan algunos elementos que eran similares a otros, como un video de página de inicio de ancho completo y videos posteriores en su lista de productos o un modo de video emergente.

     

    La API de YouTube, por ejemplo, se inicializó de manera diferente tres veces y tenía devoluciones de llamadas y funciones de accesibilidad casi idénticas creadas por módulo. Fue un poco vergonzoso que no lo construyéramos de manera más inteligente en primer lugar, pero así es como sabes que estás creciendo como desarrollador.

    Nos tomamos este tiempo para consolidar muchos de nuestros módulos para que sean ayudantes independientes. YouTube se convirtió en su propio método que podían utilizar todas las secciones de todos nuestros temas. Significó refactorizar dividiéndolo en las partes más básicas:

    • Argumentos API predeterminados (anulables por el módulo de inicialización)
    • Un ID de div para inicializar el vídeo
    • ID del vídeo de YouTube a cargar
    • Eventos (API está lista, estado del video cambiado, etc.)
    • Reproducir/pausar cuando no esté a la vista
    • Manejar el modo de bajo consumo de iOS cuando la reproducción automática no es compatible

    Mi enfoque fue hacer todo esto en papel antes de codificar, lo cual es algo que siempre me ayuda a distinguir qué es parte integral del módulo que estoy construyendo versus qué es personalizado por el padre que lo inicializa (una división del trabajo, por así decirlo).

    Ahora nuestros tres temas que inicializan vídeos de YouTube de un total de nueve formas diferentes utilizan un solo archivo. Esto supone una gran mejora en la complejidad del código para nosotros y hace que cualquier actualización futura sea mucho más fácil para mí y para otros desarrolladores que puedan tocar el código. Al utilizar este mismo enfoque para otros módulos durante la conversión a Vanilla JS, nos permitió mover casi la mitad del JS de cada tema a un único módulo compartido entre todos.

    Esto es algo que fue invaluable para nuestro equipo y nuestra configuración de múltiples proyectos y puede que no sea útil para sus proyectos exactamente, pero creo que el proceso sí lo es. Pensar en la simplicidad y evitar duplicidades siempre beneficiará a tu proyecto.

    Hicimos lo mismo con los módulos de presentación de diapositivas (presentaciones de imágenes, testimonios, imágenes de páginas de productos, barras de anuncios), cajones y modales (menús móviles, cajones de carrito, ventanas emergentes de boletines) y muchos más. Un módulo tiene un propósito y compartirá con los padres solo lo que se requiere. Esto significó menos código enviado y un código más limpio para desarrollar.

    Estadísticas de rendimiento

    Finalmente, lo bueno. ¿Valió la pena todo esto? La mayor parte de esto se hizo a ciegas, con el supuesto de que menos JS, una inicialización más inteligente y enfoques más modernos darían como resultado temas más rápidos. No nos decepcionó.

    Comenzamos todo este trabajo con Motion , nuestro primer tema. Tenía el JS más inflado y el mayor margen de mejora.

     

    • 52% menos JS enviado
    • Velocidades de la página de inicio de escritorio (con elementos pesados ​​como múltiples videos, productos destacados, presentaciones de diapositivas con imágenes grandes)
    Página de inicio de escritorio Antes Después Cambiar
    Puntuación del faro 57 76 +33
    Tiempo total de bloqueo 310ms 50 ms -83,8%
    Es hora de interactuar 2,4s 2.0s -dieciséis%
    Pintura con contenido más grande 3,8s 2,6s -31,5%
    • Páginas de productos móviles
    Página de producto móvil Antes Después Cambiar
    Puntuación del faro 26 sesenta y cinco +150%
    Tiempo total de bloqueo 1440ms 310ms -78%
    Es hora de interactuar 11,3s 6.1s -46%
    Pintura con contenido más grande 13 4,2s -67,6%

    Luego pasamos a Impulse , nuestro segundo tema y el que tiene más funciones.

    • 40% menos JS enviado
    • Velocidades de página de inicio móvil un 28 % más rápidas
    Página de inicio de escritorio Antes Después Cambiar
    Puntuación del faro 58 81 +39,6%
    Tiempo total de bloqueo 470 ms 290ms -38%
    Es hora de interactuar 6.1s 5,6s -8%
    Pintura con contenido más grande 6s 2,9s -51,6%
    • Velocidades 30% más rápidas en la página de inicio móvil y en la página de producto
    Página de producto móvil Antes Después Cambiar
    Puntuación del faro 32 45 +40,6%
    Tiempo total de bloqueo 1490ms 780 ms -47,6%
    Es hora de interactuar 10,1s 8,3s -17,8%
    Pintura con contenido más grande 10,4s 8,6s -17,3%

    Si bien puede notar que estos números mejoraron mucho, todavía no son excelentes. Los temas de Shopify están maniatados por la plataforma, por lo que nuestro punto de partida ya es un desafío. Podría ser un artículo completamente separado, pero aquí está la descripción general:

    • Shopify tiene muchos gastos generales : detección de funciones, seguimiento y botones de pago (Apple Pay, Google Pay, ShopPay). Si estás en la página de un producto con botones de pago dinámicos, puedes ver alrededor de 187 kb de scripts de Shopify frente a archivos de temas de 24,5 kb. La mayoría de los sitios tendrán Google Analytics y tal vez un píxel de Facebook u otros scripts de seguimiento cargados además de todo esto.

    ( Vista previa grande )

     

    La buena noticia es que estos scripts se cargan de manera bastante eficiente y la mayoría no bloquea mucho la visualización de la página. La mala noticia es que todavía hay mucha carga de JavaScript en esas páginas que están fuera del control del tema y provocan algunos indicadores en las puntuaciones de Lighthouse.

    ( Vista previa grande )

    • Las aplicaciones son un gran cuello de botella y los propietarios de tiendas, en general, no tienen idea. Habitualmente vemos tiendas con más de 20 aplicaciones instaladas, e incluso una aplicación sencilla puede reducir tu puntuación de velocidad de Shopify en más de 10 puntos. Aquí está el desglose de nuestro tema Impulse con tres aplicaciones instaladas.

    ( Vista previa grande )

    Nota : Aquí hay un excelente estudio de caso sobre aplicaciones y su efecto en el rendimiento .

    Todavía estamos en el proceso de finalizar estas actualizaciones de nuestro tercer tema, Streamline . Streamline también tiene otras características de rendimiento integradas que estamos explorando para agregar a nuestros otros temas, como loadCSS de Filament Group para evitar que CSS sea un recurso que bloquee el procesamiento.

    Estos números no son insignificantes. Se ha informado ampliamente que la velocidad es importante e incluso los pequeños cambios pueden generar grandes impactos . Aunque estamos contentos con todo este progreso, no es el final. El rendimiento seguirá siendo una parte dominante de nuestras compilaciones y no dejaremos de buscar más formas de simplificar el código.

    ¿Que sigue?

    El rendimiento es un desafío continuo y estamos entusiasmados de seguir avanzando. Algunas cosas en nuestra lista son:

    • Utilice el observador de cambio de tamaño en lugar de eventos de ventana
    • Pasar completamente a la carga diferida de imágenes del navegador nativo (con respaldo de tamaños diferidos para Safari)
    • Cargue solo JS que se usa en la página actual para que no enviemos un archivo enorme cada vez (un gran desafío en Shopify en este momento)
    • Aumente nuestro conocimiento sobre el desempeño con la lista de verificación de desempeño 2021 de Smashing
    • Configure Lighthouse en acciones de GitHub para ver los impactos en el rendimiento a medida que desarrollamos

    Recursos para desarrolladores de Shopify

    Si estás desarrollando Shopify o quieres comenzar, aquí tienes algunos recursos útiles:

    • Configurar un flujo de trabajo de desarrollo de temas local
    • Extensión Theme Inspector de Chrome para depurar cuellos de botella en Liquid
    • Hoja de referencia de Shopify
      ¿Qué líquido está disponible para ti?
    • Documentos sobre lenguaje de plantillas líquidas
      Hace unos años, era difícil leerlos, pero desde entonces se han convertido en oro para los desarrolladores de Shopify.

    (vf, il)Explora más en

    • Flujo de trabajo
    • javascript
    • Actuación
    • Estudios de caso





    Tal vez te puede interesar:

    1. ¿Deberían abrirse los enlaces en ventanas nuevas?
    2. 24 excelentes tutoriales de AJAX
    3. 70 técnicas nuevas y útiles de AJAX y JavaScript
    4. Más de 45 excelentes recursos y repositorios de fragmentos de código

    Mejora del rendimiento de los temas de Shopify (estudio de caso)

    Mejora del rendimiento de los temas de Shopify (estudio de caso)

    Nuestro objetivo era simpleQuitar jQueryAPI de observador de intersecciónLayzcargando imágenes yobject-fitAPI de MatchMediaBuscando código duplicadoEstadís

    programar

    es

    https://pseint.es/static/images/programar-mejora-del-rendimiento-de-los-temas-de-shopify-estudio-de-caso-1096-0.jpg

    2024-05-21

     

    Mejora del rendimiento de los temas de Shopify (estudio de caso)
    Mejora del rendimiento de los temas de Shopify (estudio de caso)

    Si crees que alguno de los contenidos (texto, imagenes o multimedia) en esta página infringe tus derechos relativos a propiedad intelectual, marcas registradas o cualquier otro de tus derechos, por favor ponte en contacto con nosotros en el mail [email protected] y retiraremos este contenido inmediatamente

     

     

    Update cookies preferences