javascriptgoogle-chrome-extensionchrome-extension-manifest-v3

callback data from sendMessage is true


I have a script that should get a value from the backgroud, basically it returns an item, but also for some reason it returns true when the function is called again.

In a background script item always object or undefined. How it got true in response is a mystery to me

market.js

async function renderMarketItem(item) {
  //parsers name, type and quality of item
  let market_item = await new Promise((resolve, reject) => {
    if (chrome.runtime?.id) {
      chrome.runtime.sendMessage({
        action: "getMarketItem",
        name: formatData(type, name, quality)
      }, (item) => {
        resolve(item);
      })
    } else resolve(undefined);
  });
  //another logic
}

chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.action == 'updateConfig') {
    $('.items-grid').children().each(function() {
      renderMarketItem($(this));
    })
  }
});

/*for example*/
$('.items-grid').children().each(function() {
  renderMarketItem($(this));
})

background.js

chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
   if (message.action == 'getMarketItem') {
        sendResponse(getMarketItem(message));
    }
    if (message.action == 'updateConfig') {
        updateConfig(message, sender, sendResponse);
    }

});
const updateConfig = (message, sender, sendResponse) => {
    const {data} = message;
    getTabs((tabs) => {
        tabs.forEach((tab) => {
            chrome.tabs.sendMessage(tab.id, { action: 'updateConfig', data });
        });
    });
}
let getTabs = (callback = ()=>{}) => {
       chrome.tabs.query({ url: /*siteUrl*/ }, (tabs) => {
          callback(tabs);
       });
}
const getMarketItem = (message) => {
    
    let targetName = message.name;
    let item;
    if (targetName) item = items.find(item => item.market_hash_name.trim() == targetName.trim());
    return item;
}

I did function async with return true and it didn't work


Solution

  • Problem was in my popup react app

    useEffect(() => {
        const handleMessage = async (message: any, sender: any, sendResponse: () => void) => {
          if (message.action === 'getConfig' && message.data) setConfig(message.data);
          return true;
        };
    
        runtime.onMessage.addListener(handleMessage);
    
        runtime.sendMessage({ action: 'needConfig' });
        return () => {
          runtime.onMessage.removeListener(handleMessage);
        };
      }, []);
    

    This listener interrupted the listener from the content script and when the popup was opened it returned true.

    I removed the listener and used the one-time request pattern where the response is returned by sendMessage:

    useEffect(() => {
        const getConfig = async() => {
          let cfg = await runtime.sendMessage({ action: 'getConfig'});
          console.log(cfg);
          setConfig(cfg);
        }
        getConfig();
      }, []);