Búsqueda de sitios web

reactjs - ¿Qué significa tener múltiples instancias de React?


Para contexto: Me he encontrado con un problema en mi aplicación React (usando npm + Create React App + TypeScript) donde parece que tengo más de una copia de React en la aplicación. Esto se basa en un fragmento de diagnóstico dado en la documentación de React donde se prueba que window.React1 === window.React2.

Esta pregunta no está pidiendo soluciones para arreglar eso (lo investigaré por separado). En cambio, me gustaría saber qué significa tener duplicados de una biblioteca. ¿Cómo termina eso entregándose al navegador como parte del gran script combinado que genera CRA, y qué duplicado se selecciona cuando escribo import React from 'react' en el código fuente? ¿Cómo podrían ocurrir bibliotecas duplicadas y por qué npm permite esto?

La respuesta podría ser, "ve y aprende cómo funciona la gestión de paquetes y el empaquetado en JS", lo cual podría ser muy razonable, pero si alguien tuviera alguna respuesta específica y referencias a más recursos para aprender, estaría muy agradecido. Gracias de antemano.

Respuesta #1

Primero, vamos a declarar claramente lo que una biblioteca duplicada puede significar en este contexto. Si descomprimieras tu proyecto empaquetado, podrías encontrar múltiples versiones de React, por ejemplo, 16 y 17. Este es un buen marco de referencia para tener en cuenta durante el resto de la discusión.

Aunque la mayoría de las veces, este tipo de duplicación es un error, hay casos en los que esto puede ser deseable. Cubramos eso primero antes de llegar a tu caso específico.

Un buen ejemplo de dónde esto puede ser beneficioso son los grandes equipos de desarrollo distribuidos que utilizan algo similar a la arquitectura de micro frontends. Explicado brevemente, dos equipos podrían ser responsables de dos partes diferentes de la página con su propio conjunto de dependencias, sin afectar al otro:

 ┌───────────────────────────┐
 │          Webpage          │
 │ ┌──────────┐ ┌──────────┐ │
 │ │ React 16 │ │ React 17 │ │
 │ └──────────┘ └──────────┘ │
 └───────────────────────────┘

Aunque esto pueda parecer un desperdicio de espacio, el equipo de desarrollo ha hecho una compensación aquí: tienen una carga de página ligeramente mayor, pero reducen la necesidad de sincronización entre equipos con respecto a las versiones. Tal vez un equipo esté listo para usar la última versión, pero el otro todavía necesita trabajar antes de estar listo para actualizar. Otro buen ejemplo es el código heredado: puede que tengas código que funcione bien, pero que no se mantiene, por lo que eliges simplemente enviarlo tal como está mientras funcione:

 ┌──────────────────────────────┐
 │           Webpage            │
 │ ┌───────────┐ ┌────────────┐ │
 │ │ Angular 1 │ │ Angular 10 │ │
 │ └───────────┘ └────────────┘ │
 └──────────────────────────────┘

Con suerte, lo anterior ilustra por qué configuraciones como esta son permitidas por el gestor de paquetes: pueden ser deseables y, en algunos casos, muy beneficiosas.

La forma en que esto se puede configurar varía tanto como los diferentes tipos de configuraciones de proyectos, pero uno de los enfoques para lo anterior es tener subproyectos de algún tipo, cada uno con su propio package.json:

project
├─ package.json
├─ one subproject
│  └─ package.json
└─ another subproject
   └─ package.json

En el caso anterior, las importaciones en un subproyecto se configurarían para resolverse mediante el package.json de esa carpeta, y las importaciones en otro subproyecto se configurarían para resolverse mediante su package.json. Una forma común de configurar la resolución de módulos es a través de la configuración resolve de Webpack, pero por supuesto, son posibles otros enfoques.

Con suerte, lo anterior explica por qué esto es posible, así como algunas pistas sobre cuándo podría ser una buena consideración.

Como se mencionó antes, sin embargo, la mayoría de las veces esto es un error. La mayoría de los usuarios no quieren hacer esto intencionalmente, y incluir la misma librería con diferencias mínimas, por ejemplo React 17.0.0 y React 17.0.1, no es lo que pretendían hacer. Para el caso de uso común, los dos anteriores deberían ser prácticamente intercambiables.

Hay varias formas de terminar con este problema, pero la más común es una configuración incorrecta de las dependencias pares. Las dependencias pares son una manera para que las bibliotecas, paquetes de componentes, etc., especifiquen de qué dependen, mientras permiten que la dependencia sea compartida. Un ejemplo común sería una biblioteca de componentes de UI que soporta cualquier versión de React siempre que sea más nueva que, digamos, React 16. Si tu proyecto usa React 17, entonces puedes incorporar felizmente esa biblioteca de componentes y tener una única versión de React en tu base de código.

El error ocurre cuando el autor de la biblioteca (involuntariamente) configura la dependencia de React 16 como una dependencia regular, no como una dependencia entre pares. En ese caso, el autor está esencialmente diciendo que la biblioteca necesita React 16 y no permite nada más, y terminarías con dos versiones de React instaladas.

Todo lo anterior es muy general y pasa por alto muchos detalles, pero con suerte esto te da algo de comprensión sobre el problema que estás resolviendo.

Artículos relacionados