Skip to main content

Plugins de Yarn 2: introducción

Escrito por
Plugin feature

13 de abril de 2020

0 minutos de lectura

Si te interesa Yarn 2 y su arquitectura de plugins, un buen punto de partida es leer la página de documentación sobre la arquitectura de plugins en yarnpkg.com y seguir el tutorial de plugins de Yarn 2 en el sitio web.

Te recomiendo leer mi artículo introductorio sobre Yarn 2 si todavía no conoces Yarn 2.

Crear un plugin para Yarn 2

Empezamos por configurar un entorno para crear el plugin. Primero, creemos un proyecto nuevo que se administrará con Yarn 2:

mkdir my-app
cd my-app
yarn policies set-version berry
yarn init

Así obtenemos un proyecto de paquete npm limpio, administrado con Yarn 2.

Para indicarle a Yarn que queremos ejecutar un plugin como parte del proceso que realiza, creamos un archivo llamado .yarnrc.yml y agregamos allí la definición del plugin con la ruta al plugin que vamos a desarrollar:

plugins:
 - ./plugin-hook-install-hello-world.js

Ahora pasemos al código del plugin. Crearemos algo que se conecte a una fase del proceso de Yarn llamada afterAllInstalled y, luego, imprima un mensaje en la consola. El código del plugin quedaría así:

const afterAllInstalled = project => {
 console.log("Everything is installed 🎉");
};

module.exports = {
 name: `plugin-hello-world`,
 factory: require => {
   return {
     default: {
       hooks: {
         afterAllInstalled
       }
     }
   };
 }
};

Para probar el plugin, solo ejecuta el comando yarn desde la CLI y debería mostrar lo siguiente:

➜ yarn
➤ YN0000: ┌ Resolution step
➤ YN0000: └ Completed in 0s
➤ YN0000: ┌ Fetch step
➤ YN0000: └ Completed in 0s
➤ YN0000: ┌ Link step
➤ YN0000: └ Completed in 0.01s
Everything is installed 🎉
➤ YN0000: Done in 0.04s

¡Genial! Ya tenemos nuestro propio plugin para Yarn 2.

Los plugins de Yarn 2 pueden hacer muchas cosas: agregar un comando al ejecutable de yarn, incorporar nuevos resolvers o fetchers —como los llama Yarn— e incluso conectar plugins de yarn entre sí.

Si quieres aprender a crear un plugin de Yarn 2 que agregue comandos a Yarn, visita la página oficial de documentación sobre plugins de Yarn, donde encontrarás los pasos.

Usar un plugin de Yarn 2 para acceder a información detallada sobre las dependencias

Como vimos en el ejemplo anterior, algunos hooks de Yarn nos permiten integrarnos de forma más estrecha, ya que proporcionan un objeto público global con metadatos detallados que Yarn recopila sobre el proyecto.

En el siguiente ejemplo, volvemos a integrarnos con el hook afterAllInstalled, que

se invoca con un parámetro adicional: el objeto público Project. Gracias a este parámetro extra, podemos acceder a toda la información que Yarn recopiló sobre el proyecto: dependencias, manifiesto del paquete, información del workspace, etc.

En el siguiente ejemplo de plugin, plugin-hook-install-hello-brave-world.js, capturamos la información de este objeto en la variable _ y escribimos su contenido en un archivo JSON para poder inspeccionarlo:

const fs = require("fs");
const util = require("util");

module.exports = {
 name: `plugin-hello-brave-world`,
 factory: require => {
   return {
     default: {
       hooks: {
         afterAllInstalled(_) {
           console.log("🎉 afterAllInstalled hook invoked");
           fs.writeFileSync("afterAll.json", util.inspect(_, false, 10));
         }
       }
     }
   };
 }
};

La estructura del objeto Project está definida en packages/berry-core/sources/Project.ts. A continuación, se muestra una lista parcial de las claves de nivel raíz del objeto:

Project {
 configuration: {},
 cwd: {},
 workspaces: Map {},
 storedResolutions: Map {},
 storedDescriptors: Map {},
 storedPackages: Map {},
 storedChecksums: Map {},
 ...
}

