Estoy trabajando en la herramienta de línea de comandos npm y el paquete https://github.com/ecma-make/ecmake . Me encontré con un extraño conflicto entre una versión del paquete instalada globalmente y localmente.
Puedo evitar este conflicto vinculando uno contra la biblioteca del otro. Entonces solo hay una instancia de la biblioteca y no hay conflicto. Ahora tengo que pensar en el usuario, que instala el paquete en ambos lugares, una vez globalmente para poder ejecutar el comando sin el prefijo npx , una vez localmente para que la biblioteca aparezca en la sección de desarrollo de package.json .
# prepare test fixture mkdir ecmakeTest cd ecmakeTest/ npm init -y # install globally npm install -g @ecmake/ecmake@0.3.1 npm ls -g @ecmake/ecmake # install locally npm install --save-dev @ecmake/ecmake@0.3.1 npm ls @ecmake/ecmake # init ecmakeCode.js npx ecmake --init # run with local lib => shows the expected behaviour npx ecmake all # run with global lib => NoRootTaskError ecmake all El seguimiento de la pila nos guía a la línea dentro de la instalación global: /usr/local/lib/node_modules/@ecmake/ecmake/lib/runner/reader.js:21:13 .
if (!(root instanceof Task)) { throw new Reader.NoRootTaskError(this.makefile); } La root del objeto creada con la biblioteca local se comparó con la definición de clase de la biblioteca global. Tienen el mismo código pero son copias diferentes del mismo código.
El ecmake runner global requiere el archivo MAKE local ecmakeCode.js . Este archivo, a su vez, requiere la definición de Task de la biblioteca local.
const root = module.exports = require('@ecmake/ecmake').makeRoot(); root.default .described('defaults to all') .awaits(root.all); [...]Podemos verificar que en realidad ambas bibliotecas han sido llamadas poniendo una instrucción de registro en ambas.
Gulp y Grunt exportan una función que toma la dependencia real por inyección. Mientras que la inyección de dependencia es generalmente muy inteligente, en este caso no es tan bonita. Todo el archivo se envuelve. Me gustaría evitar esta función de ajuste.
Consulte: https://gulpjs.com/docs/en/getting-started/quick-start#create-a-gulpfile
Ver: https://gruntjs.com/getting-started
El corredor podría verificar primero, si existe tal conflicto. En caso de que pueda delegar los argumentos dados a ecmake global a npx ecmake local ejecutando un proceso secundario.
Por desgracia, esto retrasaría al corredor. Se requiere al menos un subproceso, tal vez más para verificar la situación.
¿Tiene una solución general para abordar este desafío (aparte de las que ya nombré con sus desventajas)?
Como primera parte de mi propia respuesta, investigo por qué es poco probable una solución canónica. Después de la fecha límite de la recompensa, agregaré algunas estrategias para encontrar una solución.
El archivo MAKE crea un modelo de datos. El corredor carga e inspecciona este modelo de datos y ejecuta las instrucciones almacenadas en él. Tanto el corredor como el modelo de datos necesitan una biblioteca. Hay una instalación global de npm y otra local . Esto ya da cuatro combinaciones posibles.
El corredor ecmake proporciona una opción --base directory modelada make partir de la herramienta de creación original. El significado es "cambiar al directorio nombrado antes de hacer nada". Esto le da un segundo lugar a una biblioteca local. Estamos en tres por tres combinaciones.
Voy a nombrar varias estrategias de solución. Combinando todo esto, hay decenas de opciones más o menos razonables. Esto hace que una respuesta canónica sea poco probable. No obstante, los desafíos fundamentales de este ejemplo generalmente se aplican a muchas herramientas de línea de comandos.
Las respuestas que abordan con precisión las preguntas originales son aquellas estrategias, que desacoplan el modelo y el corredor o que tengan cuidado, que solo se llame a una instancia de la biblioteca.
La vida real no responde a las preguntas exactamente. En el caso de ecmake la búsqueda de soluciones planteó limitaciones adicionales. Quiero asegurarme de que las versiones del modelo y el corredor coincidan con la versión principal, contra la cual se codificó el archivo MAKE . Los conflictos de versión en los cambios de versión importantes deben evitarse de antemano.
Por lo tanto, el archivo MAKE debe incluirse con la versión adecuada en package.json . Si solo hay una instalación global, debería intentar ejecutarse, pero se debería dar una advertencia de que falta una instalación local.
Para venir después de la fecha límite de la recompensa.