Portando extensiones de Chrome a Firefox con WebExtensions

18 febrero, 2016 3:41 por

Esta es una traducción del artículo original publicado en el blog de Mozilla Hacks.

Después de leer “Escribamos una WebExtension“, me inspiré a intentar portar un complemento del mundo real a una WebExtension. Específicamente, intenté portar la versión para Chrome del popular “Reddit Enhancement Suite” (RES) de código abierto a Firefox. Aquí está lo que aprendí, y lo que puedes hacer hoy para preparar tus propios complementos para la transición.

Nota: Los autores de RES están emocionados sobre WebExtensions y planean oficialmente portar su complemento, pero ésto no es eso. Si quieres usar RES, debes instalar la versión soportada desde AMO.

Primero, quiero subrayar que WebExtensions es un proyecto de concepto amplio y de muchos años. Nuestras primeras versiones se centrarán en construir los fundamentos de APIs básicas, bien soportadas, y para varios navegadores. Esto significa que puede tomar un tiempo antes que estemos listos para un soporte de complementos complejos que se apoyan en características únicas del Firefox, pero eventualmente lo tendremos.

Ya que todo aquí todavía es muy temprano y experimental, necesitarás usar una versión Nightly de Firefox si quieres continuar. Esto es un vistazo, no algo que debas planear en distribuir.

Habiendo dicho ésto, si tienes una extensión de Chrome o un complemento para varios navegadores, ahora es un buen momento para experimentar con WebExtensions y enviarnos tus comentarios. Tu aporte será crucial para ayudar a Mozilla sobre cuáles APIs priorizar y soportar inicialmente.

Preparándonos para portar

  1. Descargar e instalar la versión Nightly de Firefox.
  2. Crear un nuevo perfil para pruebas y desarrollo.
  3. Visitar about:config y establecer xpinstall.signatures.required a false.

Declarando la compatibilidad de Firefox

Debes marcar explícitamente tu complemento como compatible con Firefox agregando una clave applications a tu manifest.json. Eso debe verse como esto:

"applications": {
  "gecko": {
    "id": "TU_ID"
  }
}

Cambia “TU_ID” a uno hecho en forma de cadena de texto formateado como “ext@example.org“. Si planeas actualizar directamente a tus usuarios desde un complemento existente de Firefox a una versión con WebExtension de la misma, debes reusar el valor encontrado en el campo “id” de tu package.json (o install.rdf).

Verificando el soporte del manifiesto

El siguiente paso es comparar las claves en tu manifest.json con las que soporta Firefox. Las claves no soportadas son ignoradas, así que puedes dejarlas en tu manifiesto hasta que sean implementadas, en este momento, esas claves deberán funcionar.

Revisando el manifiesto de Reddit Enhancement Suite, estamos en buena forma. Todos los atributos de metadatos están implementados, y hay suficiente soporte para que background, content_scripts, y web_accessible_resources funcionen con RES.

Vamos a revisar lo que falta, y qué impacto tiene:

  1. options_page: Estamos bien sin esto, ya que RES también inyecta un enlace a su configuración a través de content_scripts, en lugar de depender únicamente en la propiedad options_page.
  2. page_action: Estamos bien aquí, también. RES solamente lo usa como un atajo para alternar un checkbox que inyecta dentro de las páginas a través de content_scripts.
  3. permissions: Todos los permisos que RES requiere están soportados, excepto history, que no ha sido implementado todavía. RES solamente usa el API del historial para marcar los enlaces como visitados cuando se previsualizan imágenes en línea desde un botón para expandir. La falta de esto significa una leve degradación en funcionalidad, pero nada catastrófica.
  4. optional_permissions: No tenemos soporte de los permisos opcionales todavía, lo que para RES significa que no queremos soportar la inclusión de vistas previas en línea desde Twitter o OneDrive a través de botones de expandir. Lamentable, pero no es terrible.

En este punto, me siento bien sobre nuestros prospectos. La mayoría de las APIs que necesitamos están soportadas, y debemos ser capaces de entregar la mayoría de funcionalidades de RES a pesar de no tener algunas APIs.

¡A Bugzilla!

Ya que hemos identificado algunos vacíos en la cobertura de las APIs de Firefox relativas a nuestras necesidades, es tiempo de apuntar hacia Bugzilla. Ingresar y votar por bugs son dos de las más importantes contribuciones que puedes hacer como un desarrollador de complementos. Además para mantenerte informado del progreso, esto nos ayuda a juzgar cuáles API son más importantes a implementar.

Nota: Bugzilla tiene una sintaxis de búsqueda un tanto esotérica. Para buscar todos los errores abiertos y cerrados de WebExtension que mencionan la API history, prueba buscando por ALL Component:WebExtensions #history, que debe devolver el Bug 1208334: “Implementar la API history para una API de extensión abierta”.

