Chrome Extension boilerplate for manifest v3.
![]()
This template uses Parcel Web Extension Config and release-it for GitHub releases.
- Click Use this template button on the top of the page.
- After project initialization, change the
namefield in thepackage.jsonfile. This field will be used as a name for.zipwith production build. - Update
repository,author,bugs,license, andhomepageprops inpackage.jsonaccording to your needs. - There is configured Dependabot version updates.
If you do not want PRs with your dependency version updates, remove the
.github/dependabot.ymlfile.
- Check if your Node.js version is >= 20.
- Run
npm installto install the dependencies. - Run
npm start - Load your extension on Chrome following:
- Access
chrome://extensions/ - Check
Developer mode - Click on
Load unpacked extension - Select the
distfolder.
- Access
- Stop the development script (if it is running)
- Run
npm run build - Load your extension on Chrome following:
- Access
chrome://extensions/ - Check
Developer mode - Click on
Load unpacked extension - Select the
distfolder
- Access
zip file with the production extension's code will be created in the releases folder.
This code is ready to be published in the Chrome Web Store.
During the release script execution you will be asked for a new version number, so there is no need to change the version manually.
The script will bump the version in package.json and manifest.json.
This template uses release-it for release on GitHub.
- Generate
personal access tokenin GitHub. Go to Github->Settings->DeveloperSettings->PersonalAccessTokens. Onlyreposcope is required. - Rename the existing
.env.examplefile to.envand put the generatedpersonal access tokenthere. It will look like:GITHUB_TOKEN="your generated token" - Run
npm run release. Under the hood, it will make a version bump (in bothpackage.jsonandmanifest.json), runnpm run buildsteps, commit, push, and make a GitHub release with the generatedzipfile attached.
Parcel Web Extension Config does not support scripting API
(executeScript, insertCSS, etc.)
As a workaround, take a look at the recipe below.
If you need to inject scripts dynamically using chrome.scripting API, you could add these scripts to manifest.json
as an additional entry point.
For such code
chrome.scripting.executeScript({
target: {tabId},
files: ["checker/index.js"],
})you could update your scripts in manifest.json like this:
"start": "parcel watch src/manifest.json src/checker/index.js --host localhost",
"build": "parcel build src/manifest.json src/checker/index.js --no-cache"
If you need to use assets in such a dynamically injected script,
put them in web_accessible_resources in your manifest.json:
"web_accessible_resources": [
{
"resources": [
"web-accessible/icon.png"
],
"matches": [
"<all_urls>"
]
}
]
And in your code, you will need to use them like
<image src={chrome.runtime.getURL('web-accessible/icon.png')}/>Do not use import icon from "./web-accessible/icon.png" in such scripts.
The same goes for a page(s) not listed in manifest.json.
You can add it as an additional entry point(s).
Something like that:
"start": "parcel watch src/manifest.json src/panel/panel.html --host localhost",
"build": "parcel build src/manifest.json src/panel/panel.html --no-cache"
In that case panel folder will be created in dist and you can reference it from your code like panel/panel.html.
You can take a look at this example. There is an additional entry point (offscreen.html) that is not listed in manifest.json (chrome.offscreen API usage).
If you do not need to use React in your extension:
npm uninstall react react-dom @types/react @types/react-dom eslint-plugin-react eslint-plugin-react-hooksReact is used only in popup,
so remove src/popup/App.js and update src/popup/index.js to meet your needs.
In the .eslintrc.json file remove all the strings related to react (in extends, plugins, and rules props ).