Understanding the manifest.ts File in CRXJS: Purpose, Structure, and Type Safety
The manifest.ts file in CRXJS provides a strongly-typed TypeScript schema for Chrome Extension Manifest V3, enabling compile-time validation and IDE autocomplete for extension manifests across the entire toolchain.
The crxjs/chrome-extension-tools repository uses this central type definition file to power its Vite and Rollup plugins. Located at packages/vite-plugin/src/node/manifest.ts, it exports the ManifestV3 interface and related helper types that allow developers to write their extension configuration in TypeScript rather than raw JSON, catching errors before runtime.
Purpose of the manifest.ts File in CRXJS
The primary purpose of manifest.ts is to provide an exhaustive, strongly-typed representation of the Chrome (and Firefox) extension manifest schema. According to the CRXJS source code, this file serves three critical functions:
- Compile-time validation – Developers writing
manifest.tsfiles get immediate TypeScript errors for misspelled keys or incorrect value types (e.g., passing a number where the schema expects a string). - IDE intelligence – The interfaces provide autocomplete for Chrome-specific keys like
chrome_url_overrides,declarative_net_request, andweb_accessible_resources. - Tooling consistency – Both the Vite plugin and Rollup plugin import these same definitions from
packages/vite-plugin/src/node/manifest.ts, ensuring manifests are interpreted identically across the entire CRXJS toolchain.
Structure of the manifest.ts Type Definitions
The file organizes type definitions into logical sections that mirror the official Chrome extension manifest schema while accounting for cross-browser compatibility.
Utility Types for Complex Manifest Fields
The file begins with small, reusable interfaces for nested manifest structures. These handle complex fields that appear multiple times throughout the schema.
export interface DeclarativeNetRequestResource {
id: string
enabled: boolean
path: string
}
export interface WebAccessibleResourceByMatch {
matches: string[]
resources: string[]
use_dynamic_url?: boolean
}
These utility types ensure that web_accessible_resources and declarative_net_request rules maintain consistent structure across different extension configurations.
Browser-Specific Background Script Types
CRXJS handles the divergence between Chrome and Firefox background script implementations through distinct interfaces combined into a union type.
ChromeManifestBackground– Defines the Chrome-specificservice_workerfield with optionaltype: 'module'for ES module support.FirefoxManifestBackground– Defines Firefox'sscriptsarray andpersistentboolean flag.
These are exported as a union type ChromeManifestBackground | FirefoxManifestBackground assigned to the background property in the main manifest interface.
The ManifestV3 Interface
The centerpiece of the file is the massive ManifestV3 interface that implements the complete Manifest V3 specification. It organizes fields by requirement level:
export interface ManifestV3 {
// Required fields
manifest_version: number
name: string
version: string
// Recommended fields
default_locale?: string
description?: string
icons?: chrome.runtime.ManifestIcons
// Optional Chrome-specific sections
action?: chrome.runtime.ManifestAction
background?: ChromeManifestBackground | FirefoxManifestBackground
content_scripts?: chrome.runtime.ManifestContentScript[]
permissions?: chrome.runtime.ManifestPermissions[]
host_permissions?: string[]
// ... additional optional fields
}
The interface references Chrome's official type definitions (e.g., chrome.runtime.ManifestAction) while extending them with CRXJS-specific browser compatibility layers.
Firefox Gecko Permissions
For Firefox-specific extensions, the file includes GeckoPermissionsRequired and GeckoPermissionsOptional interfaces. These type the browser_specific_settings.gecko.data_collection_permissions field, allowing developers to declare Firefox-specific permissions while maintaining type safety.
How CRXJS Uses manifest.ts for Type Checking
The Vite plugin and Rollup plugin consume these type definitions to validate user configurations at build time. When a developer writes their manifest in TypeScript (typically as src/manifest.ts), the plugins import the ManifestV3 interface to enforce schema compliance.
For example, the fixture at packages/rollup-plugin/__fixtures__/extensions/mv3-manifest-ts-single-input/src/manifest.ts demonstrates real-world usage, importing the interface and exporting a fully typed manifest object. This approach prevents runtime manifest errors that would otherwise only surface during extension loading in the browser.
Practical Examples: Writing Type-Safe Extension Manifests
Defining a Standard ManifestV3 Configuration
// src/manifest.ts
import { ManifestV3 } from '@crxjs/vite-plugin';
const manifest: ManifestV3 = {
manifest_version: 3,
name: 'My Awesome Extension',
version: '1.0.0',
action: {
default_popup: 'popup.html',
},
background: {
service_worker: 'service_worker.ts',
type: 'module',
},
content_scripts: [
{
matches: ['https://*/*', 'http://*/*'],
js: ['content.ts'],
run_at: 'document_idle',
},
],
permissions: ['storage', 'tabs'],
host_permissions: ['*://*.example.com/*'],
};
export default manifest;
The TypeScript compiler immediately flags invalid keys (such as permissoins instead of permissions) or incorrect types (such as passing a number for the version field).
Configuring Firefox-Specific Background Scripts
import { ManifestV3 } from '@crxjs/vite-plugin';
const manifest: ManifestV3 = {
manifest_version: 3,
name: 'Cross-Browser Demo',
version: '0.1',
background: {
scripts: ['background.js'],
persistent: false,
},
};
Because background accepts the union type ChromeManifestBackground | FirefoxManifestBackground, TypeScript enforces that only Firefox-compatible properties (scripts, persistent) are present when targeting that browser.
Declaring Web Accessible Resources with Dynamic URLs
import { ManifestV3 } from '@crxjs/vite-plugin';
const manifest: ManifestV3 = {
manifest_version: 3,
name: 'Dynamic Assets',
version: '1.0',
web_accessible_resources: [
{
matches: ['*://*/*'],
resources: ['images/*.png'],
use_dynamic_url: true,
},
],
};
The WebAccessibleResourceByMatch interface ensures the use_dynamic_url property is correctly typed as an optional boolean, preventing accidental string assignments.
Summary
- The
manifest.tsfile atpackages/vite-plugin/src/node/manifest.tsserves as the central TypeScript schema for Chrome Extension Manifest V3 within CRXJS. - It exports the
ManifestV3interface along with browser-specific types likeChromeManifestBackgroundandFirefoxManifestBackgroundto handle cross-platform differences. - The file enables compile-time validation and IDE autocomplete for extension developers using the Vite or Rollup plugins.
- Utility interfaces such as
DeclarativeNetRequestResourceandWebAccessibleResourceByMatchprovide granular type safety for complex manifest fields. - Real-world usage examples in the repository demonstrate how importing these types prevents runtime manifest errors.
Frequently Asked Questions
Where is the manifest.ts file located in the CRXJS repository?
The main type definitions reside at packages/vite-plugin/src/node/manifest.ts. This file exports all manifest-related interfaces used throughout the CRXJS toolchain, including the primary ManifestV3 interface consumed by both the Vite and Rollup plugins.
What is the difference between ChromeManifestBackground and FirefoxManifestBackground?
ChromeManifestBackground defines the Chrome-specific structure using service_worker and optional type: 'module' for ES modules, while FirefoxManifestBackground uses the scripts array and persistent boolean required by Firefox's Manifest V3 implementation. The ManifestV3 interface accepts these as a union type for the background property, ensuring only valid properties for the target browser are allowed.
Can I use manifest.ts with the Rollup plugin or only Vite?
Both plugins support TypeScript manifest files. The Rollup plugin fixture at packages/rollup-plugin/__fixtures__/extensions/mv3-manifest-ts-single-input/src/manifest.ts demonstrates importing ManifestV3 from @crxjs/vite-plugin and using it to type-check a Rollup-based extension build.
Does the ManifestV3 interface support Manifest V2 fields?
No, the ManifestV3 interface specifically targets Chrome Extension Manifest V3. It omits V2-specific fields like browser_action and page_action (replaced by the unified action field in V3) and enforces manifest_version: 3. Developers targeting Manifest V2 would need to use different type definitions or extend the interfaces manually.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →