node.js - mac - npm version
¿Cuál es la diferencia entre las dependencias, devDependencies y peerDependencies en el archivo npm package.json? (10)
Esta documentación responde mi pregunta muy mal. No entendí esas explicaciones. ¿Alguien puede decir en palabras más simples? Tal vez con ejemplos si es difícil elegir palabras simples?
EDIT también agregó peerDependencies
, que están estrechamente relacionadas y podrían causar confusión.
Como ejemplo, mocha normalmente sería una dependencia de Dev, ya que las pruebas no son necesarias en producción, mientras que Express sería una dependencia.
Cuando intente distribuir un paquete npm, debe evitar el uso de dependencies
. En su lugar, debe considerar agregarlo a peerDependencies
o eliminarlo de las dependencies
.
Hay algunos módulos y paquetes solo necesarios para el desarrollo, que no son necesarios en la producción. Como lo dice en la documentation :
Si alguien está planeando descargar y usar su módulo en su programa, entonces probablemente no quieran o necesiten descargar y crear la prueba externa o el marco de documentación que utiliza. En este caso, es mejor enumerar estos elementos adicionales en un hash devDependencies.
Me gustaría añadir a la respuesta mi opinión sobre estas explicaciones de dependencias.
-
dependencies
se usan para el uso directo en su base de código, cosas que generalmente terminan en el código de producción o trozos de código. -
devDependencies
se utilizan para el proceso de compilación, herramientas que lo ayudan a administrar cómo terminará el código final, módulos de prueba de terceros (por ejemplo, paquete web)
Para guardar un paquete en package.json como dependencias de desarrollo:
npm install "$package" --save-dev
Cuando ejecute npm install
, instalará devDependencies
y dependencies
. Para evitar instalar devDependencies
ejecute:
npm install --production
Resumen de las diferencias de comportamiento importantes:
dependencies
se instalan tanto en:-
npm install
desde un directorio que contienepackage.json
-
npm install $package
en cualquier otro directorio
-
devDependencies
son:- también se instala en
npm install
en un directorio que contienepackage.json
, a menos que pase la marca --production (suba la respuesta de Gayan Charith ). - no está instalado en
npm install "$package"
en cualquier otro directorio, a menos que le dé la opción--dev
. - no se instalan transitivamente.
- también se instala en
- antes de 3.0: siempre se instalan si faltan, y genera un error si diferentes dependencias usarían versiones incompatibles de la dependencia.
- se espera que comience en 3.0 (no probado): dé una advertencia si falta en la
npm install
, y tendrá que resolver la dependencia manualmente. Cuando se ejecuta, si falta la dependencia, aparece un error (mencionado por @nextgentech )
Transitividad (mencionada por Ben Hutchison ):
dependencies
se instalan de forma transitiva: si A requiere B, y B requiere C, entonces C se instala, de lo contrario B no podría funcionar, y tampoco lo haría A.devDependencies
no se instalan transitivamente. Por ejemplo, no necesitamos probar B para probar A, por lo que las dependencias de prueba de B pueden omitirse.
Opciones relacionadas no discutidas aquí:
-
bundledDependencies
que se analiza en la siguiente pregunta: Ventajas de bundledDependencies sobre las dependencias normales en NPM -
optionalDependencies
(mencionadas por Aidan Feldman )
Dependencias
se requieren dependencies
para ejecutar, devDependencies
solo para desarrollar, por ejemplo: pruebas unitarias, transpilación de CoffeeScript a JavaScript, minificación, ...
Si va a desarrollar un paquete, lo descarga (por ejemplo, a través de git clone
), vaya a su raíz que contiene package.json
y ejecute:
npm install
Ya que tiene la fuente real, está claro que desea desarrollarla, por lo que, de manera predeterminada, ambas dependencies
(ya que, por supuesto, deben ejecutarse para desarrollar) y devDependency
dependencias de dependencia de devDependency
también están instaladas.
Sin embargo, si solo eres un usuario final que solo quiere instalar un paquete para usarlo, lo harás desde cualquier directorio:
npm install "$package"
En ese caso, normalmente no desea las dependencias de desarrollo, por lo que solo obtiene lo que se necesita para usar el paquete: dependencies
.
Si realmente desea instalar paquetes de desarrollo en ese caso, puede establecer la opción de configuración dev
en true
, posiblemente desde la línea de comandos como:
npm install "$package" --dev
La opción es false
por defecto ya que este es un caso mucho menos común.
dependencias peer
(Probado antes de 3.0)
Fuente: https://nodejs.org/en/blog/npm/peer-dependencies/
Con las dependencias regulares, puede tener varias versiones de la dependencia: simplemente se instala dentro de los node_modules
de node_modules
de la dependencia.
Por ejemplo, si dependency1
y dependency2
dependen de dependency3
en diferentes versiones, el árbol del proyecto se verá así:
root/node_modules/
|
+- dependency1/node_modules/
| |
| +- dependency3 v1.0/
|
|
+- dependency2/node_modules/
|
+- dependency3 v2.0/
Sin embargo, los complementos son paquetes que normalmente no requieren el otro paquete, que se denomina host en este contexto. En lugar:
- los complementos son requeridos por el host
- Los complementos ofrecen una interfaz estándar que el host espera encontrar.
- solo el host será llamado directamente por el usuario, por lo que debe haber una única versión del mismo.
Por ejemplo, si dependency1
y dependency2
peer dependen de dependency3
, el árbol del proyecto se verá así:
root/node_modules/
|
+- dependency1/
|
+- dependency2/
|
+- dependency3 v1.0/
Esto sucede aunque nunca mencione dependency3
en su archivo package.json
.
Creo que esta es una instancia del patrón de diseño de Inversión de Control .
Un ejemplo prototípico de dependencias entre pares es Grunt, el host y sus complementos.
Por ejemplo, en un complemento Grunt como https://github.com/gruntjs/grunt-contrib-uglify , verá que:
-
grunt
es unapeerDependency
- el único
require(''grunt'')
está bajotests/
: no es realmente utilizado por el programa.
Luego, cuando el usuario usará un complemento, implícitamente requerirá el complemento del Gruntfile
agregando una línea grunt.loadNpmTasks(''grunt-contrib-uglify'')
, pero es un grunt
que el usuario llamará directamente.
Esto no funcionaría si cada plugin requiriera una versión Grunt diferente.
Manual
Creo que la documentación responde a la pregunta bastante bien, quizás no esté lo suficientemente familiarizado con los administradores de nodos / otros paquetes. Probablemente solo lo entiendo porque sé un poco sobre Ruby bundler.
La línea clave es:
Estas cosas se instalarán cuando se realicen npm link o npm install desde la raíz de un paquete, y se pueden administrar como cualquier otro parámetro de configuración de npm. Consulte npm-config (7) para más información sobre el tema.
Y luego bajo npm-config (7) encuentra dev
:
Default: false
Type: Boolean
Install dev-dependencies along with packages.
Si no desea instalar devDependencies, simplemente puede usar npm install --production
Una explicación simple que lo hizo más claro para mí es:
Cuando implemente su aplicación, los módulos en las dependencias deben instalarse o su aplicación no funcionará. Los módulos en devDependencies no necesitan instalarse en el servidor de producción ya que no está desarrollando en esa máquina. link
peerDependencies
no tenía mucho sentido para mí hasta que leí este fragmento de una publicación del blog sobre el tema que Ciro mencionó anteriormente :
Lo que necesitan los [ complementos ] es una forma de expresar estas "dependencias" entre los complementos y su paquete host. Alguna forma de decir: "Solo trabajo cuando estoy conectado a la versión 1.2.x de mi paquete de host, así que si me instalas, asegúrate de que esté junto a un host compatible". Llamamos a esta relación dependencia de compañeros.
El complemento espera una versión específica del host ...
peerDependencies
son para complementos, bibliotecas que requieren una biblioteca "host" para realizar su función, pero pueden haberse escrito antes de que se lanzara la última versión del host.
Es decir, si escribo PluginX v1
para HostLibraryX v3
y me alejo, no hay garantía de que PluginX v1
funcione cuando se HostLibraryX v4
(o incluso HostLibraryX v3.0.1
).
... pero el plugin no depende del host ...
Desde el punto de vista del complemento, solo agrega funciones a la biblioteca del host. Realmente no "necesito" el host para agregar una dependencia a un complemento, y los complementos a menudo no dependen literalmente de su host. Si no tiene el host, el complemento no hace nada inofensivamente.
Esto significa que las dependencies
no son realmente el concepto correcto para los complementos.
Lo que es peor, si mi host fuera tratado como una dependencia, terminaríamos en esta situación que menciona la misma publicación del blog (editada un poco para usar el host y el complemento creados de esta respuesta):
Pero ahora, [si tratamos la versión contemporánea de HostLibraryX como una dependencia para PluginX,] ejecutar resultados de
npm install
en el gráfico de dependencia inesperado de
├── [email protected] └─┬ [email protected] └── [email protected]
Dejaré las sutiles fallas que provienen del complemento utilizando una API [HostLibraryX] diferente a la de la aplicación principal para su imaginación.
... y el anfitrión obviamente no depende del complemento ...
... ese es el punto de los complementos. Ahora, si el anfitrión fue lo suficientemente bueno como para incluir información de dependencia para todos sus complementos, eso resolvería el problema, pero también introduciría un nuevo problema cultural : ¡la administración de complementos!
El punto central de los complementos es que pueden emparejarse de forma anónima. En un mundo perfecto, hacer que el anfitrión los administre a todos sería limpio y ordenado, pero no vamos a necesitar bibliotecas y gatos.
Si no somos jerárquicamente dependientes, tal vez somos compañeros intradependientes ...
En cambio, tenemos el concepto de ser pares. Ni el host ni el complemento se encuentran en el grupo de dependencias del otro. Ambos viven en el mismo nivel del gráfico de dependencia.
... pero esto no es una relación automatizable
Si soy PluginX v1
y espero un par de (es decir, tengo una dependencia de HostLibraryX v3
) de HostLibraryX v3
, lo diré. Si se actualizó automáticamente a la última HostLibraryX v4
(tenga en cuenta que es la versión 4 ) Y tiene instalado el Plugin v1
, debe saberlo, ¿verdad?
npm
no puede manejar esta situación por mí
"¡Eh, veo que estás usando
PluginX v1
! Estoy degradando automáticamenteHostLibraryX
de v4 a v3, ¿kk?"
... o ...
"Hey, veo que estás usando
PluginX v1
. Eso esperaHostLibraryX v3
, que dejaste en el polvo durante tu última actualización. ¡Para estar seguro, estoy desinstalando automáticamentePlugin v1
! 1!
¿Qué tal no, npm ?!
Así que npm no lo hace. Le alerta sobre la situación y le permite averiguar si HostLibraryX v4
es un compañero adecuado para Plugin v1
.
Coda
Una buena gestión de peerDependency
en los complementos hará que este concepto funcione de manera más intuitiva en la práctica. De la entrada del blog , una vez más ...
Un consejo: los requisitos de dependencia de los compañeros, a diferencia de los de las dependencias regulares, deben ser indulgentes. No debe bloquear las dependencias de sus compañeros en versiones específicas de parches. Sería realmente molesto si un complemento de Chai dependiera de Chai 1.4.1, mientras que otro dependiera de Chai 1.5.0, simplemente porque los autores eran perezosos y no pasaron el tiempo calculando la versión mínima real de Chai que son. compatible con.
dependencias
Dependencias que su proyecto necesita para ejecutar, como una biblioteca que proporciona funciones a las que llama desde su código.
Se instalan de forma transitiva (si A depende de B depende de C, npm install en A instalará B y C).
Ejemplo: lodash: su proyecto llama algunas funciones lodash.
Dependencias
Dependencias que solo necesita durante el desarrollo o la liberación, como compiladores que toman su código y lo compilan en javascript, marcos de prueba o generadores de documentación.
No se instalan de forma transitoria (si A depende de B dev-depende de C, npm install en A solo instalará B).
Ejemplo: grunt: tu proyecto usa grunt para construirse.
dependencias peer
Dependencias en las que su proyecto se enlaza o modifica en el proyecto principal, generalmente un complemento para alguna otra biblioteca o herramienta. Solo pretende ser una verificación, asegurándose de que el proyecto principal (proyecto que dependerá de su proyecto) tenga una dependencia del proyecto al que se conecte. Por lo tanto, si crea un complemento C que agrega funcionalidad a la biblioteca B, entonces alguien que realice un proyecto A deberá tener una dependencia en B si tiene una dependencia en C.
No están instalados (a menos que npm <3), solo se comprueban.
Ejemplo: grunt: su proyecto agrega funcionalidad a grunt y solo se puede usar en proyectos que usan grunt.
Esta documentación explica muy bien las dependencias entre pares: https://nodejs.org/en/blog/npm/peer-dependencies/
Además, la documentación de npm se ha mejorado con el tiempo y ahora tiene mejores explicaciones de los diferentes tipos de dependencias: https://github.com/npm/npm/blob/master/doc/files/package.json.md#devdependencies