Estas claves stored* nos ayudarán a entender las dependencias y a crear el árbol de este proyecto.

Para simplificar, ejecutaremos este plugin en un proyecto npm que solo tiene una dependencia: debug. A su vez, debug también depende de ms.

El objeto storedPackages es nuestro punto de partida para obtener la lista de dependencias del proyecto. Ten en cuenta que este objeto también incluye una entrada para el nombre real del proyecto, identificada con la referencia workspace: key.

Veamos cómo aparece la dependencia debug en el Map storedPackages:

'a1f870a4a95fff67eeac2388e06345982ebf1149c710f8efe18fe5d1967fec40db60987022a5c6fe55708167d1add4b63bc8ad6f755e20c6fba140d721180595' => { identHash:
       'd027b0b474dd440d333c0ae6200111acff30aa5931aeacf1841b1eb9212edea377606a118ff0f8675b69eabe9ff00db4f2f16659519c82810c6b534f9b8ad82d',
      scope: undefined,
      name: 'debug',
      locatorHash:
       'a1f870a4a95fff67eeac2388e06345982ebf1149c710f8efe18fe5d1967fec40db60987022a5c6fe55708167d1add4b63bc8ad6f755e20c6fba140d721180595',
      reference: 'npm:4.1.1',
      version: '4.1.1',
      languageName: 'node',
      linkType: 'hard',
      dependencies:
       Map {
         '299701b4a21f15498c990a6ec8bf49b0331f01e1d610cefaa6f7040bab1be634be89d1462245207c21d1334b31690861f303a0a71aa94f80445d80b9ee37eaf6' => { identHash:
            '299701b4a21f15498c990a6ec8bf49b0331f01e1d610cefaa6f7040bab1be634be89d1462245207c21d1334b31690861f303a0a71aa94f80445d80b9ee37eaf6',
           scope: undefined,
           name: 'ms',
           descriptorHash:
            '0742408cf974a8f1cd5081a9aec19656dc8016eec3c6e2358f302902e6f1f87241f601911cb45e855f3b0d26160c1520715ae79904c5ed1d29f5383ab906440e',
           range: 'npm:^2.1.1' } },
      peerDependencies: Map {},
      dependenciesMeta: Map {},
      peerDependenciesMeta: Map {},
      bin: Map {} },
    '9455a02525b0e2c50eca4e204d71900a775107249d4245c1ea1f95e3f124c8a1d27484b29ccea934895da4d0273b22dc95cefd0561c39490cd7c86ab4404ca33' => { identHash:
       '299701b4a21f15498c990a6ec8bf49b0331f01e1d610cefaa6f7040bab1be634be89d1462245207c21d1334b31690861f303a0a71aa94f80445d80b9ee37eaf6',
      scope: undefined,
      name: 'ms',
      locatorHash:
       '9455a02525b0e2c50eca4e204d71900a775107249d4245c1ea1f95e3f124c8a1d27484b29ccea934895da4d0273b22dc95cefd0561c39490cd7c86ab4404ca33',
      reference: 'npm:2.1.2',
      version: '2.1.2',
      languageName: 'node',
      linkType: 'hard',
      dependencies: Map {},
      peerDependencies: Map {},
      dependenciesMeta: Map {},
      peerDependenciesMeta: Map {},
      bin: Map {} },

La entrada de debug tiene un hash único que la identifica, algunos metadatos, como la versión resuelta, y otro objeto de dependencias anidado que enumera las dependencias de debug. Sin embargo, notarás que ms, que aparece en el objeto de dependencias anidado, no está resuelta y solo se indica mediante un rango.

Para resolver las dependencias anidadas, debemos usar descriptorHash y consultar el mapa storedResolutions, que tiene este aspecto:

storedResolutions:
  Map {
    '35f50d92512bedba8fbf78bdeae4f2bce60934a798f5e0a0ab58b087fb7dc73880c7ffee2e135c15e48ca70687336bbdf4163e75da3f90b55da5ba5e41d36051' => '35f50d92512bedba8fbf78bdeae4f2bce60934a798f5e0a0ab58b087fb7dc73880c7ffee2e135c15e48ca70687336bbdf4163e75da3f90b55da5ba5e41d36051',
    'ee78c55248c8a07a4079ce749bc462124c923d7b990785b50150c417b2821ca3363767b8dc304d80d4feae3faf9f95e1c2c46cebc582b81fe70a8f45a69b6377' => 'a1f870a4a95fff67eeac2388e06345982ebf1149c710f8efe18fe5d1967fec40db60987022a5c6fe55708167d1add4b63bc8ad6f755e20c6fba140d721180595',
    '0742408cf974a8f1cd5081a9aec19656dc8016eec3c6e2358f302902e6f1f87241f601911cb45e855f3b0d26160c1520715ae79904c5ed1d29f5383ab906440e' => '9455a02525b0e2c50eca4e204d71900a775107249d4245c1ea1f95e3f124c8a1d27484b29ccea934895da4d0273b22dc95cefd0561c39490cd7c86ab4404ca33' },

Podemos encontrar que el descriptorHash de ms, 0742408cf974a8f1cd5081a9aec19656dc8016eec3c6e2358f302902e6f1f87241f601911cb45e855f3b0d26160c1520715ae79904c5ed1d29f5383ab906440e, es el tercer elemento de storedResolutions. Este hace referencia al hash 9455a02525b0e2c50eca4e204d71900a775107249d4245c1ea1f95e3f124c8a1d27484b29ccea934895da4d0273b22dc95cefd0561c39490cd7c86ab4404ca33, que luego se vuelve a asociar con una entrada de dependencia en el mapa storedPackages. Esta vez, se trata de los metadatos de la dependencia ms completamente resuelta:

'9455a02525b0e2c50eca4e204d71900a775107249d4245c1ea1f95e3f124c8a1d27484b29ccea934895da4d0273b22dc95cefd0561c39490cd7c86ab4404ca33' => { identHash:
       '299701b4a21f15498c990a6ec8bf49b0331f01e1d610cefaa6f7040bab1be634be89d1462245207c21d1334b31690861f303a0a71aa94f80445d80b9ee37eaf6',
      scope: undefined,
      name: 'ms',
      locatorHash:
       '9455a02525b0e2c50eca4e204d71900a775107249d4245c1ea1f95e3f124c8a1d27484b29ccea934895da4d0273b22dc95cefd0561c39490cd7c86ab4404ca33',
      reference: 'npm:2.1.2',
      version: '2.1.2',
      languageName: 'node',
      linkType: 'hard',
      dependencies: Map {},
      peerDependencies: Map {},
      dependenciesMeta: Map {},
      peerDependenciesMeta: Map {},
      bin: Map {} },

Resumen de los plugins de Yarn 2

Yarn 2 aún es reciente y sigue ganando usuarios y recibiendo comentarios de la comunidad. Por eso, este es un gran momento para desarrollar plugins.

Empieza con los desafíos de Capture the Flag

Aprende a resolver desafíos de captura la bandera con nuestro taller virtual introductorio a pedido.

Publicado en:

Leer más

Blog

Verano en los estadios: la gira Snyk Connect Fan Zone

La gira Fan Zone de Snyk llevó talleres de seguridad de IA, networking y competencia amistosa a 8 ciudades y 3 sesiones virtuales. Los asistentes desarrollaron habilidades, compartieron ideas y crecieron juntos.

Blog

Snyk VulnBench JS 1.0: ¿Pueden los LLM encontrar los mismos errores dos veces?

Snyk VulnBench JS 1.0: 300 análisis repetidos muestran que los hallazgos de seguridad de los LLM varían en cada ejecución, mientras que SAST y los modelos detectan distintas vulnerabilidades.

feature insights context
Blog

Cómo construir seguridad de IA junto con nuestros clientes: 5 lecciones del programa de socios de diseño de Evo

Conoce 5 lecciones clave del programa de socios de diseño de Evo de Snyk. Descubre cómo el descubrimiento de IA, la inteligencia de riesgos y la automatización de políticas ayudan a los equipos a proteger la IA generativa y controlar la proliferación de IA a gran escala.