Paquete inteligente: cómo entregar código heredado solo a navegadores heredados

 

 

 

  • SmashingConf UX y diseño, Amberes 2024
  • Taller de diseño conductual, con Susan y Guthrie Weinschenk

  • Índice
    1. El costo de admitir navegadores heredados
      1. Transpilando a ES5
      2. ES6+ Polirellenos
      3. Plataforma web Polyfills
      4. Prefijo CSS
    2. Una guía práctica para enviar código eficiente
    3. Herramientas que necesitaremos
    4. 1. Definición de navegadores modernos y heredados
    5. 2. Transpilación y polillenado de ES6+
    6. 3. Características de la plataforma web Polyfilling
    7. 4. Prefijo CSS
    8. Poniendolo todo junto
    9. Ofreciendo el paquete adecuado a los usuarios
    10. Conclusión: ¿Vale la pena?
      1. 1. Mantenimiento y pruebas
      2. 2. Tiempo de construcción versus tiempo de ejecución
      3. 3. Velocidad progresivamente mejorada
      4. 4. Utilizar las funciones modernas del navegador con facilidad
    11. Paquete diferencial que sirve en producción
      1. Recursos adicionales

    Si bien la agrupación efectiva de recursos en la web ha recibido mucha atención en los últimos tiempos, la forma en que enviamos recursos de front-end a nuestros usuarios se ha mantenido prácticamente igual. El peso promedio de JavaScript y los recursos de estilo que incluye un sitio web está aumentando, aunque las herramientas de creación para optimizar el sitio web nunca han sido mejores. Con la participación de mercado de los navegadores tradicionales aumentando rápidamente y los navegadores lanzando soporte para nuevas funciones al mismo tiempo, ¿es hora de repensar la entrega de activos para la web moderna?

     

    Hoy en día, un sitio web recibe una gran parte de su tráfico de navegadores permanentes, la mayoría de los cuales tienen buen soporte para ES6+, nuevos estándares de JavaScript, nuevas API de plataforma web y atributos CSS. Sin embargo, los navegadores heredados aún deben ser compatibles en el futuro cercano: su uso compartido es lo suficientemente grande como para no ser ignorado, dependiendo de su base de usuarios.

    Un vistazo rápido a la tabla de uso de caniuse.com revela que los navegadores tradicionales ocupan la mayor parte del mercado de navegadores: más del 75%. A pesar de esto, la norma es prefijar CSS, transpilar todo nuestro JavaScript a ES5 e incluir polyfills para admitir a todos los usuarios que nos interesan.

    Si bien esto es comprensible desde un contexto histórico (la Web siempre se ha centrado en la mejora progresiva), la pregunta sigue siendo: ¿estamos ralentizando la Web para la mayoría de nuestros usuarios para admitir un conjunto cada vez menor de navegadores heredados?

    Las diferentes capas de compatibilidad de una aplicación web. ( Ver versión grande )

    El costo de admitir navegadores heredados

    Intentemos comprender cómo los diferentes pasos en una canalización de compilación típica pueden agregar peso a nuestros recursos de front-end:

    Transpilando a ES5

    Para estimar cuánto peso puede agregar la transpilación a un paquete de JavaScript, tomé algunas bibliotecas de JavaScript populares escritas originalmente en ES6+ y comparé los tamaños de sus paquetes antes y después de la transpilación:

    Biblioteca Tamaño
    (ES6 minificado)
    Tamaño
    (ES5 minificado)
    Diferencia
    TodoMVC 8,4 KB 11 KB 24,5%
    Arrastrable 53,5KB 77,9KB 31,3%
    Luxón 75,4KB 100,3KB 24,8%
    Vídeo.js 237,2KB 335,8KB 29,4%
    PixiJS 370,8KB 452KB 18%

    En promedio, los paquetes no transpilados son aproximadamente un 25 % más pequeños que los que se han transpilado a ES5. Esto no es sorprendente dado que ES6+ proporciona una forma más compacta y expresiva de representar la lógica equivalente y que la transpilación de algunas de estas características a ES5 puede requerir mucho código.

    ES6+ Polirellenos

    Si bien Babel hace un buen trabajo al aplicar transformaciones sintácticas a nuestro código ES6+, las características integradas introducidas en ES6+, como Promise, Mapy Set, y nuevos métodos de matriz y cadena, aún deben completarse. Ingresarlo babel-polyfilltal como está puede agregar cerca de 90 KB a su paquete minimizado.

     

    Plataforma web Polyfills

    El desarrollo de aplicaciones web modernas se ha simplificado gracias a la disponibilidad de una gran cantidad de nuevas API de navegador. Los más utilizados son fetch, para solicitar recursos, IntersectionObserverpara observar eficientemente la visibilidad de los elementos y la URLespecificación, lo que facilita la lectura y manipulación de URL en la web.

    Agregar un polyfill que cumpla con las especificaciones para cada una de estas características puede tener un impacto notable en el tamaño del paquete.

    Prefijo CSS

    Por último, veamos el impacto del prefijo CSS. Si bien los prefijos no agregarán tanto peso muerto a los paquetes como lo hacen otras transformaciones de compilación, especialmente porque se comprimen bien cuando se hacen con Gzip, todavía se pueden lograr algunos ahorros aquí.

    Biblioteca Tamaño
    (minimizado, con prefijo para las últimas 5 versiones del navegador)
    Tamaño
    (minimizado, con el prefijo de la última versión del navegador)
    Diferencia
    Oreja 159KB 132KB 17%
    Bulma 184KB 164KB 10,9%
    Base 139KB 118KB 15,1%
    IU semántica 622KB 569 KB 8,5%

    Una guía práctica para enviar código eficiente

    Probablemente sea evidente hacia dónde quiero llegar con esto. Si aprovechamos los canales de compilación existentes para enviar estas capas de compatibilidad solo a los navegadores que las requieran, podemos ofrecer una experiencia más ligera al resto de nuestros usuarios (aquellos que forman una mayoría creciente) mientras mantenemos la compatibilidad para los navegadores más antiguos.

    Bifurcando nuestros paquetes. ( Ver versión grande )

    Esta idea no es del todo nueva. Servicios como Polyfill.io son intentos de rellenar dinámicamente entornos de navegador en tiempo de ejecución. Pero enfoques como este adolecen de algunas deficiencias:

    • La selección de polyfills se limita a los enumerados en el servicio, a menos que usted mismo aloje y mantenga el servicio.
    • Debido a que el polyfilling ocurre en tiempo de ejecución y es una operación de bloqueo, el tiempo de carga de la página puede ser significativamente mayor para los usuarios de navegadores antiguos.
    • Servir un archivo polyfill personalizado a cada usuario introduce entropía en el sistema, lo que dificulta la resolución de problemas cuando algo sale mal.

    Además, esto no resuelve el problema del peso agregado por la transpilación del código de la aplicación, que a veces puede ser mayor que los propios polyfills.

     

    Veamos cómo podemos solucionar todas las fuentes de hinchazón que hemos identificado hasta ahora.

    Herramientas que necesitaremos

    • Webpack
      Esta será nuestra herramienta de compilación, aunque el proceso seguirá siendo similar al de otras herramientas de compilación, como Parcel y Rollup.
    • Lista de navegadores
      Con esto, administraremos y definiremos los navegadores que nos gustaría admitir.
    • Y usaremos algunos complementos de soporte de Browserslist .

    1. Definición de navegadores modernos y heredados

    Primero, queremos dejar claro qué queremos decir con navegadores "modernos" y "heredados". Para facilitar el mantenimiento y las pruebas, es útil dividir los navegadores en dos grupos discretos: agregar navegadores que requieren poco o ningún polyfilling o transpilación a nuestra lista moderna y colocar el resto en nuestra lista heredada. Guias y Trucos tecnologicos

    Navegadores que admiten ES6+, nuevos atributos CSS y API de navegador como Promises y Fetch. ( Ver versión grande )

    Una configuración de Browserslist en la raíz de su proyecto puede almacenar esta información. Las subsecciones "Entorno" se pueden utilizar para documentar los dos grupos de navegadores, así:

    [modern]Firefox = 53Edge = 15Chrome = 58iOS = 10.1[legacy] 1%

    La lista que se proporciona aquí es sólo un ejemplo y se puede personalizar y actualizar según los requisitos de su sitio web y el tiempo disponible. Esta configuración actuará como fuente de verdad para los dos conjuntos de paquetes de interfaz de usuario que crearemos a continuación: uno para los navegadores modernos y otro para todos los demás usuarios.

    2. Transpilación y polillenado de ES6+

    Para transpilar nuestro JavaScript de manera respetuosa con el medio ambiente, usaremos babel-preset-env.

    Inicialicemos un .babelrcarchivo en la raíz de nuestro proyecto con esto:

    { "presets": [ ["env", { "useBuiltIns": "entry"}] ]}

    Habilitar la useBuiltInsbandera permite a Babel rellenar selectivamente las funciones integradas que se introdujeron como parte de ES6+. Debido a que filtra los polirellenos para incluir solo los requeridos por el medio ambiente, mitigamos el costo de envío babel-polyfillen su totalidad.

    Para que esta bandera funcione, también necesitaremos importar babel-polyfillen nuestro punto de entrada.

    // Inimport "babel-polyfill";

    Al hacerlo, se reemplazará la babel-polyfillimportación grande con importaciones granulares, filtradas por el entorno del navegador al que nos dirigimos.

    // Transformed outputimport "core-js/modules/es7.string.pad-start";import "core-js/modules/es7.string.pad-end";import "core-js/modules/web.timers";…

    3. Características de la plataforma web Polyfilling

    Para enviar polyfills para funciones de plataforma web a nuestros usuarios, necesitaremos crear dos puntos de entrada para ambos entornos:

     

    require('whatwg-fetch');require('es6-promise').polyfill();// … other polyfills

    Y esto:

    // polyfills for modern browsers (if any)require('intersection-observer');

    Este es el único paso de nuestro flujo que requiere cierto grado de mantenimiento manual. Podemos hacer que este proceso sea menos propenso a errores agregando eslint-plugin-compat al proyecto. Este complemento nos advierte cuando utilizamos una función del navegador que aún no se ha completado.

    4. Prefijo CSS

    Finalmente, veamos cómo podemos reducir los prefijos CSS para navegadores que no lo requieren. Debido a que autoprefixerfue una de las primeras herramientas en el ecosistema que admitió la lectura de un browserslistarchivo de configuración, no tenemos mucho que hacer aquí.

    Debería ser suficiente crear un archivo de configuración PostCSS simple en la raíz del proyecto:

    module.exports = { plugins: [ require('autoprefixer') ],}

    Poniendolo todo junto

    Ahora que hemos definido todas las configuraciones de complementos requeridas, podemos armar una configuración de paquete web que las lea y genere dos compilaciones dist/moderny dist/legacycarpetas separadas.

    const MiniCssExtractPlugin = require('mini-css-extract-plugin')const isModern = process.env.BROWSERSLIST_ENV === 'modern'const buildRoot = path.resolve(__dirname, "dist")module.exports = { entry: [ isModern ? './polyfills.modern.js' : './polyfills.legacy.js', "./main.js" ], output: { path: path.join(buildRoot, isModern ? 'modern' : 'legacy'), filename: 'bundle.[hash].js', }, module: { rules: [ { test: /.jsx?$/, use: "babel-loader" }, { test: /.css$/, use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader'] } ]}, plugins: { new MiniCssExtractPlugin(), new HtmlWebpackPlugin({ template: 'index.hbs', filename: 'index.html', }), },};

    Para terminar, crearemos algunos comandos de compilación en nuestro package.jsonarchivo:

    "scripts": { "build": "yarn build:legacy yarn build:modern", "build:legacy": "BROWSERSLIST_ENV=legacy webpack -p --config webpack.config.js", "build:modern": "BROWSERSLIST_ENV=modern webpack -p --config webpack.config.js"}

    Eso es todo. La ejecución yarn buildahora debería darnos dos compilaciones, que son equivalentes en funcionalidad.

    Ofreciendo el paquete adecuado a los usuarios

    Crear compilaciones separadas nos ayuda a lograr solo la primera mitad de nuestro objetivo. Todavía necesitamos identificar y ofrecer el paquete adecuado a los usuarios.

    ¿Recuerda la configuración de Browserslist que definimos anteriormente? ¿No sería bueno si pudiéramos usar la misma configuración para determinar en qué categoría cae el usuario?

    Ingrese browserslist-useragent . Como sugiere el nombre, browserslist-useragentpuede leer nuestra browserslistconfiguración y luego hacer coincidir un agente de usuario con el entorno relevante. El siguiente ejemplo demuestra esto con un servidor Koa:

     

    const Koa = require('koa')const app = new Koa()const send = require('koa-send')const { matchesUA } = require('browserslist-useragent')var router = new Router()app.use(router.routes())router.get('/', async (ctx, next) = { const useragent = ctx.get('User-Agent') const isModernUser = matchesUA(useragent, { env: 'modern', allowHigherVersions: true, }) const index = isModernUser ? 'dist/modern/index.html', 'dist/legacy/index.html' await send(ctx, index);});

    Aquí, establecer la allowHigherVersionsbandera garantiza que si se lanzan versiones más nuevas de un navegador (aquellas que aún no forman parte de la base de datos de Can I Use), seguirán reportándose como veraces para los navegadores modernos.

    Una de browserslist-useragentlas funciones de es garantizar que se tengan en cuenta las peculiaridades de la plataforma al hacer coincidir los agentes de usuario. Por ejemplo, todos los navegadores en iOS (incluido Chrome) usan WebKit como motor subyacente y se relacionarán con la consulta de lista de navegadores específica de Safari respectiva.

    Puede que no sea prudente confiar únicamente en la exactitud del análisis del agente de usuario en producción. Al recurrir al paquete heredado para navegadores que no están definidos en la lista moderna o que tienen cadenas de agentes de usuario desconocidas o no analizables, nos aseguramos de que nuestro sitio web siga funcionando.

    Conclusión: ¿Vale la pena?

    Hemos logrado cubrir un flujo de extremo a extremo para enviar paquetes sin hinchazón a nuestros clientes. Pero es razonable preguntarse si los gastos de mantenimiento que esto añade a un proyecto valen sus beneficios. Evaluemos los pros y los contras de este enfoque:

    1. Mantenimiento y pruebas

    Se requiere uno para mantener solo una única configuración de Browserslist que impulse todas las herramientas en este proceso. La actualización de las definiciones de los navegadores modernos y heredados se puede realizar en cualquier momento en el futuro sin tener que refactorizar las configuraciones o el código de soporte. Yo diría que esto hace que los gastos generales de mantenimiento sean casi insignificantes.

    Sin embargo, existe un pequeño riesgo teórico asociado con confiar en Babel para producir dos paquetes de código diferentes, cada uno de los cuales debe funcionar bien en su entorno respectivo.

    Si bien los errores debidos a diferencias en los paquetes pueden ser poco frecuentes, monitorear estas variantes en busca de errores debería ayudar a identificar y mitigar eficazmente cualquier problema.

    2. Tiempo de construcción versus tiempo de ejecución

    A diferencia de otras técnicas que prevalecen en la actualidad, todas estas optimizaciones ocurren en el momento de la compilación y son invisibles para el cliente.

    3. Velocidad progresivamente mejorada

    La experiencia de los usuarios de los navegadores modernos se vuelve significativamente más rápida, mientras que los usuarios de los navegadores antiguos siguen recibiendo el mismo paquete que antes, sin consecuencias negativas.

    4. Utilizar las funciones modernas del navegador con facilidad

    A menudo evitamos el uso de nuevas funciones del navegador debido al tamaño de los polyfills necesarios para utilizarlas. A veces, incluso elegimos polyfills más pequeños que no cumplen con las especificaciones para ahorrar tamaño. Este nuevo enfoque nos permite utilizar polyfills que cumplan con las especificaciones sin preocuparnos mucho de afectar a todos los usuarios.

    Paquete diferencial que sirve en producción

    Dadas las importantes ventajas, adoptamos este proceso de construcción al crear una nueva experiencia de pago móvil para los clientes de Urban Ladder, uno de los minoristas de muebles y decoración más grandes de la India.

    En nuestro paquete ya optimizado, pudimos obtener ahorros de aproximadamente el 20% en los recursos CSS y JavaScript con Gzip enviados por cable a los usuarios móviles modernos. Debido a que más del 80% de nuestros visitantes diarios utilizaban estos navegadores permanentes, el esfuerzo realizado valió la pena.

    Recursos adicionales

    • “ Cargar Polyfills sólo cuando sea necesario ”, Philip Walton
    • @babel/preset-env
      Un ajuste preestablecido de Babel inteligente
    • Browserslist “Herramientas”
      Ecosistema de complementos creados para Browserslist
    • ¿Puedo utilizar
      la tabla de cuota de mercado actual del navegador?

    (dm, ra, yk, il, al)Explora más en

    • Navegadores
    • Actuación
    • javascript
    • Herramientas





    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

    Paquete inteligente: cómo entregar código heredado solo a navegadores heredados

    Paquete inteligente: cómo entregar código heredado solo a navegadores heredados

    SmashingConf UX y diseño, Amberes 2024 Taller de diseño conductual, con Susan y Guthrie Weinschenk Índice

    programar

    es

    https://aprendeprogramando.es/static/images/programar-paquete-inteligente-como-entregar-codigo-heredado-solo-a-navegadores-heredados-936-0.jpg

    2024-05-20

     

    Paquete inteligente: cómo entregar código heredado solo a navegadores heredados
    Paquete inteligente: cómo entregar código heredado solo a navegadores heredados

    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

     

     

    Top 20