# vite-vue3-browser-extension-v3: a Manifest V3 starter for Vue developers

> vite-vue3-browser-extension-v3 is an opinionated starter template for browser extensions built with Vite, Vue 3 and Manifest V3, covering the background worker, popup, options page, content script, devtools, side panel and offscreen documents in one layout, with the same commands producing a Chrome build and a Firefox build. The library was last released in 2023, while the repository is still being pushed to.

**mubaidr/vite-vue3-browser-extension-v3** — Another vite powered web extension (chrome, firefox, etc.) starter template.

- Repository: https://github.com/mubaidr/vite-vue3-browser-extension-v3
- Stars: 791 · Forks: 93
- Language: Vue
- License: MIT
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/mubaidr-vite-vue3-browser-extension-v3

## An opinionated scaffold, not an empty project

vite-vue3-browser-extension-v3 is described as another Vite powered web extension starter template for Chrome, Firefox and others, and the README calls it a modern, opinionated starter template for building browser extensions with Vite, Vue 3 and Manifest V3.

The word opinionated is the important one, because a template that fixes the stack for you is also one that fixes your stack for you. The choices made here are Vue 3 with the Composition API, Pinia for state, Vue Router, Nuxt/UI v3, shadcn-vue, Tailwind CSS 4, Lucide icons, TypeScript in strict mode, and vue-i18n for internationalisation. That is a coherent and current stack, and it is also a stack you inherit.

The other half of the value is the extension-specific plumbing. The feature list calls it a multi-context architecture, and it enumerates the contexts: background script, popup, options page, content script, devtools, side panel, and offscreen pages. A new extension usually starts with one of those working and the other six as questions, and a template that already has the service worker, the devtools panel and the offscreen document in place saves a day of work that has nothing to do with your product.

On top of that sit the two libraries that make the contexts usable together: webext-bridge for cross-context communication, and webextension-polyfill for browser API compatibility, which is what lets the same code run on Firefox and Chromium without rewriting the extension APIs behind it.

The licence is MIT, the primary language is Vue, and the last push to the repository was on 2026-06-29.

## Scaffolding with degit and running both browsers

The quick start is four commands, and the first one is worth understanding rather than copying.

```bash
npx degit mubaidr/vite-vue3-browser-extension-v3 my-webext
cd my-webext
npm install
npm run dev
```

degit is a fork of create-vue-app that downloads a repository's contents without the git history, which is the right behaviour for a template, because the point of a template is that you own the result and there is no upstream to merge from.

The command table is where the two-browser design becomes visible. There is npm run dev for development on both Chrome and Firefox, and npm run dev:chrome and npm run dev:firefox for one at a time. The same split exists for the build: npm run build for both, and npm run build:chrome and npm run build:firefox for one. Then there is npm run lint, described as running ESLint with auto-fix, npm run typecheck, and npm run format with Prettier.

The fact that a single dev command can drive two browsers at once is the interesting part, and it comes from the config layout. The repository carries manifest.config.ts alongside manifest.chrome.config.ts and manifest.firefox.config.ts, and the same pattern for the Vite side with vite.config.ts, vite.chrome.config.ts and vite.firefox.config.ts. The build scripts, the @crxjs/vite-plugin and the zip packaging plugin, vite-plugin-zip-pack, all sit on top of that.

The result is that a developer runs one command and gets a Chrome instance and a Firefox instance with the extension loaded, and the manifest differences between the two are handled by configuration rather than by branching in code.

## Loading the built extension, and the two different rituals

How you get the built extension into a browser differs enough between the two to be worth quoting exactly.

For Chrome and Edge the steps are to open chrome://extensions, enable Developer mode with the toggle in the top-right, click Load unpacked, and select the dist/chrome folder.

For Firefox the steps are to open about:debugging#/runtime/this-firefox, click Load Temporary Add-on, and select any file in the dist/firefox folder. The difference in the last step is the point: Chrome wants a directory, Firefox wants a file from inside the directory, because a Firefox temporary add-on is a single packaged manifest rather than an unpacked tree.