Ya que estoy escribiendo este artículo, voy a seguir adelante y asegurar que estos bugs estén registrados sobre estas APIs. Siéntete libre de agregarte a la lista de CC de estos bugs si quieres ser notificado de su progreso, o hacer clic en el pequeño enlace “vote” al costado del campo “Importance” si el bug es particularmente importante para ti.

  • Bug 1212684: Implementar la propiedad options_page del manifiesto para la API de extensión abierta
  • Bug 1197422: Implementar el API de pageAction para la API de extensión abierta
  • Bug 1208334: Implementar la API de history para la API de extensión abierta
  • Bug 1197420: Implementar la API de permisos y la propiedad optional_permission del manifiesto para la API de extensión abierta.

Si necesitas registrar un bug sobre WebExtensions, por favor regístralo en el componente “WebExtensions” en el producto “Toolkit”, y etiquétalo con la palabra clave “dev-doc-needed”. Este enlace debe pre-llenar todos los campos correctamente: Registra un bug sobre WebExtensions.

Buscando el código

Además de las propiedades del manifiesto, también necesitamos asegurarnos que Firefox realmente soporte las APIs que necesitamos. Hemos establecido una visualización del progreso del API en AreWeWebExtensionsYet.com, pero para detalles específicos tienes que ir a MDN. Ya que las APIs de extensiones de Chrome están expuestas como propiedades en un objeto global chrome, podemos ejecutar el comando grep para encontrar  lo que vamos a usar:

$ grep -r 'chrome\.' ./Chrome ./lib
./Chrome/background.js: chrome.tabs.sendMessage(event.id, { requestType: 'subredditStyle', action: 'toggle'  }, function(response) {
./Chrome/background.js:chrome.pageAction.onClicked.addListener(handlePageActionClick);
./Chrome/background.js:chrome.runtime.onMessage.addListener(
# y así...

De las API que RES depende, solamente unas cuantas no están implementadas:

  • history.addUrl
  • pageAction.hide, onClicked, setIcon, y show
  • permissions.remove, request
  • tabs.getCurrent

Antes de entrar al código, vamos a volver a Bugzilla y asegurarnos que los bugs han sido registrados para éstos. Los bugs mencionados anteriormente cubren History, Page Actions, y Permissions, pero no cubren tabs.getCurrent. Yo registré el Bug 1212890 para esto.

Hacks y soluciones alternativas

Ahora que hemos identificado nuestra limitaciones, necesitamos trabajar alrededor de ellas. A corto plazo, podemos simplemente insertar verificaciones para comprobar la existencia de una API antes de llamar a los métodos. Por ejemplo, vamos a revisar cómo history.addUrl es usado en background.js:

case 'addURLToHistory':
    chrome.history.addUrl({url: request.url});
    break;

Ya que chrome.history.addUrl no está definido, esto lanzará un error. En su lugar, vamos a verificar que este existe antes de ser usado:

case 'addURLToHistory':
    if (chrome.history && chrome.history.addUrl) {
        chrome.history.addUrl({url: request.url});
    }
    break;

Esto evita que el script falle, pero significa que addURLToHistory fallará silenciosamente hasta que el Bug 1208334 sea resuelto. Bajo ciertas circunstancias, como con RES, esto será aceptable. Si no lo es, necesitarás encontrar una solución creativa o esperar a que este bug sea resuelto. Recuerda: ¡registra y vota por los bugs! Es la forma cómo nosotros sabemos en qué necesitamos trabajar.

Finalmente, podríamos salir de la falta de permissions.request() moviendo todo de optional_permissions de nuestro manifest.json dentro del bloque normal permissions. Eso funcionaría, pero es mejor no requerir más permisos de los que necesitas, y cambiando la declaración de permissions generalmente resulta en que tus usuarios serán alertados para volver a autorizar tu complemento. Si es posible, sólo espera por el Bug 1197420.

Empaquetando tu WebExtension

Estamos trabajando en un mejor flujo de trabajo en el Bug 1185460, pero por ahora:

  1. Comprime tus archivos en un formato ZIP de modo que tu manifest.json esté en la raíz del archivo zip.
  2. Renombra tu archivo .zip a .xpi
  3. Navega a about:addons.
  4. Arrastra y suelta tu XPI dentro de la página.
  5. Haz clic en “Instalar” de la pantalla de confirmación.

Si algo sale mal, revisa la documentación sobre empaquetamiento e instalación en MDN por consejos para solucionar problemas.

Haciendo pruebas

A pesar que las WebExtensions son una nueva iniciativa en Mozilla, ya hemos implementado la mayoría de los bloques para construcción necesarios para soportar la Reddit Enhancement Suite. Las cosas deberían funcionar, ya que hemos tratado apropiadamente las llamadas a las APIs no soportadas.

Vamos a cargarla y ver si realmente coincide con nuestras expectativas…

redditenhancementsuite-500x301

¡Ey! ¡Eso se ve bien! ¿Puede que esté funcionando? Vamos a probar la característica que carga más contenido cuando llegas al final de la página…

NeverEndingReddit

… pues no :(. ¿Cuál fue el error?

Depurando

Para encontrar qué falló, necesitamos abrir la Consola del Navegador (Browser Console). Es un registro global de todo lo que pasa en el navegador, y es en donde las excepciones no capturadas de las WebExtensions se muestran. Y está en el menú de Desarrollador Web.

Nota: Aunque está relacionadas, la Consola del Navegador no es lo mismo que la Consola Web en ese menú.

Revisando en la Consola del Navegador, hay un excepción no capturada: “TypeError: window.Favico is not a constructor”.

browserconsole-500x282

Esto ocurre en una llamada en orangered.js:

favicon = new window.Favico();

La causa de este bug es que la librería Favico se exporta así misma como this.Favico en su script de contenido, y RES asume que esto estará disponible como window.Favico en otros scripts. Pero resulta que Firefox no funciona de la misma manera. ¡A Bugzilla para registrar el Bug 1208775!

Afortunadamente, hay una solución fácil: Sólo omite la parte de window.

favicon = new Favico();

Esto nos soluciona el error y resulta que ahora sí funciona el scroll infinito. ¡Hurra! También felicitamos a RES por corregir esto en el pull request #2456.
Claro, aún no hemos terminado. Hay muchas otros fascinantes e hilarantes bugs para encontrar, como el Bug 1208874, que evita que RES guarde cualquiera de sus configuraciones porque el localStorage de WebExtensions está siendo limpiado cada vez que el navegador se reinicia.

Recuerda mantener tu Consola del Navegador abierta y registrar bugs cuando los encuentres.

Para terminar

Como lo mencioné al inicio del artículo, las WebExtensions están todavía en una etapa de desarrollo muy temprana, y las cosas están cambiando rápidamente. Por ejemplo, el soporte de PageAction ya está listo. Esto quiere decir que las WebExtensions son asombrosamente capaces. Para complementos como RES que aíslan y minimizan código específico, portarlos a WebExtensions está sorprendentemente cerca de ser capaz en las versiones Nightly de Firefox.

Estamos a varios meses de que muchas de estas características lleguen por completo a Firefox, pero eso motivante ver el rápido progreso. Cada día estamos más cerca al futuro en que sólo complemento con código base pueda ser completamente reusado en muchos navegadores, y en donde los complementos son escritos usando la misma tecnología como lo es la Web por sí misma.

Si quieres seguir los bugs que están bloqueando que portemos RES a WebExtensions, agrégate al CC en el metabug de RES, el Bug 1208765, y revisa mi propio intento de portar RES en GitHub.

Por último, ¡considera contribuir a Firefox! Todo lo que hacemos es de código abierto, y la mayoría de las APIs de WebExtensions están implementadas en JavaScript. Si puedes hackear en JS, puedes hacer la diferencia. Revisa los bugs abiertos sobre WebExtensions y también el canal #webextensions en irc.mozilla.org para empezar.

Finalmente, unas rápidas palabras de agradecimiento a Steve Sobel, creador de Reddit Enhacement Suite, a quien le gustaría recordarte que cualquier puerto de RES a WebExtensions no está finalizado, no es oficial y no está soportado hasta que él personalmente diga lo contrario. No lo molestes por nuestros bugs 😉

The following two tabs change content below.

AngelFQC

Web Developer at BeezNest Latino
Ingeniero de Sistemas y Computación. Desarrollador PHP. Mozilla Peru. Chamilo LMS Developer.

Compartir artículo:

Notable Replies

  1. Excelente, no sabía este procedimiento. Ojalá empieze la migración masiva a estas tecnolongías

Continue the discussion foro.mozilla-hispano.org

Participants

  • ¡Participa!

    Firefox Friends »
    Agrega botones de Firefox en tu sitio web y comparte tu amor por Mozilla Firefox.
    Armada alucinante »
    Ayuda a otros usuarios en Twitter.
    Colabora con la comunidad »
    En Mozilla lo importante son las personas. Descubre cómo puedes colaborar.

    Boletín Firefox

    Suscríbete al boletín de novedades de Firefox.

  • Descargas

    Descarga los programas de Mozilla.

    Lo más visto

    cc-by-sa