Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add React components interaction with content script example on the docs #859

Open
sovetski opened this issue Jan 17, 2024 · 12 comments
Open
Labels
enhancement New feature or request

Comments

@sovetski
Copy link

Describe the problem

Hi,

Firstly, thanks for this great tool!

For me, the problem is, by following the documentation, I am not able to interact with the current website's DOM with my extension components.

For example, I have this button on my extension. When I click on it, first I want to show a basic JavaScript alert on the current website's DOM and not the extension one. But how to do it? The button comes from my App.jsx, and we can only interact with the current tab's DOM from content script.
image

I found this chrome.tabs.sendMessage and chrome.runtime.onMessage.addListener to communicate between my App.jsx and content-script.js, but it is not very clean...

Describe the proposed solution

Add an example of extension which have a button and by clicking on it, we will interact with the current tab's DOM

Alternatives considered

chrome.tabs.sendMessage and chrome.runtime.onMessage.addListener

Importance

would make my life easier

@sovetski sovetski added the enhancement New feature or request label Jan 17, 2024
@Toumash
Copy link

Toumash commented Apr 9, 2024

Outside of the build tool scope - should be closed. Im using the quoted methods just fine

@sovetski
Copy link
Author

sovetski commented Apr 9, 2024

Outside of the build tool scope - should be closed. Im using the quoted methods just fine

Great if it works for you, but it will be more useful if you share your solution with some examples here, to help other people too :)

@Toumash
Copy link

Toumash commented Apr 9, 2024

@sovetski
tl;dr
code:

// popup
const [tab] = await chrome.tabs.query({active: true,currentWindow: true});
if (tab.id === undefined) return;
await chrome.tabs.sendMessage(tab.id, { type: 'do_something' });

// content_script
function listener(msgObj, _, _) {
      if (msgObj.type === 'do_something') {
        //TODO: do something
      }
    }
chrome.runtime.onMessage.addListener(listener);

the only sample from google i could find injects a script straight from a popup - you dont need a listener then
https://github.com/GoogleChrome/chrome-extensions-samples/blob/main/functional-samples/reference.mv3-content-scripts/popup.js

My sample use case: i need to show a state in popup.js thats based on information from a content_script.
If you dont need a response (licenseState) you can just replace respond(licenseState); with your interact with the current tab's DOM code

This is a sample from react (a hook) but it doesnt matter - same methods.

note for more complex scenarios people usually communicate through a service worker (complex code that would need to run longer than popup is open) so that would be popup -> service_worker -> content_scripts.

// popup/useLicenseStatus.tsx
export const useLicenseStatus = (setLicense: (license: LicenseState) => void) => {
  useEffect(() => {
    const fetchData = async () => {
      const [tab] = await chrome.tabs.query({
        active: true,
        currentWindow: true,
      });
      if (tab.id === undefined) return;
      const response: LicenseState = await chrome.tabs.sendMessage(tab.id, { type:  'get_license_status'});
      console.log('response', response);
      if (response !== undefined) {
        setLicense(response);
      }
    };

    void fetchData();
  });
};
// contentscript.tsx
export function useShareLicenseStatus(licenseState: LicenseState) {
  const listener = useCallback(
    (msgObj, _, respond: (_: LicenseState) => void) => {
      if (msgObj.type === 'get_license_status') {
        respond(licenseState);
      }
    },
    [licenseState]
  );
  useEffect(() => {
    chrome.runtime.onMessage.addListener(listener);
    return () => chrome.runtime.onMessage.removeListener(listener);
  }, [listener]);
}

@kumaramit3
Copy link

kumaramit3 commented May 13, 2024

manifest.json

 "permissions": ["scripting"]

src/App.jsx

import React from "react";
import content from "./content?script&module"; 
import "./App.css";

const App = () => {
  const handleClick = async () => {
    const [tab] = await chrome.tabs.query({
      active: true,
      currentWindow: true,
    });
    if (!tab.id) return;
    await chrome.scripting.executeScript({
      target: { tabId: tab.id },
      files: [content],
    })
  }

  return (
    <div>
      <h2>Welcome! Coming Soon!</h2>
      <button onClick={handleClick}>Alert button example!</button>
    </div>
  );
}

export default App;

src/content.js

alert("alert from extension")

@kumaramit3
Copy link

kumaramit3 commented May 13, 2024

This Advanced Config tutorial will help you more.

@Toumash
Copy link

Toumash commented May 29, 2024

@jacksteamdev should be closed

@sovetski
Copy link
Author

I don't think that it can be considered as closed, the solutions are "home made" and are not relevant for me. Or an example can be added to the documentation may be.

@Toumash
Copy link

Toumash commented May 29, 2024

Out of scope for the repo to teach architecture of browser extensions.
Google Chrome Extension samples is a good place to discuss it.
It would probably be good to insert the code provided here into the samples repository for others to use.

https://github.com/GoogleChrome/chrome-extensions-samples/issues

@sovetski
Copy link
Author

Out of scope for the repo to teach architecture of browser extensions.

On the documentation, we have very simple explanations like right-click it and choose "Inspect popup window" and it is also out of scope but added to simplify the process and make developers more familiar with this. This repository was made to make extension development more easy, so why not add some "Examples" on the documentation?

@Toumash
Copy link

Toumash commented May 29, 2024

@sovetski Alright it makes sense - lets add something into the docs.
What do you think would be the good spot to place it?
Chrome has a full tutorial for this concept: https://developer.chrome.com/docs/extensions/develop/concepts/messaging
We could also add a link for content_scripts to already existing docs https://developer.chrome.com/docs/extensions/develop/concepts/content-scripts

"Communication" ?
image

@kumaramit3
Copy link

@sovetski I have updated my solution. Now it's working for content scripts.

@sovetski
Copy link
Author

@Toumash it looks a good idea, I think it will be useful. "Communication" or "Communication with DOM" or "DOM interaction"?

@kumaramit3 thank you for your time and help! In my case, I already finished my extension with a similar solution that you provided. I did not close the issue because if I have to create a new plugin, it will take some time because the first one was very long to find solutions for the content script. If the documentation will be updated (by adding a link like we are talking about above etc.), maybe it will be more useful, what do you think?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants