Skip to main content
Extension.js detects Vue from your dependencies. It configures single-file component (SFC) compilation, framework aliases, and dev-time update behavior automatically. Scoped styles, the Composition API, and <script setup> all work without extra bundler wiring.

When Vue is a good fit

  • You already ship production Vue apps.
  • You prefer Vue single-file component authoring with scoped styles and the Composition API.
  • You want extension UI surfaces that mirror existing Vue architecture.

Template examples

new-vue

Template screenshot Build a Vue new-tab experience with SFC support from day one.
Repository: extension-js/examples/newtab-vue

content-vue

Template screenshot Inject Vue components directly into web pages with a content-script setup.
Repository: extension-js/examples/content-vue

Usage with an existing extension

Add Vue to an existing extension with the steps below.

Installation

Install the required dependencies:
For explicit setup in existing projects, install the Vue SFC toolchain too:
When an optional Vue integration package such as vue-loader or @vue/compiler-sfc is missing, the build error names the exact version that matches the bundled toolchain. The install command in the error is phrased for the package manager that your project uses.

Configuration

Extension.js expects Vue components in .vue files. It configures vue-loader, VueLoaderPlugin, and Vue-related define flags in the Rspack pipeline. JSX and TSX pages in a Vue project compile through vue/jsx-runtime.

Development behavior

When Extension.js detects Vue, it:
  • Enables .vue compilation in the framework plugin.
  • Applies Vue runtime aliases (for consistent runtime resolution).
  • Supports content script updates by remounting after relevant Vue SFC changes.
If your project lacks optional Vue tooling, Extension.js warns with the exact install command instead of installing it for you.

Troubleshooting

  • Missing Vue tooling warning: Install vue-loader and @vue/compiler-sfc.
  • Prompt to restart after install: Stop and rerun extension dev so Extension.js can load the newly installed loader/plugin.
  • Unexpected .vue handling issues: Verify vue is present in project dependencies so Extension.js detects Vue integration.

Usage examples

In a new tab extension

To use Vue in a new tab extension, include your entry file in HTML:

In a content_script file

For content scripts, mount a Vue app into an injected root node:

Best practices

  • Keep UI entrypoints framework-first (main.ts, App.vue) and keep extension APIs in dedicated modules.
  • Use scoped styles in SFCs when possible to reduce style leaks in extension pages.
  • For large UIs, split components and shared composables to keep content scripts small.

Runtime build and the Options API

From 4.1.19, a Vue project bundles the runtime-only build, vue.runtime.esm-bundler.js, the file that the vue package names as its module entry. Extension.js aliases vue$, @vue/runtime-dom, @vue/runtime-core, and @vue/shared to that build, so your app and any transpiled workspace dependency share one Vue instance. The full build ships the template compiler, which an extension CSP cannot run, and its innerHTML and Function calls fail the addons.mozilla.org store check. The runtime build has no template compiler, so templates must be precompiled. Single-file components give you that: vue-loader compiles each <template> at build time. In-DOM templates and string template: options are not supported. Vue warns in the console and renders nothing for such a component. To keep runtime compilation, alias vue$ to the full build in extension.config.js:
extension.config.js
That build compiles templates with new Function, which needs unsafe-eval in the extension CSP. Manifest V3 extension pages forbid it, so the alias only helps a Manifest V2 project. The Options API stays on in production. Extension.js sets __VUE_OPTIONS_API__ to true in every mode, so a component written with data(), methods, or computed works in the shipped bundle. __VUE_PROD_DEVTOOLS__ and hydration mismatch details are off in production. One more define applies to every bundle, for every framework. The free identifier global is defined as globalThis, and Rspack’s own global helper is off. That helper falls back to Function("return this"), which fails the addons.mozilla.org store check, so no such shim reaches your bundle.

Next steps

Video walkthrough

See the template run