Guía de Mejores Prácticas para J2CL de Google

Guía de Mejores Prácticas para J2CL de Google

Introducción

J2CL es una herramienta que convierte código Java a JavaScript, desarrollada y mantenida por Google. Como transpilador de Java a JavaScript, J2CL genera código JavaScript altamente optimizado mientras mantiene la semántica de Java. Este artículo explorará en profundidad las mejores prácticas de J2CL para que los desarrolladores puedan aprovechar al máximo sus capacidades.

Optimización del Rendimiento de Compilación

El rendimiento de compilación es un factor crucial para la eficiencia del desarrollo. En proyectos J2CL, recomendamos agregar un archivo de configuración .bazelrc en el directorio raíz del proyecto. Este archivo debe incluirse en el control de versiones para que miembros del equipo y sistemas de integración continua compartan la misma configuración de compilación.

La mejor práctica es usar el archivo .bazelrc del propio proyecto J2CL como punto de partida y ajustarlo según las necesidades del proyecto. Una configuración de compilación adecuada puede reducir significativamente el tiempo de compilación, especialmente en proyectos grandes.

Convenciones de Nomenclatura de Librerías

En proyectos J2CL, mantener una convención de nomenclatura consistente es esencial. Para la regla j2cl_library, se sugiere utilizar el mismo nombre que su java_library correspondiente, pero añadiendo el sufijo -j2cl. Esta práctica de nomenclatura ofrece las siguientes ventajas:

  1. Consistencia entre proyectos, facilitando la comprensión para los desarrolladores
  2. Las herramientas automatizadas pueden manejar mejor las dependencias
  3. Reduce la posibilidad de conflictos de nombres

Ejemplo:

java_library(
  name = "utilidades",
  deps = ":mi-dependencia",
)

j2cl_library(
  name = "utilidades-j2cl",
  deps = ":mi-dependencia-j2cl",
)

Implementación de Código Específico de Plataforma (Super Sourcing)

Una de las mayores ventajas de J2CL es que el código Java puede ejecutarse en múltiples plataformas. Sin embargo, a veces necesitamos proporcionar implementaciones diferentes para distintas plataformas (como Android y Web). La tecnología Super Sourcing nos permite ofrecer implementaciones alternativas para diferentes entornos.

Principios de Implementación

  1. No escribir implementaciones stub que fallen en tiempo de ejecución
  2. Proporcionar implementaciones completas que funcionen correctamente en la plataforma de destino
  3. Las API incompatibles deberían fallar en tiempo de compilación, no en tiempo de ejecución

Ejemplo de Implementación

Consideremos la implementación de una funcionalidad de registro: en JVM se envía a stdout, mientras que en el navegador se usa console.log.

Implementación Java original:

class Registro {
  public static void registrar(String mensaje) {
    System.out.println(obtenerHora() + " " + mensaje);
  }

  private static String obtenerHora() {
    return System.currentTimeMillis() + "";
  }
}

Implementación alternativa para J2CL (colocada en el directorio super-j2cl/):

class Registro {
  public static void registrar(String mensaje) {
    Consola.registrar(obtenerHora() + " " + mensaje);
  }

  private static String obtenerHora() {
    return new Fecha().obtenerTiempo() + "";
  }
}

Configuración de compilación:

java_library(
  name = "registro",
  srcs = [ "Registro.java", ],
)

j2cl_library(
  name = "registro-j2cl",
  srcs = [ "super-j2cl/Registro.java" ],
)

Anotación @GwtIncompatible

La anotación @GwtIncompatible se utiliza para eliminar elementos específicos (clases, métodos, miembros, etc.) del código. Se eliminará antes de la compilación J2CL las partes no compatibles.

Sugerencias de uso:

  1. Explicar el motivo en la anotación, por ejemplo: @GwtIncompatible("java.lang.Thread no está disponible en web")
  2. Evitar su uso en la lógica de la aplicación para deshabilitar rutas de código específicas
  3. Priorizar la refactorización del código, abstrayendo las partes incompatibles en lugar de simplemente deshabilitarlas

Tamaño del Código y Rendimiento en Tiempo de Ejecución

Optimizaciones del Compilador Closure

Una de las principales ventajas de J2CL es su integración estrecha con el compilador Closure. Mediante el uso de J2CL_OPTIMIZED_DEFS se pueden habilitar todas las optimizaciones avanzadas:

load("//build_defs:reglas.bzl", "J2CL_OPTIMIZED_DEFS")

closure_js_binary(
    name = "aplicacion_j2cl_optimizada",
    defs = J2CL_OPTIMIZED_DEFS,
    deps = [":lib_js"],
)

Configuración del Tiempo de Ejecución JRE

J2CL ofrece varias opciones de configuración JRE para optimizar el tamaño del código y el rendimiento:

  1. Nivel de verificación en tiempo de ejecución:
  • Controlado mediante --define=jre.checks.checkLevel
  • Valores opcionales: NORMAL (predeterminado), OPTIMIZED, MINIMAL
  • Diferentes niveles eliminan tipos específicos de verificaciones en tiempo de ejecución
  1. Eliminación de metadatos de clase:
  • Controlado mediante --define=jre.classMetadata
  • Valores opcionales: SIMPLE, STRIPPED
  • Después de la eliminación, se remueven metadatos relacionados con la clase, afectando la reflexión
  1. Nivel de registro:
  • Controlado mediante --define=jre.logging.logLevel
  • Valores opcionales: OFF, SEVERE, WARNING, INFO, ALL
  • En entornos de producción, se pueden deshabilitar los registros para reducir el tamaño del código

Eliminación Personalizada de Código

Los desarrolladores pueden implementar eliminación personalizada de código en tiempo de compilación:

  1. Definir configuración en JavaScript:
const {agregarPropiedadSistemaDesdeGoogDefine} = goog.require('jre');
const configuracion = goog.define('mi.definicion', 'NO');
agregarPropiedadSistemaDesdeGoogDefine('mi.definicion', configuracion);

  1. Usar en Java:
if (System.getProperty("mi.definicion") == "SI") {
  // Código condicional
}

  1. Configuración de compilación:
closure_js_binary(
    name = "aplicacion_j2cl_optimizada",
    defs = ["--define=mi.definicion=SI"] + J2CL_OPTIMIZED_DEFS,
    deps = [":lib_js"],
)

Recomendaciones de Gestión de Dependencias

Al introducir librerías Java en proyectos J2CL, es necesario tener especial atención:

  1. Utilizar con precaución librerías grandes (como Guava), ya que pueden aumentar significativamente el tamaño del código
  2. Prestar atención al impacto de las herramientas de generación de código (como Dagger) en el tiempo de compilación y el tamaño del código
  3. AutoValue es una excepción, J2CL tiene optimizaciones especiales para él

Recuerde, está escribiendo código que se ejecutará en un navegador, ¡el tamaño del código afecta directamente la experiencia del usuario!

Conclusión

J2CL ofrece a los desarrolladores Java capacidades de plataforma cruzada poderosas, pero para aprovechar al máximo sus ventajas, es necesario seguir estas mejores prácticas. Desde la configuración de compilación hasta la organización del código, desde la optimización del rendimiento hasta la gestión de dependencias, cada aspecto requiere un diseño cuidadoso. Esperamos que esta guía ayude a lograr mejores resultados en sus proyectos J2CL.

Etiquetas: J2CL transpilador Java-JavaScript Google Closure optimización de código desarrollo web multiplataforma

Publicado el 6-9 02:34