Publica, instala y envía JavaScript moderno para aplicaciones más rápidas

Activa las dependencias y los resultados modernos de JavaScript para mejorar el rendimiento.

Más del 90% de los navegadores son capaces de ejecutar JavaScript moderno, pero la la prevalencia de JavaScript heredado sigue siendo una gran fuente de problemas de rendimiento en la Web hoy en día.

JavaScript moderno

JavaScript moderno no se caracteriza por ser código escrito en un ECMAScript específico específica, sino más bien en una sintaxis compatible con todas las navegadores. Los navegadores web modernos como Chrome, Edge, Firefox y Safari conforman más del 90% del mercado de navegadores los diferentes navegadores que dependen de los mismos motores de renderización subyacentes conforman una un 5% adicional. Esto significa que el 95% del tráfico web global proviene de navegadores que admiten las funciones del lenguaje JavaScript más usadas de las últimas 10 años, como las siguientes:

  • Clases (ES2015)
  • Funciones de flecha (ES2015)
  • Generadores (ES2015)
  • Alcance de bloques (ES2015)
  • Desestructuración (ES2015)
  • Parámetros de reposo y propagación (ES2015)
  • abreviación del objeto (ES2015)
  • Async/await (ES2017)

Por lo general, las funciones de las versiones más recientes de la especificación de lenguaje tienen menos compatibilidad coherente en todos los navegadores modernos. Por ejemplo, muchos ES2020 y ES2021 Las funciones solo están disponibles en el 70% del mercado de los navegadores; aun así, la mayoría de navegadores, pero no lo suficiente como para que sea seguro confiar directamente en esas funciones. Esta significa que, aunque "moderno" JavaScript es un objetivo en movimiento, ES2017 tiene la más amplio rango de compatibilidad de navegadores y, al mismo tiempo, incluir la mayoría de las funciones de sintaxis modernas de uso general. En otras palabras, ES2017 es la opción más cercana a la sintaxis moderna en la actualidad.

JavaScript heredado

JavaScript heredado es un código que evita específicamente el uso del lenguaje anterior atributos. La mayoría de los desarrolladores escriben su código fuente usando sintaxis moderna, pero compilar todo en sintaxis heredada para aumentar la compatibilidad con los navegadores. Compilación a la sintaxis heredada aumenta la compatibilidad con el navegador; sin embargo, el efecto suele ser más pequeño de lo que creemos. En muchos casos, la asistencia aumenta de alrededor del 95%. al 98% y, al mismo tiempo, generar un costo significativo:

  • El JavaScript heredado suele ser alrededor de un 20% más grande y más lento que código moderno equivalente. Deficiencias en las herramientas y configuración incorrecta frecuente ampliar esta brecha aún más.

  • Las bibliotecas instaladas representan hasta el 90% de la producción típica. Código JavaScript. El código de biblioteca genera un JavaScript heredado aún más alto. sobrecarga debido a la duplicación de polyfill y de ayuda que podría evitarse mediante la publicación de código moderno.

JavaScript moderno en npm

Recientemente, Node.js estandarizó un campo "exports" para definir puntos de entrada para un paquete:

{
  "exports": "./index.js"
}

Los módulos a los que hace referencia el campo "exports" implican una versión de nodo de al menos 12.8, que es compatible con ES2019. Esto significa que cualquier módulo al que se haga referencia con El campo "exports" se puede escribir en el código JavaScript moderno. Los consumidores de paquetes deben supongamos que los módulos con un campo "exports" contienen código moderno y transpila si necesario.

Solo moderno

Si quieres publicar un paquete con código moderno y dejarlo en manos de la consumidor para manejar la transpilación cuando lo usa como dependencia; utiliza solo la "exports".

{
  "name": "foo",
  "exports": "./modern.js"
}

Moderno con resguardo heredado

Usa el campo "exports" junto con "main" para publicar tu paquete con código moderno, pero también se incluye un resguardo ES5 + CommonJS de respaldo navegadores.

{
  "name": "foo",
  "exports": "./modern.js",
  "main": "./legacy.cjs"
}

Moderno con resguardo heredado y optimizaciones de agrupador de ESM

Además de definir un punto de entrada de CommonJS de resguardo, el campo "module" puede usarse para apuntar a un paquete de resguardo heredado similar, pero que Sintaxis del módulo de JavaScript (import y export)

{
  "name": "foo",
  "exports": "./modern.js",
  "main": "./legacy.cjs",
  "module": "./module.js"
}

Muchos agrupadores, como webpack y Rollup, dependen de este campo para aprovechar la ventaja. de funciones del módulo y permitir movimiento de árboles. Este es un paquete heredado que no contiene ningún código moderno, excepto import/export, así que usa este enfoque para enviar código moderno con una de resguardo heredado que aún está optimizado para la agrupación.

