This is a baseline project for creating cross-browser extensions. It is capable of targeting manifest versions 2 and 3. If you're brand new to extension development, be sure to read the basics so you have a handle on the different packages in this project and their purpose.
To get started, clone this repository and follow the startup guide below.
- What's included
- Technologies used
- Getting started
- Packaging
- All commands
- Project structure
- Troubleshooting
A toolbar popup for your extension that's built using a handful of simple
Preact components. Any other libraries or frameworks
may be used alongside or in place of Preact. Read about the
action
/
browser_action
section of your manifest to make sure your tools of choice are supported.
A minimal content script that prints a message to the console. Additionally, it highlights the cross-package import system provided by NPM workspaces and Typescript paths.
A very basic background script that prints a message when the extension has been installed.
Easily manage different
manifest versions
directly inside package.json
.
- Typescript - Strongly-typed JavaScript
- Vite - Development server, HMR, bundler and more
- Preact - Lightweight React alternative
- Lerna - Monorepo package management
- NodeJS version 20 or higher
- Recommended: nvm - Run
nvm use
to use the required version ornvm install 20
to install it.
- Recommended: nvm - Run
If you've done this kind of thing before, these commands will get you up and running quickly:
- Initialize a new project:
npm run init
- Targeting manifest version 3, start a development server and watch for file
changes:
npm run start 3
- Build output is located in your dist directory. Take a look at the rest of the commands and the project structure to learn more.
To get started, you first need to initialize your project. The boilerplate
contains several things that need customizing such as your extension's display
name (details). In addition to renaming things, the initialization
script also takes care of installing dependencies. Use the npm install
command
in the future if your dependencies change.
-
Run initialization command
npm run init
-
Complete initialization and verify
After running
npm run init
, proceed through the series of prompts and confirm your choices when you're ready. A number of files will be updated and it is recommended to inspect the changes to make sure they align with your expectations. -
Optional: Update manifest permissions
By default, the manifest settings ask for very broad permissions such as accessing data on all sites and modifying local storage. While this may be okay during early stages of development, you should take time to de-scope the parts that say
<all_urls>
andpermissions
. Before publishing, your extension's permissions should require only those necessary for it to function.See the section about updating the manifest for instructions.
-
Start server
Depending on which browser you'd like to use, you now have a choice of either manifest version 2 or 3. Run the
start
command with your desired version (details):npm run start 3 # or... npm run start 2
-
Find your build
Notice a new
dist
directory has been created which holds the output of yourstart
command. After all packages have started, you're ready to load the unpacked extension from this location in your browser of choice. The process for this varies so be sure to look up the latest steps recommended by your browser. Here are some instructions for two popular ones:
Once your extension has reached a state ready for publish, use the package
command to generate a new version. It uses the version
value in
package.json which will need to be updated beforehand:
- Open package.json
- Increase the
version
number to whatever makes sense for the given changes - Review semantic versioning if you're not sure. - Run the
package
command for each desired manifest version:npm run package 3
- The new version is placed in the
versions
directory where it is ready to be uploaded to the extension stores
Commands can be found in the root package.json
under scripts
. Following are
details about each one and how to run them. Commands are executed using NPM with
the format npm run <command>
and most require a manifest version as the last
argument (see start below). Whenever you see a 3
in a command,
you're specifying manifest version three. If you are targeting version two, use
a 2
instead.
Begins a series of prompts where you'll give names to certain things like your extension's display name. This is necessary to replace pieces of boilerplate code so they reflect your own extension. This only needs to be run once at the beginning of any new project.
npm run init
Starts the project and watches for file changes. When a change occurs, a new build is initiated and your extension is updated. Certain actions may still require refreshing the extension in your browser settings.
npm run start 3
Creates an optimized build of the project. Builds generated using this command
are minified. This behavior can be changed by modifying a package's
vite.config.ts
file.
npm run build 3
Prepares your project for publishing to the extension stores. It generates a ZIP
file, with the given manifest version, that may be uploaded directly in the
extension management dashboards. Output files are placed in the versions
directory.
npm run package 3
dist/
-build
andstart
output directory. This is where to load unpacked extensions in your browser settings when testing changes.packages/
- NPM workspaces directory that stores individual project packages.packages/background/
- Background script code and tooling.packages/content/
- Content script code and public assets directory.packages/content/public/assets/
- Files placed here are available to your extension as web-accessible resources. This is enabled by theweb_accessible_resources
setting inpackage.json
. At build time, assets are copied todist/assets/
and their access URLs may be generated using thegetAssetURL
helper method in theshared
package.
packages/popup/
- The extension's Popup window.packages/shared/
- Common configurations and helper methods used across more than one package.packages/types/
- All of the project's types.
scripts/
- Various scripts defined in the root package.json.versions/
-package
command output directory.
Manifest configurations are located in the root-level
package.json under the key manifestJSON
. To make changes:
- Open the file package.json
- Find the section
manifestJSON
- Notice the two sections
v2
andv3
for each manifest version - Add, modify or delete values based on the features and versions you intend to
support - If you change something under
v3
and plan to publish a manifest version 2 of your extension, you'll need to make the equivalent change underv2
. - Changing manifest JSON requires a project re-build using either the
build
orstart
commands
The background
, content
, and popup
packages are individually optional. If
you do not need one or more of them, there are two methods of removal:
-
Silent (preferred) - Omit a package from the main build by updating its relative
build
command inpackage.json
with the following change:# Filename: # packages/popup/package.json { "scripts": { - "build": "tsc && vite build", + "build": "echo \"Info: no build specified\"", } }
In this example, we quietly disable the popup package entirely while maintaining its source code. It is no longer part of our build but is ready to be included any time in the future.
-
Nuclear - Delete the package's directory from
packages
. This is permanent and should only be done if you are certain you won't need it.
- If you've already ran the initialization script
npm run init
, see if runningnpm install
clears anything up.
- Make sure you're running a version supported by the browser you're using.
Version 2 manifests cannot be loaded in Chrome. If you've ran
npm run start 2
ornpm run build 2
, you'll need to re-run them with a target version of3
instead.