@crxjs/vite-plugin
Version:
Build Chrome Extensions with this Vite plugin.
384 lines (376 loc) • 13.2 kB
TypeScript
import { ConfigEnv, Plugin, PluginOption } from 'vite';
import { Options } from 'fast-glob';
import { PluginContext, OutputBundle } from 'rollup';
interface DeclarativeNetRequestResource {
id: string;
enabled: boolean;
path: string;
}
interface WebAccessibleResourceByMatch {
matches: string[];
resources: string[];
use_dynamic_url?: boolean;
}
interface WebAccessibleResourceById {
extension_ids: string[];
resources: string[];
use_dynamic_url?: boolean;
}
interface ChromeManifestBackground {
service_worker: string;
type?: 'module' | (string & {});
}
interface FirefoxManifestBackground {
scripts: string[];
persistent?: false;
}
interface ManifestV3 {
manifest_version: number;
name: string;
version: string;
default_locale?: string | undefined;
description?: string | undefined;
icons?: chrome.runtime.ManifestIcons | undefined;
action?: chrome.runtime.ManifestAction | undefined;
/**
* @see https://developer.chrome.com/docs/extensions/reference/manifest/author
*/
author?: {
email: string;
} | undefined;
background?: ChromeManifestBackground | FirefoxManifestBackground | undefined;
chrome_settings_overrides?: {
homepage?: string | undefined;
search_provider?: chrome.runtime.SearchProvider | undefined;
startup_pages?: string[] | undefined;
} | undefined;
chrome_ui_overrides?: {
bookmarks_ui?: {
remove_bookmark_shortcut?: boolean | undefined;
remove_button?: boolean | undefined;
} | undefined;
} | undefined;
chrome_url_overrides?: {
bookmarks?: string | undefined;
history?: string | undefined;
newtab?: string | undefined;
} | undefined;
commands?: {
[name: string]: {
suggested_key?: {
default?: string | undefined;
windows?: string | undefined;
mac?: string | undefined;
chromeos?: string | undefined;
linux?: string | undefined;
} | undefined;
description?: string | undefined;
global?: boolean | undefined;
};
} | undefined;
content_capabilities?: {
matches?: string[] | undefined;
permissions?: string[] | undefined;
} | undefined;
content_scripts?: {
matches?: string[] | undefined;
exclude_matches?: string[] | undefined;
css?: string[] | undefined;
js?: string[] | undefined;
run_at?: string | undefined;
all_frames?: boolean | undefined;
match_about_blank?: boolean | undefined;
include_globs?: string[] | undefined;
exclude_globs?: string[] | undefined;
}[] | undefined;
content_security_policy?: {
extension_pages?: string;
sandbox?: string;
};
converted_from_user_script?: boolean | undefined;
current_locale?: string | undefined;
declarative_net_request?: {
rule_resources: DeclarativeNetRequestResource[];
};
devtools_page?: string | undefined;
event_rules?: {
event?: string | undefined;
actions?: {
type: string;
}[] | undefined;
conditions?: chrome.declarativeContent.PageStateMatcherProperties[] | undefined;
}[] | undefined;
externally_connectable?: {
ids?: string[] | undefined;
matches?: string[] | undefined;
accepts_tls_channel_id?: boolean | undefined;
} | undefined;
file_browser_handlers?: {
id?: string | undefined;
default_title?: string | undefined;
file_filters?: string[] | undefined;
}[] | undefined;
file_system_provider_capabilities?: {
configurable?: boolean | undefined;
watchable?: boolean | undefined;
multiple_mounts?: boolean | undefined;
source?: string | undefined;
} | undefined;
homepage_url?: string | undefined;
host_permissions?: string[] | undefined;
import?: {
id: string;
minimum_version?: string | undefined;
}[] | undefined;
export?: {
whitelist?: string[] | undefined;
} | undefined;
incognito?: string | undefined;
input_components?: {
name: string;
id?: string | undefined;
language?: string | string[] | undefined;
layouts?: string | string[] | undefined;
input_view?: string | undefined;
options_page?: string | undefined;
}[] | undefined;
key?: string | undefined;
minimum_chrome_version?: string | undefined;
nacl_modules?: {
path: string;
mime_type: string;
}[] | undefined;
oauth2?: {
client_id: string;
scopes?: string[] | undefined;
} | undefined;
offline_enabled?: boolean | undefined;
omnibox?: {
keyword: string;
} | undefined;
optional_host_permissions?: string[] | undefined;
optional_permissions?: chrome.runtime.ManifestPermissions[] | string[] | undefined;
options_page?: string | undefined;
options_ui?: {
page?: string | undefined;
chrome_style?: boolean | undefined;
open_in_tab?: boolean | undefined;
} | undefined;
permissions?: chrome.runtime.ManifestPermissions[] | string[] | undefined;
platforms?: {
nacl_arch?: string | undefined;
sub_package_path: string;
}[] | undefined;
plugins?: {
path: string;
}[] | undefined;
requirements?: {
'3D'?: {
features?: string[] | undefined;
} | undefined;
plugins?: {
npapi?: boolean | undefined;
} | undefined;
} | undefined;
sandbox?: {
pages: string[];
content_security_policy?: string | undefined;
} | undefined;
side_panel?: {
default_path?: string | undefined;
} | undefined;
short_name?: string | undefined;
spellcheck?: {
dictionary_language?: string | undefined;
dictionary_locale?: string | undefined;
dictionary_format?: string | undefined;
dictionary_path?: string | undefined;
} | undefined;
storage?: {
managed_schema: string;
} | undefined;
tts_engine?: {
voices: {
voice_name: string;
lang?: string | undefined;
gender?: string | undefined;
event_types?: string[] | undefined;
}[];
} | undefined;
update_url?: string | undefined;
version_name?: string | undefined;
web_accessible_resources?: (WebAccessibleResourceById | WebAccessibleResourceByMatch)[] | undefined;
}
type ManifestV3Fn = (env: ConfigEnv) => ManifestV3 | Promise<ManifestV3>;
type ManifestV3Export = ManifestV3 | Promise<ManifestV3> | ManifestV3Fn;
type Code = '.' | '/' | '\\';
type ManifestFilePath<T extends string> = T extends `${Code}${string}` ? never : T extends `${string}.${infer Ext}` ? Ext extends '' ? never : T : never;
interface ManifestIcons<T extends string> {
[size: number]: ManifestFilePath<T>;
}
type FilePathFields<T extends string> = {
icons?: ManifestIcons<T>;
action?: {
/**
* - Relative to Vite project root (where vite.config.js is)
* - Format: "subdir/icon.png" (no leading ./ or /)
*
* @example "assets/icon.png"
*/
default_icon?: ManifestIcons<T>;
default_title?: string;
/**
* - Relative to Vite project root (where vite.config.js is)
* - Format: "subdir/index.html" (no leading ./ or /)
*
* @example "src/popup.html"
*/
default_popup?: ManifestFilePath<T>;
};
background?: {
/**
* - Relative to Vite project root (where vite.config.js is)
* - Format: "subdir/index.js" (no leading ./ or /)
*
* @example "src/background.js"
*/
service_worker: ManifestFilePath<T>;
type?: 'module' | (string & {});
} | FirefoxManifestBackground;
content_scripts?: {
matches?: string[];
exclude_matches?: string[];
/**
* - Relative to Vite project root (where vite.config.js is)
* - Format: "subdir/content.css" (no leading ./ or /)
*
* @example "src/content.css"
*/
css?: ManifestFilePath<T>[];
/**
* - Relative to Vite project root (where vite.config.js is)
* - Format: "subdir/content.js" (no leading ./ or /)
*
* @example "src/content.js"
*/
js?: ManifestFilePath<T>[];
run_at?: string;
all_frames?: boolean;
match_about_blank?: boolean;
include_globs?: string[];
exclude_globs?: string[];
}[];
input_components?: {
name: string;
id?: string;
language?: string | string[];
layouts?: string | string[];
input_view?: string;
/**
* - Relative to Vite project root (where vite.config.js is)
* - Format: "subdir/options.html" (no leading ./ or /)
*
* @example "src/options.html"
*/
options_page?: ManifestFilePath<T>;
}[];
/**
* - Relative to Vite project root (where vite.config.js is)
* - Format: "subdir/options.html" (no leading ./ or /)
*
* @example "src/options.html"
*/
options_page?: ManifestFilePath<T>;
/**
* - Relative to Vite project root (where vite.config.js is)
* - Format: "subdir/devtools.html" (no leading ./ or /)
*
* @example "src/devtools.html"
*/
devtools_page?: ManifestFilePath<T>;
};
type ManifestOptions<T extends string> = Omit<ManifestV3, keyof FilePathFields<string>> & FilePathFields<T>;
type ManifestV3Options<T extends string = string> = ManifestOptions<T> | Promise<ManifestOptions<T>> | ManifestV3Define<T>;
type ManifestV3Define<T extends string> = (env: ConfigEnv) => ManifestOptions<T> | Promise<ManifestOptions<T>>;
declare const defineManifest: <T extends string>(manifest: ManifestV3Options<T>) => ManifestV3Export;
/**
* Content script resources like CSS and image files must be declared in the
* manifest under `web_accessible_resources`. Manifest V3 uses a match pattern
* to narrow the origins that can access a Chrome CRX resource.
*
* Content script resources use the same match pattern as the content script for
* web accessible resources.
*
* You don't need to define a match pattern for dynamic content script
* resources, but if you want to do so, you can use the helper function
* `defineDynamicResource` to define your web accessible resources in a
* TypeScript file:
*
* ```typescript
* import { crx, defineManifest, defineDynamicResource }
* const manifest = defineManifest({
* "web_accessible_resources": [
* defineDynamicResource({
* matches: ["https://example.com/*", "file:///*.mp3", "..."]
* use_dynamic_url?: true
* })
* ]
* })
* ```
*/
declare const defineDynamicResource: ({ matches, use_dynamic_url, }: Omit<WebAccessibleResourceByMatch, 'resources'>) => WebAccessibleResourceByMatch;
type CrxDevAssetId = {
id: string;
type: 'asset';
source?: string | Uint8Array;
};
type CrxDevScriptId = {
id: string;
type: 'module' | 'iife';
};
interface CrxPlugin extends Plugin {
/**
* Runs during the transform hook for the manifest. Filenames use input
* filenames.
*/
transformCrxManifest?: (this: PluginContext, manifest: ManifestV3) => Promise<ManifestV3 | null | undefined> | ManifestV3 | null | undefined;
/**
* Runs during generateBundle, before manifest output. Filenames use output
* filenames.
*/
renderCrxManifest?: (this: PluginContext, manifest: ManifestV3, bundle: OutputBundle) => Promise<ManifestV3 | null | undefined> | ManifestV3 | null | undefined;
/**
* Runs in the file writer on content scripts during development. `script.id`
* is Vite URL format.
*/
renderCrxDevScript?: (code: string, script: CrxDevScriptId) => Promise<string | null | undefined> | string | null | undefined;
}
interface CrxOptions {
contentScripts?: {
preambleCode?: string | false;
hmrTimeout?: number;
injectCss?: boolean;
};
fastGlobOptions?: Options;
/**
* The browser that this extension is targeting, can be "firefox" or "chrome".
* Default is "chrome".
*/
browser?: Browser;
}
type Browser = 'firefox' | 'chrome';
/** Resolves when all existing files in scriptFiles are written. */
declare function allFilesReady(): Promise<void>;
type FileWriterId = {
type: CrxDevAssetId['type'] | CrxDevScriptId['type'] | 'loader';
id: string;
};
/** Resolves when file and dependencies are written. */
declare function fileReady(script: FileWriterId): Promise<void>;
declare const crx: (options: {
manifest: ManifestV3Export;
} & CrxOptions) => PluginOption[];
declare const chromeExtension: (options: {
manifest: ManifestV3Export;
} & CrxOptions) => PluginOption[];
export { CrxPlugin, ManifestV3Export, allFilesReady, chromeExtension, crx, defineDynamicResource, defineManifest, fileReady as filesReady };