Close Menu

    Ecosistema Stacks Defi: las mejores aplicaciones y herramientas STX DeFi (con comentarios)

    May 5, 2024

    Minería a través del halving de Bitcoin: estrategias de supervivencia para 2024

    April 14, 2024

    Los 7 principales fabricantes de baterías de iones de litio

    April 14, 2024

    El retroceso del mercado alcista de las criptomonedas | Sin banco

    April 14, 2024
    Facebook X (Twitter) Instagram
    Facebook X (Twitter) Instagram
    despertarcripto.com
    • Home
    • Blog
    • Criptomonedas
    • Blockchain
    • DeFi
    • Privacidad Cripto
    • NFT & Arte Digital
    • Airdrop
    • Educacional
    • Regulación
    • Seguridad
    despertarcripto.com
    Home»Recursos Educacionales»Comunicación para herramientas de desarrollo personalizadas
    Recursos Educacionales

    Comunicación para herramientas de desarrollo personalizadas

    despertarcripto.comBy despertarcripto.comFebruary 20, 2024No Comments10 Mins Read
    Share
    Facebook Twitter LinkedIn Pinterest Email
    Ilustración de código

    Por Matthew Curtis, ingeniero de software sénior

    Fondo

    Hola, soy Matthew y trabajo en un proyecto llamado Perseus. Es un proyecto de código abierto responsable de la experiencia de ejercicio en Khan Academy. Si alguna vez respondiste una pregunta usando el widget de radio o escribiste una ecuación usando nuestro teclado matemático, ¡has usado Perseus!

    Dado que Perseus está separado de nuestro sitio web principal (también conocido como Webapp), a veces podemos encontrarnos con problemas que son difíciles de depurar: no podemos agregar fácilmente el registro al código de Perseus y, a veces, la dependencia de Webapp de los subpaquetes de Perseus no está sincronizada. Contamos con un conjunto de herramientas de desarrollo integradas en Webapp, pero se agregan al DOM, lo que crea una desconexión entre lo que ven los usuarios internos y lo que ven nuestros alumnos.

    Entonces, para un hackathon reciente, decidí crear un prototipo de Perseus Dev Tools, una extensión de navegador que agrega herramientas adicionales a las herramientas de desarrollo integradas del navegador, inspirada en React Dev Tools y Redux Dev Tools. El objetivo es hacer lo siguiente:

    • Danos una mirada en profundidad al ejercicio que estamos viendo en Webapp.
    • Compare las dependencias de Perseus de Webapp con las últimas versiones de npm
    • Danos un lugar para colocar otras herramientas de desarrollo específicas de Khan Academy.
    • Evite cambiar el DOM para que podamos ver lo que ven los alumnos.

    Como no había muchos ejemplos sobre cómo hacer que esto funcionara, decidí crear una extensión simulada que muestre esta funcionalidad y escribir algunos aspectos destacados del código. Sin embargo, este no será un tutorial completo. El código está disponible y MDN ha escrito mejores documentos que yo. Esta es solo una descripción general de alto nivel de cómo encajan las piezas, junto con un ejemplo práctico.

    Hablando de eso, aquí está el código de demostración.

    La demostración

    El sitio de demostración es un sitio de la aplicación Create React que tiene un par de componentes Counter. Queremos que la extensión haga lo siguiente:

    • Muestra el estado de conteo actual de cada componente del contador.
    • A medida que cambia el estado del sitio, el estado de la extensión debería cambiar.
    • La extensión tiene un botón de “restablecer” que restablecerá un contador específico.
    • Si el sitio está abierto en varias pestañas, la extensión no debería modificar los contadores en otras pestañas.

    Para configurarlo:

    La estructura de las extensiones de herramientas de desarrollo

    Una extensión de herramienta de desarrollador es solo un tipo específico de extensión de navegador. En el manifiesto de extensión, especificamos una ruta para la interfaz de usuario de la herramienta de desarrollo usando devtools_pagey en el JS para esa UI, creamos un panel usando browser.devtools.panels.create. Cada pestaña tendrá una instancia de la interfaz de usuario, y la interfaz de usuario puede tener cualquier número de paneles.

    Mi expectativa original era que la aplicación y la herramienta de desarrollo pudieran comunicarse directamente, pero resultó ser incorrecta. Hay varias capas a considerar y, por razones de seguridad, estas capas se comunican publicando y escuchando mensajes. El sitio debe optar explícitamente por comunicarse con estas capas. El script inyectado en la aplicación (el script de contenido) tiene acceso muy limitado a la aplicación host, pero poder recibir mensajes que publica la aplicación anfitriona; así es como transmitiremos los datos.

    Estas son las capas:

    • El Solicitud es el sitio web del que queremos recibir datos y enviar comandos.
    • El Guión de contenido es el código que se inyecta en la aplicación. Esto nos permite enviar mensajes entre la aplicación y el script en segundo plano.
    • El Guión de fondo es un código que se ejecuta en el nivel del navegador (en lugar de en el nivel de la aplicación). Puede coordinar mensajes entre múltiples pestañas y paneles de herramientas de desarrollo.
    • Ahí está el Herramienta de desarrollo en general, que es capaz de renderizar múltiples paneles.
    • Finalmente, está el Panel, que utilizamos para la interfaz real de la herramienta. Puede enviar/recibir mensajes hacia/desde el script en segundo plano.

    Entonces, para enviar un mensaje desde un Panel hacia Solicitud: Panel → Fondo → Contenido → Aplicación. Para enviar un mensaje desde el Solicitud hacia Panel: Aplicación → Contenido → Fondo → Panel.

    ⚠️⚠️⚠️ Hay un “¡Te tengo!” aunque. El script en segundo plano funciona con muchas pestañas y muchos paneles. Tenemos que asegurarnos de comunicarnos con las instancias de aquellas con las que pretendemos interactuar. ⚠️⚠️⚠️

    Mensajes

    Si alguna vez trabajó con iFrames, probablemente haya usado mensajes. Es una forma de que el código en el entorno sandbox se comunique fuera de su entorno sandbox. Para cada capa, usaremos un sistema para escuchar y enviar mensajes.

    Una consideración es que otras extensiones pueden estar enviando mensajes. Otras partes de nuestro El código puede estar enviando mensajes. Para facilitar el seguimiento y garantizar que solo respondamos a los mensajes que queremos responder, así es como se verán nuestros mensajes:

    const message = {
      extension: "blog-ext",
      source: "application",
      action: "rendered",
      data: {
        widgetId: "counter-exercise-1",
        count: 42,
      },
    }
    

    usaremos extension para diferenciar nuestros mensajes de otros mensajes, y usaremos source para realizar un seguimiento de qué capa está enviando el mensaje. action será lo que sucedió, y los datos serán la carga útil.

    Envío de datos desde la aplicación

    Vamos a empezar enviando un mensaje desde la aplicación con algunos datos; esto significa que necesitaremos controlar la aplicación host (como en este ejemplo) o podemos publicar mensajes desde una dependencia de la aplicación host (como React envía mensajes a React Dev Tools a través de la aplicación que usa React).

    En este caso, cada vez que rendericemos, enviaremos un mensaje similar a este:

    // application/src/Counter.js
    
    window.postMessage({
      extension: "blog-ext",
      source: "application",
      action: "rendered",
      data: {
        widgetId: "counter-exercise-1",
        count: 42,
      },
    })
    

    El script de contenido, que se inyecta en la aplicación web, lo captará y enviará su propia versión:

    // dev-tools/scripts/content.js
    
    /**
     * Listen to messages from the application,
     * forward them to the background script
     */
    window.addEventListener("message", (event) => {
      // Only accept messages from the same frame
      if (event.source !== window) {
        return;
      }
    
      const message = event.data;
      // Only accept messages that we know are ours
      if (message?.extension !== "blog-ext" || message?.source !== "application") {
        return;
      }
    
      browser.runtime.sendMessage({
        extension: "blog-ext",
        source: "content",
        action: message.action,
        data: message.data,
      });
    });
    

    La secuencia de comandos en segundo plano es un poco más complicada ya que solo hay una instancia de la secuencia de comandos en segundo plano que coordina los datos para varias pestañas. Necesita realizar un seguimiento de cada pestaña y de múltiples conexiones a los paneles de herramientas de desarrollo. También realizaremos un seguimiento del estado para que cuando un panel se conecte, pueda solicitar el estado de una pestaña específica.

    // dev-tools/scripts/background.js
    
    const connections = {};
    const latestState = {};
    
    /**
     * Listen to messages from the content script,
     * save data for when/if the dev tools panel connects,
     * and forward messages to the dev tools panel
     */
    browser.runtime.onMessage.addListener((message, sender) => {
      // Only accept messages that we know are ours
      if (message?.extension !== "blog-ext" || message?.source !== "content") {
        return;
      }
    
      // Messages from content scripts should have sender.tab set
      if (sender.tab) {
        const tabId = sender.tab.id;
    
        // store state for when dev tool panel connects
        if (message.action === "rendered") {
          if (!latestState[tabId]) {
            latestState[tabId] = {};
          }
    
          latestState[tabId][message.data.widgetId] = message.data.count;
        } else if (message.action === "removed") {
          if (!latestState[tabId]) {
            return;
          }
    
          delete latestState[tabId][message.data.widgetId];
        }
    
        // foward messages
        if (tabId in connections) {
          connections[tabId].postMessage({
            extension: "blog-ext",
            source: "background",
            action: message.action,
            data: message.data,
          });
        } else {
          console.log("Tab not found in connection list.");
        }
      } else {
        console.log("sender.tab not defined.");
      }
    });
    

    Finalmente, podemos recibir esos datos en el código del panel:

    // dev-tools/ui/panel/panel.js
    
    let widgets = {};
    
    /**
     * Create a connection to the background script
     */
    const backgroundPageConnection = browser.runtime.connect({
      name: "panel",
    });
    
    /**
     * Listen for messages from background script
     */
    backgroundPageConnection.onMessage.addListener((request) => {
      // Only accept messages that we know are ours
      if (message?.extension !== "blog-ext" || message?.source !== "background") {
        return;
      }
    
      switch (request.action) {
        case "rendered":
          widgets[request.data.widgetId] = request.data.count;
          break;
        case "removed":
          delete widgets[request.data.widgetId];
          break;
        case "hydrate-state":
          widgets = { ...widgets, ...request.data };
          break;
      }
    
      // update panel UI
      render();
    });
    

    Envío de comandos desde herramientas de desarrollo

    Ahora hagamos las cosas al revés. Comenzaremos con un mensaje de “inicio” para obtener el estado guardado del script en segundo plano. También enviaremos un mensaje de “restablecimiento” desde el panel, pero al igual que en el ejemplo anterior, necesitaremos agregar algunos datos para ayudar a que este mensaje llegue a la pestaña correcta.

    // dev-tools/ui/panel/panel.js
    
    /**
     * Send an init message back to background script
     * to request existing state
     */
    backgroundPageConnection.postMessage(
      formatMessage({
        extension: "blog-ext",
        source: "panel",
        action: "init",
        data: {
          tabId: browser.devtools.inspectedWindow.tabId,
        },
      })
    );
    
    /**
     * Callback for UI button press
     */
    function handleClickReset(widgetId) {
      backgroundPageConnection.postMessage(
        formatMessage({
          extension: "blog-ext",
          source: "panel",
          action: "reset",
          data: {
            widgetId,
            tabId: browser.devtools.inspectedWindow.tabId,
          },
        })
      );
    }
    

    Una vez más, el guión de fondo es un poco más complicado. Agregaremos un oyente para los mensajes del panel, pero también agregaremos un oyente de desconexión para limpiar las conexiones cuando sea necesario.

    // dev-tools/scripts/background.js
    
    /**
     * Listen to messages from the dev tools panel,
     * and either respond or foward them to the content script
     */
    browser.runtime.onConnect.addListener((port) => {
      function extensionListener(message) {
        // Only accept messages that we know are ours
        if (message?.extension !== "blog-ext" || message?.source !== "panel") {
          return;
        }
    
        // Listen for the panel to connect, save a reference to it,
        // and hydrate its state
        if (message.action === "init") {
          connections[message.data.tabId] = port;
          port.postMessage({
            extension: "blog-ext",
            source: "background",
            action: "hydrate-state",
            data: latestState[message.data.tabId],
          });
          return;
        }
    
        // forward everything else to the content script
        browser.tabs.sendMessage(
          message.data.tabId,
          {
            extension: "blog-ext",
            source: "background",
            action: message.action,
            data: message.data,
          }
        );
      }
    
      // Listen to messages sent from the DevTools page
      port.onMessage.addListener(extensionListener);
    
      port.onDisconnect.addListener((port) => {
        port.onMessage.removeListener(extensionListener);
    
        var tabs = Object.keys(connections);
        for (let i = 0; i < tabs.length; i++) {
          if (connections[tabs[i]] == port) {
            delete connections[tabs[i]];
            break;
          }
        }
      });
    });
    

    Captaremos los mensajes reenviados en el script de contenido y los reenviaremos a la aplicación:

    // dev-tools/scripts/content.js
    
    /**
     * Listen to messages from the background script,
     * forward them to the application
     */
    browser.runtime.onMessage.addListener((message) => {
      // Only accept messages that we know are ours
      if (message?.extension !== "blog-ext" || message?.source !== "background") {
        return;
      }
    
      window.postMessage({
        extension: "blog-ext",
        source: "content",
        action: message.action,
        data: message.data,
      });
    });
    

    Luego, finalmente, podemos juntar todo esto en el componente Contador:

    // application/src/Counter.js
    
    // Listen to messages from the content script
    function handleMessage(event) {
      const message = event.data;
    
      // Only accept messages that we know are ours
      if (message?.extension !== "blog-ext" || message?.source !== "content") {
        return;
      }
    
      const messageWidgetId = message.data.widgetId;
      const messageAction = message.action;
      if (messageWidgetId === widgetId && messageAction === "reset") {
        onChange(0);
      }
    }
    
    useEffect(() => {
      window.postMessage({
        extension: "blog-ext",
        source: "application",
        action: "rendered",
        data: {
          widgetId,
          count,
        },
      });
      window.addEventListener("message", handleMessage);
    
      return () => {
        window.postMessage({
          extension: "blog-ext",
          source: "application",
          action: "removed",
          data: {
            widgetId,
          },
        });
        window.removeEventListener("message", handleMessage);
      };
    });
    

    Conclusión

    ¡Eso es todo! Parte de este código es un poco detallado y algunas de las comprobaciones son demasiado cautelosas, pero esperamos que esto ayude a mostrar cómo interactúan las capas entre sí. ¡Gracias por leer!

    Fuentes:

    Fuente Original Khan Academy Blog

    Share. Facebook Twitter Pinterest LinkedIn Tumblr Email
    despertarcripto.com
    • Website

    Related Posts

    Entrevista a Miles Fuller: ¡Se revelan los secretos fiscales criptográficos del IRS!

    April 11, 2024

    Entrevista a JW Verret: el ataque de la SEC a las criptomonedas y las pérdidas en los tribunales y ¿quién será el próximo presidente de la SEC?

    April 9, 2024

    Entrevista a David Schwed: exponiendo problemas de seguridad con las criptomonedas

    April 8, 2024

    Entrevista a Amanda Tuminelli: ¿Crypto tendrá que acudir a la Corte Suprema en busca de claridad?

    April 4, 2024
    Add A Comment

    Leave A Reply Cancel Reply

    Latest Post

    Ecosistema Stacks Defi: las mejores aplicaciones y herramientas STX DeFi (con comentarios)

    May 5, 2024

    Minería a través del halving de Bitcoin: estrategias de supervivencia para 2024

    April 14, 2024

    Los 7 principales fabricantes de baterías de iones de litio

    April 14, 2024

    El retroceso del mercado alcista de las criptomonedas | Sin banco

    April 14, 2024
    Most Viewed
    Cripto

    Ecosistema Stacks Defi: las mejores aplicaciones y herramientas STX DeFi (con comentarios)

    By despertarcripto.comMay 5, 2024

    Aplicación/ProtocoloUtilidadNotasbilletera xverseLa mejor billetera para STXFácil de usar y ofrece apuestas nativas con rendimiento en…

    Privacidad Cripto

    Minería a través del halving de Bitcoin: estrategias de supervivencia para 2024

    By despertarcripto.comApril 14, 2024

    El cuarto evento de reducción a la mitad de Bitcoin está programado para el 22…

    Analisis de Mercado

    Los 7 principales fabricantes de baterías de iones de litio

    By despertarcripto.comApril 14, 2024

    Las baterías de iones de litio se han convertido en la piedra angular de los…

    DeFi

    El retroceso del mercado alcista de las criptomonedas | Sin banco

    By despertarcripto.comApril 14, 2024

    1️⃣ Los criptomercados se ven en rojoLos criptomercados terminaron la semana en un mar rojo…

    About Us
    About Us

    Here is All information you will get related crypto Tech and many others
    Thank You!

    Facebook X (Twitter) Instagram
    Latest Post

    Ecosistema Stacks Defi: las mejores aplicaciones y herramientas STX DeFi (con comentarios)

    May 5, 2024

    Minería a través del halving de Bitcoin: estrategias de supervivencia para 2024

    April 14, 2024

    Los 7 principales fabricantes de baterías de iones de litio

    April 14, 2024

    El retroceso del mercado alcista de las criptomonedas | Sin banco

    April 14, 2024
    Must Viewed

    Las 10 principales monedas de privacidad: 101 blockchains

    April 12, 2024

    Las NFT intentan otro regreso: el volumen de ventas comerciales de NFT aumenta un 46% esta semana

    April 12, 2024

    Blog de IBM

    April 12, 2024

    Metacade desencadena los juegos Web3: la integración de cadenas múltiples une a la industria

    April 11, 2024
    © 2025 By Despertarcripto.com

    Type above and press Enter to search. Press Esc to cancel.