Documentación
/

Solución de problemas

/

Evitar colisiones de identificadores

Evitar colisiones de identificadores entre archivos ofuscados

Cuando varios archivos ofuscados con VM acaban en el mismo bundle, pueden declarar el mismo identificador de nivel superior y hacer que la página falle al analizar el código. Aquí se explica por qué ocurre y cómo solucionarlo.

El síntoma

Tu build se ejecuta sin problemas, pero el navegador lanza un error al analizar el código, antes de que arranque la aplicación:

Text

Para ver cuántos chunks declaran el nombre que aparece en el error, cuenta los archivos que contienen una declaración de él:

Text

-l muestra cada archivo coincidente una sola vez y -w solo encuentra palabras completas, así que vmdX no se cuenta. var queda fuera porque repetir una declaración var no es un error por sí solo. Un resultado mayor que 1 significa que el nombre se declara en más de un chunk. Sustituye vmd por el nombre de tu mensaje de error.

Las colisiones de identificadores solo importan cuando las declaraciones comparten ámbito. Que el mismo nombre se repita en módulos o closures separados no demuestra una colisión; el error de análisis anterior sí.

Por qué ocurre

Los preajustes de VM usan mangled-shuffled como Identifier Names Generator. Recorre un alfabeto pequeño en un orden barajado y, con la ofuscación VM, cada variable global renombrada recibe el prefijo vm (el identifiersPrefix predeterminado). El orden barajado se guarda en caché por proceso, así que los archivos ofuscados en el mismo proceso, o con el mismo seed fijo, toman nombres de la misma secuencia: la primera variable global de cada archivo comparte nombre, la segunda comparte otro, y así sucesivamente.

Cada archivo se ofusca de forma independiente y el generador vuelve a empezar desde el principio de su secuencia en cada uno. Cuando dos archivos acaban en el mismo ámbito, los nombres colisionan. Dos declaraciones const vmd = … de nivel superior quedan en el mismo ámbito y el analizador rechaza la segunda.

Las opciones que introducen más identificadores de nivel superior aumentan la probabilidad de que dos archivos lleguen al mismo nombre generado. vmWrapTopLevelInitializers es una de ellas, y todos los preajustes VM ya la activan; opciones como vmDynamicOpcodes o vmBytecodeEncoding añaden más.

Soluciones

Es preferible agrupar primero y después ofuscar el bundle una sola vez. Si ofuscas por separado y los scripts comparten un ámbito global, elige una de las siguientes opciones:

  • Activa randomIdentifiersPrefix (recomendado)

    Cada ejecución de la ofuscación obtiene un prefijo aleatorio que se antepone a todos los identificadores globales (con la ofuscación VM sustituye al prefijo vm por defecto). Los nombres de archivos distintos ya no comparten espacio de nombres, así que las colisiones desaparecen sin que tengas que coordinar los prefijos a mano.

  • Define un identifiersPrefix único por archivo

    Pasa manualmente un prefijo distinto al ofuscar cada archivo (por ejemplo, identifiersPrefix: 'auth_' para uno y checkout_ para otro). Es eficaz, pero propenso a errores si tienes muchos archivos; es preferible la opción aleatoria anterior.

    JavaScript

  • Cambia identifierNamesGenerator a hexadecimal

    Los nombres hexadecimales usan un espacio de claves mucho mayor, así que es mucho menos probable que dos archivos produzcan el mismo identificador, aunque la unicidad no está garantizada. Contrapartida: los identificadores son más largos que la salida de mangled-shuffled, por lo que el bundle es algo mayor.

  • Usa la interfaz de lotes de varios archivos o revisa tu plugin del bundler

    El panel añade un prefijo distinto por archivo cuando usas la ofuscación por lotes de varios archivos, disponible en los planes de pago. Si usas un plugin del bundler, verifica su comportamiento en lugar de suponer que hace lo mismo. Si configuras la ofuscación manualmente con la API de npm, tienes que activar un prefijo tú mismo.

Para verificar la solución, vuelve a generar y a cargar la aplicación combinada y confirma que el SyntaxError ha desaparecido. El nombre del mensaje de error anterior ya no debería declararse en más de un chunk; un prefijo cambia todos los nombres generados, así que el grep anterior solo te informa de ese nombre concreto, no de los nuevos.

Opciones relacionadas