In my quest to develop a Chrome Extension using React and TypeScript, I found that existing resources didn't quite meet my needs. This prompted me to embark on a journey of creating my own guide, tailored to my specific requirements.
Here's what I aimed to achieve:
- Develop a Chrome extension featuring an interactive popup screen for enhanced user experience.
- Write the code in TypeScript, leveraging its robust typing system for better maintainability and error prevention. Generate two distinct outputs for the published code:
- A Popup app
- Content scripts, background scripts, and other necessary components
- Prepare the code for publication, which includes:
- Uglifying the code to minimize its size and improve performance
- Compressing the code into a ZIP file, creating a package ready for Chrome Extension publication.
Create React app
Prepare environment
npx create-react-app chrome-react --template typescript
When created I remove react-script package and copies build dependencies, configuration files and scripts into the app directory. It is needed to modify webpack.config
file. (Another solution is to use react-app-rewired
npm run eject
Then for be sure everything works I have run a build
npm run build
Now I want to be able to create build for development so I need to add
npm install -g win-node-env
I set $env:NODE_ENV="production"
in Powershell terminal.
Prepare project files
I deleted marked files from /src
directory
Then I have updated two left files which are now:
App.tsx
import React from 'react';
function App() {
return (
<div>
Chrome extension popup
</div>
);
}
export default App;
index.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
Another directory to cleanup is public
. There are few files to remove:
And the content of index.html
needs to be updated so it will looks like that:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<title>Chrome Extension </title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
The second file to update is the hearth of extension - manifest.json file.
The current manifest.json
is file created by create-react-app
and it content is related to Web App Manifest which mostly is useful for mobile devices. As I am working on Chrome Extension I can removed its contents and put the valid extension manifest
{
"name": "Chrome Extension",
"description": "Chrome Extension Description",
"version": "1.0",
"manifest_version": 3,
"action": {
"default_popup": "index.html",
"default_title": "Open the popup"
}
}
Now I build project and check if I can load properly extension into the Chrome by this steps:
Open chrome://extensions/
then Load Unpacked Extension and point to build directory in the source of project.
Here we go! Extension works. But this is only beginning.
Content script
Now I've created directory extension
where I want to put all files related to work with browsing page.
Then created new file extension\content.ts
and put sample code console.log('hello')
Now it will be good to compile this file as separate in output.
Edit config\webpack.config.js
Go to line 205 and edit value of entry
property
entry: {
main: paths.appIndexJs,
contentScript: paths.contentScript
},
Then add in config\paths.js
property with path to contentScript
contentScript: resolveModule(resolveApp, 'extension/content'),
Good... I have content script file in build directory but it contains hash which during development will make difficulties as it need to be statically typed into manifest.json
So for development process edit scripts\build.js
and edit line 50 and set running configFactory with development
parameter.
const config = configFactory('development');
REMEMBER if this script will be used to make final build it needs to be switched back to production
value.
Yes, the right solution is to put parameter with value of environment variable. But I will skip this for now as do t manually is enough for me.
Now I can check if everything is allright...
npm run build
and the result is:
Of course! Webpack in development mode is set to put all files content to bundle.js so it needs to be updated.
Go to webpack.config.js
line 216-218 and change development value of filename to be dynamic based on name of entries.
filename: isEnvProduction
? 'static/js/[name].[contenthash:8].js'
: isEnvDevelopment && 'static/js/[name].js',
Ooops next issue
It means I need to turn off fast refresh
Powershell
$env:FAST_REFRESH="false"
CMD
set FAST_REFRESH=false
Voilà! Build success and now it is time to make an last update to manifest file to include content script.
{
"name": "Chrome Extension",
"description": "Chrome Extension Description",
"version": "1.0",
"manifest_version": 3,
"action": {
"default_popup": "index.html",
"default_title": "Open the popup"
},
"content_scripts": [
{
"matches": [
"https://*.com/*"
],
"js": [
"static/js/contentScript.js"
],
"run_at": "document_end"
}
]
}
Refresh extension in Chrome and check console in devtools when enter for any page with com domain.
Preparation to publish
This part will be described later.
Top comments (0)