2

I've just started learning React and was trying to create a chrome extension using it. I am trying to create an extension with a button whose onClick will highlight certain given words on a webpage. I am able to highlight words in content I am introducing to the page but not in the content already present on the page

Here is the code I have come up with -

There is a button on the popup HTML with class highlight-hazardous-words

popup.js (extensions popup):

window.onload = () => {
const $highlightHazardousButton = document.querySelector('.highlight-hazardous-words');

$highlightHazardousButton.onclick = () => {
    // Get active tab
    chrome.tabs.query({
        active: true,
        currentWindow: true,
    }, (tabs) => {
        // Send message to script file
        chrome.tabs.sendMessage(
        tabs[0].id,
        { injectApp: true },
        response => window.close()
);
});
};
};

main.js(main react app content lies here):

import React from 'react';
import ReactDOM from 'react-dom';
import Highlighter from "react-highlight-words"

class HighlightHazardous extends React.Component {
    constructor(props) {
        super(props);
        this.state = {searchWords : this.props.searchWords, textToHighlight : this.props.textToHighlight}
    }

    render() {
        return (
            <Highlighter
                highlightClassName="highlighted-text"
                searchWords = {this.state.searchWords}
                autoEscape = {true}
                textToHighlight = {document.body.innerText}
            />
        )
    }
}
// Message Listener function
chrome.runtime.onMessage.addListener((request, sender, response) => {
    // If message is injectApp
    if(request.injectApp) {
        // Inject our app to DOM and send response
        injectApp();
        response({
            startedExtension: true,
        });
    }
});

function injectApp() {
    const newDiv = document.createElement("div");
    newDiv.setAttribute("id", "chromeExtensionReactApp");
    document.body.appendChild(newDiv);
    ReactDOM.render(<HighlightHazardous searchWords={['hazardous', 'alcoholic']}/>, newDiv);
}

Here the newDiv appended has highlighted words with the whole page's body, I want to highlight hazardous or alcoholic present anywhere on any webpage and not in new div, basically, I don't want to inject this new div and change the content of the page already present.

1 Answer 1

3

The only way to access web-page's DOM content is to use Content Scripts component where Chrome Extensions use content-scripts to mention a JS and CSS file in manifest.json, that need to be injected into the underlying page.

As stated below:

The problem with our create-react-app is that the build step will generate the output JS file in different name each time (if the content changed). So we have no way to know the actual file name of the JS file, hence we can’t mention it in our manifest.json file.

The workaround for this is to eject out of create-react-app and modify the webpack configuration by hand to create a separate entry point for content script.

Sources:

Sign up to request clarification or add additional context in comments.

3 Comments

Another option is that you could inject an iframe into the DOM and load the react app's index.html into the frame.
And yet another option is that you could rewire your build to prevent code splitting (and give the output JS file a static name) as described here: mtm.dev/disable-code-splitting-create-react-app
Is this answer still true?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.