JavaScript moderno en aplicaciones

Las dependencias de terceros conforman la gran mayoría de la producción típica. Código JavaScript en aplicaciones web. Aunque, históricamente, las dependencias de npm una sintaxis de ES5 heredada, esto ya no es una suposición segura y corre el riesgo de que las actualizaciones de dependencias afecten la compatibilidad del navegador con tu aplicación.

Con una cantidad cada vez mayor de paquetes de npm que se trasladan al JavaScript moderno, es importante asegurarse de que las herramientas de compilación estén configuradas para manejarlos. Hay un hay buenas probabilidades de que algunos de los paquetes de npm de los que dependes ya usen entornos de lenguaje comunes. Hay una serie de opciones disponibles para usar código moderno de npm sin dañar tu aplicación en navegadores antiguos, pero la idea es hacer que el sistema de compilación transpila las dependencias a la misma sintaxis objetivo como tu código fuente.

webpack

A partir del paquete web 5, es posible configurar la sintaxis que utilizará el webpack. cuando se genera código para paquetes y módulos. Esto no transpila tus código o dependencias, solo afecta la “unión” que generó webpack. Para especificar el destino de compatibilidad del navegador, agrega un Configuración de la lista de navegadores a tu proyecto o hacerlo directamente en la configuración de webpack:

module.exports = {
  target: ['web', 'es2017'],
};

También se puede configurar webpack para generar paquetes optimizados que omitir las funciones de wrapper innecesarias cuando se oriente a los módulos ES modernos en un entorno de nube. También configura webpack para cargar paquetes divididos de código con <script type="module">

module.exports = {
  target: ['web', 'es2017'],
  output: {
    module: true,
  },
  experiments: {
    outputModule: true,
  },
};

Hay varios complementos disponibles de webpack que permiten compilar y publicar JavaScript moderno sin dejar de admitir navegadores heredados como Optimize y BabelEsmPlugin.

Complemento Optimize

El complemento Optimize es un paquete web complemento que transforma el paquete final del código de JavaScript moderno a heredado en lugar de cada archivo de origen individual. Es una configuración independiente que le permite tu configuración de webpack para asumir que todo es JavaScript moderno sin una ramificación especial para varias salidas o sintaxis.

Como el complemento Optimize opera en paquetes en lugar de módulos individuales, procesa el código de tu aplicación y tus dependencias por igual. Esto hace que usar dependencias modernas de JavaScript de npm, ya que su código se agrupar y transpilar a la sintaxis correcta. También puede ser más rápido que soluciones tradicionales que implican dos pasos de compilación y que, al mismo tiempo, generan paquetes independientes para los navegadores modernos y los heredados. Los dos conjuntos de paquetes se diseñada para cargarse con el patrón módulo/nomódulo

// webpack.config.js
const OptimizePlugin = require('optimize-plugin');

module.exports = {
  // ...
  plugins: [new OptimizePlugin()],
};

Optimize Plugin puede ser más rápido y eficiente que un paquete web personalizado de configuraciones, que suelen agrupar el código moderno y el heredado por separado. Integra también controla la ejecución de Babel por ti y reduce paquetes que usen Terser con una configuración óptima independiente para los resultados modernos y heredados. Por último, los polyfills que necesita el objeto los paquetes heredados se extraen en una secuencia de comandos dedicada, de manera que nunca se están duplicados o se cargan innecesariamente en navegadores más nuevos.

Comparación: transpilar módulos de origen dos veces frente a transpilar paquetes generados

BabelEsmPlugin

BabelEsmPlugin es un webpack. que funciona junto con @babel/preset-env para generar versiones modernas de paquetes existentes para enviar código menos transpilado navegadores modernos. Es la solución lista para usar más popular module/nomodule, que usan Next.js y CLI de Preact.

// webpack.config.js
const BabelEsmPlugin = require('babel-esm-plugin');

module.exports = {
  //...
  module: {
    rules: [
      // your existing babel-loader configuration:
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env'],
          },
        },
      },
    ],
  },
  plugins: [new BabelEsmPlugin()],
};

BabelEsmPlugin es compatible con una amplia variedad de configuraciones de webpack, ya que ejecuta dos compilaciones independientes de tu aplicación. La compilación dos veces puede tardar un un poco de tiempo extra para aplicaciones grandes; sin embargo, esta técnica permite BabelEsmPlugin para integrarse sin problemas a las configuraciones existentes de Webpack y lo convierte en una de las opciones más convenientes disponibles.

Cómo configurar babel-loader para transpilar node_modules

