6/5/2024

PWA Studio Extensibility - Targets & Targetables

No morir en el intento al momento de tener que modificar PWA Studio utilizando extensibility - targets y targetables

PWA Studio Extensibility - Targets & Targetables

PWA Studio extensibility es la forma que PWA Studio nos brinda para modificar / extender el proyecto. Que sea la forma que el framework nos brinda, no garantiza que sea simple ni mucho menos fácil de entender… Pero bueno, hay que seguir las buenas prácticas.

Targets

Los targets son objetos que representan áreas del código a las que podemos acceder e interceptar. Es una variante del patrón javascript llamado Tapable hook (comparte algunas funcionalidades con EventEmitter de NodeJS)

Un ejemplo es asociar un componente a un método de pago:

module.exports = targets => {
  targets
    // intercepta a @magento/pwa-buildpack 
    // para acceder a specialFeatures    
    .of('@magento/pwa-buildpack')
    .specialFeatures.tap(flags => {
      flags[targets.name] = {
          esModules: true,
          cssModules: true,
          graphqlQueries: true,
          i18n: true
      };
  });
  
  targets
    // intercepta a @magento/venia-ui 
    // para acceder a checkoutPagePaymentTypes
    .of('@magento/venia-ui')
    .checkoutPagePaymentTypes.tap(payments =>
      payments.add({
          paymentCode: 'paymentCode',
          importPath:
              targets.name + '/src/components/payment.js'
      })
  );
}

Referencia de paquetes que pueden ser interceptados en PWA Studio

Interceptar Peregrine lo veremos luego ya que necesita su propia nota!

Targetables

Los objetos Targetables nos permiten acceder a archivos fuente del proyecto o biblioteca. A diferencia de Target, los objetos Targetable brindan acceso al código fuente del módulo.

En este apartado hay varias formas de acceder al código fuente:

Acceder al código fuente mediante esModule

const { Targetables } = require('@magento/pwa-buildpack');

module.exports = targets => {
 // se instancia Targetables pasando como parámetro targets
 const targetables = Targetables.using(targets);

 // instanciamos esModule para interceptar el archivo a modificar
 const SearchTrigger = targetables.esModule(
   '@magento/venia-ui/lib/components/Header/searchTrigger'
 );

 // importamos un ícono para utilizar luego
 SearchTrigger.addImport("{ X as CloseIcon } from 'react-feather'");
 
 // accedemos al código del archivo y antes de la siguiente aparición
 // insertamos nuestro código
 SearchTrigger.insertBeforeSource(
     'SearchIcon} />\n',
     'active ? CloseIcon : '
 );
}

Métodos disponibles para utilizar con esModule

Las referencias las podemos encontrar en su archivo fuente TargetableESModule.js

Acceder al componente React mediante reactComponent

Extiende de esModule, por lo que también se pueden acceder a los métodos que nos brinda esModule

const { Targetables } = require('@magento/pwa-buildpack');

module.exports = targets => {
 // se instancia Targetables pasando como parámetro targets
   const targetables = Targetables.using(targets);

   // instanciamos reactComponent para interceptar
   // el componente a modificar
   const MegaMenuComponent = targetables.reactComponent(
       '@magento/venia-ui/lib/components/MegaMenu/megaMenu'
   );

   // editamos una de sus propiedades
   MegaMenuComponent.setJSXProps('MegaMenuItem', {
       categoryUrlSuffix: '{categoryUrlSuffix(category)}'
   });
};

Métodos disponibles para utilizar con reactComponent

Las referencias las podemos encontrar en su archivo fuente TargetableReactComponent.js

Y como esta clase extiende de TargetableESModule.js podemos también usar sus métodos.

Buenas prácticas

Quiénes ya hayan trabajado con estas herramientas realmente saben que tienen un grado de aprendizaje y lógica alto debido a que es necesario evaluar las soluciones antes de implementarlas y generar muchas intercepciones si se modifican componentes principales.

Les dejo algunas recomendaciones:

Reemplazar componente si se necesitan hacer muchas intercepciones

Muchas veces tenemos que importar componentes o paquetes, modificar lógica y estilos. En esos casos recomiendo crear un componente propio y reemplazarlo con replaceJSX

Utilizar extensiones que nos ayuden a estructurar nuestros targets

Yo creé la extensión simplifying-targetables la cual pueden utilizar o tomar como punto de partida. Esta extensión permite que estructuremos nuestras intercepciones de la siguiente manera


  Root
    - src
      - targets
      - wrappers

Dentro de targets ubicamos nuestros estilos y componentes a interceptar, y en wrappers los talons. Se utilizan con el mismo nombre original del archivo lo cual ayuda a que sea más simples las modificaciones.

Esta extensión está basada en el siguiente paquete @larsroettig/component-targetables

Tratar de abstraer los componentes en paquetes

Siempre que sea posible, creo que es una buena práctica abstraer los componentes en paquetes locales para luego poder reutilizarlos en otros proyectos.

En mi caso creo una carpeta llamada packages en la raíz del proyecto y ahí coloco mis paquetes nombrados como @vendor/package-name Y los instalo mediante yarn add link:./packages/@vendor/package-name

En fin… Este tema dá para largo por lo cual por ahora vamos a dejar por acá y de seguro iré publicando otras notas con más contenido que pueda ser de ayuda a quiénes estén comenzando con PWA Studio.