vitesse-webext: a Vite starter template for Chrome and Firefox extensions
⚡️ WebExtension Vite Starter Template
At a glance
- What is it?
- The antfu-collective/vitesse-webext template gives a WebExtension a Vite dev server with HMR, Vue 3, TypeScript and UnoCSS, plus a typed manifest. It is a starting point, not a framework, and the README leaves packaging and store submission to you.
- Who is it for?
- Adopt vitesse-webext if you are starting a new Chrome or Firefox extension and want Vite HMR, Vue 3 and a typed manifest from the first commit. Do not adopt it if you need a maintained runtime library, a build pipeline that already produces store-ready artifacts, or a project with release notes to track: the repository's last push was on 2026-03-03 and it has no published releases.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Activity is slowing. The repository last received commits 8 months ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.
Star history
- antfu-collective/vitesse-webext3,376 ★ · -3
| Repository | 2026-09-24 | 2026-11-14 |
|---|---|---|
| antfu-collective/vitesse-webext | 3.4k | 3.4k |
-3 Stars in the last 51 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
What vitesse-webext actually is, and who it is for
vitesse-webext is a starter template, not a library you install as a dependency. The README describes it as a Vite powered WebExtension starter template for Chrome, Firefox and others, and the repository is published under the MIT licence with TypeScript as the primary language. Its job is to remove the setup work between an empty directory and a browser extension that has a popup, an options page, a background script and a content script.
The intended user is a frontend developer who already knows Vue and wants the extension development loop to feel like a web app development loop. The README's first feature bullet is instant HMR, and the fourth is effortless communications powered by webext-bridge and VueUse storage. That pairing tells you the target audience: people who find refreshing the extension manually on every change annoying, and who want message passing between the background, popup and content script without writing their own wrapper.
It is less suitable for someone who wants a minimal, dependency-light extension. The template pre-packs webextension-polyfill, webext-bridge, unplugin-auto-import, unplugin-vue-components, unplugin-icons, VueUse and UnoCSS. That is a lot of moving parts to inherit on day one, and each one is a decision you would otherwise make yourself.
The Vite dev loop and the three build configs
The mechanism is unusual enough to be worth spelling out. A browser extension cannot be served by a normal Vite dev server, because the browser loads files from an extension directory rather than from an HTTP origin. The template works around this with separate Vite configs for separate targets. The repository root contains vite.config.mts, vite.config.background.mts and vite.config.content.mts, and the package.json scripts build each one separately: build:web runs vite build, build:background runs vite build --config vite.config.background.mts, and build:js runs vite build --config vite.config.content.mts.
The extension package root is the extension/ directory, which holds static assets mainly for the manifest and a dist/ directory that the README says also serves as the stub entry for Vite during development. The source lives in src/, with contentScript/, background/, components/, styles/, assets/ and manifest.ts. That manifest.ts file is the dynamic manifest with full type support mentioned in the features list, so the manifest is generated by scripts/prepare.ts rather than edited by hand.
Message passing is handled by webext-bridge, which the README lists under WebExtension libraries alongside webextension-polyfill. The polyfill gives you the browser API with types across browsers; webext-bridge gives you a channel between contexts so the popup can talk to the background script without you writing chrome.runtime.sendMessage plumbing. The template also injects a Vue app into the content script, which the README illustrates with a screenshot.
Installing vitesse-webext and running pnpm dev
The README offers two routes. The first is the GitHub template button, which creates a repository from the template. The second is a manual clone with degit, which the README recommends if you prefer a cleaner git history. The README notes that if you do not have pnpm installed, you should run npm install -g pnpm first.
npx degit antfu/vitesse-webext my-webext
cd my-webext
pnpm iAfter installation, the development command starts the Vite dev server and the background and content script builds in parallel. The package.json dev script runs npm run clear first, then cross-env NODE_ENV=development run-p dev:*, so the extension/dist and extension/manifest.json directories are removed before each start.
pnpm devThe README then says to load the extension in the browser with the extension/ folder. That means opening the browser's extension management page and pointing the unpacked extension loader at that directory. For Firefox there is a separate command, and the README states that web-ext auto reloads the extension when files in extension/ change.
pnpm dev-firefoxThe README still recommends the Extensions Reloader browser extension for cleaner hard reloading, which is an admission that Vite HMR does not cover every case in an extension context. When you are ready to ship, pnpm build runs the production sequence, and the README says to pack the files under extension/ and upload extension.crx or extension.xpi to the appropriate store. The pack scripts in package.json produce exactly those: pack:crx uses crx pack, and pack:xpi uses web-ext build with WEB_EXT_ARTIFACTS_DIR set to the repository root.
Where the template stops helping
The README does not document rollback, versioning strategy or a release process, and the repository has no published releases. The version field in package.json is 0.0.1 and the package is marked private, which is consistent with a template that is meant to be copied rather than published. If you are looking for a dependency you can pin and upgrade, this is the wrong shape of project.
The maintenance picture matters here. The last push to the repository was on 2026-03-03. That is the only maintenance signal available, and it is old enough that you should not assume the template tracks current browser extension requirements. Chrome's manifest version requirements and Firefox's add-on policies change on their own schedule, and the README does not state which manifest version the generated manifest targets. You will find that out by reading src/manifest.ts after cloning.
The auto-import configuration is another trade-off. unplugin-auto-import lets you use browser and the Vue Composition API without importing them, and unplugin-vue-components auto-imports components. That reduces boilerplate, but it also means a reader of the code cannot tell from a single file where a symbol comes from. If your team prefers explicit imports, you are fighting the template's defaults rather than benefiting from them.
The README also does not explain how the content script build handles CSS injection or how the background script's service worker lifecycle is managed, both of which are common sources of bugs in Manifest V3 extensions. Those are questions the template leaves to you.
vitesse-webext versus a framework like WXT
The real alternative to a starter template is an extension framework. WXT is the one that appears in the related searches for this project, and the difference in approach is structural rather than cosmetic. vitesse-webext is a repository you copy: you own every file from the first commit, and upgrading means diffing against the template or merging upstream changes by hand. A framework like WXT is a dependency you install: the build pipeline, the manifest generation and the entry point conventions live in the package, and upgrading means changing a version number.
That trade-off cuts both ways. Copying gives you full control and no upgrade treadmill, which is why the README's degit route exists. Depending on a framework gives you a maintained upgrade path but constrains how you lay out entry points. If your extension is a small popup with a background script, the template's freedom costs you little. If you expect to track browser API changes for years, a framework's release cadence is worth more than the ability to edit every config file.
The second alternative is simply not using a template at all. Vite can build an extension with a hand-written config and a static manifest, and that removes the unplugin-auto-import, unplugin-icons and UnoCSS layers entirely. The cost is that you write the three-config split yourself, which is the part of this template that saves the most time.
Licence and what upgrading costs
The repository is MIT licensed, and the LICENSE file sits at the top level. For a template that you copy into your own repository, that is the permissive case: you can keep the licence file, or replace it, without the copyleft obligations that a GPL-licensed template would impose. This is not legal advice, and if you are shipping a commercial extension you should confirm the terms of the bundled dependencies separately, since the template pulls in webext-bridge, webextension-polyfill, VueUse, UnoCSS and the unplugin packages, each with its own licence.
The upgrade cost is the part templates hide. Because there is no release channel, there is no changelog to read and no migration guide. The package.json pins pnpm as the package manager at [email protected] and lists devDependencies with caret ranges, so a fresh pnpm i today will resolve newer minor versions than the template was written against. The lint configuration comes from @antfu/eslint-config, which is opinionated about formatting: single quotes and no semicolons, as the README states. If your team's style differs, you are either changing the config or changing your habits.
The e2e directory and playwright.config.ts at the top level indicate that Playwright tests are part of the template, and package.json exposes test:e2e for them and test via vitest. Those are real scripts you inherit, and they are also scripts you now have to keep working as the dependencies move.
Editorial conclusion
Adopt vitesse-webext if you are starting a new Chrome or Firefox extension and want Vite HMR, Vue 3 and a typed manifest from the first commit. Do not adopt it if you need a maintained runtime library, a build pipeline that already produces store-ready artifacts, or a project with release notes to track: the repository's last push was on 2026-03-03 and it has no published releases. Before committing, verify that `pnpm dev` loads the `extension/` folder in your target browser, that `pnpm build` produces a manifest matching the MV2 or MV3 requirements of the stores you plan to submit to, and that the `webext-bridge` version in package.json still matches the API you call.
Frequently asked questions
How do I install vitesse-webext?
The README gives two routes: create a repository from the GitHub template, or run npx degit antfu/vitesse-webext my-webext followed by cd my-webext and pnpm i. If pnpm is not installed, the README says to run npm install -g pnpm first.
How do I load the extension in the browser while developing vitesse-webext?
Run pnpm dev, then load the extension in the browser using the extension/ folder. For Firefox, run pnpm dev-firefox instead, and the README states that web-ext auto reloads the extension when files in extension/ change.
Does vitesse-webext support Firefox as well as Chrome?
Yes. The README describes it as an isomorphic extension for Chrome, Firefox and others, and lists webextension-polyfill among the pre-packed libraries. It also provides a separate dev-firefox script and a pack:xpi script that builds extension.xpi with web-ext.
How do I build vitesse-webext for an extension store?
Run pnpm build, then pack the files under extension/ and upload extension.crx or extension.xpi to the appropriate store, as the README states. The pack scripts in package.json produce those artifacts: pack:crx uses crx pack and pack:xpi uses web-ext build.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/antfu-collective-vitesse-webext)Star history chart for your README
[](https://hysenlabs.com/projects/antfu-collective-vitesse-webext)Was this useful?