Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 57a12c1711 | |||
| d13ca3983f | |||
| 9769ce4ac9 | |||
| 55dc263dc9 | |||
| e56ae23747 | |||
| bfd4af5d69 | |||
| 9673604878 | |||
| ae55aecb0d | |||
| a14d0b4f2f | |||
| 301e4a17da | |||
| 19cebbf673 | |||
| ef73c07dfe | |||
| ca5ad7e51b | |||
| 5dab944abc | |||
| adaae6e1a4 | |||
| 4524cbdf76 |
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
# Set default
|
# Set default
|
||||||
* @aklinker1 @Timeraa
|
* @aklinker1
|
||||||
|
|
||||||
# Secure Directories
|
# Secure Directories
|
||||||
/.github/ @aklinker1
|
/.github/ @aklinker1
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
with:
|
||||||
|
ref: ${{ github.ref }}
|
||||||
|
|
||||||
- name: Setup
|
- name: Setup
|
||||||
uses: ./.github/actions/setup
|
uses: ./.github/actions/setup
|
||||||
@@ -47,5 +49,8 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
commit_message: 'docs: Update `wxt init` GIF'
|
commit_message: 'docs: Update `wxt init` GIF'
|
||||||
|
commit_user_name: github-actions[bot]
|
||||||
|
commit_user_email: github-actions[bot]@users.noreply.github.com
|
||||||
|
commit_author: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
|
||||||
# https://github.com/charmbracelet/vhs#output
|
# https://github.com/charmbracelet/vhs#output
|
||||||
file_pattern: 'docs/assets/*.gif'
|
file_pattern: 'docs/assets/*.gif'
|
||||||
|
|||||||
@@ -1,2 +1,4 @@
|
|||||||
singleQuote: true
|
singleQuote: true
|
||||||
endOfLine: lf
|
endOfLine: lf
|
||||||
|
plugins:
|
||||||
|
- prettier-plugin-jsdoc
|
||||||
|
|||||||
@@ -119,6 +119,8 @@ const chromeExtensionIds = [
|
|||||||
'mfjdonmgmgcijagclnkfhmjiblbfjaid', // KeyFloat - Floating multilingual keyboard with native key mappings, drag, dark mode, sounds, and dynamic layouts for macOS & Windows
|
'mfjdonmgmgcijagclnkfhmjiblbfjaid', // KeyFloat - Floating multilingual keyboard with native key mappings, drag, dark mode, sounds, and dynamic layouts for macOS & Windows
|
||||||
'dhiekgdaipindoapjmcnpompdknjeijf', // Glossy New Tab - Say Goodbye to Boring Tabs with live wallpapers
|
'dhiekgdaipindoapjmcnpompdknjeijf', // Glossy New Tab - Say Goodbye to Boring Tabs with live wallpapers
|
||||||
'lapnciffpekdengooeolaienkeoilfeo', // All API Hub – AI Relay & New API Manager - https://github.com/qixing-jk/all-api-hub
|
'lapnciffpekdengooeolaienkeoilfeo', // All API Hub – AI Relay & New API Manager - https://github.com/qixing-jk/all-api-hub
|
||||||
|
'bhgobenflkkhfcgkikejaaejenoddcmo', // Scrape Similar - Extract data from websites into spreadsheets - https://github.com/zizzfizzix/scrape-similar
|
||||||
|
'kinlknncggaihnhdcalijdmpbhbflalm', // isTrust - https://github.com/Internet-Society-Belgium/isTrust/
|
||||||
];
|
];
|
||||||
|
|
||||||
const { data, err, isLoading } = useListExtensionDetails(chromeExtensionIds);
|
const { data, err, isLoading } = useListExtensionDetails(chromeExtensionIds);
|
||||||
|
|||||||
@@ -77,9 +77,7 @@ export function menuItem(
|
|||||||
return { text, link };
|
return { text, link };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Clean up and add badges to typedoc leaf sections */
|
||||||
* Clean up and add badges to typedoc leaf sections
|
|
||||||
*/
|
|
||||||
export function prepareTypedocSidebar(items: SidebarItem[]) {
|
export function prepareTypedocSidebar(items: SidebarItem[]) {
|
||||||
// skip contents file
|
// skip contents file
|
||||||
const filtered = items.slice(1);
|
const filtered = items.slice(1);
|
||||||
|
|||||||
+10
-9
@@ -16,27 +16,28 @@
|
|||||||
"docs:preview": "pnpm -s docs:gen && vitepress preview docs"
|
"docs:preview": "pnpm -s docs:gen && vitepress preview docs"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@aklinker1/buildc": "^1.1.6",
|
"@aklinker1/buildc": "^1.1.7",
|
||||||
"@aklinker1/check": "^2.2.0",
|
"@aklinker1/check": "^2.2.0",
|
||||||
"@commitlint/config-conventional": "^20.4.1",
|
"@commitlint/config-conventional": "^20.4.3",
|
||||||
"@commitlint/types": "^20.4.0",
|
"@commitlint/types": "^20.4.3",
|
||||||
"@types/fs-extra": "^11.0.4",
|
"@types/fs-extra": "^11.0.4",
|
||||||
"@types/semver": "^7.7.1",
|
"@types/semver": "^7.7.1",
|
||||||
"@vitest/coverage-v8": "^4.0.18",
|
"@vitest/coverage-v8": "^4.0.18",
|
||||||
"changelogen": "^0.6.2",
|
"changelogen": "^0.6.2",
|
||||||
"consola": "^3.4.2",
|
"consola": "^3.4.2",
|
||||||
"fast-glob": "^3.3.3",
|
|
||||||
"feed": "^5.2.0",
|
"feed": "^5.2.0",
|
||||||
"fs-extra": "^11.3.3",
|
"fs-extra": "^11.3.4",
|
||||||
"lint-staged": "^16.2.7",
|
"lint-staged": "^16.3.2",
|
||||||
"markdown-it-footnote": "^4.0.0",
|
"markdown-it-footnote": "^4.0.0",
|
||||||
"markdownlint-cli": "^0.47.0",
|
"markdownlint-cli": "^0.48.0",
|
||||||
"nano-spawn": "^2.0.0",
|
"nano-spawn": "^2.0.0",
|
||||||
"p-map": "^7.0.4",
|
"p-map": "^7.0.4",
|
||||||
"prettier": "^3.8.1",
|
"prettier": "^3.8.1",
|
||||||
|
"prettier-plugin-jsdoc": "^1.8.0",
|
||||||
"semver": "^7.7.4",
|
"semver": "^7.7.4",
|
||||||
"simple-git-hooks": "^2.13.1",
|
"simple-git-hooks": "^2.13.1",
|
||||||
"tsdown": "^0.20.3",
|
"tinyglobby": "^0.2.15",
|
||||||
|
"tsdown": "^0.21.0",
|
||||||
"tsx": "4.21.0",
|
"tsx": "4.21.0",
|
||||||
"typedoc": "^0.25.4",
|
"typedoc": "^0.25.4",
|
||||||
"typedoc-plugin-frontmatter": "^1.3.1",
|
"typedoc-plugin-frontmatter": "^1.3.1",
|
||||||
@@ -48,7 +49,7 @@
|
|||||||
"vitepress-plugin-group-icons": "^1.7.1",
|
"vitepress-plugin-group-icons": "^1.7.1",
|
||||||
"vitepress-plugin-llms": "^1.11.0",
|
"vitepress-plugin-llms": "^1.11.0",
|
||||||
"vitest-mock-extended": "^3.1.0",
|
"vitest-mock-extended": "^3.1.0",
|
||||||
"vue": "^3.5.27",
|
"vue": "^3.5.29",
|
||||||
"wxt": "workspace:*"
|
"wxt": "workspace:*"
|
||||||
},
|
},
|
||||||
"simple-git-hooks": {
|
"simple-git-hooks": {
|
||||||
|
|||||||
@@ -62,7 +62,8 @@ export function createAnalytics(config?: AnalyticsConfig): Analytics {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an analytics client in the background responsible for uploading events to the server to avoid CORS errors.
|
* Creates an analytics client in the background responsible for uploading
|
||||||
|
* events to the server to avoid CORS errors.
|
||||||
*/
|
*/
|
||||||
function createBackgroundAnalytics(
|
function createBackgroundAnalytics(
|
||||||
config: AnalyticsConfig | undefined,
|
config: AnalyticsConfig | undefined,
|
||||||
@@ -219,9 +220,7 @@ function createBackgroundAnalytics(
|
|||||||
return analytics;
|
return analytics;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Creates an analytics client for non-background contexts. */
|
||||||
* Creates an analytics client for non-background contexts.
|
|
||||||
*/
|
|
||||||
function createFrontendAnalytics(): Analytics {
|
function createFrontendAnalytics(): Analytics {
|
||||||
const port = browser.runtime.connect({ name: ANALYTICS_PORT });
|
const port = browser.runtime.connect({ name: ANALYTICS_PORT });
|
||||||
const sessionId = Date.now();
|
const sessionId = Date.now();
|
||||||
|
|||||||
@@ -8,36 +8,39 @@ export interface Analytics {
|
|||||||
) => void;
|
) => void;
|
||||||
/** Save information about the user. */
|
/** Save information about the user. */
|
||||||
identify: (userId: string, userProperties?: Record<string, string>) => void;
|
identify: (userId: string, userProperties?: Record<string, string>) => void;
|
||||||
/** Automatically setup and track user interactions, returning a function to remove any listeners that were setup. */
|
/**
|
||||||
|
* Automatically setup and track user interactions, returning a function to
|
||||||
|
* remove any listeners that were setup.
|
||||||
|
*/
|
||||||
autoTrack: (root: Document | ShadowRoot | Element) => () => void;
|
autoTrack: (root: Document | ShadowRoot | Element) => () => void;
|
||||||
/** Calls `config.enabled.setValue`. */
|
/** Calls `config.enabled.setValue`. */
|
||||||
setEnabled: (enabled: boolean) => void;
|
setEnabled: (enabled: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AnalyticsConfig {
|
export interface AnalyticsConfig {
|
||||||
/**
|
/** Array of providers to send analytics to. */
|
||||||
* Array of providers to send analytics to.
|
|
||||||
*/
|
|
||||||
providers: AnalyticsProvider[];
|
providers: AnalyticsProvider[];
|
||||||
/**
|
/** Enable debug logs and other provider-specific debugging features. */
|
||||||
* Enable debug logs and other provider-specific debugging features.
|
|
||||||
*/
|
|
||||||
debug?: boolean;
|
debug?: boolean;
|
||||||
/**
|
/**
|
||||||
* Your extension's version, reported alongside events.
|
* Your extension's version, reported alongside events.
|
||||||
|
*
|
||||||
* @default browser.runtime.getManifest().version`.
|
* @default browser.runtime.getManifest().version`.
|
||||||
*/
|
*/
|
||||||
version?: string;
|
version?: string;
|
||||||
/**
|
/**
|
||||||
* Configure how the enabled flag is persisted. Defaults to using `browser.storage.local`.
|
* Configure how the enabled flag is persisted. Defaults to using
|
||||||
|
* `browser.storage.local`.
|
||||||
*/
|
*/
|
||||||
enabled?: AnalyticsStorageItem<boolean>;
|
enabled?: AnalyticsStorageItem<boolean>;
|
||||||
/**
|
/**
|
||||||
* Configure how the user Id is persisted. Defaults to using `browser.storage.local`.
|
* Configure how the user Id is persisted. Defaults to using
|
||||||
|
* `browser.storage.local`.
|
||||||
*/
|
*/
|
||||||
userId?: AnalyticsStorageItem<string | undefined>;
|
userId?: AnalyticsStorageItem<string | undefined>;
|
||||||
/**
|
/**
|
||||||
* Configure how user properties are persisted. Defaults to using `browser.storage.local`.
|
* Configure how user properties are persisted. Defaults to using
|
||||||
|
* `browser.storage.local`.
|
||||||
*/
|
*/
|
||||||
userProperties?: AnalyticsStorageItem<Record<string, string>>;
|
userProperties?: AnalyticsStorageItem<Record<string, string>>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/ua-parser-js": "^0.7.39",
|
"@types/ua-parser-js": "^0.7.39",
|
||||||
"publint": "^0.3.17",
|
"publint": "^0.3.18",
|
||||||
"typescript": "^5.9.3",
|
"typescript": "^5.9.3",
|
||||||
"wxt": "workspace:*"
|
"wxt": "workspace:*"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -47,12 +47,12 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"defu": "^6.1.4",
|
"defu": "^6.1.4",
|
||||||
"fs-extra": "^11.3.3",
|
"fs-extra": "^11.3.4",
|
||||||
"sharp": "^0.34.5"
|
"sharp": "^0.34.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"oxlint": "^1.43.0",
|
"oxlint": "^1.51.0",
|
||||||
"publint": "^0.3.17",
|
"publint": "^0.3.18",
|
||||||
"typescript": "^5.9.3",
|
"typescript": "^5.9.3",
|
||||||
"vitest": "^4.0.18",
|
"vitest": "^4.0.18",
|
||||||
"wxt": "workspace:*"
|
"wxt": "workspace:*"
|
||||||
|
|||||||
@@ -109,12 +109,11 @@ export default defineWxtModule<AutoIconsOptions>({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/** Options for the auto-icons module */
|
||||||
* Options for the auto-icons module
|
|
||||||
*/
|
|
||||||
export interface AutoIconsOptions {
|
export interface AutoIconsOptions {
|
||||||
/**
|
/**
|
||||||
* Enable auto-icons generation
|
* Enable auto-icons generation
|
||||||
|
*
|
||||||
* @default true
|
* @default true
|
||||||
*/
|
*/
|
||||||
enabled?: boolean;
|
enabled?: boolean;
|
||||||
@@ -122,27 +121,30 @@ export interface AutoIconsOptions {
|
|||||||
* Path to the image to use.
|
* Path to the image to use.
|
||||||
*
|
*
|
||||||
* Path is relative to the project's src directory.
|
* Path is relative to the project's src directory.
|
||||||
* @default "<srcDir>/assets/icon.png"
|
*
|
||||||
|
* @default '<srcDir>/assets/icon.png'
|
||||||
*/
|
*/
|
||||||
baseIconPath?: string;
|
baseIconPath?: string;
|
||||||
/**
|
/**
|
||||||
* Apply a visual indicator to the icon when running in development mode.
|
* Apply a visual indicator to the icon when running in development mode.
|
||||||
*
|
*
|
||||||
* "grayscale" converts the icon to grayscale.
|
* "grayscale" converts the icon to grayscale. "overlay" covers the bottom
|
||||||
* "overlay" covers the bottom half with a yellow rectangle and writes "DEV" in black text.
|
* half with a yellow rectangle and writes "DEV" in black text. Set to `false`
|
||||||
* Set to `false` to disable any indicator.
|
* to disable any indicator.
|
||||||
*
|
*
|
||||||
* @default "grayscale"
|
* @default 'grayscale'
|
||||||
*/
|
*/
|
||||||
developmentIndicator?: 'grayscale' | 'overlay' | false;
|
developmentIndicator?: 'grayscale' | 'overlay' | false;
|
||||||
/**
|
/**
|
||||||
* Grayscale the image when in development mode to indicate development
|
* Grayscale the image when in development mode to indicate development
|
||||||
* @default true
|
*
|
||||||
* @deprecated Use `developmentIndicator` instead
|
* @deprecated Use `developmentIndicator` instead
|
||||||
|
* @default true
|
||||||
*/
|
*/
|
||||||
grayscaleOnDevelopment?: boolean;
|
grayscaleOnDevelopment?: boolean;
|
||||||
/**
|
/**
|
||||||
* Sizes to generate icons for
|
* Sizes to generate icons for
|
||||||
|
*
|
||||||
* @default [128, 48, 32, 16]
|
* @default [128, 48, 32, 16]
|
||||||
*/
|
*/
|
||||||
sizes?: number[];
|
sizes?: number[];
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
],
|
],
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/chrome": "0.1.37",
|
"@types/chrome": "0.1.37",
|
||||||
"fs-extra": "^11.3.3",
|
"fs-extra": "^11.3.4",
|
||||||
"nano-spawn": "^2.0.0",
|
"nano-spawn": "^2.0.0",
|
||||||
"typescript": "^5.9.3",
|
"typescript": "^5.9.3",
|
||||||
"vitest": "^4.0.18"
|
"vitest": "^4.0.18"
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
],
|
],
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/chrome": "{{chromeTypesVersion}}",
|
"@types/chrome": "{{chromeTypesVersion}}",
|
||||||
"fs-extra": "^11.3.3",
|
"fs-extra": "^11.3.4",
|
||||||
"nano-spawn": "^2.0.0",
|
"nano-spawn": "^2.0.0",
|
||||||
"typescript": "^5.9.3",
|
"typescript": "^5.9.3",
|
||||||
"vitest": "^4.0.18"
|
"vitest": "^4.0.18"
|
||||||
|
|||||||
@@ -28,8 +28,8 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@wxt-dev/browser": "workspace:^",
|
"@wxt-dev/browser": "workspace:^",
|
||||||
"chokidar": "^5.0.0",
|
"chokidar": "^5.0.0",
|
||||||
"confbox": "^0.1.8 || ^0.2.2",
|
"confbox": "^0.2.4",
|
||||||
"fast-glob": "^3.3.3"
|
"tinyglobby": "^0.2.15"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"wxt": ">=0.19.7"
|
"wxt": ">=0.19.7"
|
||||||
@@ -41,8 +41,8 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^20.17.6",
|
"@types/node": "^20.17.6",
|
||||||
"oxlint": "^1.43.0",
|
"oxlint": "^1.51.0",
|
||||||
"publint": "^0.3.17",
|
"publint": "^0.3.18",
|
||||||
"typescript": "^5.9.3",
|
"typescript": "^5.9.3",
|
||||||
"vitest": "^4.0.18",
|
"vitest": "^4.0.18",
|
||||||
"vitest-plugin-random-seed": "^1.1.2",
|
"vitest-plugin-random-seed": "^1.1.2",
|
||||||
|
|||||||
@@ -51,7 +51,8 @@ export type MessageFormat = 'JSON5' | 'YAML' | 'TOML';
|
|||||||
//
|
//
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See https://developer.chrome.com/docs/extensions/reference/api/i18n#overview-predefined
|
* See
|
||||||
|
* https://developer.chrome.com/docs/extensions/reference/api/i18n#overview-predefined
|
||||||
*/
|
*/
|
||||||
const PREDEFINED_MESSAGES: Record<string, ChromeMessage> = {
|
const PREDEFINED_MESSAGES: Record<string, ChromeMessage> = {
|
||||||
'@@extension_id': {
|
'@@extension_id': {
|
||||||
@@ -110,9 +111,7 @@ const ALLOWED_CHROME_MESSAGE_KEYS: Set<string> = new Set<keyof ChromeMessage>([
|
|||||||
// PARSING
|
// PARSING
|
||||||
//
|
//
|
||||||
|
|
||||||
/**
|
/** Parse a messages file, extract the messages. Supports JSON, JSON5, and YAML. */
|
||||||
* Parse a messages file, extract the messages. Supports JSON, JSON5, and YAML.
|
|
||||||
*/
|
|
||||||
export async function parseMessagesFile(
|
export async function parseMessagesFile(
|
||||||
file: string,
|
file: string,
|
||||||
): Promise<ParsedMessage[]> {
|
): Promise<ParsedMessage[]> {
|
||||||
@@ -121,9 +120,7 @@ export async function parseMessagesFile(
|
|||||||
return parseMessagesText(text, EXT_FORMATS_MAP[ext] ?? 'JSON5');
|
return parseMessagesText(text, EXT_FORMATS_MAP[ext] ?? 'JSON5');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Parse a string, extracting the messages. Supports JSON, JSON5, and YAML. */
|
||||||
* Parse a string, extracting the messages. Supports JSON, JSON5, and YAML.
|
|
||||||
*/
|
|
||||||
export function parseMessagesText(
|
export function parseMessagesText(
|
||||||
text: string,
|
text: string,
|
||||||
format: 'JSON5' | 'YAML' | 'TOML',
|
format: 'JSON5' | 'YAML' | 'TOML',
|
||||||
@@ -131,9 +128,7 @@ export function parseMessagesText(
|
|||||||
return parseMessagesObject(PARSERS[format](text));
|
return parseMessagesObject(PARSERS[format](text));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Given the JS object form of a raw messages file, extract the messages. */
|
||||||
* Given the JS object form of a raw messages file, extract the messages.
|
|
||||||
*/
|
|
||||||
export function parseMessagesObject(object: any): ParsedMessage[] {
|
export function parseMessagesObject(object: any): ParsedMessage[] {
|
||||||
return _parseMessagesObject(
|
return _parseMessagesObject(
|
||||||
[],
|
[],
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
/**
|
/** @module @wxt-dev/i18n */
|
||||||
* @module @wxt-dev/i18n
|
|
||||||
*/
|
|
||||||
import {
|
import {
|
||||||
I18nStructure,
|
I18nStructure,
|
||||||
DefaultI18nStructure,
|
DefaultI18nStructure,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* ```ts
|
* ```ts
|
||||||
* export default defineConfig({
|
* export default defineConfig({
|
||||||
* modules: ["@wxt-dev/i18n/module"],
|
* modules: ['@wxt-dev/i18n/module'],
|
||||||
* });
|
* });
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
@@ -18,7 +18,7 @@ import {
|
|||||||
generateTypeText,
|
generateTypeText,
|
||||||
SUPPORTED_LOCALES,
|
SUPPORTED_LOCALES,
|
||||||
} from './build';
|
} from './build';
|
||||||
import glob from 'fast-glob';
|
import { glob } from 'tinyglobby';
|
||||||
import { basename, extname, join, resolve } from 'node:path';
|
import { basename, extname, join, resolve } from 'node:path';
|
||||||
import { watch } from 'chokidar';
|
import { watch } from 'chokidar';
|
||||||
import { GeneratedPublicFile, WxtDirFileEntry } from 'wxt';
|
import { GeneratedPublicFile, WxtDirFileEntry } from 'wxt';
|
||||||
@@ -47,6 +47,7 @@ export default defineWxtModule<I18nOptions>({
|
|||||||
const files = await glob('*.{json,json5,jsonc,yml,yaml,toml}', {
|
const files = await glob('*.{json,json5,jsonc,yml,yaml,toml}', {
|
||||||
cwd: localesDir,
|
cwd: localesDir,
|
||||||
absolute: true,
|
absolute: true,
|
||||||
|
expandDirectories: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
const unsupportedLocales: string[] = [];
|
const unsupportedLocales: string[] = [];
|
||||||
@@ -180,13 +181,12 @@ export { type GeneratedI18nStructure }
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/** Options for the i18n module */
|
||||||
* Options for the i18n module
|
|
||||||
*/
|
|
||||||
export interface I18nOptions {
|
export interface I18nOptions {
|
||||||
/**
|
/**
|
||||||
* Directory containing files that define the translations.
|
* Directory containing files that define the translations.
|
||||||
* @default "${config.srcDir}/locales"
|
*
|
||||||
|
* @default '${config.srcDir}/locales'
|
||||||
*/
|
*/
|
||||||
localesDir?: string;
|
localesDir?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,8 +15,8 @@
|
|||||||
"@wxt-dev/browser": "workspace:^"
|
"@wxt-dev/browser": "workspace:^"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"oxlint": "^1.43.0",
|
"oxlint": "^1.51.0",
|
||||||
"publint": "^0.3.17",
|
"publint": "^0.3.18",
|
||||||
"typescript": "^5.9.3",
|
"typescript": "^5.9.3",
|
||||||
"vitest": "^4.0.18"
|
"vitest": "^4.0.18"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
/**
|
/**
|
||||||
* This module uses a lazy getter function so the logic isn't ran until it's needed.
|
* This module uses a lazy getter function so the logic isn't ran until it's
|
||||||
|
* needed.
|
||||||
*
|
*
|
||||||
* This has a few benefits:
|
* This has a few benefits:
|
||||||
|
*
|
||||||
* 1. Easier to mock in tests
|
* 1. Easier to mock in tests
|
||||||
* 2. Safe to import in NodeJS environments (but it should be safe to run just in-case)
|
* 2. Safe to import in NodeJS environments (but it should be safe to run just
|
||||||
* 3. Keeps startup fast by waiting to run the slow functions (`instanceof` or `browser.extension.getBackgroundPage`) until needed
|
* in-case)
|
||||||
|
* 3. Keeps startup fast by waiting to run the slow functions (`instanceof` or
|
||||||
|
* `browser.extension.getBackgroundPage`) until needed
|
||||||
*
|
*
|
||||||
* @module @wxt-dev/is-background
|
* @module @wxt-dev/is-background
|
||||||
*/
|
*/
|
||||||
@@ -16,10 +20,10 @@ let cached: boolean | undefined;
|
|||||||
* Getter that returns if the current context is apart of an extension's
|
* Getter that returns if the current context is apart of an extension's
|
||||||
* background or not.
|
* background or not.
|
||||||
*
|
*
|
||||||
* > This function caches the result when called for the first time so it
|
* > This function caches the result when called for the first time so it doesn't
|
||||||
* > doesn't have to recalculate.
|
* > have to recalculate.
|
||||||
*
|
*
|
||||||
* @returns true when in a background page or service worker.
|
* @returns True when in a background page or service worker.
|
||||||
*/
|
*/
|
||||||
export function isBackground(): boolean {
|
export function isBackground(): boolean {
|
||||||
if (cached == null) cached = getIsBackground();
|
if (cached == null) cached = getIsBackground();
|
||||||
|
|||||||
@@ -1,5 +1,27 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## v1.2.0
|
||||||
|
|
||||||
|
[compare changes](https://github.com/wxt-dev/wxt/compare/module-react-v1.1.5...module-react-v1.2.0)
|
||||||
|
|
||||||
|
### 🚀 Enhancements
|
||||||
|
|
||||||
|
- Add `vitePluginsBefore` option ([#2170](https://github.com/wxt-dev/wxt/pull/2170))
|
||||||
|
- Vite 8 support ([bfd4af5d](https://github.com/wxt-dev/wxt/commit/bfd4af5d))
|
||||||
|
|
||||||
|
### 🏡 Chore
|
||||||
|
|
||||||
|
- Upgrade dev and non-major prod dependencies ([#2000](https://github.com/wxt-dev/wxt/pull/2000))
|
||||||
|
- Use `tsdown` to build packages ([#2006](https://github.com/wxt-dev/wxt/pull/2006))
|
||||||
|
- Move script-only dev dependencies to top-level `package.json` ([#2007](https://github.com/wxt-dev/wxt/pull/2007))
|
||||||
|
- Update dependencies ([#2069](https://github.com/wxt-dev/wxt/pull/2069))
|
||||||
|
- **deps:** Upgrade deps ([#2175](https://github.com/wxt-dev/wxt/pull/2175))
|
||||||
|
|
||||||
|
### ❤️ Contributors
|
||||||
|
|
||||||
|
- Aaron ([@aklinker1](https://github.com/aklinker1))
|
||||||
|
- Martin Broder <hello@martinbroder.com>
|
||||||
|
|
||||||
## v1.1.5
|
## v1.1.5
|
||||||
|
|
||||||
[compare changes](https://github.com/wxt-dev/wxt/compare/module-react-v1.1.4...module-react-v1.1.5)
|
[compare changes](https://github.com/wxt-dev/wxt/compare/module-react-v1.1.4...module-react-v1.1.5)
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
import 'wxt';
|
import 'wxt';
|
||||||
import { addImportPreset, addViteConfig, defineWxtModule } from 'wxt/modules';
|
import { addImportPreset, addViteConfig, defineWxtModule } from 'wxt/modules';
|
||||||
import react, { Options as PluginOptions } from '@vitejs/plugin-react';
|
import react, { Options as PluginOptions } from '@vitejs/plugin-react';
|
||||||
|
import type { PluginOption } from 'vite';
|
||||||
|
|
||||||
export default defineWxtModule<ReactModuleOptions>({
|
export default defineWxtModule<ReactModuleOptions>({
|
||||||
name: '@wxt-dev/module-react',
|
name: '@wxt-dev/module-react',
|
||||||
configKey: 'react',
|
configKey: 'react',
|
||||||
setup(wxt, options) {
|
setup(wxt, options) {
|
||||||
const { vite } = options ?? {};
|
const { vite, vitePluginsBefore } = options ?? {};
|
||||||
|
|
||||||
addViteConfig(wxt, () => ({
|
addViteConfig(wxt, () => ({
|
||||||
plugins: [react(vite)],
|
plugins: [...(vitePluginsBefore ?? []), react(vite)],
|
||||||
}));
|
}));
|
||||||
|
|
||||||
addImportPreset(wxt, 'react');
|
addImportPreset(wxt, 'react');
|
||||||
@@ -30,6 +31,12 @@ export default defineWxtModule<ReactModuleOptions>({
|
|||||||
|
|
||||||
export interface ReactModuleOptions {
|
export interface ReactModuleOptions {
|
||||||
vite?: PluginOptions;
|
vite?: PluginOptions;
|
||||||
|
/**
|
||||||
|
* Vite plugins to add before the `react()` plugin. Some plugins like the
|
||||||
|
* `@tanstack/router-plugin` need to be added before `react()` to work
|
||||||
|
* correctly.
|
||||||
|
*/
|
||||||
|
vitePluginsBefore?: PluginOption[];
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module 'wxt' {
|
declare module 'wxt' {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"funding": "https://github.com/sponsors/wxt-dev",
|
"funding": "https://github.com/sponsors/wxt-dev",
|
||||||
"version": "1.1.5",
|
"version": "1.2.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./dist/index.cjs",
|
"main": "./dist/index.cjs",
|
||||||
"module": "./dist/index.mjs",
|
"module": "./dist/index.mjs",
|
||||||
@@ -45,18 +45,20 @@
|
|||||||
"prepare": "buildc --deps-only -- wxt prepare"
|
"prepare": "buildc --deps-only -- wxt prepare"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
"vite": "^5.4.19 || ^6.3.4 || ^7.0.0 || ^8.0.0-0",
|
||||||
"wxt": ">=0.19.16"
|
"wxt": ">=0.19.16"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vitejs/plugin-react": "^4.4.1 || ^5.0.0"
|
"@vitejs/plugin-react": "^4.4.1 || ^5.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/react": "^19.2.13",
|
"@types/react": "^19.2.14",
|
||||||
"@types/react-dom": "^19.2.3",
|
"@types/react-dom": "^19.2.3",
|
||||||
"publint": "^0.3.17",
|
"publint": "^0.3.18",
|
||||||
"react": "^19.2.4",
|
"react": "^19.2.4",
|
||||||
"react-dom": "^19.2.4",
|
"react-dom": "^19.2.4",
|
||||||
"typescript": "^5.9.3",
|
"typescript": "^5.9.3",
|
||||||
|
"vite": "^7.0.0",
|
||||||
"wxt": "workspace:*"
|
"wxt": "workspace:*"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@
|
|||||||
"vite-plugin-solid": "^2.11.10"
|
"vite-plugin-solid": "^2.11.10"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"publint": "^0.3.17",
|
"publint": "^0.3.18",
|
||||||
"solid-js": "^1.9.11",
|
"solid-js": "^1.9.11",
|
||||||
"typescript": "^5.9.3",
|
"typescript": "^5.9.3",
|
||||||
"wxt": "workspace:*"
|
"wxt": "workspace:*"
|
||||||
|
|||||||
@@ -50,7 +50,7 @@
|
|||||||
"@sveltejs/vite-plugin-svelte": "^4.0.0 || ^5.0.0 || ^6.0.0"
|
"@sveltejs/vite-plugin-svelte": "^4.0.0 || ^5.0.0 || ^6.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"publint": "^0.3.17",
|
"publint": "^0.3.18",
|
||||||
"typescript": "^5.9.3",
|
"typescript": "^5.9.3",
|
||||||
"wxt": "workspace:*"
|
"wxt": "workspace:*"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,7 +49,7 @@
|
|||||||
"@vitejs/plugin-vue": "^5.2.3 || ^6.0.0"
|
"@vitejs/plugin-vue": "^5.2.3 || ^6.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"publint": "^0.3.17",
|
"publint": "^0.3.18",
|
||||||
"typescript": "^5.9.3",
|
"typescript": "^5.9.3",
|
||||||
"wxt": "workspace:*"
|
"wxt": "workspace:*"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,8 +28,8 @@
|
|||||||
"prepublishOnly": "pnpm build"
|
"prepublishOnly": "pnpm build"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"oxlint": "^1.43.0",
|
"oxlint": "^1.51.0",
|
||||||
"publint": "^0.3.17",
|
"publint": "^0.3.18",
|
||||||
"typescript": "^5.9.3",
|
"typescript": "^5.9.3",
|
||||||
"vitest": "^4.0.18"
|
"vitest": "^4.0.18"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -124,7 +124,8 @@ export const KNOWN_BROWSER_PATHS: Record<
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When targeting a browser, this map contains the other targets to fall back on when a binary could not be found for the primary target.
|
* When targeting a browser, this map contains the other targets to fall back on
|
||||||
|
* when a binary could not be found for the primary target.
|
||||||
*/
|
*/
|
||||||
export const FALLBACK_TARGETS: Partial<Record<KnownTarget, KnownTarget[]>> = {
|
export const FALLBACK_TARGETS: Partial<Record<KnownTarget, KnownTarget[]>> = {
|
||||||
chrome: [
|
chrome: [
|
||||||
|
|||||||
@@ -4,8 +4,11 @@ import { createCdpConnection } from './cdp';
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Install an extension to an already running instance of Firefox.
|
* Install an extension to an already running instance of Firefox.
|
||||||
* @param debuggerUrl The URL of the Firefox BiDi server (ex: `ws://127.0.0.1:45912`).
|
*
|
||||||
* @param extensionDir Absolute path to the directory containing the extension to be installed.
|
* @param debuggerUrl The URL of the Firefox BiDi server (ex:
|
||||||
|
* `ws://127.0.0.1:45912`).
|
||||||
|
* @param extensionDir Absolute path to the directory containing the extension
|
||||||
|
* to be installed.
|
||||||
*/
|
*/
|
||||||
export async function installFirefox(
|
export async function installFirefox(
|
||||||
debuggerUrl: string,
|
debuggerUrl: string,
|
||||||
@@ -33,7 +36,8 @@ export type BidiWebExtensionInstallResponse = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a child process of Chrome, install an extension. The process must be started with the following flags:
|
* Given a child process of Chrome, install an extension. The process must be
|
||||||
|
* started with the following flags:
|
||||||
*
|
*
|
||||||
* - `--remote-debugging-pipe`
|
* - `--remote-debugging-pipe`
|
||||||
* - `--user-data-dir=...`
|
* - `--user-data-dir=...`
|
||||||
|
|||||||
@@ -17,21 +17,46 @@ export type Target = KnownTarget | UnknownTarget;
|
|||||||
export type RunOptions = {
|
export type RunOptions = {
|
||||||
/** Paths to binaries to use for each target. */
|
/** Paths to binaries to use for each target. */
|
||||||
browserBinaries?: Record<string, string>;
|
browserBinaries?: Record<string, string>;
|
||||||
/** Customize the arguments passed to the chromium binary. Conflicting arguments with required ones to install extensions are ignored. */
|
/**
|
||||||
|
* Customize the arguments passed to the chromium binary. Conflicting
|
||||||
|
* arguments with required ones to install extensions are ignored.
|
||||||
|
*/
|
||||||
chromiumArgs?: string[];
|
chromiumArgs?: string[];
|
||||||
/** Control how data is persisted between launches. Either save data at a user level, project level, or don't persist data at all. Defaults to `project`. */
|
/**
|
||||||
|
* Control how data is persisted between launches. Either save data at a user
|
||||||
|
* level, project level, or don't persist data at all. Defaults to `project`.
|
||||||
|
*/
|
||||||
dataPersistence?: 'user' | 'project' | 'none';
|
dataPersistence?: 'user' | 'project' | 'none';
|
||||||
/** Customize where your profile's data is stored when using `dataPersistence: 'project'`. Can be absolute or relative to the current working directory. */
|
/**
|
||||||
|
* Customize where your profile's data is stored when using `dataPersistence:
|
||||||
|
* 'project'`. Can be absolute or relative to the current working directory.
|
||||||
|
*/
|
||||||
projectDataDir?: string;
|
projectDataDir?: string;
|
||||||
/** Customize the port Chrome's debugger is listening on. Defaults to a random open port. */
|
/**
|
||||||
|
* Customize the port Chrome's debugger is listening on. Defaults to a random
|
||||||
|
* open port.
|
||||||
|
*/
|
||||||
chromiumRemoteDebuggingPort?: number;
|
chromiumRemoteDebuggingPort?: number;
|
||||||
/** Directory where the extension will be installed from. Should contain a `manifest.json` file. Can be relative to the current working directory. Defaults to the current working directory. */
|
/**
|
||||||
|
* Directory where the extension will be installed from. Should contain a
|
||||||
|
* `manifest.json` file. Can be relative to the current working directory.
|
||||||
|
* Defaults to the current working directory.
|
||||||
|
*/
|
||||||
extensionDir?: string;
|
extensionDir?: string;
|
||||||
/** Customize the arguments passed to the firefox binary. Conflicting arguments with required ones to install extensions are ignored. */
|
/**
|
||||||
|
* Customize the arguments passed to the firefox binary. Conflicting arguments
|
||||||
|
* with required ones to install extensions are ignored.
|
||||||
|
*/
|
||||||
firefoxArgs?: string[];
|
firefoxArgs?: string[];
|
||||||
/** Customize the port Firefox's debugger is listening on. Defaults to a random open port. */
|
/**
|
||||||
|
* Customize the port Firefox's debugger is listening on. Defaults to a random
|
||||||
|
* open port.
|
||||||
|
*/
|
||||||
firefoxRemoteDebuggingPort?: number;
|
firefoxRemoteDebuggingPort?: number;
|
||||||
/** Specify the browser to open. Defaults to `"chrome"`, but you can pass any string. */
|
/**
|
||||||
|
* Specify the browser to open. Defaults to `"chrome"`, but you can pass any
|
||||||
|
* string.
|
||||||
|
*/
|
||||||
target?: Target;
|
target?: Target;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -219,8 +244,9 @@ async function pathExists(path: string): Promise<boolean> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copied from https://github.com/GoogleChrome/chrome-launcher/blob/main/src/flags.ts
|
* Copied from
|
||||||
* with some flags commented out. Run tests after updating to compare.
|
* https://github.com/GoogleChrome/chrome-launcher/blob/main/src/flags.ts with
|
||||||
|
* some flags commented out. Run tests after updating to compare.
|
||||||
*/
|
*/
|
||||||
const CHROME_LAUNCHER_DEFAULT_FLAGS = [
|
const CHROME_LAUNCHER_DEFAULT_FLAGS = [
|
||||||
'--disable-features=' +
|
'--disable-features=' +
|
||||||
|
|||||||
@@ -36,8 +36,8 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@webext-core/fake-browser": "^1.3.4",
|
"@webext-core/fake-browser": "^1.3.4",
|
||||||
"oxlint": "^1.43.0",
|
"oxlint": "^1.51.0",
|
||||||
"publint": "^0.3.17",
|
"publint": "^0.3.18",
|
||||||
"typescript": "^5.9.3",
|
"typescript": "^5.9.3",
|
||||||
"vitest": "^4.0.18"
|
"vitest": "^4.0.18"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import { beforeEach, describe, expect, expectTypeOf, it, vi } from 'vitest';
|
|||||||
import { MigrationError, type WxtStorageItem, storage } from '../index';
|
import { MigrationError, type WxtStorageItem, storage } from '../index';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This works because fakeBrowser is synchronous, and is will finish any number of chained
|
* This works because fakeBrowser is synchronous, and is will finish any number
|
||||||
* calls within a single tick of the event loop, ie: a timeout of 0.
|
* of chained calls within a single tick of the event loop, ie: a timeout of 0.
|
||||||
*/
|
*/
|
||||||
async function waitForMigrations() {
|
async function waitForMigrations() {
|
||||||
return new Promise((res) => setTimeout(res));
|
return new Promise((res) => setTimeout(res));
|
||||||
|
|||||||
+64
-100
@@ -1,7 +1,9 @@
|
|||||||
/**
|
/**
|
||||||
* Simplified storage APIs with support for versioned fields, snapshots, metadata, and item definitions.
|
* Simplified storage APIs with support for versioned fields, snapshots,
|
||||||
|
* metadata, and item definitions.
|
||||||
*
|
*
|
||||||
* See [the guide](https://wxt.dev/storage.html) for more information.
|
* See [the guide](https://wxt.dev/storage.html) for more information.
|
||||||
|
*
|
||||||
* @module @wxt-dev/storage
|
* @module @wxt-dev/storage
|
||||||
*/
|
*/
|
||||||
import { browser, type Browser } from '@wxt-dev/browser';
|
import { browser, type Browser } from '@wxt-dev/browser';
|
||||||
@@ -689,7 +691,7 @@ export interface WxtStorage {
|
|||||||
* Get an item from storage, or return `null` if it doesn't exist.
|
* Get an item from storage, or return `null` if it doesn't exist.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* await storage.getItem<number>("local:installDate");
|
* await storage.getItem<number>('local:installDate');
|
||||||
*/
|
*/
|
||||||
getItem<TValue>(
|
getItem<TValue>(
|
||||||
key: StorageItemKey,
|
key: StorageItemKey,
|
||||||
@@ -702,11 +704,11 @@ export interface WxtStorage {
|
|||||||
): Promise<TValue | null>;
|
): Promise<TValue | null>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get multiple items from storage. The return order is guaranteed to be the same as the order
|
* Get multiple items from storage. The return order is guaranteed to be the
|
||||||
* requested.
|
* same as the order requested.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* await storage.getItems(["local:installDate", "session:someCounter"]);
|
* await storage.getItems(['local:installDate', 'session:someCounter']);
|
||||||
*/
|
*/
|
||||||
getItems(
|
getItems(
|
||||||
keys: Array<
|
keys: Array<
|
||||||
@@ -717,11 +719,11 @@ export interface WxtStorage {
|
|||||||
): Promise<Array<{ key: StorageItemKey; value: any }>>;
|
): Promise<Array<{ key: StorageItemKey; value: any }>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return an object containing metadata about the key. Object is stored at `key + "$"`. If value
|
* Return an object containing metadata about the key. Object is stored at
|
||||||
* is not an object, it returns an empty object.
|
* `key + "$"`. If value is not an object, it returns an empty object.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* await storage.getMeta("local:installDate");
|
* await storage.getMeta('local:installDate');
|
||||||
*/
|
*/
|
||||||
getMeta<T extends Record<string, unknown>>(key: StorageItemKey): Promise<T>;
|
getMeta<T extends Record<string, unknown>>(key: StorageItemKey): Promise<T>;
|
||||||
|
|
||||||
@@ -736,22 +738,23 @@ export interface WxtStorage {
|
|||||||
): Promise<Array<{ key: StorageItemKey; meta: any }>>;
|
): Promise<Array<{ key: StorageItemKey; meta: any }>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a value in storage. Setting a value to `null` or `undefined` is equivalent to calling
|
* Set a value in storage. Setting a value to `null` or `undefined` is
|
||||||
* `removeItem`.
|
* equivalent to calling `removeItem`.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* await storage.setItem<number>("local:installDate", Date.now());
|
* await storage.setItem<number>('local:installDate', Date.now());
|
||||||
*/
|
*/
|
||||||
setItem<T>(key: StorageItemKey, value: T | null): Promise<void>;
|
setItem<T>(key: StorageItemKey, value: T | null): Promise<void>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set multiple values in storage. If a value is set to `null` or `undefined`, the key is removed.
|
* Set multiple values in storage. If a value is set to `null` or `undefined`,
|
||||||
|
* the key is removed.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* await storage.setItem([
|
* await storage.setItem([
|
||||||
* { key: "local:installDate", value: Date.now() },
|
* { key: "local:installDate", value: Date.now() },
|
||||||
* { key: "session:someCounter, value: 5 },
|
* { key: "session:someCounter, value: 5 },
|
||||||
* ]);
|
* ]);
|
||||||
*/
|
*/
|
||||||
setItems(
|
setItems(
|
||||||
values: Array<
|
values: Array<
|
||||||
@@ -761,11 +764,11 @@ export interface WxtStorage {
|
|||||||
): Promise<void>;
|
): Promise<void>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets metadata properties. If some properties are already set, but are not included in the
|
* Sets metadata properties. If some properties are already set, but are not
|
||||||
* `properties` parameter, they will not be removed.
|
* included in the `properties` parameter, they will not be removed.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* await storage.setMeta("local:installDate", { appVersion });
|
* await storage.setMeta('local:installDate', { appVersion });
|
||||||
*/
|
*/
|
||||||
setMeta<T extends Record<string, unknown>>(
|
setMeta<T extends Record<string, unknown>>(
|
||||||
key: StorageItemKey,
|
key: StorageItemKey,
|
||||||
@@ -788,13 +791,11 @@ export interface WxtStorage {
|
|||||||
* Removes an item from storage.
|
* Removes an item from storage.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* await storage.removeItem("local:installDate");
|
* await storage.removeItem('local:installDate');
|
||||||
*/
|
*/
|
||||||
removeItem(key: StorageItemKey, opts?: RemoveItemOptions): Promise<void>;
|
removeItem(key: StorageItemKey, opts?: RemoveItemOptions): Promise<void>;
|
||||||
|
|
||||||
/**
|
/** Remove a list of keys from storage. */
|
||||||
* Remove a list of keys from storage.
|
|
||||||
*/
|
|
||||||
removeItems(
|
removeItems(
|
||||||
keys: Array<
|
keys: Array<
|
||||||
| StorageItemKey
|
| StorageItemKey
|
||||||
@@ -804,48 +805,41 @@ export interface WxtStorage {
|
|||||||
>,
|
>,
|
||||||
): Promise<void>;
|
): Promise<void>;
|
||||||
|
|
||||||
/**
|
/** Removes all items from the provided storage area. */
|
||||||
* Removes all items from the provided storage area.
|
|
||||||
*/
|
|
||||||
clear(base: StorageArea): Promise<void>;
|
clear(base: StorageArea): Promise<void>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove the entire metadata for a key, or specific properties by name.
|
* Remove the entire metadata for a key, or specific properties by name.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* // Remove all metadata properties from the item
|
* // Remove all metadata properties from the item
|
||||||
* await storage.removeMeta("local:installDate");
|
* await storage.removeMeta('local:installDate');
|
||||||
*
|
*
|
||||||
* // Remove only specific the "v" field
|
* // Remove only specific the "v" field
|
||||||
* await storage.removeMeta("local:installDate", "v")
|
* await storage.removeMeta('local:installDate', 'v');
|
||||||
*/
|
*/
|
||||||
removeMeta(
|
removeMeta(
|
||||||
key: StorageItemKey,
|
key: StorageItemKey,
|
||||||
properties?: string | string[],
|
properties?: string | string[],
|
||||||
): Promise<void>;
|
): Promise<void>;
|
||||||
|
|
||||||
/**
|
/** Return all the items in storage. */
|
||||||
* Return all the items in storage.
|
|
||||||
*/
|
|
||||||
snapshot(
|
snapshot(
|
||||||
base: StorageArea,
|
base: StorageArea,
|
||||||
opts?: SnapshotOptions,
|
opts?: SnapshotOptions,
|
||||||
): Promise<Record<string, unknown>>;
|
): Promise<Record<string, unknown>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Restores the results of `snapshot`. If new properties have been saved since the snapshot, they are
|
* Restores the results of `snapshot`. If new properties have been saved since
|
||||||
* not overridden. Only values existing in the snapshot are overridden.
|
* the snapshot, they are not overridden. Only values existing in the snapshot
|
||||||
|
* are overridden.
|
||||||
*/
|
*/
|
||||||
restoreSnapshot(base: StorageArea, data: any): Promise<void>;
|
restoreSnapshot(base: StorageArea, data: any): Promise<void>;
|
||||||
|
|
||||||
/**
|
/** Watch for changes to a specific key in storage. */
|
||||||
* Watch for changes to a specific key in storage.
|
|
||||||
*/
|
|
||||||
watch<T>(key: StorageItemKey, cb: WatchCallback<T | null>): Unwatch;
|
watch<T>(key: StorageItemKey, cb: WatchCallback<T | null>): Unwatch;
|
||||||
|
|
||||||
/**
|
/** Remove all watch listeners. */
|
||||||
* Remove all watch listeners.
|
|
||||||
*/
|
|
||||||
unwatch(): void;
|
unwatch(): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -894,61 +888,42 @@ export interface WxtStorageItem<
|
|||||||
TValue,
|
TValue,
|
||||||
TMetadata extends Record<string, unknown>,
|
TMetadata extends Record<string, unknown>,
|
||||||
> {
|
> {
|
||||||
/**
|
/** The storage key passed when creating the storage item. */
|
||||||
* The storage key passed when creating the storage item.
|
|
||||||
*/
|
|
||||||
key: StorageItemKey;
|
key: StorageItemKey;
|
||||||
|
|
||||||
/**
|
/** @deprecated Renamed to fallback, use it instead. */
|
||||||
* @deprecated Renamed to fallback, use it instead.
|
|
||||||
*/
|
|
||||||
defaultValue: TValue;
|
defaultValue: TValue;
|
||||||
|
|
||||||
/**
|
/** The value provided by the `fallback` option. */
|
||||||
* The value provided by the `fallback` option.
|
|
||||||
*/
|
|
||||||
fallback: TValue;
|
fallback: TValue;
|
||||||
|
|
||||||
/**
|
/** Get the latest value from storage. */
|
||||||
* Get the latest value from storage.
|
|
||||||
*/
|
|
||||||
getValue(): Promise<TValue>;
|
getValue(): Promise<TValue>;
|
||||||
|
|
||||||
/**
|
/** Get metadata. */
|
||||||
* Get metadata.
|
|
||||||
*/
|
|
||||||
getMeta(): Promise<NullablePartial<TMetadata>>;
|
getMeta(): Promise<NullablePartial<TMetadata>>;
|
||||||
|
|
||||||
/**
|
/** Set the value in storage. */
|
||||||
* Set the value in storage.
|
|
||||||
*/
|
|
||||||
setValue(value: TValue): Promise<void>;
|
setValue(value: TValue): Promise<void>;
|
||||||
|
|
||||||
/**
|
/** Set metadata properties. */
|
||||||
* Set metadata properties.
|
|
||||||
*/
|
|
||||||
setMeta(properties: NullablePartial<TMetadata>): Promise<void>;
|
setMeta(properties: NullablePartial<TMetadata>): Promise<void>;
|
||||||
|
|
||||||
/**
|
/** Remove the value from storage. */
|
||||||
* Remove the value from storage.
|
|
||||||
*/
|
|
||||||
removeValue(opts?: RemoveItemOptions): Promise<void>;
|
removeValue(opts?: RemoveItemOptions): Promise<void>;
|
||||||
|
|
||||||
/**
|
/** Remove all metadata or certain properties from metadata. */
|
||||||
* Remove all metadata or certain properties from metadata.
|
|
||||||
*/
|
|
||||||
removeMeta(properties?: string[]): Promise<void>;
|
removeMeta(properties?: string[]): Promise<void>;
|
||||||
|
|
||||||
/**
|
/** Listen for changes to the value in storage. */
|
||||||
* Listen for changes to the value in storage.
|
|
||||||
*/
|
|
||||||
watch(cb: WatchCallback<TValue>): Unwatch;
|
watch(cb: WatchCallback<TValue>): Unwatch;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If there are migrations defined on the storage item, migrate to the latest version.
|
* If there are migrations defined on the storage item, migrate to the latest
|
||||||
|
* version.
|
||||||
*
|
*
|
||||||
* **This function is ran automatically whenever the extension updates**, so you don't have to call it
|
* **This function is ran automatically whenever the extension updates**, so
|
||||||
* manually.
|
* you don't have to call it manually.
|
||||||
*/
|
*/
|
||||||
migrate(): Promise<void>;
|
migrate(): Promise<void>;
|
||||||
}
|
}
|
||||||
@@ -957,14 +932,10 @@ export type StorageArea = 'local' | 'session' | 'sync' | 'managed';
|
|||||||
export type StorageItemKey = `${StorageArea}:${string}`;
|
export type StorageItemKey = `${StorageArea}:${string}`;
|
||||||
|
|
||||||
export interface GetItemOptions<T> {
|
export interface GetItemOptions<T> {
|
||||||
/**
|
/** @deprecated Renamed to `fallback`, use it instead. */
|
||||||
* @deprecated Renamed to `fallback`, use it instead.
|
|
||||||
*/
|
|
||||||
defaultValue?: T;
|
defaultValue?: T;
|
||||||
|
|
||||||
/**
|
/** Default value returned when `getItem` would otherwise return `null`. */
|
||||||
* Default value returned when `getItem` would otherwise return `null`.
|
|
||||||
*/
|
|
||||||
fallback?: T;
|
fallback?: T;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -979,21 +950,17 @@ export interface RemoveItemOptions {
|
|||||||
|
|
||||||
export interface SnapshotOptions {
|
export interface SnapshotOptions {
|
||||||
/**
|
/**
|
||||||
* Exclude a list of keys. The storage area prefix should be removed since the snapshot is for a
|
* Exclude a list of keys. The storage area prefix should be removed since the
|
||||||
* specific storage area already.
|
* snapshot is for a specific storage area already.
|
||||||
*/
|
*/
|
||||||
excludeKeys?: string[];
|
excludeKeys?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WxtStorageItemOptions<T> {
|
export interface WxtStorageItemOptions<T> {
|
||||||
/**
|
/** @deprecated Renamed to `fallback`, use it instead. */
|
||||||
* @deprecated Renamed to `fallback`, use it instead.
|
|
||||||
*/
|
|
||||||
defaultValue?: T;
|
defaultValue?: T;
|
||||||
|
|
||||||
/**
|
/** Default value returned when `getValue` would otherwise return `null`. */
|
||||||
* Default value returned when `getValue` would otherwise return `null`.
|
|
||||||
*/
|
|
||||||
fallback?: T;
|
fallback?: T;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1005,25 +972,26 @@ export interface WxtStorageItemOptions<T> {
|
|||||||
init?: () => T | Promise<T>;
|
init?: () => T | Promise<T>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provide a version number for the storage item to enable migrations. When changing the version
|
* Provide a version number for the storage item to enable migrations. When
|
||||||
* in the future, migration functions will be ran on application startup.
|
* changing the version in the future, migration functions will be ran on
|
||||||
|
* application startup.
|
||||||
*/
|
*/
|
||||||
version?: number;
|
version?: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A map of version numbers to the functions used to migrate the data to that version.
|
* A map of version numbers to the functions used to migrate the data to that
|
||||||
|
* version.
|
||||||
*/
|
*/
|
||||||
migrations?: Record<number, (oldValue: any) => any>;
|
migrations?: Record<number, (oldValue: any) => any>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Print debug logs, such as migration process.
|
* Print debug logs, such as migration process.
|
||||||
|
*
|
||||||
* @default false
|
* @default false
|
||||||
*/
|
*/
|
||||||
debug?: boolean;
|
debug?: boolean;
|
||||||
|
|
||||||
/**
|
/** A callback function that runs on migration complete. */
|
||||||
* A callback function that runs on migration complete.
|
|
||||||
*/
|
|
||||||
onMigrationComplete?: (migratedValue: T, targetVersion: number) => void;
|
onMigrationComplete?: (migratedValue: T, targetVersion: number) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1032,21 +1000,17 @@ export type StorageAreaChanges = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Same as `Partial`, but includes `| null`. It makes all the properties of an object optional and
|
* Same as `Partial`, but includes `| null`. It makes all the properties of an
|
||||||
* nullable.
|
* object optional and nullable.
|
||||||
*/
|
*/
|
||||||
type NullablePartial<T> = {
|
type NullablePartial<T> = {
|
||||||
[key in keyof T]+?: T[key] | undefined | null;
|
[key in keyof T]+?: T[key] | undefined | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/** Callback called when a value in storage is changed. */
|
||||||
* Callback called when a value in storage is changed.
|
|
||||||
*/
|
|
||||||
export type WatchCallback<T> = (newValue: T, oldValue: T) => void;
|
export type WatchCallback<T> = (newValue: T, oldValue: T) => void;
|
||||||
|
|
||||||
/**
|
/** Call to remove a watch listener */
|
||||||
* Call to remove a watch listener
|
|
||||||
*/
|
|
||||||
export type Unwatch = () => void;
|
export type Unwatch = () => void;
|
||||||
|
|
||||||
export class MigrationError extends Error {
|
export class MigrationError extends Error {
|
||||||
|
|||||||
@@ -40,14 +40,14 @@
|
|||||||
"wxt": ">=0.19.0"
|
"wxt": ">=0.19.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"oxlint": "^1.43.0",
|
"oxlint": "^1.51.0",
|
||||||
"publint": "^0.3.17",
|
"publint": "^0.3.18",
|
||||||
"typescript": "^5.9.3",
|
"typescript": "^5.9.3",
|
||||||
"unocss": "^0.64.0 || ^0.65.0 || ^65.0.0 || ^66.0.0",
|
"unocss": "^0.64.0 || ^0.65.0 || ^65.0.0 || ^66.0.0",
|
||||||
"wxt": "workspace:*"
|
"wxt": "workspace:*"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"defu": "^6.1.4",
|
"defu": "^6.1.4",
|
||||||
"fast-glob": "^3.3.3"
|
"tinyglobby": "^0.2.15"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,12 +38,11 @@ export default defineWxtModule<UnoCSSOptions>({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/** Options for the UnoCSS module */
|
||||||
* Options for the UnoCSS module
|
|
||||||
*/
|
|
||||||
export interface UnoCSSOptions<Theme extends object = object> {
|
export interface UnoCSSOptions<Theme extends object = object> {
|
||||||
/**
|
/**
|
||||||
* Enable UnoCSS
|
* Enable UnoCSS
|
||||||
|
*
|
||||||
* @default true
|
* @default true
|
||||||
*/
|
*/
|
||||||
enabled?: boolean;
|
enabled?: boolean;
|
||||||
@@ -51,12 +50,17 @@ export interface UnoCSSOptions<Theme extends object = object> {
|
|||||||
* List of entrypoint names that UnoCSS is not used in. By default, the UnoCSS
|
* List of entrypoint names that UnoCSS is not used in. By default, the UnoCSS
|
||||||
* vite plugin is added to all build steps, but this option is used to exclude
|
* vite plugin is added to all build steps, but this option is used to exclude
|
||||||
* it from specific builds.
|
* it from specific builds.
|
||||||
* @example ["popup", "options"]
|
*
|
||||||
* @default []
|
* @example
|
||||||
|
* {undefined} ('popup',
|
||||||
|
* 'options');
|
||||||
|
*
|
||||||
|
* @default [ ]
|
||||||
*/
|
*/
|
||||||
excludeEntrypoints?: string[];
|
excludeEntrypoints?: string[];
|
||||||
/**
|
/**
|
||||||
* The path to your `unocss.config.ts` file, relative to <rootDir>, or inline configuration.
|
* The path to your `unocss.config.ts` file, relative to <rootDir>, or inline
|
||||||
|
* configuration.
|
||||||
*/
|
*/
|
||||||
configOrPath?: Parameters<typeof UnoCSS<Theme>>[0];
|
configOrPath?: Parameters<typeof UnoCSS<Theme>>[0];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,8 +45,8 @@
|
|||||||
"wxt": ">=0.20.0"
|
"wxt": ">=0.20.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/webextension-polyfill": "^0.12.4",
|
"@types/webextension-polyfill": "^0.12.5",
|
||||||
"publint": "^0.3.17",
|
"publint": "^0.3.18",
|
||||||
"typescript": "^5.9.3",
|
"typescript": "^5.9.3",
|
||||||
"webextension-polyfill": "^0.12.0",
|
"webextension-polyfill": "^0.12.0",
|
||||||
"wxt": "workspace:*"
|
"wxt": "workspace:*"
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
"react-dom": "^19.2.4"
|
"react-dom": "^19.2.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/react": "^19.2.13",
|
"@types/react": "^19.2.14",
|
||||||
"@types/react-dom": "^19.2.3",
|
"@types/react-dom": "^19.2.3",
|
||||||
"@wxt-dev/auto-icons": "workspace:*",
|
"@wxt-dev/auto-icons": "workspace:*",
|
||||||
"@wxt-dev/unocss": "workspace:*",
|
"@wxt-dev/unocss": "workspace:*",
|
||||||
|
|||||||
@@ -1,5 +1,59 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## v0.20.18
|
||||||
|
|
||||||
|
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.20.17...wxt-v0.20.18)
|
||||||
|
|
||||||
|
### 🚀 Enhancements
|
||||||
|
|
||||||
|
- Create tests for all func of `network.ts` ([#2132](https://github.com/wxt-dev/wxt/pull/2132))
|
||||||
|
- Use Navigation API for location change detection with polling fallback ([#2136](https://github.com/wxt-dev/wxt/pull/2136))
|
||||||
|
- **modules:** Add support for augumenting entrypoint options ([#2149](https://github.com/wxt-dev/wxt/pull/2149))
|
||||||
|
- New `@wxt-dev/is-background` package ([#2152](https://github.com/wxt-dev/wxt/pull/2152))
|
||||||
|
- Add `globalName` entrypoint option. ([#2017](https://github.com/wxt-dev/wxt/pull/2017))
|
||||||
|
|
||||||
|
### 🩹 Fixes
|
||||||
|
|
||||||
|
- Add `getAppConfig` as an alias to `useAppConfig` ([#2144](https://github.com/wxt-dev/wxt/pull/2144))
|
||||||
|
- Enable mv3 dev mode with firefox 147 ([#2135](https://github.com/wxt-dev/wxt/pull/2135))
|
||||||
|
- **types:** Add type safety to `browser.runtime.executeScript` `files` option ([#2142](https://github.com/wxt-dev/wxt/pull/2142))
|
||||||
|
- **types:** Include CSS entrypoints in PublicPath generation ([#2150](https://github.com/wxt-dev/wxt/pull/2150))
|
||||||
|
- Fix submit command ([#2157](https://github.com/wxt-dev/wxt/pull/2157))
|
||||||
|
|
||||||
|
### 📖 Documentation
|
||||||
|
|
||||||
|
- Added "Glossy New Tab" to the homepage ([#2133](https://github.com/wxt-dev/wxt/pull/2133))
|
||||||
|
- Add All API Hub to showcase extensions ([#2137](https://github.com/wxt-dev/wxt/pull/2137))
|
||||||
|
- Add `wxt-local-analytics` to community resources ([#2141](https://github.com/wxt-dev/wxt/pull/2141))
|
||||||
|
- Add deep outline to modules page to show recipes ([653608c9](https://github.com/wxt-dev/wxt/commit/653608c9))
|
||||||
|
|
||||||
|
### 🏡 Chore
|
||||||
|
|
||||||
|
- Add missing `async` to network.ts ([#2107](https://github.com/wxt-dev/wxt/pull/2107))
|
||||||
|
- Make type for `__ENTRYPOINT__` of vitest.globalSetup.ts ([#2128](https://github.com/wxt-dev/wxt/pull/2128))
|
||||||
|
- Remove unnecessary `@ts-ignore` of `builders/vite` index.ts ([#2127](https://github.com/wxt-dev/wxt/pull/2127))
|
||||||
|
- Rename `zipdir` to `zipDir` ([#2126](https://github.com/wxt-dev/wxt/pull/2126))
|
||||||
|
- Simplify imports in `wxt/e2e` ([#2122](https://github.com/wxt-dev/wxt/pull/2122))
|
||||||
|
- Remove `@ts-expect-error` from manifest.test.ts and fix typo ([#2123](https://github.com/wxt-dev/wxt/pull/2123))
|
||||||
|
|
||||||
|
### 🤖 CI
|
||||||
|
|
||||||
|
- Fix VHS action ([#2155](https://github.com/wxt-dev/wxt/pull/2155))
|
||||||
|
|
||||||
|
### ❤️ Contributors
|
||||||
|
|
||||||
|
- Aaron ([@aklinker1](https://github.com/aklinker1))
|
||||||
|
- Jonathan Viney ([@jviney](https://github.com/jviney))
|
||||||
|
- Tam Dang ([@dahomita](https://github.com/dahomita))
|
||||||
|
- Nick Doan ([@nickbar01234](https://github.com/nickbar01234))
|
||||||
|
- Patryk Kuniczak ([@PatrykKuniczak](https://github.com/PatrykKuniczak))
|
||||||
|
- Anthony Ciccarello ([@aciccarello](https://github.com/aciccarello))
|
||||||
|
- Henrik Wenz ([@HaNdTriX](https://github.com/HaNdTriX))
|
||||||
|
- Sheng Zhang ([@Arktomson](https://github.com/Arktomson))
|
||||||
|
- Oleksii ([@Aler1x](https://github.com/Aler1x))
|
||||||
|
- Qixing-jk <vq3d5d8c@duck.com>
|
||||||
|
- Muzammil ([@oyzamil](https://github.com/oyzamil))
|
||||||
|
|
||||||
## v0.20.17
|
## v0.20.17
|
||||||
|
|
||||||
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.20.16...wxt-v0.20.17)
|
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.20.16...wxt-v0.20.17)
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
/**
|
/**
|
||||||
* A alias around `publish-extension` that is always installed on the path without having to install
|
* A alias around `publish-extension` that is always installed on the path
|
||||||
* `publish-browser-extension` as a direct dependency (like for PNPM, which doesn't link
|
* without having to install `publish-browser-extension` as a direct dependency
|
||||||
* sub-dependency binaries to "node_modules/.bin")
|
* (like for PNPM, which doesn't link sub-dependency binaries to
|
||||||
|
* "node_modules/.bin")
|
||||||
*/
|
*/
|
||||||
import 'publish-browser-extension/cli';
|
await import('publish-browser-extension/cli');
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { describe, it, expect } from 'vitest';
|
import { describe, it, expect } from 'vitest';
|
||||||
import { TestProject, WXT_PACKAGE_DIR } from '../utils';
|
import { TestProject, WXT_PACKAGE_DIR } from '../utils';
|
||||||
import spawn from 'nano-spawn';
|
import spawn from 'nano-spawn';
|
||||||
import glob from 'fast-glob';
|
import { glob } from 'tinyglobby';
|
||||||
import { mkdir, writeJson } from 'fs-extra';
|
import { mkdir, writeJson } from 'fs-extra';
|
||||||
|
|
||||||
describe('Init command', () => {
|
describe('Init command', () => {
|
||||||
@@ -21,6 +21,7 @@ describe('Init command', () => {
|
|||||||
cwd: project.root,
|
cwd: project.root,
|
||||||
onlyFiles: true,
|
onlyFiles: true,
|
||||||
dot: true,
|
dot: true,
|
||||||
|
expandDirectories: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(files.sort()).toMatchInlineSnapshot(`
|
expect(files.sort()).toMatchInlineSnapshot(`
|
||||||
|
|||||||
+12
-15
@@ -1,4 +1,4 @@
|
|||||||
import glob from 'fast-glob';
|
import { glob } from 'tinyglobby';
|
||||||
import fs, { mkdir } from 'fs-extra';
|
import fs, { mkdir } from 'fs-extra';
|
||||||
import merge from 'lodash.merge';
|
import merge from 'lodash.merge';
|
||||||
import spawn from 'nano-spawn';
|
import spawn from 'nano-spawn';
|
||||||
@@ -59,9 +59,7 @@ export class TestProject {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Add a `wxt.config.ts` to the project with specific contents. */
|
||||||
* Add a `wxt.config.ts` to the project with specific contents.
|
|
||||||
*/
|
|
||||||
setConfigFileConfig(config: UserConfig = {}) {
|
setConfigFileConfig(config: UserConfig = {}) {
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.files.push([
|
this.files.push([
|
||||||
@@ -109,9 +107,7 @@ export class TestProject {
|
|||||||
return server;
|
return server;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Call `path.resolve` relative to the project's root directory. */
|
||||||
* Call `path.resolve` relative to the project's root directory.
|
|
||||||
*/
|
|
||||||
resolvePath(...path: string[]): string {
|
resolvePath(...path: string[]): string {
|
||||||
return resolve(this.root, ...path);
|
return resolve(this.root, ...path);
|
||||||
}
|
}
|
||||||
@@ -141,11 +137,11 @@ export class TestProject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read all the files from the test project's `.output` directory and combine them into a string
|
* Read all the files from the test project's `.output` directory and combine
|
||||||
* that can be used in a snapshot.
|
* them into a string that can be used in a snapshot.
|
||||||
*
|
*
|
||||||
* Optionally, provide a list of filenames whose content is not printed (because it's inconsistent
|
* Optionally, provide a list of filenames whose content is not printed
|
||||||
* or not relevant to a test).
|
* (because it's inconsistent or not relevant to a test).
|
||||||
*/
|
*/
|
||||||
serializeOutput(ignoreContentsOfFilenames?: string[]): Promise<string> {
|
serializeOutput(ignoreContentsOfFilenames?: string[]): Promise<string> {
|
||||||
return this.serializeDir('.output', ignoreContentsOfFilenames);
|
return this.serializeDir('.output', ignoreContentsOfFilenames);
|
||||||
@@ -154,8 +150,8 @@ export class TestProject {
|
|||||||
/**
|
/**
|
||||||
* Deeply print the filename and contents of all files in a directory.
|
* Deeply print the filename and contents of all files in a directory.
|
||||||
*
|
*
|
||||||
* Optionally, provide a list of filenames whose content is not printed (because it's inconsistent
|
* Optionally, provide a list of filenames whose content is not printed
|
||||||
* or not relevant to a test).
|
* (because it's inconsistent or not relevant to a test).
|
||||||
*/
|
*/
|
||||||
private async serializeDir(
|
private async serializeDir(
|
||||||
dir: string,
|
dir: string,
|
||||||
@@ -164,6 +160,7 @@ export class TestProject {
|
|||||||
const outputFiles = await glob('**/*', {
|
const outputFiles = await glob('**/*', {
|
||||||
cwd: this.resolvePath(dir),
|
cwd: this.resolvePath(dir),
|
||||||
ignore: ['**/node_modules', '**/.output'],
|
ignore: ['**/node_modules', '**/.output'],
|
||||||
|
expandDirectories: false,
|
||||||
});
|
});
|
||||||
outputFiles.sort();
|
outputFiles.sort();
|
||||||
const fileContents = [];
|
const fileContents = [];
|
||||||
@@ -179,8 +176,8 @@ export class TestProject {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param path An absolute path to a file or a path relative to the root.
|
* @param path An absolute path to a file or a path relative to the root.
|
||||||
* @param ignoreContents An optional boolean that, when true, causes this function to not print
|
* @param ignoreContents An optional boolean that, when true, causes this
|
||||||
* the file contents.
|
* function to not print the file contents.
|
||||||
*/
|
*/
|
||||||
async serializeFile(path: string, ignoreContents?: boolean): Promise<string> {
|
async serializeFile(path: string, ignoreContents?: boolean): Promise<string> {
|
||||||
const absolutePath = this.resolvePath(path);
|
const absolutePath = this.resolvePath(path);
|
||||||
|
|||||||
Vendored
+1
@@ -1,3 +1,4 @@
|
|||||||
|
// oxlint-disable-next-line eslint(no-shadow-restricted-names)
|
||||||
declare namespace globalThis {
|
declare namespace globalThis {
|
||||||
var __ENTRYPOINT__: string;
|
var __ENTRYPOINT__: string;
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-17
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "wxt",
|
"name": "wxt",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "0.20.17",
|
"version": "0.20.18",
|
||||||
"description": "⚡ Next-gen Web Extension Framework",
|
"description": "⚡ Next-gen Web Extension Framework",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -25,45 +25,45 @@
|
|||||||
"@wxt-dev/storage": "workspace:^1.0.0",
|
"@wxt-dev/storage": "workspace:^1.0.0",
|
||||||
"async-mutex": "^0.5.0",
|
"async-mutex": "^0.5.0",
|
||||||
"c12": "^3.3.3",
|
"c12": "^3.3.3",
|
||||||
"cac": "^6.7.14",
|
"cac": "^6.7.14 || ^7.0.0",
|
||||||
"chokidar": "^5.0.0",
|
"chokidar": "^5.0.0",
|
||||||
"ci-info": "^4.4.0",
|
"ci-info": "^4.4.0",
|
||||||
"consola": "^3.4.2",
|
"consola": "^3.4.2",
|
||||||
"defu": "^6.1.4",
|
"defu": "^6.1.4",
|
||||||
"dotenv": "^17.2.4",
|
"dotenv": "^17.3.1",
|
||||||
"dotenv-expand": "^12.0.3",
|
"dotenv-expand": "^12.0.3",
|
||||||
"esbuild": "^0.27.1",
|
"esbuild": "^0.27.1",
|
||||||
"fast-glob": "^3.3.3",
|
|
||||||
"filesize": "^11.0.13",
|
"filesize": "^11.0.13",
|
||||||
"fs-extra": "^11.3.3",
|
"fs-extra": "^11.3.4",
|
||||||
"get-port-please": "^3.2.0",
|
"get-port-please": "^3.2.0",
|
||||||
"giget": "^1.2.3 || ^2.0.0 || ^3.0.0",
|
"giget": "^1.2.3 || ^2.0.0 || ^3.0.0",
|
||||||
"hookable": "^6.0.1",
|
"hookable": "^6.0.1",
|
||||||
"import-meta-resolve": "^4.2.0",
|
"import-meta-resolve": "^4.2.0",
|
||||||
"is-wsl": "^3.1.0",
|
"is-wsl": "^3.1.1",
|
||||||
"json5": "^2.2.3",
|
"json5": "^2.2.3",
|
||||||
"jszip": "^3.10.1",
|
"jszip": "^3.10.1",
|
||||||
"linkedom": "^0.18.12",
|
"linkedom": "^0.18.12",
|
||||||
"magicast": "^0.5.2",
|
"magicast": "^0.5.2",
|
||||||
"minimatch": "^10.1.2",
|
"minimatch": "^10.2.4",
|
||||||
"nano-spawn": "^2.0.0",
|
"nano-spawn": "^2.0.0",
|
||||||
|
"nanospinner": "^1.2.2",
|
||||||
"normalize-path": "^3.0.0",
|
"normalize-path": "^3.0.0",
|
||||||
"nypm": "^0.6.5",
|
"nypm": "^0.6.5",
|
||||||
"ohash": "^2.0.11",
|
"ohash": "^2.0.11",
|
||||||
"open": "^11.0.0",
|
"open": "^11.0.0",
|
||||||
"ora": "^9.3.0",
|
|
||||||
"perfect-debounce": "^2.1.0",
|
"perfect-debounce": "^2.1.0",
|
||||||
"picocolors": "^1.1.1",
|
"picocolors": "^1.1.1",
|
||||||
"prompts": "^2.4.2",
|
"prompts": "^2.4.2",
|
||||||
"publish-browser-extension": "^2.3.0 || ^3.0.2 || ^4.0.0",
|
"publish-browser-extension": "^2.3.0 || ^3.0.2 || ^4.0.4",
|
||||||
"scule": "^1.3.0",
|
"scule": "^1.3.0",
|
||||||
"unimport": "^3.13.1 || ^4.0.0 || ^5.0.0",
|
"tinyglobby": "^0.2.15",
|
||||||
"vite": "^5.4.19 || ^6.3.4 || ^7.0.0",
|
"unimport": "^3.13.1 || ^4.0.0 || ^5.0.0 || ^6.0.0",
|
||||||
|
"vite": "^5.4.19 || ^6.3.4 || ^7.0.0 || ^8.0.0-0",
|
||||||
"vite-node": "^3.2.4 || ^5.0.0",
|
"vite-node": "^3.2.4 || ^5.0.0",
|
||||||
"web-ext-run": "^0.2.4"
|
"web-ext-run": "^0.2.4"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"eslint": "^8.57.0 || ^9.0.0"
|
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0"
|
||||||
},
|
},
|
||||||
"peerDependenciesMeta": {
|
"peerDependenciesMeta": {
|
||||||
"eslint": {
|
"eslint": {
|
||||||
@@ -71,18 +71,18 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@faker-js/faker": "^10.2.0",
|
"@faker-js/faker": "^10.3.0",
|
||||||
"@types/fs-extra": "^11.0.4",
|
"@types/fs-extra": "^11.0.4",
|
||||||
"@types/lodash.merge": "^4.6.9",
|
"@types/lodash.merge": "^4.6.9",
|
||||||
"@types/node": "^20.17.6",
|
"@types/node": "^20.17.6",
|
||||||
"@types/normalize-path": "^3.0.2",
|
"@types/normalize-path": "^3.0.2",
|
||||||
"@types/prompts": "^2.4.9",
|
"@types/prompts": "^2.4.9",
|
||||||
"eslint": "^9.38.0",
|
"eslint": "^10.0.0",
|
||||||
"extract-zip": "^2.0.1",
|
"extract-zip": "^2.0.1",
|
||||||
"happy-dom": "^20.5.0",
|
"happy-dom": "^20.8.3",
|
||||||
"lodash.merge": "^4.6.2",
|
"lodash.merge": "^4.6.2",
|
||||||
"oxlint": "^1.43.0",
|
"oxlint": "^1.51.0",
|
||||||
"publint": "^0.3.17",
|
"publint": "^0.3.18",
|
||||||
"typescript": "^5.9.3",
|
"typescript": "^5.9.3",
|
||||||
"vitest": "^4.0.18",
|
"vitest": "^4.0.18",
|
||||||
"vitest-plugin-random-seed": "^1.1.2"
|
"vitest-plugin-random-seed": "^1.1.2"
|
||||||
|
|||||||
@@ -1,25 +1,32 @@
|
|||||||
/**
|
/**
|
||||||
* Contains the `browser` export which you should use to access the extension APIs in your project:
|
* Contains the `browser` export which you should use to access the extension
|
||||||
|
* APIs in your project:
|
||||||
|
*
|
||||||
* ```ts
|
* ```ts
|
||||||
* import { browser } from 'wxt/browser';
|
* import { browser } from 'wxt/browser';
|
||||||
*
|
*
|
||||||
* browser.runtime.onInstalled.addListener(() => {
|
* browser.runtime.onInstalled.addListener(() => {
|
||||||
* // ...
|
* // ...
|
||||||
* })
|
* });
|
||||||
* ```
|
* ```
|
||||||
|
*
|
||||||
* @module wxt/browser
|
* @module wxt/browser
|
||||||
*/
|
*/
|
||||||
import { browser as _browser, type Browser } from '@wxt-dev/browser';
|
import { browser as _browser, type Browser } from '@wxt-dev/browser';
|
||||||
import type { ScriptPublicPath } from './utils/inject-script';
|
import type { ScriptPublicPath } from './utils/inject-script';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This interface is empty because it is generated per-project when running `wxt prepare`. See:
|
* This interface is empty because it is generated per-project when running `wxt
|
||||||
|
* prepare`. See:
|
||||||
|
*
|
||||||
* - `.wxt/types/paths.d.ts`
|
* - `.wxt/types/paths.d.ts`
|
||||||
*/
|
*/
|
||||||
export interface WxtRuntime {}
|
export interface WxtRuntime {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This interface is empty because it is generated per-project when running `wxt prepare`. See:
|
* This interface is empty because it is generated per-project when running `wxt
|
||||||
|
* prepare`. See:
|
||||||
|
*
|
||||||
* - `.wxt/types/i18n.d.ts`
|
* - `.wxt/types/i18n.d.ts`
|
||||||
*/
|
*/
|
||||||
export interface WxtI18n {}
|
export interface WxtI18n {}
|
||||||
@@ -36,9 +43,7 @@ type InjectionResult<Result> = Array<
|
|||||||
|
|
||||||
export interface WxtScripting {
|
export interface WxtScripting {
|
||||||
executeScript: {
|
executeScript: {
|
||||||
/**
|
/** @see {@link Browser.scripting.executeScript} */
|
||||||
* @see {@link Browser.scripting.executeScript}
|
|
||||||
*/
|
|
||||||
<Args extends any[], Result>(
|
<Args extends any[], Result>(
|
||||||
injection: ScriptInjection<Args, Result>,
|
injection: ScriptInjection<Args, Result>,
|
||||||
): Promise<InjectionResult<Result>>;
|
): Promise<InjectionResult<Result>>;
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ import { registerWxt } from '../core/wxt';
|
|||||||
import spawn from 'nano-spawn';
|
import spawn from 'nano-spawn';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrap an action handler to add a timer, error handling, and maybe enable debug mode.
|
* Wrap an action handler to add a timer, error handling, and maybe enable debug
|
||||||
|
* mode.
|
||||||
*/
|
*/
|
||||||
export function wrapAction(
|
export function wrapAction(
|
||||||
cb: (
|
cb: (
|
||||||
@@ -54,8 +55,8 @@ export function wrapAction(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Array flags, when not passed, are either `undefined` or `[undefined]`. This function filters out
|
* Array flags, when not passed, are either `undefined` or `[undefined]`. This
|
||||||
* the
|
* function filters out the
|
||||||
*/
|
*/
|
||||||
export function getArrayFromFlags<T>(
|
export function getArrayFromFlags<T>(
|
||||||
flags: any,
|
flags: any,
|
||||||
|
|||||||
@@ -3,17 +3,18 @@ import { internalBuild } from './utils/building';
|
|||||||
import { registerWxt } from './wxt';
|
import { registerWxt } from './wxt';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bundles the extension for production. Returns a promise of the build result. Discovers the `wxt.config.ts` file in
|
* Bundles the extension for production. Returns a promise of the build result.
|
||||||
* the root directory, and merges that config with what is passed in.
|
* Discovers the `wxt.config.ts` file in the root directory, and merges that
|
||||||
|
* config with what is passed in.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* // Use config from `wxt.config.ts`
|
* // Use config from `wxt.config.ts`
|
||||||
* const res = await build()
|
* const res = await build();
|
||||||
*
|
*
|
||||||
* // or override config `from wxt.config.ts`
|
* // or override config `from wxt.config.ts`
|
||||||
* const res = await build({
|
* const res = await build({
|
||||||
* // Override config...
|
* // Override config...
|
||||||
* })
|
* });
|
||||||
*/
|
*/
|
||||||
export async function build(config?: InlineConfig): Promise<BuildOutput> {
|
export async function build(config?: InlineConfig): Promise<BuildOutput> {
|
||||||
await registerWxt('build', config);
|
await registerWxt('build', config);
|
||||||
|
|||||||
@@ -37,7 +37,8 @@ export async function createViteBuilder(
|
|||||||
const vite = await import('vite');
|
const vite = await import('vite');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the base vite config shared by all builds based on the inline and user config.
|
* Returns the base vite config shared by all builds based on the inline and
|
||||||
|
* user config.
|
||||||
*/
|
*/
|
||||||
const getBaseConfig = async (baseConfigOptions?: {
|
const getBaseConfig = async (baseConfigOptions?: {
|
||||||
excludeAnalysisPlugin?: boolean;
|
excludeAnalysisPlugin?: boolean;
|
||||||
@@ -102,7 +103,8 @@ export async function createViteBuilder(
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the basic config for building an entrypoint in [lib mode](https://vitejs.dev/guide/build.html#library-mode).
|
* Return the basic config for building an entrypoint in [lib
|
||||||
|
* mode](https://vitejs.dev/guide/build.html#library-mode).
|
||||||
*/
|
*/
|
||||||
const getLibModeConfig = (entrypoint: Entrypoint): vite.InlineConfig => {
|
const getLibModeConfig = (entrypoint: Entrypoint): vite.InlineConfig => {
|
||||||
const entry = getRollupEntry(entrypoint);
|
const entry = getRollupEntry(entrypoint);
|
||||||
@@ -177,7 +179,8 @@ export async function createViteBuilder(
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the basic config for building multiple entrypoints in [multi-page mode](https://vitejs.dev/guide/build.html#multi-page-app).
|
* Return the basic config for building multiple entrypoints in [multi-page
|
||||||
|
* mode](https://vitejs.dev/guide/build.html#multi-page-app).
|
||||||
*/
|
*/
|
||||||
const getMultiPageConfig = (entrypoints: Entrypoint[]): vite.InlineConfig => {
|
const getMultiPageConfig = (entrypoints: Entrypoint[]): vite.InlineConfig => {
|
||||||
const htmlEntrypoints = new Set(
|
const htmlEntrypoints = new Set(
|
||||||
@@ -210,7 +213,8 @@ export async function createViteBuilder(
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the basic config for building a single CSS entrypoint in [multi-page mode](https://vitejs.dev/guide/build.html#multi-page-app).
|
* Return the basic config for building a single CSS entrypoint in [multi-page
|
||||||
|
* mode](https://vitejs.dev/guide/build.html#multi-page-app).
|
||||||
*/
|
*/
|
||||||
const getCssConfig = (entrypoint: Entrypoint): vite.InlineConfig => {
|
const getCssConfig = (entrypoint: Entrypoint): vite.InlineConfig => {
|
||||||
return {
|
return {
|
||||||
@@ -387,8 +391,8 @@ function getBuildOutputChunks(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the input module ID (virtual or real file) for an entrypoint. The returned string should
|
* Returns the input module ID (virtual or real file) for an entrypoint. The
|
||||||
* be passed as an input to rollup.
|
* returned string should be passed as an input to rollup.
|
||||||
*/
|
*/
|
||||||
function getRollupEntry(entrypoint: Entrypoint): string {
|
function getRollupEntry(entrypoint: Entrypoint): string {
|
||||||
let virtualEntrypointType: VirtualEntrypointType | undefined;
|
let virtualEntrypointType: VirtualEntrypointType | undefined;
|
||||||
@@ -413,15 +417,17 @@ function getRollupEntry(entrypoint: Entrypoint): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensures the HTML files output by a multipage build are in the correct location. This does two
|
* Ensures the HTML files output by a multipage build are in the correct
|
||||||
* things:
|
* location. This does two things:
|
||||||
*
|
*
|
||||||
* 1. Moves the HTML files to their final location at `<outDir>/<entrypoint.name>.html`.
|
* 1. Moves the HTML files to their final location at
|
||||||
* 2. Updates the bundle so it summarizes the files correctly in the returned build output.
|
* `<outDir>/<entrypoint.name>.html`.
|
||||||
|
* 2. Updates the bundle so it summarizes the files correctly in the returned build
|
||||||
|
* output.
|
||||||
*
|
*
|
||||||
* Assets (JS and CSS) are output to the `<outDir>/assets` directory, and don't need to be modified.
|
* Assets (JS and CSS) are output to the `<outDir>/assets` directory, and don't
|
||||||
* HTML files access them via absolute URLs, so we don't need to update any import paths in the HTML
|
* need to be modified. HTML files access them via absolute URLs, so we don't
|
||||||
* files either.
|
* need to update any import paths in the HTML files either.
|
||||||
*/
|
*/
|
||||||
async function moveHtmlFiles(
|
async function moveHtmlFiles(
|
||||||
config: ResolvedConfig,
|
config: ResolvedConfig,
|
||||||
@@ -465,9 +471,7 @@ async function moveHtmlFiles(
|
|||||||
return movedChunks;
|
return movedChunks;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Recursively remove all directories that are empty/ */
|
||||||
* Recursively remove all directories that are empty/
|
|
||||||
*/
|
|
||||||
export async function removeEmptyDirs(dir: string): Promise<void> {
|
export async function removeEmptyDirs(dir: string): Promise<void> {
|
||||||
const files = await fs.readdir(dir);
|
const files = await fs.readdir(dir);
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
|
|||||||
@@ -15,9 +15,7 @@ export function bundleAnalysis(config: ResolvedConfig): vite.Plugin {
|
|||||||
}) as vite.Plugin;
|
}) as vite.Plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** @internal FOR TESTING ONLY. */
|
||||||
* @internal FOR TESTING ONLY.
|
|
||||||
*/
|
|
||||||
export function resetBundleIncrement() {
|
export function resetBundleIncrement() {
|
||||||
increment = 0;
|
increment = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,14 +3,16 @@ import { Entrypoint, ResolvedConfig } from '../../../../types';
|
|||||||
import { getEntrypointBundlePath } from '../../../utils/entrypoints';
|
import { getEntrypointBundlePath } from '../../../utils/entrypoints';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rename CSS entrypoint outputs to ensure a JS file is not generated, and that the CSS file is
|
* Rename CSS entrypoint outputs to ensure a JS file is not generated, and that
|
||||||
* placed in the correct place.
|
* the CSS file is placed in the correct place.
|
||||||
*
|
*
|
||||||
* It:
|
* It:
|
||||||
|
*
|
||||||
* 1. Renames CSS files to their final paths
|
* 1. Renames CSS files to their final paths
|
||||||
* 2. Removes the JS file that get's output by lib mode
|
* 2. Removes the JS file that get's output by lib mode
|
||||||
*
|
*
|
||||||
* THIS PLUGIN SHOULD ONLY BE APPLIED TO CSS LIB MODE BUILDS. It should not be added to every build.
|
* THIS PLUGIN SHOULD ONLY BE APPLIED TO CSS LIB MODE BUILDS. It should not be
|
||||||
|
* added to every build.
|
||||||
*/
|
*/
|
||||||
export function cssEntrypoints(
|
export function cssEntrypoints(
|
||||||
entrypoint: Entrypoint,
|
entrypoint: Entrypoint,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* Overrides definitions for `import.meta.*`
|
* Overrides definitions for `import.meta.*`
|
||||||
*
|
*
|
||||||
* - `import.meta.url`: Without this, background service workers crash trying to access
|
* - `import.meta.url`: Without this, background service workers crash trying to
|
||||||
* `document.location`, see https://github.com/wxt-dev/wxt/issues/392
|
* access `document.location`, see https://github.com/wxt-dev/wxt/issues/392
|
||||||
*/
|
*/
|
||||||
export function defineImportMeta() {
|
export function defineImportMeta() {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ import { hash } from 'ohash';
|
|||||||
const inlineScriptContents: Record<string, string> = {};
|
const inlineScriptContents: Record<string, string> = {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pre-renders the HTML entrypoints when building the extension to connect to the dev server.
|
* Pre-renders the HTML entrypoints when building the extension to connect to
|
||||||
|
* the dev server.
|
||||||
*/
|
*/
|
||||||
export function devHtmlPrerender(
|
export function devHtmlPrerender(
|
||||||
config: ResolvedConfig,
|
config: ResolvedConfig,
|
||||||
@@ -40,32 +41,32 @@ export function devHtmlPrerender(
|
|||||||
},
|
},
|
||||||
// Convert scripts like src="./main.tsx" -> src="http://localhost:3000/entrypoints/popup/main.tsx"
|
// Convert scripts like src="./main.tsx" -> src="http://localhost:3000/entrypoints/popup/main.tsx"
|
||||||
// before the paths are replaced with their bundled path
|
// before the paths are replaced with their bundled path
|
||||||
transform(code, id) {
|
transform: {
|
||||||
if (
|
filter: {
|
||||||
config.command !== 'serve' ||
|
id: /\.html$/,
|
||||||
server == null ||
|
},
|
||||||
!id.endsWith('.html')
|
handler(code, id) {
|
||||||
)
|
if (config.command !== 'serve' || server == null) return;
|
||||||
return;
|
|
||||||
|
|
||||||
const { document } = parseHTML(code);
|
const { document } = parseHTML(code);
|
||||||
|
|
||||||
const _pointToDevServer = (querySelector: string, attr: string) =>
|
const _pointToDevServer = (querySelector: string, attr: string) =>
|
||||||
pointToDevServer(config, server, id, document, querySelector, attr);
|
pointToDevServer(config, server, id, document, querySelector, attr);
|
||||||
_pointToDevServer('script[type=module]', 'src');
|
_pointToDevServer('script[type=module]', 'src');
|
||||||
_pointToDevServer('link[rel=stylesheet]', 'href');
|
_pointToDevServer('link[rel=stylesheet]', 'href');
|
||||||
|
|
||||||
// Add a script to add page reloading
|
// Add a script to add page reloading
|
||||||
const reloader = document.createElement('script');
|
const reloader = document.createElement('script');
|
||||||
reloader.src = htmlReloadId;
|
reloader.src = htmlReloadId;
|
||||||
reloader.type = 'module';
|
reloader.type = 'module';
|
||||||
document.head.appendChild(reloader);
|
document.head.appendChild(reloader);
|
||||||
|
|
||||||
const newHtml = document.toString();
|
const newHtml = document.toString();
|
||||||
config.logger.debug('transform ' + id);
|
config.logger.debug('transform ' + id);
|
||||||
config.logger.debug('Old HTML:\n' + code);
|
config.logger.debug('Old HTML:\n' + code);
|
||||||
config.logger.debug('New HTML:\n' + newHtml);
|
config.logger.debug('New HTML:\n' + newHtml);
|
||||||
return newHtml;
|
return newHtml;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
// Pass the HTML through the dev server to add dev-mode specific code
|
// Pass the HTML through the dev server to add dev-mode specific code
|
||||||
@@ -113,29 +114,37 @@ export function devHtmlPrerender(
|
|||||||
{
|
{
|
||||||
name: 'wxt:virtualize-inline-scripts',
|
name: 'wxt:virtualize-inline-scripts',
|
||||||
apply: 'serve',
|
apply: 'serve',
|
||||||
resolveId(id) {
|
resolveId: {
|
||||||
// Resolve inline scripts
|
filter: {
|
||||||
if (id.startsWith(virtualInlineScript)) {
|
id: [new RegExp(`^${virtualInlineScript}`), new RegExp('^/chunks/')],
|
||||||
return '\0' + id;
|
},
|
||||||
}
|
handler(id) {
|
||||||
|
// Ignore chunks during HTML file pre-rendering
|
||||||
|
if (id.startsWith('/chunks/')) {
|
||||||
|
return '\0noop';
|
||||||
|
}
|
||||||
|
|
||||||
// Ignore chunks during HTML file pre-rendering
|
return `\0${id}`;
|
||||||
if (id.startsWith('/chunks/')) {
|
},
|
||||||
return '\0noop';
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
load(id) {
|
load: {
|
||||||
// Resolve virtualized inline scripts
|
filter: {
|
||||||
if (id.startsWith(resolvedVirtualInlineScript)) {
|
id: [
|
||||||
|
new RegExp(`^${resolvedVirtualInlineScript}`),
|
||||||
|
//eslint-disable-next-line no-control-regex
|
||||||
|
new RegExp('^\x00noop'),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
handler(id) {
|
||||||
|
// Ignore chunks during HTML file pre-rendering
|
||||||
|
if (id === '\0noop') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
// id="virtual:wxt-inline-script?<key>"
|
// id="virtual:wxt-inline-script?<key>"
|
||||||
const key = id.substring(id.indexOf('?') + 1);
|
const key = id.substring(id.indexOf('?') + 1);
|
||||||
return inlineScriptContents[key];
|
return inlineScriptContents[key];
|
||||||
}
|
},
|
||||||
|
|
||||||
// Ignore chunks during HTML file pre-rendering
|
|
||||||
if (id === '\0noop') {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ import type { Plugin } from 'vite';
|
|||||||
import type { ResolvedConfig, WxtDevServer } from '../../../../types';
|
import type { ResolvedConfig, WxtDevServer } from '../../../../types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines global constants about the dev server. Helps scripts connect to the server's web socket.
|
* Defines global constants about the dev server. Helps scripts connect to the
|
||||||
|
* server's web socket.
|
||||||
*/
|
*/
|
||||||
export function devServerGlobals(
|
export function devServerGlobals(
|
||||||
config: ResolvedConfig,
|
config: ResolvedConfig,
|
||||||
|
|||||||
@@ -3,24 +3,33 @@ import type { ResolvedConfig } from '../../../../types';
|
|||||||
import { fetchCached } from '../../../utils/network';
|
import { fetchCached } from '../../../utils/network';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Downloads any URL imports, like Google Analytics, into virtual modules so they are bundled with
|
* Downloads any URL imports, like Google Analytics, into virtual modules so
|
||||||
* the extension instead of depending on remote code at runtime.
|
* they are bundled with the extension instead of depending on remote code at
|
||||||
|
* runtime.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* import "url:https://google-tagmanager.com/gtag?id=XYZ";
|
* import 'url:https://google-tagmanager.com/gtag?id=XYZ';
|
||||||
*/
|
*/
|
||||||
export function download(config: ResolvedConfig): Plugin {
|
export function download(config: ResolvedConfig): Plugin {
|
||||||
return {
|
return {
|
||||||
name: 'wxt:download',
|
name: 'wxt:download',
|
||||||
resolveId(id) {
|
resolveId: {
|
||||||
if (id.startsWith('url:')) return '\0' + id;
|
filter: {
|
||||||
|
id: /^url:/,
|
||||||
|
},
|
||||||
|
handler(id) {
|
||||||
|
return `\0${id}`;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
load(id) {
|
load: {
|
||||||
if (!id.startsWith('\0url:')) return;
|
filter: {
|
||||||
|
//eslint-disable-next-line no-control-regex
|
||||||
// Load file from network or cache
|
id: /^\x00url:/,
|
||||||
const url = id.replace('\0url:', '');
|
},
|
||||||
return fetchCached(url, config);
|
handler(id) {
|
||||||
|
const url = id.replace('\0url:', '');
|
||||||
|
return fetchCached(url, config);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,7 @@ import type * as vite from 'vite';
|
|||||||
import { EntrypointGroup } from '../../../../types';
|
import { EntrypointGroup } from '../../../../types';
|
||||||
import { getEntrypointGlobals } from '../../../utils/globals';
|
import { getEntrypointGlobals } from '../../../utils/globals';
|
||||||
|
|
||||||
/**
|
/** Define a set of global variables specific to an entrypoint. */
|
||||||
* Define a set of global variables specific to an entrypoint.
|
|
||||||
*/
|
|
||||||
export function entrypointGroupGlobals(
|
export function entrypointGroupGlobals(
|
||||||
entrypointGroup: EntrypointGroup,
|
entrypointGroup: EntrypointGroup,
|
||||||
): vite.PluginOption {
|
): vite.PluginOption {
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ import type * as vite from 'vite';
|
|||||||
import { ResolvedConfig } from '../../../../types';
|
import { ResolvedConfig } from '../../../../types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mock `wxt/browser` and stub the global `browser`/`chrome` types with a fake version of the extension APIs
|
* Mock `wxt/browser` and stub the global `browser`/`chrome` types with a fake
|
||||||
|
* version of the extension APIs
|
||||||
*/
|
*/
|
||||||
export function extensionApiMock(config: ResolvedConfig): vite.PluginOption {
|
export function extensionApiMock(config: ResolvedConfig): vite.PluginOption {
|
||||||
const virtualSetupModule = 'virtual:wxt-setup';
|
const virtualSetupModule = 'virtual:wxt-setup';
|
||||||
@@ -32,11 +33,21 @@ export function extensionApiMock(config: ResolvedConfig): vite.PluginOption {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
resolveId(id) {
|
resolveId: {
|
||||||
if (id.endsWith(virtualSetupModule)) return resolvedVirtualSetupModule;
|
filter: {
|
||||||
|
id: new RegExp(`${virtualSetupModule}$`),
|
||||||
|
},
|
||||||
|
handler() {
|
||||||
|
return resolvedVirtualSetupModule;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
load(id) {
|
load: {
|
||||||
if (id === resolvedVirtualSetupModule) return setupTemplate;
|
filter: {
|
||||||
|
id: new RegExp(`^${resolvedVirtualSetupModule}$`),
|
||||||
|
},
|
||||||
|
handler() {
|
||||||
|
return setupTemplate;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import type { Plugin } from 'vite';
|
import type { Plugin } from 'vite';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a footer with the returned value so it can return values to `scripting.executeScript`
|
* Add a footer with the returned value so it can return values to
|
||||||
* Footer is added a part of esbuild to make sure it's not minified. It
|
* `scripting.executeScript` Footer is added a part of esbuild to make sure it's
|
||||||
* get's removed if added to `build.rollupOptions.output.footer`
|
* not minified. It get's removed if added to
|
||||||
* See https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/scripting/executeScript#return_value
|
* `build.rollupOptions.output.footer` See
|
||||||
|
* https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/scripting/executeScript#return_value
|
||||||
*/
|
*/
|
||||||
export function iifeFooter(iifeReturnValueName: string): Plugin {
|
export function iifeFooter(iifeReturnValueName: string): Plugin {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -2,21 +2,30 @@ import type { Plugin } from 'vite';
|
|||||||
import { VIRTUAL_NOOP_BACKGROUND_MODULE_ID } from '../../../utils/constants';
|
import { VIRTUAL_NOOP_BACKGROUND_MODULE_ID } from '../../../utils/constants';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* In dev mode, if there's not a background script listed, we need to add one so that the web socket
|
* In dev mode, if there's not a background script listed, we need to add one so
|
||||||
* connection is setup and the extension reloads HTML pages and content scripts correctly.
|
* that the web socket connection is setup and the extension reloads HTML pages
|
||||||
|
* and content scripts correctly.
|
||||||
*/
|
*/
|
||||||
export function noopBackground(): Plugin {
|
export function noopBackground(): Plugin {
|
||||||
const virtualModuleId = VIRTUAL_NOOP_BACKGROUND_MODULE_ID;
|
const virtualModuleId = VIRTUAL_NOOP_BACKGROUND_MODULE_ID;
|
||||||
const resolvedVirtualModuleId = '\0' + virtualModuleId;
|
const resolvedVirtualModuleId = '\0' + virtualModuleId;
|
||||||
return {
|
return {
|
||||||
name: 'wxt:noop-background',
|
name: 'wxt:noop-background',
|
||||||
resolveId(id) {
|
resolveId: {
|
||||||
if (id === virtualModuleId) return resolvedVirtualModuleId;
|
filter: {
|
||||||
|
id: new RegExp(`^${virtualModuleId}$`),
|
||||||
|
},
|
||||||
|
handler() {
|
||||||
|
return resolvedVirtualModuleId;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
load(id) {
|
load: {
|
||||||
if (id === resolvedVirtualModuleId) {
|
filter: {
|
||||||
|
id: new RegExp(`^${resolvedVirtualModuleId}$`),
|
||||||
|
},
|
||||||
|
handler() {
|
||||||
return `import { defineBackground } from 'wxt/utils/define-background';\nexport default defineBackground(() => void 0)`;
|
return `import { defineBackground } from 'wxt/utils/define-background';\nexport default defineBackground(() => void 0)`;
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ import { removeMainFunctionCode } from '../../../utils/transform';
|
|||||||
import { resolve } from 'node:path';
|
import { resolve } from 'node:path';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transforms entrypoints, removing the main function from the entrypoint if it exists.
|
* Transforms entrypoints, removing the main function from the entrypoint if it
|
||||||
|
* exists.
|
||||||
*/
|
*/
|
||||||
export function removeEntrypointMainFunction(
|
export function removeEntrypointMainFunction(
|
||||||
config: ResolvedConfig,
|
config: ResolvedConfig,
|
||||||
@@ -16,14 +17,15 @@ export function removeEntrypointMainFunction(
|
|||||||
name: 'wxt:remove-entrypoint-main-function',
|
name: 'wxt:remove-entrypoint-main-function',
|
||||||
transform: {
|
transform: {
|
||||||
order: 'pre',
|
order: 'pre',
|
||||||
handler(code, id) {
|
filter: {
|
||||||
if (id === absPath) {
|
id: new RegExp(`^${absPath}$`),
|
||||||
const newCode = removeMainFunctionCode(code);
|
},
|
||||||
config.logger.debug('vite-node transformed entrypoint', path);
|
handler(code) {
|
||||||
config.logger.debug(`Original:\n---\n${code}\n---`);
|
const newCode = removeMainFunctionCode(code);
|
||||||
config.logger.debug(`Transformed:\n---\n${newCode.code}\n---`);
|
config.logger.debug('vite-node transformed entrypoint', path);
|
||||||
return newCode;
|
config.logger.debug(`Original:\n---\n${code}\n---`);
|
||||||
}
|
config.logger.debug(`Transformed:\n---\n${newCode.code}\n---`);
|
||||||
|
return newCode;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ import type * as vite from 'vite';
|
|||||||
import { ResolvedConfig } from '../../../../types';
|
import { ResolvedConfig } from '../../../../types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When importing `virtual:app-config`, resolve it to the `app.config.ts` file in the project.
|
* When importing `virtual:app-config`, resolve it to the `app.config.ts` file
|
||||||
|
* in the project.
|
||||||
*/
|
*/
|
||||||
export function resolveAppConfig(config: ResolvedConfig): vite.Plugin {
|
export function resolveAppConfig(config: ResolvedConfig): vite.Plugin {
|
||||||
const virtualModuleId = 'virtual:app-config';
|
const virtualModuleId = 'virtual:app-config';
|
||||||
@@ -22,15 +23,23 @@ export function resolveAppConfig(config: ResolvedConfig): vite.Plugin {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
async resolveId(id) {
|
resolveId: {
|
||||||
if (id !== virtualModuleId) return;
|
filter: {
|
||||||
|
id: new RegExp(`^${virtualModuleId}$`),
|
||||||
return (await pathExists(appConfigFile))
|
},
|
||||||
? appConfigFile
|
async handler() {
|
||||||
: resolvedVirtualModuleId;
|
return (await pathExists(appConfigFile))
|
||||||
|
? appConfigFile
|
||||||
|
: resolvedVirtualModuleId;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
load(id) {
|
load: {
|
||||||
if (id === resolvedVirtualModuleId) return `export default {}`;
|
filter: {
|
||||||
|
id: new RegExp(`^${resolvedVirtualModuleId}$`),
|
||||||
|
},
|
||||||
|
handler() {
|
||||||
|
return `export default {}`;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,36 +5,43 @@ import {
|
|||||||
VirtualModuleId,
|
VirtualModuleId,
|
||||||
virtualModuleNames,
|
virtualModuleNames,
|
||||||
} from '../../../utils/virtual-modules';
|
} from '../../../utils/virtual-modules';
|
||||||
import fs from 'fs-extra';
|
|
||||||
import { resolve } from 'path';
|
import { resolve } from 'path';
|
||||||
|
import fs from 'fs-extra';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve all the virtual modules to the `node_modules/wxt/dist/virtual` directory.
|
* Resolve all the virtual modules to the `node_modules/wxt/dist/virtual`
|
||||||
|
* directory.
|
||||||
*/
|
*/
|
||||||
export function resolveVirtualModules(config: ResolvedConfig): Plugin[] {
|
export function resolveVirtualModules(config: ResolvedConfig): Plugin[] {
|
||||||
return virtualModuleNames.map((name) => {
|
return virtualModuleNames.map((name) => {
|
||||||
const virtualId: `${VirtualModuleId}?` = `virtual:wxt-${name}?`;
|
const virtualId: `${VirtualModuleId}?` = `virtual:wxt-${name}?`;
|
||||||
const resolvedVirtualId = '\0' + virtualId;
|
const resolvedVirtualId = '\0' + virtualId;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: `wxt:resolve-virtual-${name}`,
|
name: `wxt:resolve-virtual-${name}`,
|
||||||
resolveId(id) {
|
resolveId: {
|
||||||
// Id doesn't start with prefix, it looks like this:
|
filter: {
|
||||||
// /path/to/project/virtual:wxt-background?/path/to/project/entrypoints/background.ts
|
id: new RegExp(virtualId),
|
||||||
const index = id.indexOf(virtualId);
|
},
|
||||||
if (index === -1) return;
|
handler(id) {
|
||||||
|
const inputPath = normalizePath(
|
||||||
const inputPath = normalizePath(id.substring(index + virtualId.length));
|
id.substring(id.indexOf(virtualId) + virtualId.length),
|
||||||
return resolvedVirtualId + inputPath;
|
);
|
||||||
|
return resolvedVirtualId + inputPath;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
async load(id) {
|
load: {
|
||||||
if (!id.startsWith(resolvedVirtualId)) return;
|
filter: {
|
||||||
|
id: new RegExp(`^${resolvedVirtualId}`),
|
||||||
const inputPath = id.replace(resolvedVirtualId, '');
|
},
|
||||||
const template = await fs.readFile(
|
async handler(id) {
|
||||||
resolve(config.wxtModuleDir, `dist/virtual/${name}.mjs`),
|
const inputPath = id.replace(resolvedVirtualId, '');
|
||||||
'utf-8',
|
const template = await fs.readFile(
|
||||||
);
|
resolve(config.wxtModuleDir, `dist/virtual/${name}.mjs`),
|
||||||
return template.replace(`virtual:user-${name}`, inputPath);
|
'utf-8',
|
||||||
|
);
|
||||||
|
return template.replace(`virtual:user-${name}`, inputPath);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,7 +4,9 @@ import { normalizePath } from '../../../utils';
|
|||||||
import { ResolvedConfig } from '../../../../types';
|
import { ResolvedConfig } from '../../../../types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve and load plugins for each entrypoint. This handles both JS entrypoints via the `virtual:wxt-plugins` import, and HTML files by adding `virtual:wxt-html-plugins` to the document's `<head>`
|
* Resolve and load plugins for each entrypoint. This handles both JS
|
||||||
|
* entrypoints via the `virtual:wxt-plugins` import, and HTML files by adding
|
||||||
|
* `virtual:wxt-html-plugins` to the document's `<head>`
|
||||||
*/
|
*/
|
||||||
export function wxtPluginLoader(config: ResolvedConfig): vite.Plugin {
|
export function wxtPluginLoader(config: ResolvedConfig): vite.Plugin {
|
||||||
const virtualModuleId = 'virtual:wxt-plugins';
|
const virtualModuleId = 'virtual:wxt-plugins';
|
||||||
@@ -14,33 +16,50 @@ export function wxtPluginLoader(config: ResolvedConfig): vite.Plugin {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
name: 'wxt:plugin-loader',
|
name: 'wxt:plugin-loader',
|
||||||
resolveId(id) {
|
resolveId: {
|
||||||
if (id === virtualModuleId) return resolvedVirtualModuleId;
|
filter: {
|
||||||
if (id === virtualHtmlModuleId) return resolvedVirtualHtmlModuleId;
|
id: [
|
||||||
},
|
new RegExp(`^${virtualModuleId}$`),
|
||||||
load(id) {
|
new RegExp(`^${virtualHtmlModuleId}$`),
|
||||||
if (id === resolvedVirtualModuleId) {
|
],
|
||||||
// Import and init all plugins
|
},
|
||||||
const imports = config.plugins
|
handler(id) {
|
||||||
.map(
|
if (id === virtualModuleId) {
|
||||||
(plugin, i) =>
|
return resolvedVirtualModuleId;
|
||||||
`import initPlugin${i} from '${normalizePath(plugin)}';`,
|
}
|
||||||
)
|
|
||||||
.join('\n');
|
|
||||||
const initCalls = config.plugins
|
|
||||||
.map((_, i) => ` initPlugin${i}();`)
|
|
||||||
.join('\n');
|
|
||||||
return `${imports}\n\nexport function initPlugins() {\n${initCalls}\n}`;
|
|
||||||
}
|
|
||||||
if (id === resolvedVirtualHtmlModuleId) {
|
|
||||||
return `import { initPlugins } from '${virtualModuleId}';
|
|
||||||
|
|
||||||
try {
|
return resolvedVirtualHtmlModuleId;
|
||||||
initPlugins();
|
},
|
||||||
} catch (err) {
|
},
|
||||||
console.error("[wxt] Failed to initialize plugins", err);
|
load: {
|
||||||
}`;
|
filter: {
|
||||||
}
|
id: [
|
||||||
|
new RegExp(`^${resolvedVirtualModuleId}$`),
|
||||||
|
new RegExp(`^${resolvedVirtualHtmlModuleId}$`),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
handler(id) {
|
||||||
|
if (id === resolvedVirtualModuleId) {
|
||||||
|
// Import and init all plugins
|
||||||
|
const imports = config.plugins
|
||||||
|
.map(
|
||||||
|
(plugin, i) =>
|
||||||
|
`import initPlugin${i} from '${normalizePath(plugin)}';`,
|
||||||
|
)
|
||||||
|
.join('\n');
|
||||||
|
const initCalls = config.plugins
|
||||||
|
.map((_, i) => ` initPlugin${i}();`)
|
||||||
|
.join('\n');
|
||||||
|
return `${imports}\n\nexport function initPlugins() {\n${initCalls}\n}`;
|
||||||
|
} else {
|
||||||
|
return `import { initPlugins } from '${virtualModuleId}';
|
||||||
|
try {
|
||||||
|
initPlugins();
|
||||||
|
} catch (err) {
|
||||||
|
console.error("[wxt] Failed to initialize plugins", err);
|
||||||
|
}`;
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
transformIndexHtml: {
|
transformIndexHtml: {
|
||||||
// Use "pre" so the new script is added before vite bundles all the scripts
|
// Use "pre" so the new script is added before vite bundles all the scripts
|
||||||
@@ -63,7 +82,8 @@ try {
|
|||||||
const newHead = document.createElement('head');
|
const newHead = document.createElement('head');
|
||||||
document.documentElement.prepend(newHead);
|
document.documentElement.prepend(newHead);
|
||||||
}
|
}
|
||||||
document.head.prepend(script);
|
|
||||||
|
document.head?.prepend(script);
|
||||||
return document.toString();
|
return document.toString();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import glob from 'fast-glob';
|
import { glob } from 'tinyglobby';
|
||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
import pc from 'picocolors';
|
import pc from 'picocolors';
|
||||||
import { InlineConfig } from '../types';
|
import { InlineConfig } from '../types';
|
||||||
@@ -8,21 +8,21 @@ import { registerWxt, wxt } from './wxt';
|
|||||||
/**
|
/**
|
||||||
* Remove generated/temp files from the directory.
|
* Remove generated/temp files from the directory.
|
||||||
*
|
*
|
||||||
* @param config Optional config that will override your `<root>/wxt.config.ts`.
|
|
||||||
*
|
|
||||||
* @example
|
* @example
|
||||||
* await clean();
|
* await clean();
|
||||||
|
*
|
||||||
|
* @param config Optional config that will override your `<root>/wxt.config.ts`.
|
||||||
*/
|
*/
|
||||||
export async function clean(config?: InlineConfig): Promise<void>;
|
export async function clean(config?: InlineConfig): Promise<void>;
|
||||||
/**
|
/**
|
||||||
* Remove generated/temp files from the directory.
|
* Remove generated/temp files from the directory.
|
||||||
*
|
*
|
||||||
* @deprecated
|
* @deprecated
|
||||||
*
|
|
||||||
* @param root The directory to look for generated/temp files in. Defaults to `process.cwd()`. Can be relative to `process.cwd()` or absolute.
|
|
||||||
*
|
|
||||||
* @example
|
* @example
|
||||||
* await clean();
|
* await clean();
|
||||||
|
*
|
||||||
|
* @param root The directory to look for generated/temp files in. Defaults to
|
||||||
|
* `process.cwd()`. Can be relative to `process.cwd()` or absolute.
|
||||||
*/
|
*/
|
||||||
export async function clean(root?: string): Promise<void>;
|
export async function clean(root?: string): Promise<void>;
|
||||||
|
|
||||||
@@ -48,6 +48,7 @@ export async function clean(config?: string | InlineConfig) {
|
|||||||
absolute: true,
|
absolute: true,
|
||||||
onlyDirectories: true,
|
onlyDirectories: true,
|
||||||
deep: 2,
|
deep: 2,
|
||||||
|
expandDirectories: false,
|
||||||
});
|
});
|
||||||
if (directories.length === 0) {
|
if (directories.length === 0) {
|
||||||
wxt.logger.debug('No generated files found.');
|
wxt.logger.debug('No generated files found.');
|
||||||
|
|||||||
@@ -32,13 +32,14 @@ import { createKeyboardShortcuts } from './keyboard-shortcuts';
|
|||||||
import { isBabelSyntaxError, logBabelSyntaxError } from './utils/syntax-errors';
|
import { isBabelSyntaxError, logBabelSyntaxError } from './utils/syntax-errors';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a dev server and pre-builds all the files that need to exist before loading the extension.
|
* Creates a dev server and pre-builds all the files that need to exist before
|
||||||
|
* loading the extension.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const server = await wxt.createServer({
|
* const server = await wxt.createServer({
|
||||||
* // Enter config...
|
* // Enter config...
|
||||||
* });
|
* });
|
||||||
* await server.start();
|
* await server.start();
|
||||||
*/
|
*/
|
||||||
export async function createServer(
|
export async function createServer(
|
||||||
inlineConfig?: InlineConfig,
|
inlineConfig?: InlineConfig,
|
||||||
@@ -199,8 +200,8 @@ async function createServerInternal(): Promise<WxtDevServer> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a function responsible for reloading different parts of the extension when a file
|
* Returns a function responsible for reloading different parts of the extension
|
||||||
* changes.
|
* when a file changes.
|
||||||
*/
|
*/
|
||||||
function createFileReloader(server: WxtDevServer) {
|
function createFileReloader(server: WxtDevServer) {
|
||||||
const fileChangedMutex = new Mutex();
|
const fileChangedMutex = new Mutex();
|
||||||
@@ -295,7 +296,8 @@ function createFileReloader(server: WxtDevServer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* From the server, tell the client to reload content scripts from the provided build step outputs.
|
* From the server, tell the client to reload content scripts from the provided
|
||||||
|
* build step outputs.
|
||||||
*/
|
*/
|
||||||
function reloadContentScripts(steps: BuildStepOutput[], server: WxtDevServer) {
|
function reloadContentScripts(steps: BuildStepOutput[], server: WxtDevServer) {
|
||||||
if (wxt.config.manifestVersion === 3) {
|
if (wxt.config.manifestVersion === 3) {
|
||||||
@@ -350,6 +352,7 @@ function getFilenameList(names: string[]): string {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Based on the current build output, return a list of files that are:
|
* Based on the current build output, return a list of files that are:
|
||||||
|
*
|
||||||
* 1. Not in node_modules
|
* 1. Not in node_modules
|
||||||
* 2. Not inside project root
|
* 2. Not inside project root
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
import consola from 'consola';
|
import consola from 'consola';
|
||||||
import { WebExtConfig } from '../types';
|
import { WebExtConfig } from '../types';
|
||||||
|
|
||||||
/**
|
/** @deprecated Use `defineWebExtConfig` instead. Same function, different name. */
|
||||||
* @deprecated Use `defineWebExtConfig` instead. Same function, different name.
|
|
||||||
*/
|
|
||||||
export function defineRunnerConfig(config: WebExtConfig): WebExtConfig {
|
export function defineRunnerConfig(config: WebExtConfig): WebExtConfig {
|
||||||
consola.warn(
|
consola.warn(
|
||||||
'`defineRunnerConfig` is deprecated, use `defineWebExtConfig` instead. See https://wxt.dev/guide/resources/upgrading.html#v0-19-0-rarr-v0-20-0',
|
'`defineRunnerConfig` is deprecated, use `defineWebExtConfig` instead. See https://wxt.dev/guide/resources/upgrading.html#v0-19-0-rarr-v0-20-0',
|
||||||
@@ -12,7 +10,8 @@ export function defineRunnerConfig(config: WebExtConfig): WebExtConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configure how [`web-ext`](https://github.com/mozilla/web-ext) starts the browser during development.
|
* Configure how [`web-ext`](https://github.com/mozilla/web-ext) starts the
|
||||||
|
* browser during development.
|
||||||
*/
|
*/
|
||||||
export function defineWebExtConfig(config: WebExtConfig): WebExtConfig {
|
export function defineWebExtConfig(config: WebExtConfig): WebExtConfig {
|
||||||
return config;
|
return config;
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ import { writeFileIfDifferent, getPublicFiles } from './utils/fs';
|
|||||||
import { wxt } from './wxt';
|
import { wxt } from './wxt';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate and write all the files inside the `InternalConfig.typesDir` directory.
|
* Generate and write all the files inside the `InternalConfig.typesDir`
|
||||||
|
* directory.
|
||||||
*/
|
*/
|
||||||
export async function generateWxtDir(entrypoints: Entrypoint[]): Promise<void> {
|
export async function generateWxtDir(entrypoints: Entrypoint[]): Promise<void> {
|
||||||
await fs.ensureDir(wxt.config.typesDir);
|
await fs.ensureDir(wxt.config.typesDir);
|
||||||
|
|||||||
@@ -87,13 +87,9 @@ export async function initialize(options: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface Template {
|
interface Template {
|
||||||
/**
|
/** Template's name. */
|
||||||
* Template's name.
|
|
||||||
*/
|
|
||||||
name: string;
|
name: string;
|
||||||
/**
|
/** Path to template directory in github repo. */
|
||||||
* Path to template directory in github repo.
|
|
||||||
*/
|
|
||||||
path: string;
|
path: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,8 +157,8 @@ async function cloneProject({
|
|||||||
directory: string;
|
directory: string;
|
||||||
template: Template;
|
template: Template;
|
||||||
}) {
|
}) {
|
||||||
const { default: ora } = await import('ora');
|
const { createSpinner } = await import('nanospinner');
|
||||||
const spinner = ora('Downloading template').start();
|
const spinner = createSpinner('Downloading template').start();
|
||||||
try {
|
try {
|
||||||
// 1. Clone repo
|
// 1. Clone repo
|
||||||
await downloadTemplate(`gh:${REPO}/${template.path}`, {
|
await downloadTemplate(`gh:${REPO}/${template.path}`, {
|
||||||
@@ -180,9 +176,9 @@ async function cloneProject({
|
|||||||
consola.warn('Failed to move _gitignore to .gitignore:', err),
|
consola.warn('Failed to move _gitignore to .gitignore:', err),
|
||||||
);
|
);
|
||||||
|
|
||||||
spinner.succeed();
|
spinner.success();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
spinner.fail();
|
spinner.error();
|
||||||
throw Error(`Failed to setup new project: ${JSON.stringify(err, null, 2)}`);
|
throw Error(`Failed to setup new project: ${JSON.stringify(err, null, 2)}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,9 +9,7 @@ export interface KeyboardShortcutWatcher {
|
|||||||
printHelp(flags: { canReopenBrowser: boolean }): void;
|
printHelp(flags: { canReopenBrowser: boolean }): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Function that creates a keyboard shortcut handler for the extension. */
|
||||||
* Function that creates a keyboard shortcut handler for the extension.
|
|
||||||
*/
|
|
||||||
export function createKeyboardShortcuts(
|
export function createKeyboardShortcuts(
|
||||||
server: WxtDevServer,
|
server: WxtDevServer,
|
||||||
): KeyboardShortcutWatcher {
|
): KeyboardShortcutWatcher {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import defu from 'defu';
|
|||||||
import { NullablyRequired } from './utils/types';
|
import { NullablyRequired } from './utils/types';
|
||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
import { normalizePath } from './utils';
|
import { normalizePath } from './utils';
|
||||||
import glob from 'fast-glob';
|
import { glob } from 'tinyglobby';
|
||||||
import { builtinModules } from '../builtin-modules';
|
import { builtinModules } from '../builtin-modules';
|
||||||
import { getEslintVersion } from './utils/eslint';
|
import { getEslintVersion } from './utils/eslint';
|
||||||
import { safeStringToNumber } from './utils/number';
|
import { safeStringToNumber } from './utils/number';
|
||||||
@@ -31,11 +31,12 @@ import { getPort } from 'get-port-please';
|
|||||||
import { fileURLToPath, pathToFileURL } from 'node:url';
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given an inline config, discover the config file if necessary, merge the results, resolve any
|
* Given an inline config, discover the config file if necessary, merge the
|
||||||
* relative paths, and apply any defaults.
|
* results, resolve any relative paths, and apply any defaults.
|
||||||
*
|
*
|
||||||
* Inline config always has priority over user config. Cli flags are passed as inline config if set.
|
* Inline config always has priority over user config. Cli flags are passed as
|
||||||
* If unset, undefined is passed in, letting this function decide default values.
|
* inline config if set. If unset, undefined is passed in, letting this function
|
||||||
|
* decide default values.
|
||||||
*/
|
*/
|
||||||
export async function resolveConfig(
|
export async function resolveConfig(
|
||||||
inlineConfig: InlineConfig,
|
inlineConfig: InlineConfig,
|
||||||
@@ -249,7 +250,8 @@ async function resolveManifestConfig(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Merge the inline config and user config. Inline config is given priority. Defaults are not applied here.
|
* Merge the inline config and user config. Inline config is given priority.
|
||||||
|
* Defaults are not applied here.
|
||||||
*/
|
*/
|
||||||
async function mergeInlineConfig(
|
async function mergeInlineConfig(
|
||||||
inlineConfig: InlineConfig,
|
inlineConfig: InlineConfig,
|
||||||
@@ -528,9 +530,7 @@ async function getUnimportEslintOptions(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Returns the path to `node_modules/wxt`. */
|
||||||
* Returns the path to `node_modules/wxt`.
|
|
||||||
*/
|
|
||||||
function resolveWxtModuleDir() {
|
function resolveWxtModuleDir() {
|
||||||
// TODO: Switch to import.meta.resolve() once the parent argument is unflagged
|
// TODO: Switch to import.meta.resolve() once the parent argument is unflagged
|
||||||
// (e.g. --experimental-import-meta-resolve) and all Node.js versions we support
|
// (e.g. --experimental-import-meta-resolve) and all Node.js versions we support
|
||||||
@@ -554,9 +554,7 @@ function logMissingDir(logger: Logger, name: string, expected: string) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Map of `ConfigEnv` commands to their default modes. */
|
||||||
* Map of `ConfigEnv` commands to their default modes.
|
|
||||||
*/
|
|
||||||
const COMMAND_MODES: Record<WxtCommand, string> = {
|
const COMMAND_MODES: Record<WxtCommand, string> = {
|
||||||
build: 'production',
|
build: 'production',
|
||||||
serve: 'development',
|
serve: 'development',
|
||||||
@@ -614,6 +612,7 @@ export async function resolveWxtUserModules(
|
|||||||
const localModulePaths = await glob(['*.[tj]s', '*/index.[tj]s'], {
|
const localModulePaths = await glob(['*.[tj]s', '*/index.[tj]s'], {
|
||||||
cwd: modulesDir,
|
cwd: modulesDir,
|
||||||
onlyFiles: true,
|
onlyFiles: true,
|
||||||
|
expandDirectories: false,
|
||||||
}).catch(() => []);
|
}).catch(() => []);
|
||||||
// Sort modules to ensure a consistent execution order
|
// Sort modules to ensure a consistent execution order
|
||||||
localModulePaths.sort();
|
localModulePaths.sort();
|
||||||
|
|||||||
@@ -2,9 +2,7 @@ import { ExtensionRunner } from '../../types';
|
|||||||
import { relative } from 'node:path';
|
import { relative } from 'node:path';
|
||||||
import { wxt } from '../wxt';
|
import { wxt } from '../wxt';
|
||||||
|
|
||||||
/**
|
/** The manual runner tells the user to load the unpacked extension manually. */
|
||||||
* The manual runner tells the user to load the unpacked extension manually.
|
|
||||||
*/
|
|
||||||
export function createManualRunner(): ExtensionRunner {
|
export function createManualRunner(): ExtensionRunner {
|
||||||
return {
|
return {
|
||||||
async openBrowser() {
|
async openBrowser() {
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ import { relative } from 'node:path';
|
|||||||
import { wxt } from '../wxt';
|
import { wxt } from '../wxt';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Safari runner just logs a warning message because `web-ext` doesn't work with Safari.
|
* The Safari runner just logs a warning message because `web-ext` doesn't work
|
||||||
|
* with Safari.
|
||||||
*/
|
*/
|
||||||
export function createSafariRunner(): ExtensionRunner {
|
export function createSafariRunner(): ExtensionRunner {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -4,9 +4,7 @@ import { formatDuration } from '../utils/time';
|
|||||||
import defu from 'defu';
|
import defu from 'defu';
|
||||||
import { wxt } from '../wxt';
|
import { wxt } from '../wxt';
|
||||||
|
|
||||||
/**
|
/** Create an `ExtensionRunner` backed by `web-ext`. */
|
||||||
* Create an `ExtensionRunner` backed by `web-ext`.
|
|
||||||
*/
|
|
||||||
export function createWebExtRunner(): ExtensionRunner {
|
export function createWebExtRunner(): ExtensionRunner {
|
||||||
let runner: WebExtRunInstance | undefined;
|
let runner: WebExtRunInstance | undefined;
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ import { relative } from 'node:path';
|
|||||||
import { wxt } from '../wxt';
|
import { wxt } from '../wxt';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The WSL runner just logs a warning message because `web-ext` doesn't work in WSL.
|
* The WSL runner just logs a warning message because `web-ext` doesn't work in
|
||||||
|
* WSL.
|
||||||
*/
|
*/
|
||||||
export function createWslRunner(): ExtensionRunner {
|
export function createWslRunner(): ExtensionRunner {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
/**
|
/** Checks if `predicate` returns truthy for all elements of the array. */
|
||||||
* Checks if `predicate` returns truthy for all elements of the array.
|
|
||||||
*/
|
|
||||||
export function every<T>(
|
export function every<T>(
|
||||||
array: T[],
|
array: T[],
|
||||||
predicate: (item: T, index: number) => boolean,
|
predicate: (item: T, index: number) => boolean,
|
||||||
@@ -10,9 +8,7 @@ export function every<T>(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Returns true when any of the predicates return true; */
|
||||||
* Returns true when any of the predicates return true;
|
|
||||||
*/
|
|
||||||
export function some<T>(
|
export function some<T>(
|
||||||
array: T[],
|
array: T[],
|
||||||
predicate: (item: T, index: number) => boolean,
|
predicate: (item: T, index: number) => boolean,
|
||||||
@@ -22,9 +18,7 @@ export function some<T>(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Convert an item or array to an array. */
|
||||||
* Convert an item or array to an array.
|
|
||||||
*/
|
|
||||||
export function toArray<T>(a: T | T[]): T[] {
|
export function toArray<T>(a: T | T[]): T[] {
|
||||||
return Array.isArray(a) ? a : [a];
|
return Array.isArray(a) ? a : [a];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,12 +12,12 @@ import {
|
|||||||
import { resolve } from 'path';
|
import { resolve } from 'path';
|
||||||
import { findEntrypoints } from '../find-entrypoints';
|
import { findEntrypoints } from '../find-entrypoints';
|
||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
import glob from 'fast-glob';
|
import { glob } from 'tinyglobby';
|
||||||
import { fakeResolvedConfig, setFakeWxt } from '../../testing/fake-objects';
|
import { fakeResolvedConfig, setFakeWxt } from '../../testing/fake-objects';
|
||||||
import { unnormalizePath } from '../../paths';
|
import { unnormalizePath } from '../../paths';
|
||||||
import { wxt } from '../../../wxt';
|
import { wxt } from '../../../wxt';
|
||||||
|
|
||||||
vi.mock('fast-glob');
|
vi.mock('tinyglobby');
|
||||||
const globMock = vi.mocked(glob);
|
const globMock = vi.mocked(glob);
|
||||||
|
|
||||||
vi.mock('fs-extra');
|
vi.mock('fs-extra');
|
||||||
|
|||||||
@@ -7,26 +7,28 @@ import {
|
|||||||
import { getPublicFiles } from '../fs';
|
import { getPublicFiles } from '../fs';
|
||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
import { dirname, resolve } from 'path';
|
import { dirname, resolve } from 'path';
|
||||||
import type { Ora } from 'ora';
|
import type { Spinner } from 'nanospinner';
|
||||||
import pc from 'picocolors';
|
import pc from 'picocolors';
|
||||||
import { wxt } from '../../wxt';
|
import { wxt } from '../../wxt';
|
||||||
import { toArray } from '../arrays';
|
import { toArray } from '../arrays';
|
||||||
|
|
||||||
export async function buildEntrypoints(
|
export async function buildEntrypoints(
|
||||||
groups: EntrypointGroup[],
|
groups: EntrypointGroup[],
|
||||||
spinner: Ora,
|
spinner: Spinner,
|
||||||
): Promise<Omit<BuildOutput, 'manifest'>> {
|
): Promise<Omit<BuildOutput, 'manifest'>> {
|
||||||
const steps: BuildStepOutput[] = [];
|
const steps: BuildStepOutput[] = [];
|
||||||
for (let i = 0; i < groups.length; i++) {
|
for (let i = 0; i < groups.length; i++) {
|
||||||
const group = groups[i];
|
const group = groups[i];
|
||||||
const groupNames = toArray(group).map((e) => e.name);
|
const groupNames = toArray(group).map((e) => e.name);
|
||||||
const groupNameColored = groupNames.join(pc.dim(', '));
|
const groupNameColored = groupNames.join(pc.dim(', '));
|
||||||
spinner.text =
|
spinner.update({
|
||||||
pc.dim(`[${i + 1}/${groups.length}]`) + ` ${groupNameColored}`;
|
text: pc.dim(`[${i + 1}/${groups.length}]`) + ` ${groupNameColored}`,
|
||||||
|
});
|
||||||
try {
|
try {
|
||||||
steps.push(await wxt.builder.build(group));
|
steps.push(await wxt.builder.build(group));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
spinner.stop().clear();
|
spinner.stop();
|
||||||
|
spinner.clear();
|
||||||
wxt.logger.error(err);
|
wxt.logger.error(err);
|
||||||
throw Error(`Failed to build ${groupNames.join(', ')}`, { cause: err });
|
throw Error(`Failed to build ${groupNames.join(', ')}`, { cause: err });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,27 +9,36 @@ import { normalizePath } from '../paths';
|
|||||||
import { wxt } from '../../wxt';
|
import { wxt } from '../../wxt';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compare the changed files vs the build output and determine what kind of reload needs to happen:
|
* Compare the changed files vs the build output and determine what kind of
|
||||||
|
* reload needs to happen:
|
||||||
*
|
*
|
||||||
* - Do nothing
|
* - Do nothing
|
||||||
* - CSS or JS file associated with an HTML page is changed - this is handled automatically by the
|
*
|
||||||
* dev server
|
* - CSS or JS file associated with an HTML page is changed - this is handled
|
||||||
|
* automatically by the dev server
|
||||||
* - Change isn't used by any of the entrypoints
|
* - Change isn't used by any of the entrypoints
|
||||||
* - Reload Content script
|
* - Reload Content script
|
||||||
|
*
|
||||||
* - CSS or JS file associated with a content script
|
* - CSS or JS file associated with a content script
|
||||||
* - Background script will be told to reload the content script
|
* - Background script will be told to reload the content script
|
||||||
* - Reload HTML file
|
* - Reload HTML file
|
||||||
* - HTML file itself is saved - HMR doesn't handle this because the HTML pages are pre-rendered
|
*
|
||||||
* - Chrome is OK reloading the page when the HTML file is changed without reloading the whole
|
* - HTML file itself is saved - HMR doesn't handle this because the HTML pages
|
||||||
* extension. Not sure about firefox, this might need to change to an extension reload
|
* are pre-rendered
|
||||||
|
* - Chrome is OK reloading the page when the HTML file is changed without
|
||||||
|
* reloading the whole extension. Not sure about firefox, this might need
|
||||||
|
* to change to an extension reload
|
||||||
* - Reload extension
|
* - Reload extension
|
||||||
|
*
|
||||||
* - Background script is changed
|
* - Background script is changed
|
||||||
* - Manifest is different
|
* - Manifest is different
|
||||||
* - Restart browser
|
* - Restart browser
|
||||||
* - web-ext.config.ts (runner config changes)
|
*
|
||||||
|
* - Web-ext.config.ts (runner config changes)
|
||||||
* - Full dev server restart
|
* - Full dev server restart
|
||||||
* - wxt.config.ts (main config file)
|
*
|
||||||
* - modules/* (any file related to WXT modules)
|
* - Wxt.config.ts (main config file)
|
||||||
|
* - Modules/* (any file related to WXT modules)
|
||||||
* - .env (environment variable changed could effect build)
|
* - .env (environment variable changed could effect build)
|
||||||
*/
|
*/
|
||||||
export function detectDevChanges(
|
export function detectDevChanges(
|
||||||
@@ -126,7 +135,8 @@ export function detectDevChanges(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For a single change, return all the step of the build output that were effected by it.
|
* For a single change, return all the step of the build output that were
|
||||||
|
* effected by it.
|
||||||
*/
|
*/
|
||||||
function findEffectedSteps(
|
function findEffectedSteps(
|
||||||
changedFile: string,
|
changedFile: string,
|
||||||
@@ -165,8 +175,8 @@ function findEffectedSteps(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains information about what files changed, what needs rebuilt, and the type of reload that is
|
* Contains information about what files changed, what needs rebuilt, and the
|
||||||
* required.
|
* type of reload that is required.
|
||||||
*/
|
*/
|
||||||
export type DevModeChange =
|
export type DevModeChange =
|
||||||
| NoChange
|
| NoChange
|
||||||
@@ -181,13 +191,9 @@ interface NoChange {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface RebuildChange {
|
interface RebuildChange {
|
||||||
/**
|
/** The list of entrypoints that need rebuilt. */
|
||||||
* The list of entrypoints that need rebuilt.
|
|
||||||
*/
|
|
||||||
rebuildGroups: EntrypointGroup[];
|
rebuildGroups: EntrypointGroup[];
|
||||||
/**
|
/** The previous output stripped of any files are going to change. */
|
||||||
* The previous output stripped of any files are going to change.
|
|
||||||
*/
|
|
||||||
cachedOutput: BuildOutput;
|
cachedOutput: BuildOutput;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import fs from 'fs-extra';
|
|||||||
import { minimatch } from 'minimatch';
|
import { minimatch } from 'minimatch';
|
||||||
import { parseHTML } from 'linkedom';
|
import { parseHTML } from 'linkedom';
|
||||||
import JSON5 from 'json5';
|
import JSON5 from 'json5';
|
||||||
import glob from 'fast-glob';
|
import { glob } from 'tinyglobby';
|
||||||
import {
|
import {
|
||||||
getEntrypointName,
|
getEntrypointName,
|
||||||
isHtmlEntrypoint,
|
isHtmlEntrypoint,
|
||||||
@@ -30,7 +30,8 @@ import { wxt } from '../../wxt';
|
|||||||
import { camelCase } from 'scule';
|
import { camelCase } from 'scule';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return entrypoints and their configuration by looking through the project's files.
|
* Return entrypoints and their configuration by looking through the project's
|
||||||
|
* files.
|
||||||
*/
|
*/
|
||||||
export async function findEntrypoints(): Promise<Entrypoint[]> {
|
export async function findEntrypoints(): Promise<Entrypoint[]> {
|
||||||
// Make sure required TSConfig file exists to load dependencies
|
// Make sure required TSConfig file exists to load dependencies
|
||||||
@@ -49,6 +50,7 @@ export async function findEntrypoints(): Promise<Entrypoint[]> {
|
|||||||
|
|
||||||
const relativePaths = await glob(Object.keys(PATH_GLOB_TO_TYPE_MAP), {
|
const relativePaths = await glob(Object.keys(PATH_GLOB_TO_TYPE_MAP), {
|
||||||
cwd: wxt.config.entrypointsDir,
|
cwd: wxt.config.entrypointsDir,
|
||||||
|
expandDirectories: false,
|
||||||
});
|
});
|
||||||
// Ensure consistent output
|
// Ensure consistent output
|
||||||
relativePaths.sort();
|
relativePaths.sort();
|
||||||
@@ -195,7 +197,10 @@ async function importEntrypoints(infos: EntrypointInfo[]) {
|
|||||||
return resMap;
|
return resMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Extract `manifest.` and `wxt.` options from meta tags, converting snake_case keys to camelCase */
|
/**
|
||||||
|
* Extract `manifest.` and `wxt.` options from meta tags, converting snake_case
|
||||||
|
* keys to camelCase
|
||||||
|
*/
|
||||||
async function importHtmlEntrypoint(
|
async function importHtmlEntrypoint(
|
||||||
info: EntrypointInfo,
|
info: EntrypointInfo,
|
||||||
): Promise<Record<string, any>> {
|
): Promise<Record<string, any>> {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { Entrypoint, EntrypointGroup } from '../../../types';
|
import { Entrypoint, EntrypointGroup } from '../../../types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Entrypoints are built in groups. HTML pages can all be built together in a single step,
|
* Entrypoints are built in groups. HTML pages can all be built together in a
|
||||||
* content scripts must be build individually, etc.
|
* single step, content scripts must be build individually, etc.
|
||||||
*
|
*
|
||||||
* This function returns the entrypoints put into these types of groups.
|
* This function returns the entrypoints put into these types of groups.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import fs from 'fs-extra';
|
|||||||
import { groupEntrypoints } from './group-entrypoints';
|
import { groupEntrypoints } from './group-entrypoints';
|
||||||
import { formatDuration } from '../time';
|
import { formatDuration } from '../time';
|
||||||
import { printBuildSummary } from '../log';
|
import { printBuildSummary } from '../log';
|
||||||
import glob from 'fast-glob';
|
import { glob } from 'tinyglobby';
|
||||||
import { unnormalizePath } from '../paths';
|
import { unnormalizePath } from '../paths';
|
||||||
import { rebuild } from './rebuild';
|
import { rebuild } from './rebuild';
|
||||||
import { relative } from 'node:path';
|
import { relative } from 'node:path';
|
||||||
@@ -20,13 +20,14 @@ import { mergeJsonOutputs } from '@aklinker1/rollup-plugin-visualizer';
|
|||||||
import { isCI } from 'ci-info';
|
import { isCI } from 'ci-info';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds the extension based on an internal config. No more config discovery is performed, the
|
* Builds the extension based on an internal config. No more config discovery is
|
||||||
* build is based on exactly what is passed in.
|
* performed, the build is based on exactly what is passed in.
|
||||||
*
|
*
|
||||||
* This function:
|
* This function:
|
||||||
|
*
|
||||||
* 1. Cleans the output directory
|
* 1. Cleans the output directory
|
||||||
* 2. Executes the rebuild function with a blank previous output so everything is built (see
|
* 2. Executes the rebuild function with a blank previous output so everything is
|
||||||
* `rebuild` for more details)
|
* built (see `rebuild` for more details)
|
||||||
* 3. Prints the summary
|
* 3. Prints the summary
|
||||||
*/
|
*/
|
||||||
export async function internalBuild(): Promise<BuildOutput> {
|
export async function internalBuild(): Promise<BuildOutput> {
|
||||||
@@ -99,6 +100,7 @@ async function combineAnalysisStats(): Promise<void> {
|
|||||||
const unixFiles = await glob(`${wxt.config.analysis.outputName}-*.json`, {
|
const unixFiles = await glob(`${wxt.config.analysis.outputName}-*.json`, {
|
||||||
cwd: wxt.config.analysis.outputDir,
|
cwd: wxt.config.analysis.outputDir,
|
||||||
absolute: true,
|
absolute: true,
|
||||||
|
expandDirectories: false,
|
||||||
});
|
});
|
||||||
const absolutePaths = unixFiles.map(unnormalizePath);
|
const absolutePaths = unixFiles.map(unnormalizePath);
|
||||||
|
|
||||||
|
|||||||
@@ -4,22 +4,25 @@ import { buildEntrypoints } from './build-entrypoints';
|
|||||||
import { generateManifest, writeManifest } from '../../utils/manifest';
|
import { generateManifest, writeManifest } from '../../utils/manifest';
|
||||||
import { wxt } from '../../wxt';
|
import { wxt } from '../../wxt';
|
||||||
import type { Browser } from '@wxt-dev/browser';
|
import type { Browser } from '@wxt-dev/browser';
|
||||||
|
import { createSpinner } from 'nanospinner';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a configuration, list of entrypoints, and an existing, partial output, build the
|
* Given a configuration, list of entrypoints, and an existing, partial output,
|
||||||
* entrypoints and merge the new output with the existing output.
|
* build the entrypoints and merge the new output with the existing output.
|
||||||
*
|
*
|
||||||
* This function will:
|
* This function will:
|
||||||
|
*
|
||||||
* 1. Generate the .wxt directory's types
|
* 1. Generate the .wxt directory's types
|
||||||
* 2. Build the `entrypointGroups` (and copies public files)
|
* 2. Build the `entrypointGroups` (and copies public files)
|
||||||
* 3. Generate the latest manifest for all entrypoints
|
* 3. Generate the latest manifest for all entrypoints
|
||||||
* 4. Write the new manifest to the file system
|
* 4. Write the new manifest to the file system
|
||||||
*
|
*
|
||||||
* @param config Internal config containing all the project information.
|
* @param config Internal config containing all the project information.
|
||||||
* @param allEntrypoints List of entrypoints used to generate the types inside .wxt directory.
|
* @param allEntrypoints List of entrypoints used to generate the types inside
|
||||||
|
* .wxt directory.
|
||||||
* @param entrypointGroups The list of entrypoint groups to build.
|
* @param entrypointGroups The list of entrypoint groups to build.
|
||||||
* @param existingOutput The previous output to combine the rebuild results into. An emptry array if
|
* @param existingOutput The previous output to combine the rebuild results
|
||||||
* this is the first build.
|
* into. An emptry array if this is the first build.
|
||||||
*/
|
*/
|
||||||
export async function rebuild(
|
export async function rebuild(
|
||||||
allEntrypoints: Entrypoint[],
|
allEntrypoints: Entrypoint[],
|
||||||
@@ -33,8 +36,7 @@ export async function rebuild(
|
|||||||
manifest: Browser.runtime.Manifest;
|
manifest: Browser.runtime.Manifest;
|
||||||
warnings: any[][];
|
warnings: any[][];
|
||||||
}> {
|
}> {
|
||||||
const { default: ora } = await import('ora');
|
const spinner = createSpinner('Preparing...').start();
|
||||||
const spinner = ora(`Preparing...`).start();
|
|
||||||
|
|
||||||
// Update types directory with new files and types
|
// Update types directory with new files and types
|
||||||
await generateWxtDir(allEntrypoints).catch((err) => {
|
await generateWxtDir(allEntrypoints).catch((err) => {
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import { dirname, resolve } from 'path';
|
|||||||
import { writeFileIfDifferent } from './fs';
|
import { writeFileIfDifferent } from './fs';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A basic file system cache stored at `<srcDir>/.wxt/cache/<key>`. Just caches a string in a
|
* A basic file system cache stored at `<srcDir>/.wxt/cache/<key>`. Just caches
|
||||||
* file for the given key.
|
* a string in a file for the given key.
|
||||||
*
|
*
|
||||||
* @param srcDir Absolute path to source directory. See `InternalConfig.srcDir`
|
* @param srcDir Absolute path to source directory. See `InternalConfig.srcDir`
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Module ID used to build the background in dev mode if the extension doesn't include a background
|
* Module ID used to build the background in dev mode if the extension doesn't
|
||||||
* script/service worker.
|
* include a background script/service worker.
|
||||||
*/
|
*/
|
||||||
export const VIRTUAL_NOOP_BACKGROUND_MODULE_ID = 'virtual:user-background';
|
export const VIRTUAL_NOOP_BACKGROUND_MODULE_ID = 'virtual:user-background';
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ import { getEntrypointBundlePath } from './entrypoints';
|
|||||||
import { ManifestContentScript } from './types';
|
import { ManifestContentScript } from './types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a unique and consistent string hash based on a content scripts options.
|
* Returns a unique and consistent string hash based on a content scripts
|
||||||
|
* options.
|
||||||
*
|
*
|
||||||
* It is able to recognize default values,
|
* It is able to recognize default values,
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* Directive names that make up CSPs. There are more, this is all I need for the plugin.
|
* Directive names that make up CSPs. There are more, this is all I need for the
|
||||||
|
* plugin.
|
||||||
*/
|
*/
|
||||||
export type CspDirective = 'default-src' | 'script-src' | 'object-src';
|
export type CspDirective = 'default-src' | 'script-src' | 'object-src';
|
||||||
|
|
||||||
@@ -25,9 +26,7 @@ export class ContentSecurityPolicy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Ensure a set of values are listed under a directive. */
|
||||||
* Ensure a set of values are listed under a directive.
|
|
||||||
*/
|
|
||||||
add(directive: CspDirective, ...newValues: string[]): ContentSecurityPolicy {
|
add(directive: CspDirective, ...newValues: string[]): ContentSecurityPolicy {
|
||||||
const values = this.data[directive] ?? [];
|
const values = this.data[directive] ?? [];
|
||||||
newValues.forEach((newValue) => {
|
newValues.forEach((newValue) => {
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ export function getEntrypointOutputFile(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return's the entrypoint's output path relative to the output directory. Used for paths in the
|
* Return's the entrypoint's output path relative to the output directory. Used
|
||||||
* manifest and rollup's bundle.
|
* for paths in the manifest and rollup's bundle.
|
||||||
*/
|
*/
|
||||||
export function getEntrypointBundlePath(
|
export function getEntrypointBundlePath(
|
||||||
entrypoint: Entrypoint,
|
entrypoint: Entrypoint,
|
||||||
@@ -40,9 +40,7 @@ export function getEntrypointBundlePath(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Given an entrypoint option, resolve it's value based on a target browser. */
|
||||||
* Given an entrypoint option, resolve it's value based on a target browser.
|
|
||||||
*/
|
|
||||||
export function resolvePerBrowserOption<T>(
|
export function resolvePerBrowserOption<T>(
|
||||||
option: PerBrowserOption<T>,
|
option: PerBrowserOption<T>,
|
||||||
browser: TargetBrowser,
|
browser: TargetBrowser,
|
||||||
@@ -55,8 +53,8 @@ export function resolvePerBrowserOption<T>(
|
|||||||
/**
|
/**
|
||||||
* Given an entrypoint option, resolve it's value based on a target browser.
|
* Given an entrypoint option, resolve it's value based on a target browser.
|
||||||
*
|
*
|
||||||
* defaultIcon is special, it's the only key that's a record, which can confuse this function. So
|
* DefaultIcon is special, it's the only key that's a record, which can confuse
|
||||||
* it's been manually excluded from resolution.
|
* this function. So it's been manually excluded from resolution.
|
||||||
*/
|
*/
|
||||||
export function resolvePerBrowserOptions<
|
export function resolvePerBrowserOptions<
|
||||||
T extends Record<string, any>,
|
T extends Record<string, any>,
|
||||||
|
|||||||
@@ -2,9 +2,7 @@ import { config } from 'dotenv';
|
|||||||
import { expand } from 'dotenv-expand';
|
import { expand } from 'dotenv-expand';
|
||||||
import type { TargetBrowser } from '../../types';
|
import type { TargetBrowser } from '../../types';
|
||||||
|
|
||||||
/**
|
/** Load environment files based on the current mode and browser. */
|
||||||
* Load environment files based on the current mode and browser.
|
|
||||||
*/
|
|
||||||
export function loadEnv(mode: string, browser: TargetBrowser) {
|
export function loadEnv(mode: string, browser: TargetBrowser) {
|
||||||
return expand(
|
return expand(
|
||||||
config({
|
config({
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
import glob from 'fast-glob';
|
import { glob } from 'tinyglobby';
|
||||||
import { unnormalizePath } from './paths';
|
import { unnormalizePath } from './paths';
|
||||||
import { wxt } from '../wxt';
|
import { wxt } from '../wxt';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Only write the contents to a file if it results in a change. This prevents unnecessary file
|
* Only write the contents to a file if it results in a change. This prevents
|
||||||
* watchers from being triggered, like WXT's dev server or the TS language server in editors.
|
* unnecessary file watchers from being triggered, like WXT's dev server or the
|
||||||
|
* TS language server in editors.
|
||||||
*
|
*
|
||||||
* @param file The file to write to.
|
* @param file The file to write to.
|
||||||
* @param newContents The new text content to write.
|
* @param newContents The new text content to write.
|
||||||
@@ -24,12 +25,15 @@ export async function writeFileIfDifferent(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all the files in the project's public directory. Returned paths are relative to the
|
* Get all the files in the project's public directory. Returned paths are
|
||||||
* `config.publicDir`.
|
* relative to the `config.publicDir`.
|
||||||
*/
|
*/
|
||||||
export async function getPublicFiles(): Promise<string[]> {
|
export async function getPublicFiles(): Promise<string[]> {
|
||||||
if (!(await fs.pathExists(wxt.config.publicDir))) return [];
|
if (!(await fs.pathExists(wxt.config.publicDir))) return [];
|
||||||
|
|
||||||
const files = await glob('**/*', { cwd: wxt.config.publicDir });
|
const files = await glob('**/*', {
|
||||||
|
cwd: wxt.config.publicDir,
|
||||||
|
expandDirectories: false,
|
||||||
|
});
|
||||||
return files.map(unnormalizePath);
|
return files.map(unnormalizePath);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,9 +23,7 @@ import { wxt } from '../wxt';
|
|||||||
import { ManifestV3WebAccessibleResource } from './types';
|
import { ManifestV3WebAccessibleResource } from './types';
|
||||||
import type { Browser } from '@wxt-dev/browser';
|
import type { Browser } from '@wxt-dev/browser';
|
||||||
|
|
||||||
/**
|
/** Writes the manifest to the output directory and the build output. */
|
||||||
* Writes the manifest to the output directory and the build output.
|
|
||||||
*/
|
|
||||||
export async function writeManifest(
|
export async function writeManifest(
|
||||||
manifest: Browser.runtime.Manifest,
|
manifest: Browser.runtime.Manifest,
|
||||||
output: BuildOutput,
|
output: BuildOutput,
|
||||||
@@ -44,9 +42,7 @@ export async function writeManifest(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Generates the manifest based on the config and entrypoints. */
|
||||||
* Generates the manifest based on the config and entrypoints.
|
|
||||||
*/
|
|
||||||
export async function generateManifest(
|
export async function generateManifest(
|
||||||
allEntrypoints: Entrypoint[],
|
allEntrypoints: Entrypoint[],
|
||||||
buildOutput: Omit<BuildOutput, 'manifest'>,
|
buildOutput: Omit<BuildOutput, 'manifest'>,
|
||||||
@@ -155,8 +151,9 @@ export async function generateManifest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes suffixes from the version, like X.Y.Z-alpha1 (which browsers don't allow), so it's a
|
* Removes suffixes from the version, like X.Y.Z-alpha1 (which browsers don't
|
||||||
* simple version number, like X or X.Y or X.Y.Z, which browsers allow.
|
* allow), so it's a simple version number, like X or X.Y or X.Y.Z, which
|
||||||
|
* browsers allow.
|
||||||
*/
|
*/
|
||||||
function simplifyVersion(versionName: string): string {
|
function simplifyVersion(versionName: string): string {
|
||||||
// Regex adapted from here: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/version#version_format
|
// Regex adapted from here: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/version#version_format
|
||||||
@@ -514,8 +511,8 @@ function addDevModePermissions(manifest: Browser.runtime.Manifest) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the bundle paths to CSS files associated with a list of content scripts, or undefined if
|
* Returns the bundle paths to CSS files associated with a list of content
|
||||||
* there is no associated CSS.
|
* scripts, or undefined if there is no associated CSS.
|
||||||
*/
|
*/
|
||||||
export function getContentScriptCssFiles(
|
export function getContentScriptCssFiles(
|
||||||
contentScripts: ContentScriptEntrypoint[],
|
contentScripts: ContentScriptEntrypoint[],
|
||||||
@@ -541,9 +538,9 @@ export function getContentScriptCssFiles(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Content scripts configured with `cssInjectionMode: "ui"` need to add their CSS files to web
|
* Content scripts configured with `cssInjectionMode: "ui"` need to add their
|
||||||
* accessible resources so they can be fetched as text and added to shadow roots that the UI is
|
* CSS files to web accessible resources so they can be fetched as text and
|
||||||
* added to.
|
* added to shadow roots that the UI is added to.
|
||||||
*/
|
*/
|
||||||
export function getContentScriptCssWebAccessibleResources(
|
export function getContentScriptCssWebAccessibleResources(
|
||||||
contentScripts: ContentScriptEntrypoint[],
|
contentScripts: ContentScriptEntrypoint[],
|
||||||
@@ -571,8 +568,8 @@ export function getContentScriptCssWebAccessibleResources(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Based on the build output, return a Record of each content script's name to it CSS file if the
|
* Based on the build output, return a Record of each content script's name to
|
||||||
* script includes one.
|
* it CSS file if the script includes one.
|
||||||
*/
|
*/
|
||||||
export function getContentScriptsCssMap(
|
export function getContentScriptsCssMap(
|
||||||
buildOutput: Omit<BuildOutput, 'manifest'>,
|
buildOutput: Omit<BuildOutput, 'manifest'>,
|
||||||
@@ -610,8 +607,8 @@ function addHostPermission(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* - "<all_urls>" → "<all_urls>"
|
* - "<all_urls>" → "<all_urls>"
|
||||||
* - "*://play.google.com/books/*" → "*://play.google.com/*"
|
* - "_://play.google.com/books/_" → "_://play.google.com/_"
|
||||||
*/
|
*/
|
||||||
export function stripPathFromMatchPattern(pattern: string) {
|
export function stripPathFromMatchPattern(pattern: string) {
|
||||||
const protocolSepIndex = pattern.indexOf('://');
|
const protocolSepIndex = pattern.indexOf('://');
|
||||||
@@ -622,9 +619,10 @@ export function stripPathFromMatchPattern(pattern: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts all MV3 web accessible resources to their MV2 forms. MV3 web accessible resources are
|
* Converts all MV3 web accessible resources to their MV2 forms. MV3 web
|
||||||
* generated in this file, and may be defined by the user in their manifest. In both cases, when
|
* accessible resources are generated in this file, and may be defined by the
|
||||||
* targeting MV2, automatically convert their definitions down to the basic MV2 array.
|
* user in their manifest. In both cases, when targeting MV2, automatically
|
||||||
|
* convert their definitions down to the basic MV2 array.
|
||||||
*/
|
*/
|
||||||
export function convertWebAccessibleResourcesToMv2(
|
export function convertWebAccessibleResourcesToMv2(
|
||||||
manifest: Browser.runtime.Manifest,
|
manifest: Browser.runtime.Manifest,
|
||||||
@@ -674,9 +672,7 @@ function convertCspToMv2(manifest: Browser.runtime.Manifest): void {
|
|||||||
manifest.content_security_policy.extension_pages;
|
manifest.content_security_policy.extension_pages;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Make sure all resources are in MV3 format. If not, add a warning. */
|
||||||
* Make sure all resources are in MV3 format. If not, add a warning.
|
|
||||||
*/
|
|
||||||
function validateMv3WebAccessibleResources(
|
function validateMv3WebAccessibleResources(
|
||||||
manifest: Browser.runtime.Manifest,
|
manifest: Browser.runtime.Manifest,
|
||||||
): void {
|
): void {
|
||||||
@@ -694,9 +690,7 @@ function validateMv3WebAccessibleResources(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Remove keys from the manifest based on the build target. */
|
||||||
* Remove keys from the manifest based on the build target.
|
|
||||||
*/
|
|
||||||
function stripKeys(manifest: Browser.runtime.Manifest): void {
|
function stripKeys(manifest: Browser.runtime.Manifest): void {
|
||||||
let keysToRemove: string[] = [];
|
let keysToRemove: string[] = [];
|
||||||
if (wxt.config.manifestVersion === 2) {
|
if (wxt.config.manifestVersion === 2) {
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ import { minimatch, MinimatchOptions } from 'minimatch';
|
|||||||
* matches any of the negative patterns, it will return `false`.
|
* matches any of the negative patterns, it will return `false`.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* ```ts
|
* ```ts
|
||||||
* minimatchMultiple('a.json', ['*.json', '!b.json']); // => true
|
* minimatchMultiple('a.json', ['*.json', '!b.json']); // => true
|
||||||
* minimatchMultiple('b.json', ['*.json', '!b.json']); // => false
|
* minimatchMultiple('b.json', ['*.json', '!b.json']); // => false
|
||||||
* ```
|
* ```;
|
||||||
*/
|
*/
|
||||||
export function minimatchMultiple(
|
export function minimatchMultiple(
|
||||||
search: string,
|
search: string,
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ export async function isOnline(): Promise<boolean> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches a URL with a simple GET request. Grabs it from cache if it doesn't exist, or throws an
|
* Fetches a URL with a simple GET request. Grabs it from cache if it doesn't
|
||||||
* error if it can't be resolved via the network or cache.
|
* exist, or throws an error if it can't be resolved via the network or cache.
|
||||||
*/
|
*/
|
||||||
export async function fetchCached(
|
export async function fetchCached(
|
||||||
url: string,
|
url: string,
|
||||||
|
|||||||
@@ -2,15 +2,16 @@ import systemPath from 'node:path';
|
|||||||
import normalize from 'normalize-path';
|
import normalize from 'normalize-path';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts system paths to normalized bundler path.
|
* Converts system paths to normalized bundler path. On Windows, this returns
|
||||||
* On Windows, this returns paths with `/` instead of `\`.
|
* paths with `/` instead of `\`.
|
||||||
*/
|
*/
|
||||||
export function normalizePath(path: string): string {
|
export function normalizePath(path: string): string {
|
||||||
return normalize(path);
|
return normalize(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a normalized path, convert it to the system path style. On Windows, switch to \, otherwise use /.
|
* Given a normalized path, convert it to the system path style. On Windows,
|
||||||
|
* switch to , otherwise use /.
|
||||||
*/
|
*/
|
||||||
export function unnormalizePath(path: string): string {
|
export function unnormalizePath(path: string): string {
|
||||||
return systemPath.normalize(path);
|
return systemPath.normalize(path);
|
||||||
|
|||||||
@@ -7,9 +7,7 @@ export function kebabCaseAlphanumeric(str: string): string {
|
|||||||
.replace(/\s+/g, '-'); // Replace spaces with hyphens
|
.replace(/\s+/g, '-'); // Replace spaces with hyphens
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Return a safe variable name for a given string. */
|
||||||
* Return a safe variable name for a given string.
|
|
||||||
*/
|
|
||||||
export function safeVarName(str: string): string {
|
export function safeVarName(str: string): string {
|
||||||
const name = camelCase(kebabCaseAlphanumeric(str));
|
const name = camelCase(kebabCaseAlphanumeric(str));
|
||||||
if (name.match(/^[a-z]/)) return name;
|
if (name.match(/^[a-z]/)) return name;
|
||||||
@@ -18,15 +16,16 @@ export function safeVarName(str: string): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts a string to a valid filename (NOT path), stripping out invalid characters.
|
* Converts a string to a valid filename (NOT path), stripping out invalid
|
||||||
|
* characters.
|
||||||
*/
|
*/
|
||||||
export function safeFilename(str: string): string {
|
export function safeFilename(str: string): string {
|
||||||
return kebabCaseAlphanumeric(str);
|
return kebabCaseAlphanumeric(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes import statements from the top of a file. Keeps import.meta and inline, async `import()`
|
* Removes import statements from the top of a file. Keeps import.meta and
|
||||||
* calls.
|
* inline, async `import()` calls.
|
||||||
*/
|
*/
|
||||||
export function removeImportStatements(text: string): string {
|
export function removeImportStatements(text: string): string {
|
||||||
return text.replace(
|
return text.replace(
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
/**
|
/** SHOULD ONLY BE IMPORTED IN TESTS. */
|
||||||
* SHOULD ONLY BE IMPORTED IN TESTS.
|
|
||||||
*/
|
|
||||||
import { resolve } from 'path';
|
import { resolve } from 'path';
|
||||||
import { faker } from '@faker-js/faker';
|
import { faker } from '@faker-js/faker';
|
||||||
import merge from 'lodash.merge';
|
import merge from 'lodash.merge';
|
||||||
|
|||||||
@@ -5,9 +5,7 @@ export function formatDuration(duration: number): string {
|
|||||||
return `${(duration / 1e3).toFixed(0)} s`;
|
return `${(duration / 1e3).toFixed(0)} s`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Add a timeout to a promise. */
|
||||||
* Add a timeout to a promise.
|
|
||||||
*/
|
|
||||||
export function withTimeout<T>(
|
export function withTimeout<T>(
|
||||||
promise: Promise<T>,
|
promise: Promise<T>,
|
||||||
duration: number,
|
duration: number,
|
||||||
@@ -24,7 +22,8 @@ export function withTimeout<T>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Don't use in production, just for testing and slowing things down.
|
* @deprecated Don't use in production, just for testing and slowing things
|
||||||
|
* down.
|
||||||
*/
|
*/
|
||||||
export function sleep(ms: number): Promise<void> {
|
export function sleep(ms: number): Promise<void> {
|
||||||
return new Promise((res) => setTimeout(res, ms));
|
return new Promise((res) => setTimeout(res, ms));
|
||||||
|
|||||||
@@ -2,10 +2,13 @@ import { ProxifiedModule, parseModule } from 'magicast';
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes any code used at runtime related to an entrypoint's main function.
|
* Removes any code used at runtime related to an entrypoint's main function.
|
||||||
|
*
|
||||||
* 1. Removes or clears out `main` function from returned object
|
* 1. Removes or clears out `main` function from returned object
|
||||||
* 2. Removes any unused functions/variables outside the definition that aren't being called/used
|
* 2. Removes any unused functions/variables outside the definition that aren't
|
||||||
|
* being called/used
|
||||||
* 3. Removes unused imports
|
* 3. Removes unused imports
|
||||||
* 3. Removes value-less, side-effect only imports (like `import "./styles.css"` or `import "polyfill"`)
|
* 4. Removes value-less, side-effect only imports (like `import "./styles.css"` or
|
||||||
|
* `import "polyfill"`)
|
||||||
*/
|
*/
|
||||||
export function removeMainFunctionCode(code: string): {
|
export function removeMainFunctionCode(code: string): {
|
||||||
code: string;
|
code: string;
|
||||||
@@ -216,7 +219,8 @@ function removeSideEffectImports(mod: ProxifiedModule): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Util to get the AST as a simple JSON object, stripping out large objects and file locations to keep it readible
|
* Util to get the AST as a simple JSON object, stripping out large objects and
|
||||||
|
* file locations to keep it readible
|
||||||
*/
|
*/
|
||||||
function getSimpleAstJson(ast: any): any {
|
function getSimpleAstJson(ast: any): any {
|
||||||
if (!ast) {
|
if (!ast) {
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import type { Browser } from '@wxt-dev/browser';
|
|||||||
* Remove optional from key, but keep undefined if present
|
* Remove optional from key, but keep undefined if present
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* type Test = NullablyRequired<{a?: string, b: number}>
|
* type Test = NullablyRequired<{ a?: string; b: number }>;
|
||||||
* // type Test = {a: string | undefined, b: number}
|
* // type Test = {a: string | undefined, b: number}
|
||||||
*/
|
*/
|
||||||
export type NullablyRequired<T> = { [K in keyof Required<T>]: T[K] };
|
export type NullablyRequired<T> = { [K in keyof Required<T>]: T[K] };
|
||||||
|
|
||||||
|
|||||||
@@ -7,19 +7,22 @@ export const virtualEntrypointTypes = [
|
|||||||
export type VirtualEntrypointType = (typeof virtualEntrypointTypes)[0];
|
export type VirtualEntrypointType = (typeof virtualEntrypointTypes)[0];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All the names of entrypoint files in the `src/virtual/` and `dist/virtual/` directories, minus the extension.
|
* All the names of entrypoint files in the `src/virtual/` and `dist/virtual/`
|
||||||
|
* directories, minus the extension.
|
||||||
*/
|
*/
|
||||||
export const virtualEntrypointModuleNames = virtualEntrypointTypes.map(
|
export const virtualEntrypointModuleNames = virtualEntrypointTypes.map(
|
||||||
(name) => `${name}-entrypoint` as const,
|
(name) => `${name}-entrypoint` as const,
|
||||||
);
|
);
|
||||||
/**
|
/**
|
||||||
* Name of entrypoint files in the `src/virtual/` and `dist/virtual/` directories, minus the extension.
|
* Name of entrypoint files in the `src/virtual/` and `dist/virtual/`
|
||||||
|
* directories, minus the extension.
|
||||||
*/
|
*/
|
||||||
export type VirtualEntrypointModuleName =
|
export type VirtualEntrypointModuleName =
|
||||||
(typeof virtualEntrypointModuleNames)[0];
|
(typeof virtualEntrypointModuleNames)[0];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All the names of files in the `src/virtual/` and `dist/virtual/` directories, minus the extension.
|
* All the names of files in the `src/virtual/` and `dist/virtual/` directories,
|
||||||
|
* minus the extension.
|
||||||
*/
|
*/
|
||||||
export const virtualModuleNames = [
|
export const virtualModuleNames = [
|
||||||
...virtualEntrypointModuleNames,
|
...virtualEntrypointModuleNames,
|
||||||
@@ -27,11 +30,10 @@ export const virtualModuleNames = [
|
|||||||
'reload-html' as const,
|
'reload-html' as const,
|
||||||
];
|
];
|
||||||
/**
|
/**
|
||||||
* Name of files in the `src/virtual/` and `dist/virtual/` directories, minus the extension.
|
* Name of files in the `src/virtual/` and `dist/virtual/` directories, minus
|
||||||
|
* the extension.
|
||||||
*/
|
*/
|
||||||
export type VirtualModuleName = (typeof virtualModuleNames)[0];
|
export type VirtualModuleName = (typeof virtualModuleNames)[0];
|
||||||
|
|
||||||
/**
|
/** Import alias used for importing a virtual module */
|
||||||
* Import alias used for importing a virtual module
|
|
||||||
*/
|
|
||||||
export type VirtualModuleId = `virtual:wxt-${VirtualModuleName}`;
|
export type VirtualModuleId = `virtual:wxt-${VirtualModuleName}`;
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
// TODO: Someone smarter than me should just mock this module instead.
|
// TODO: Someone smarter than me should just mock this module instead.
|
||||||
import isWsl_ from 'is-wsl';
|
import isWsl_ from 'is-wsl';
|
||||||
|
|
||||||
/**
|
/** Returns true when running on WSL or WSL2. */
|
||||||
* Returns true when running on WSL or WSL2.
|
|
||||||
*/
|
|
||||||
export function isWsl(): boolean {
|
export function isWsl(): boolean {
|
||||||
return isWsl_;
|
return isWsl_;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,13 +7,15 @@ import { builtinModules } from '../builtin-modules';
|
|||||||
import { relative } from 'path';
|
import { relative } from 'path';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Global variable set once `createWxt` is called once. Since this variable is used everywhere, this
|
* Global variable set once `createWxt` is called once. Since this variable is
|
||||||
* global can be used instead of passing the variable as a function parameter everywhere.
|
* used everywhere, this global can be used instead of passing the variable as a
|
||||||
|
* function parameter everywhere.
|
||||||
*/
|
*/
|
||||||
export let wxt: Wxt;
|
export let wxt: Wxt;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create and register a global instance of the Wxt interface for use throughout the project.
|
* Create and register a global instance of the Wxt interface for use throughout
|
||||||
|
* the project.
|
||||||
*/
|
*/
|
||||||
export async function registerWxt(
|
export async function registerWxt(
|
||||||
command: WxtCommand,
|
command: WxtCommand,
|
||||||
@@ -94,20 +96,18 @@ async function initWxtModule(module: WxtModule<any>): Promise<void> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Unloads WXT modules. */
|
||||||
* Unloads WXT modules.
|
|
||||||
*/
|
|
||||||
export function deinitWxtModules(): void {
|
export function deinitWxtModules(): void {
|
||||||
wxt.hooks.removeAllHooks();
|
wxt.hooks.removeAllHooks();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal ONLY USE FOR TESTING.
|
|
||||||
*
|
|
||||||
* @example
|
* @example
|
||||||
* setWxtForTesting(fakeWxt({ ... }));
|
* setWxtForTesting(fakeWxt({ ... }));
|
||||||
* // Or use the shorthand
|
* // Or use the shorthand
|
||||||
* setFakeWxt({ ... })
|
* setFakeWxt({ ... })
|
||||||
|
*
|
||||||
|
* @internal ONLY USE FOR TESTING.
|
||||||
*/
|
*/
|
||||||
export function setWxtForTesting(testInstance: Wxt) {
|
export function setWxtForTesting(testInstance: Wxt) {
|
||||||
wxt = testInstance;
|
wxt = testInstance;
|
||||||
|
|||||||
@@ -8,12 +8,13 @@ import { printFileList } from './utils/log';
|
|||||||
import { findEntrypoints, internalBuild } from './utils/building';
|
import { findEntrypoints, internalBuild } from './utils/building';
|
||||||
import { registerWxt, wxt } from './wxt';
|
import { registerWxt, wxt } from './wxt';
|
||||||
import JSZip from 'jszip';
|
import JSZip from 'jszip';
|
||||||
import glob from 'fast-glob';
|
import { glob } from 'tinyglobby';
|
||||||
import { normalizePath } from './utils';
|
import { normalizePath } from './utils';
|
||||||
import { minimatchMultiple } from './utils/minimatch-multiple';
|
import { minimatchMultiple } from './utils/minimatch-multiple';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build and zip the extension for distribution.
|
* Build and zip the extension for distribution.
|
||||||
|
*
|
||||||
* @param config Optional config that will override your `<root>/wxt.config.ts`.
|
* @param config Optional config that will override your `<root>/wxt.config.ts`.
|
||||||
* @returns A list of all files included in the ZIP.
|
* @returns A list of all files included in the ZIP.
|
||||||
*/
|
*/
|
||||||
@@ -119,6 +120,7 @@ async function zipDir(
|
|||||||
// Ignore node_modules, otherwise this glob step takes forever
|
// Ignore node_modules, otherwise this glob step takes forever
|
||||||
ignore: ['**/node_modules'],
|
ignore: ['**/node_modules'],
|
||||||
onlyFiles: true,
|
onlyFiles: true,
|
||||||
|
expandDirectories: false,
|
||||||
})
|
})
|
||||||
).filter((relativePath) => {
|
).filter((relativePath) => {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* This module contains:
|
* This module contains:
|
||||||
|
*
|
||||||
* - JS APIs used by the CLI to build extensions or start dev mode.
|
* - JS APIs used by the CLI to build extensions or start dev mode.
|
||||||
* - Helper functions for defining project config.
|
* - Helper functions for defining project config.
|
||||||
* - Types for building and extension or configuring WXT.
|
* - Types for building and extension or configuring WXT.
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user