The two builds are not the same artefact with a different name. The folder names differ, and the manifests behind them come from the separate manifest.chrome.config.ts and manifest.firefox.config.ts files, which is how the Manifest V3 versus Manifest V2 question is handled. The browser support list says Chrome with Manifest V3, Firefox with Manifest V2 or V3, Edge, and other Chromium-based browsers.

One consequence for a project that has to ship in both stores is worth planning for: the build produces a Chrome-flavoured extension and a Firefox-flavoured extension, and the signing, review and update paths for those are entirely separate. The template makes the build easy. It does not make the release easy, and the difference matters for a team that intends to publish.

## File-based routing for the UI pages

The second feature is file-based routing, described as auto-registered UI pages from src/ui/*/pages, and the project structure explains how that fits together.

The src directory is organised by context first. There are separate directories for the background service worker, shared Vue components, composables, content scripts, the DevTools panel, offscreen documents, Pinia state stores, TypeScript definitions and shared utilities. Then there is the ui directory, described as the UI entrypoints for things like the popup and the options page, and inside it a pages directory per entrypoint.

That is the mechanism behind the auto-registration. Each page file in a pages folder becomes a route, so adding a new options page is adding a file rather than editing a route table. The Vue Router dependency and the file-based routing feature are two halves of the same idea.

The organisation is worth a moment's thought because it is not the only sensible layout. Some teams organise by feature, so that the popup, options and devtools code for one product area live together. This template organises by context, which means everything about the background worker is in one place and everything about the popup is in another. That is the right choice when a developer works on one context at a time, and the wrong one when a feature spans contexts, which is exactly what webext-bridge exists to make possible.

The doc directory holds DEVELOPMENT.md, which the README points to for architecture, design principles, folder structure and best practices, and the repository also ships an AGENTS.md with coding guidelines written for AI assistants, which is a small but telling signal about how the maintainer expects the template to be used.

## The component and styling stack

The UI layer of the template is worth naming, because it is the part that shapes how your extension looks on day one.

The feature list gives the components as Nuxt/UI v3, shadcn-vue, Tailwind CSS 4 and Lucide icons. Nuxt/UI is the Vue component library, shadcn-vue is the Vue port of the shadcn approach, where you copy component source into your own project rather than depending on a package, and the presence of a components.json file at the repository root is the giveaway, since that is the shadcn configuration file.

That is an opinionated choice with a specific consequence. A shadcn-vue component is code in your repository, not a dependency you can upgrade with npm, so when the template is updated the components do not move with it. For a project that intends to live a long time, that is a trade you take knowingly, and it is one of the reasons to read the DEVELOPMENT.md before starting rather than after.

The icons are Lucide, in the form of the @iconify-json/lucide package, alongside @iconify-json/ph and @iconify-json/svg-spinners, which is the Iconify approach of pulling icon sets as data rather than as components. Tailwind 4 and the tw-animate-css package handle the styling layer, and the vite-plugin-vue-devtools and unplugin-turbo-console entries in the dev dependencies point to a template that is set up for a comfortable development loop rather than for a minimal bundle.

For internationalisation there is vue-i18n with the unplugin-vue-i18n build integration, and the feature list describes the project as i18n ready rather than shipping with a dozen locales, which is the sensible default for a template.

## What the toolchain pins, and what the release history says

The dependency list in the package manifest is long, and it describes a project that has been kept current. Vite is at 7.3.1, Vue at 3.5.28, Vue Router at 5.0.0, Pinia at 3.0.4, Tailwind at 4.1.18, Nuxt/UI at 4.4.0, TypeScript at 5.9.3, vue-tsc at 3.2.4 and vue-i18n at 11.2.8, with webext-bridge at 6.0.1 and webextension-polyfill at 0.12.0. Type checking is done with vue-tsc, and linting with ESLint 9 through a flat config file, eslint.config.mjs, with formatting by Prettier 3.

The presence of vue-tsc rather than plain tsc is the detail to note, because the types of a Vue single file component are only meaningful if the checker understands the template.

The release record is where the caveats live. There is a single tag, 0.0.2, named Fix router warnings, from 2023-09-05. The last push was on 2026-06-29, so the tree is being worked on, but three years separate the newest published version from the newest commit.

For a template that is a starting point rather than a dependency, that matters less than it would for a library, because you copy the code and own it. What it does mean is that if you read a tutorial or a blog post about this template from 2023 or 2024, the advice may describe a Vite 4 or Vue 3.3 world, and the current versions in the manifest have moved on.

## Conclusion

vite-vue3-browser-extension-v3 suits a Vue developer who wants to start an extension with the boring parts already solved, the popup, options page, content script, devtools panel, side panel and offscreen document all wired up, and the Chrome and Firefox build differences already handled in separate config files. It is the wrong choice if you want a minimal scaffold with no opinions, because the template commits you to Vue 3, Nuxt/UI, Tailwind 4 and Pinia, and it is the wrong choice if you need a plugin distributed through the Chrome Web Store with a reproducible release, since the newest published tag is from September 2023. Verify three things before you start: that the dev and build commands produce a dist/chrome and a dist/firefox folder that your browser will actually load, that the file-based routing convention for UI pages is what you want for your extension, and how far the pinned toolchain versions, Vite 7 and Vue 3.5, drift from what your own applications run.

## FAQ

### What is vite-vue3-browser-extension-v3?

It is an opinionated starter template for building browser extensions with Vite, Vue 3 and Manifest V3, supporting Chrome, Firefox, Edge and other Chromium-based browsers. It ships the background script, popup, options page, content script, devtools panel, side panel and offscreen document contexts, and it is MIT licensed.

### How do I start a new extension from this template?

Run npx degit mubaidr/vite-vue3-browser-extension-v3 my-webext, change into the new directory, run npm install and then npm run dev. degit copies the template contents without the git history, so the result is yours to own.

### How do I load the built extension into Chrome and Firefox?

In Chrome or Edge, open chrome://extensions, enable Developer mode, click Load unpacked and select the dist/chrome folder. In Firefox, open about:debugging#/runtime/this-firefox, click Load Temporary Add-on and select any file inside the dist/firefox folder.

### Which npm scripts does the template provide?

There are dev, dev:chrome and dev:firefox for development, build, build:chrome and build:firefox for packaging, plus lint for ESLint with auto-fix, typecheck for TypeScript checking and format for Prettier. The default dev and build commands cover both browsers at once.

### How does file-based routing work in this template?

UI pages are auto-registered from the src/ui/*/pages directories, so a new page is a new file rather than an entry in a route table. The src tree is organised by context, with separate directories for background, components, composables, content-script, devtools, offscreen, stores, types and utils.

### Is the template still being released?

The repository was last pushed on 2026-06-29, but the most recent published tag is 0.0.2 from 2023-09-05, named Fix router warnings. Since a template is copied rather than depended on, the gap matters less than it would for a library, but older tutorials about it may describe older tool versions.

## Sources

- [Issues](https://github.com/mubaidr/vite-vue3-browser-extension-v3/issues)
- [License: MIT](https://github.com/mubaidr/vite-vue3-browser-extension-v3/blob/master/LICENSE)
- [mubaidr/vite-vue3-browser-extension-v3 on GitHub](https://github.com/mubaidr/vite-vue3-browser-extension-v3)
- [README](https://github.com/mubaidr/vite-vue3-browser-extension-v3/blob/master/README.md)
- [Releases](https://github.com/mubaidr/vite-vue3-browser-extension-v3/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/mubaidr-vite-vue3-browser-extension-v3