Si usas babel-loader sin uno de los dos complementos anteriores, haz lo siguiente: se requiere un paso importante para usar npm moderno de JavaScript módulos. Definir dos configuraciones de babel-loader independientes hace posible para compilar automáticamente las funciones modernas de lenguaje que se encuentran en node_modules para ES2017 sin dejar de transpilar tu código propio con la API de complementos y ajustes predeterminados definidos en la configuración de tu proyecto. Esto no generar paquetes modernos y heredados para la configuración de módulos/no módulos, pero sí posibilitan la instalación y el uso de paquetes npm que contengan JavaScript moderno sin dañar los navegadores anteriores.

webpack-plugin-modern-npm usa esta técnica para compilar dependencias de npm que tienen un campo "exports" en su package.json, ya que pueden contener sintaxis moderna:

// webpack.config.js
const ModernNpmPlugin = require('webpack-plugin-modern-npm');

module.exports = {
  plugins: [
    // auto-transpile modern stuff found in node_modules
    new ModernNpmPlugin(),
  ],
};

Como alternativa, puedes implementar la técnica manualmente en tu webpack configuración comprobando el campo "exports" en el package.json de módulos a medida que se resuelven. Omite el almacenamiento en caché para abreviar, una acción personalizada implementación podría verse de la siguiente manera:

// webpack.config.js
module.exports = {
  module: {
    rules: [
      // Transpile for your own first-party code:
      {
        test: /\.js$/i,
        loader: 'babel-loader',
        exclude: /node_modules/,
      },
      // Transpile modern dependencies:
      {
        test: /\.js$/i,
        include(file) {
          let dir = file.match(/^.*[/\\]node_modules[/\\](@.*?[/\\])?.*?[/\\]/);
          try {
            return dir && !!require(dir[0] + 'package.json').exports;
          } catch (e) {}
        },
        use: {
          loader: 'babel-loader',
          options: {
            babelrc: false,
            configFile: false,
            presets: ['@babel/preset-env'],
          },
        },
      },
    ],
  },
};

Cuando uses este enfoque, deberás asegurarte de que la sintaxis moderna sea compatible tu minificador. Ambos Terser y uglify-es tienes la opción de especificar {ecma: 2017} para preservarlos y, en algunos casos, generar sintaxis de ES2017 durante la compresión y el formateo.

Resumen

Rollup tiene compatibilidad integrada para generar varios conjuntos de paquetes como parte de en una sola compilación y genera código moderno de forma predeterminada. Como resultado, Rollup puede Debe configurarse para generar paquetes modernos y heredados con complementos oficiales. que probablemente ya estés utilizando.

@rollup/plugin-babel

Si utilizas Rollup, Método getBabelOutputPlugin() (proporcionadas por el equipo de complemento oficial de Babel) transforma el código en paquetes generados en lugar de módulos de origen individuales. Rollup tiene compatibilidad integrada para generar varios conjuntos de paquetes como parte de en una sola compilación, cada una con sus propios complementos. Puedes usar esto para producir paquetes diferentes para el diseño moderno y el heredado, ya que pasa cada uno por una Configuración del complemento de salida de Babel:

// rollup.config.js
import {getBabelOutputPlugin} from '@rollup/plugin-babel';

export default {
  input: 'src/index.js',
  output: [
    // modern bundles:
    {
      format: 'es',
      plugins: [
        getBabelOutputPlugin({
          presets: [
            [
              '@babel/preset-env',
              {
                targets: {esmodules: true},
                bugfixes: true,
                loose: true,
              },
            ],
          ],
        }),
      ],
    },
    // legacy (ES5) bundles:
    {
      format: 'amd',
      entryFileNames: '[name].legacy.js',
      chunkFileNames: '[name]-[hash].legacy.js',
      plugins: [
        getBabelOutputPlugin({
          presets: ['@babel/preset-env'],
        }),
      ],
    },
  ],
};

Herramientas de compilación adicionales

La fusión y el webpack son altamente configurables, lo que generalmente significa que cada proyecto debe actualizar su configuración, habilitar la sintaxis moderna de JavaScript en las dependencias. También hay herramientas de compilación de nivel superior que favorecen las convenciones y los valores predeterminados por sobre configuración, como Parcel, Snowpack, Vite y WMR. La mayoría de estas herramientas se da por sentado que las dependencias de npm pueden contener sintaxis moderna y las transpilarán a los niveles de sintaxis adecuados cuando compilas para la producción.

Además de los complementos dedicados para Webpack y Rollup, el lenguaje JavaScript moderno los paquetes con resguardos heredados se pueden agregar a cualquier proyecto usando devolución. La devolución es un independiente que transforma la salida de un sistema de compilación para producir de JavaScript, lo que permite que los paquetes y las transformaciones asuman un objetivo de salida.