How to inject a React app into a Chrome Extension as a content script

Chrome Extensions are great tools that give let you interact with the browser and websites in a variety of ways.
- Browser and Page actions which appear as icons in the browser toolbar and can show an optional popup window.
- New Tab pages which override the default new tab
- Options pages for configuring Chrome Extensions
- Chrome context menus which appear with a right click
- Notifications, which slide in at the top right of the screen
- Content scripts, which inject JavaScript into a web page and can alter its user interface
This article is about loading a React app in a content script. Install create-react-app first if you don’t have it. Here is the repository if you just want to see the code.
Create a new React app
create-react-app react-content-script
Update the manifest file
- Find it in
/public/manifest.json
The manifest.json file is required to provide important information for the Chrome Extension. The manifest_version, name, and version are required for the Chrome Extension to be valid. The content_scripts array is what we will inject our React app into https://www.google.com/.
You can inject a content script into a specific page as we are doing here or you can use the match key to specify the urls that you want your code to load in. For example ["<all_urls>"] loads the content script matches any valid url scheme.
Update the App component
Remove import logo from './logo.svg'; and replace the src for the image tag with "https://facebook.github.io/react/img/logo.svg".
Update App.css to be more presentable.
Append the app to the DOM
This is where we actually inject the content script into the DOM on https://www.google.com. First examine the DOM of the website (or websites) that you want to inject a content script into. Then select an element based on where you want you want to append your code to the DOM.
I chose the <div class="ctr-p" id="viewport">, but you might have to experiment to find what works best for you. You might not even need to inject any HTML at all.

Deploy
- Next build the app for production by running the command
yarn run buildform/package.json. - Open the Extensions tab under more tools in the Customize and control Google Chrome menu (with the three vertical dots at the far right of the browser toolbar) or navigate to
chrome://extensions. - Check the Developer mode checkbox.
- Click on Load unpacked extension… then find and select the
buildfolder inreact-content-script/src/to load the extension.

The extension failed to load because the "css" and "js" filenames we specified in the manifest are different than the ones generated by Webpack.

Modify the build output filenames
You could just rename main.css and main.js every time there are changes in your build e.g. main.cacbacc7.css and main.f0a6875b.js in this case, but a better solution is to modify the Webpack production configuration output filenames so you don’t have to update the manually when you want to load your extension. In order to access /config/webpack.config/prod, you have to eject from Create React App.
- Eject from Create React App with
yarn run ejectand typeyto confirm. - Remove the generated hashes from the the CSS and JavaScript output filenames. Compare ORIGINAL to UPDATED in
/config/webpack.config/prod.
// ... (Other configuration)// Note: defined here because it will be used more than once.
// ORIGINAL // const cssFilename = 'static/css/[name].[contenthash:8].css';
// UPDATED
const cssFilename = 'static/css/[name].css';// ... (Other configuration)output: {
// The build folder.
path: paths.appBuild,
// Generated JS file names (with nested folders).
// There will be one main bundle, and one file per asynchronous chunk.
// We don't currently advertise code splitting but Webpack supports it.
// ORIGINAL // filename: 'static/js/[name].[chunkhash:8].js',
// UPDATED
filename: 'static/js/[name].js',// ... (Other configuration)
Rebuild and reload and verify that the filenames are correct before loading the build into Chrome.

That’s it. Thanks for reading and let me know if you have any questions.
