CRXJS Vite Plugin enables modern Chrome extension development with built-in Hot Module Replacement (HMR) and zero-configuration setup. It provides full Vite plugin ecosystem support for building Chrome extensions with TypeScript, React, Vue, Svelte, and other modern frameworks while maintaining compatibility with Chrome's security requirements and Manifest V3 specification.
npm install @crxjs/vite-pluginimport { crx, defineManifest, defineDynamicResource, allFilesReady, filesReady } from "@crxjs/vite-plugin";Alternative import (alias):
import { chromeExtension, defineManifest, defineDynamicResource, allFilesReady, filesReady } from "@crxjs/vite-plugin";For CommonJS:
const { crx, defineManifest, defineDynamicResource, allFilesReady, filesReady } = require("@crxjs/vite-plugin");import { defineConfig } from "vite";
import { crx, defineManifest } from "@crxjs/vite-plugin";
const manifest = defineManifest({
manifest_version: 3,
name: "My Extension",
version: "1.0.0",
background: {
service_worker: "src/background.ts",
},
content_scripts: [
{
matches: ["https://example.com/*"],
js: ["src/content.ts"],
},
],
action: {
default_popup: "src/popup.html",
},
});
export default defineConfig({
plugins: [crx({ manifest })],
});CRXJS Vite Plugin is built around several key components:
Core plugin function that creates Chrome extension configuration for Vite, returning an array of specialized plugins for different extension features.
function crx(options: {
manifest: ManifestV3Export;
} & CrxOptions): PluginOption[];
// Alias for crx function
const chromeExtension = crx;
interface CrxOptions {
contentScripts?: {
preambleCode?: string | false;
hmrTimeout?: number;
injectCss?: boolean;
};
fastGlobOptions?: FastGlobOptions;
browser?: 'firefox' | 'chrome'; // default: 'chrome'
}Type-safe manifest definition utilities with TypeScript support for Chrome Extension Manifest V3, including file path validation and dynamic resource management.
function defineManifest<T extends string>(
manifest: ManifestV3Options<T>
): ManifestV3Export;
function defineDynamicResource(options: {
matches?: string[];
use_dynamic_url?: boolean;
}): WebAccessibleResourceByMatch;
type ManifestV3Export = ManifestV3 | Promise<ManifestV3> | ManifestV3Fn;
type ManifestV3Fn = (env: ConfigEnv) => ManifestV3 | Promise<ManifestV3>;Development server integration providing file watching, processing, and build coordination for Chrome extension assets with HMR support.
function allFilesReady(): Promise<void>;
function fileReady(script: FileWriterId): Promise<void>;Automatic handling of content script injection, CSS processing, and web-accessible resource generation with support for different script formats and execution environments.
interface ContentScript {
type: 'module' | 'iife' | 'loader';
id: string;
refId: string;
resolvedId?: string;
scriptId?: string;
loaderName?: string;
fileName?: string;
isDynamicScript?: boolean;
matches: string[];
css?: string[];
}Special import syntax and type definitions for content scripts, enabling different script formats and execution environments with HMR support.
// Module declarations for special imports
declare module '*?script' {
const fileName: string;
export default fileName;
}
declare module '*?script&loader' {
const fileName: string;
export default fileName;
}
declare module '*?script&iife' {
const fileName: string;
export default fileName;
}
declare module '*?script&module' {
const fileName: string;
export default fileName;
}interface CrxPlugin extends VitePlugin {
transformCrxManifest?(
this: PluginContext,
manifest: ManifestV3
): Promise<ManifestV3 | null | undefined> | ManifestV3 | null | undefined;
renderCrxManifest?(
this: PluginContext,
manifest: ManifestV3,
bundle: OutputBundle
): Promise<ManifestV3 | null | undefined> | ManifestV3 | null | undefined;
renderCrxDevScript?(
code: string,
script: CrxDevScriptId
): Promise<string | null | undefined> | string | null | undefined;
}
interface CrxDevAssetId {
id: string;
type: 'asset';
source?: string | Uint8Array;
}
interface CrxDevScriptId {
id: string;
type: 'module' | 'iife';
}
type Browser = 'firefox' | 'chrome';interface ManifestFiles {
contentScripts: string[];
contentStyles: string[];
html: string[];
icons: string[];
locales: string[];
rulesets: string[];
background: string[];
webAccessibleResources: string[];
}
interface WebAccessibleFiles {
webScripts: string[];
webResources: string[];
}type CrxHMRPayload =
| {
type: 'custom';
event: 'crx:runtime-reload';
}
| {
type: 'custom';
event: 'crx:content-script-payload';
data: HMRPayload;
};interface WebAccessibleResourceByMatch {
matches: string[];
resources: string[];
use_dynamic_url?: boolean;
}
type ManifestV3Options<T extends string> = Omit<ManifestV3, keyof FilePathFields<string>> & FilePathFields<T>;
type FileWriterId = string;