feat(experimental): First-class support for excluding webextension-polyfill (#847)
This commit is contained in:
@@ -21,6 +21,7 @@
|
||||
"react-dom": "^18.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/chrome": "^0.0.268",
|
||||
"@types/react": "^18.3.3",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"sass": "^1.77.8",
|
||||
|
||||
@@ -2,6 +2,7 @@ import { defineConfig } from 'wxt';
|
||||
|
||||
export default defineConfig({
|
||||
srcDir: 'src',
|
||||
extensionApi: 'chrome',
|
||||
manifest: {
|
||||
permissions: ['storage'],
|
||||
default_locale: 'en',
|
||||
|
||||
@@ -13,7 +13,7 @@ export default defineBuildConfig([
|
||||
{
|
||||
builder: 'mkdist',
|
||||
input: 'src',
|
||||
pattern: ['**/*', '!**/__tests__', '!**/*.md', '!virtual'],
|
||||
pattern: ['**/*', '!**/__tests__', '!**/*.md', '!virtual', '!@types'],
|
||||
declaration: true,
|
||||
},
|
||||
],
|
||||
|
||||
@@ -192,10 +192,8 @@ describe('Module Helpers', () => {
|
||||
const expectedText = addPluginModule(project);
|
||||
|
||||
await project.build({
|
||||
experimental: {
|
||||
// reduce build output when comparing test failures
|
||||
includeBrowserPolyfill: false,
|
||||
},
|
||||
// reduce build output when comparing test failures
|
||||
extensionApi: 'chrome',
|
||||
});
|
||||
|
||||
await expect(project.serializeOutput()).resolves.toContain(expectedText);
|
||||
@@ -214,10 +212,8 @@ describe('Module Helpers', () => {
|
||||
const expectedText = addPluginModule(project);
|
||||
|
||||
await project.build({
|
||||
experimental: {
|
||||
// reduce build output when comparing test failures
|
||||
includeBrowserPolyfill: false,
|
||||
},
|
||||
// reduce build output when comparing test failures
|
||||
extensionApi: 'chrome',
|
||||
});
|
||||
|
||||
await expect(project.serializeOutput()).resolves.toContain(expectedText);
|
||||
@@ -237,10 +233,8 @@ describe('Module Helpers', () => {
|
||||
const expectedText = addPluginModule(project);
|
||||
|
||||
await project.build({
|
||||
experimental: {
|
||||
// reduce build output when comparing test failures
|
||||
includeBrowserPolyfill: false,
|
||||
},
|
||||
// reduce build output when comparing test failures
|
||||
extensionApi: 'chrome',
|
||||
});
|
||||
|
||||
await expect(project.serializeOutput()).resolves.toContain(expectedText);
|
||||
@@ -255,10 +249,8 @@ describe('Module Helpers', () => {
|
||||
const expectedText = addPluginModule(project);
|
||||
|
||||
await project.build({
|
||||
experimental: {
|
||||
// reduce build output when comparing test failures
|
||||
includeBrowserPolyfill: false,
|
||||
},
|
||||
// reduce build output when comparing test failures
|
||||
extensionApi: 'chrome',
|
||||
});
|
||||
|
||||
await expect(project.serializeOutput()).resolves.toContain(expectedText);
|
||||
|
||||
@@ -262,10 +262,9 @@ describe('Output Directory Structure', () => {
|
||||
project.addFile('entrypoints/popup/main.ts', `logHello('popup')`);
|
||||
|
||||
await project.build({
|
||||
experimental: {
|
||||
// Simplify the build output for comparison
|
||||
includeBrowserPolyfill: false,
|
||||
},
|
||||
// Simplify the build output for comparison
|
||||
extensionApi: 'chrome',
|
||||
|
||||
vite: () => ({
|
||||
build: {
|
||||
// Make output for snapshot readible
|
||||
@@ -278,6 +277,7 @@ describe('Output Directory Structure', () => {
|
||||
.toMatchInlineSnapshot(`
|
||||
".output/chrome-mv3/background.js
|
||||
----------------------------------------
|
||||
var _a, _b;
|
||||
import { l as logHello, i as initPlugins } from "./chunks/_virtual_wxt-plugins-OjKtWpmY.js";
|
||||
function defineBackground(arg) {
|
||||
if (typeof arg === "function") return { main: arg };
|
||||
@@ -289,7 +289,11 @@ describe('Output Directory Structure', () => {
|
||||
logHello("background");
|
||||
}
|
||||
});
|
||||
chrome;
|
||||
// @ts-expect-error
|
||||
((_b = (_a = globalThis.browser) == null ? void 0 : _a.runtime) == null ? void 0 : _b.id) == null ? globalThis.chrome : (
|
||||
// @ts-expect-error
|
||||
globalThis.browser
|
||||
);
|
||||
function print(method, ...args) {
|
||||
return;
|
||||
}
|
||||
@@ -343,10 +347,9 @@ describe('Output Directory Structure', () => {
|
||||
project.addFile('entrypoints/popup/main.ts', `logHello('popup')`);
|
||||
|
||||
await project.build({
|
||||
experimental: {
|
||||
// Simplify the build output for comparison
|
||||
includeBrowserPolyfill: false,
|
||||
},
|
||||
// Simplify the build output for comparison
|
||||
extensionApi: 'chrome',
|
||||
|
||||
vite: () => ({
|
||||
build: {
|
||||
// Make output for snapshot readible
|
||||
@@ -361,6 +364,7 @@ describe('Output Directory Structure', () => {
|
||||
----------------------------------------
|
||||
var _background = function() {
|
||||
"use strict";
|
||||
var _a, _b;
|
||||
function defineBackground(arg) {
|
||||
if (typeof arg === "function") return { main: arg };
|
||||
return arg;
|
||||
@@ -377,7 +381,11 @@ describe('Output Directory Structure', () => {
|
||||
_background;
|
||||
function initPlugins() {
|
||||
}
|
||||
chrome;
|
||||
// @ts-expect-error
|
||||
((_b = (_a = globalThis.browser) == null ? void 0 : _a.runtime) == null ? void 0 : _b.id) == null ? globalThis.chrome : (
|
||||
// @ts-expect-error
|
||||
globalThis.browser
|
||||
);
|
||||
function print(method, ...args) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ describe('TypeScript Project', () => {
|
||||
| "/popup.html"
|
||||
| "/sandbox.html"
|
||||
type HtmlPublicPath = Extract<PublicPath, \`\${string}.html\`>
|
||||
export interface WxtRuntime extends Runtime.Static {
|
||||
export interface WxtRuntime {
|
||||
getURL(path: PublicPath): string;
|
||||
getURL(path: \`\${HtmlPublicPath}\${string}\`): string;
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ describe('User Config', () => {
|
||||
`);
|
||||
});
|
||||
|
||||
it('should exclude the polyfill when the experimental setting is set to false', async () => {
|
||||
it('should exclude the polyfill when extensionApi="chrome"', async () => {
|
||||
const buildBackground = async (config?: InlineConfig) => {
|
||||
const background = `export default defineBackground(() => console.log(browser.runtime.id));`;
|
||||
const projectWithPolyfill = new TestProject();
|
||||
@@ -101,9 +101,7 @@ describe('User Config', () => {
|
||||
|
||||
const withPolyfill = await buildBackground();
|
||||
const withoutPolyfill = await buildBackground({
|
||||
experimental: {
|
||||
includeBrowserPolyfill: false,
|
||||
},
|
||||
extensionApi: 'chrome',
|
||||
});
|
||||
expect(withoutPolyfill).not.toBe(withPolyfill);
|
||||
});
|
||||
|
||||
@@ -46,8 +46,12 @@
|
||||
"default": "./dist/sandbox/index.mjs"
|
||||
},
|
||||
"./browser": {
|
||||
"types": "./dist/browser.d.ts",
|
||||
"default": "./dist/browser.mjs"
|
||||
"types": "./dist/browser/index.d.ts",
|
||||
"default": "./dist/browser/index.mjs"
|
||||
},
|
||||
"./browser/chrome": {
|
||||
"types": "./dist/browser/chrome.d.ts",
|
||||
"import": "./dist/browser/chrome.mjs"
|
||||
},
|
||||
"./testing": {
|
||||
"types": "./dist/testing/index.d.ts",
|
||||
@@ -121,6 +125,7 @@
|
||||
"devDependencies": {
|
||||
"@aklinker1/check": "^1.3.1",
|
||||
"@faker-js/faker": "^8.4.1",
|
||||
"@types/chrome": "^0.0.268",
|
||||
"@types/fs-extra": "^11.0.4",
|
||||
"@types/lodash.merge": "^4.6.9",
|
||||
"@types/natural-compare": "^1.4.3",
|
||||
@@ -138,5 +143,13 @@
|
||||
"unbuild": "^2.0.0",
|
||||
"vitest": "^2.0.3",
|
||||
"vitest-plugin-random-seed": "^1.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/chrome": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/chrome": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,8 +49,3 @@ declare module 'web-ext-run/util/logger' {
|
||||
}
|
||||
export const consoleStream: IConsoleStream;
|
||||
}
|
||||
|
||||
declare module 'wxt/browser' {
|
||||
// Overridden when types are generated per project
|
||||
export type PublicPath = string;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { fakeBrowser } from '@webext-core/fake-browser';
|
||||
import { describe, it, expect, beforeEach, vi, expectTypeOf } from 'vitest';
|
||||
import { browser } from '../browser';
|
||||
import { browser } from 'wxt/browser';
|
||||
import { WxtStorageItem, storage } from '../storage';
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/// <reference types="chrome" />
|
||||
/**
|
||||
* EXPERIMENTAL
|
||||
*
|
||||
* Includes the `chrome` API and types when using `extensionApi: 'chrome'`.
|
||||
*
|
||||
* @module wxt/browser/chrome
|
||||
*/
|
||||
|
||||
export interface WxtRuntime {
|
||||
// Overriden per-project
|
||||
}
|
||||
export interface WxtI18n {
|
||||
// Overriden per-project
|
||||
}
|
||||
|
||||
export type Chrome = typeof chrome;
|
||||
export type WxtBrowser = Omit<Chrome, 'runtime' | 'i18n'> & {
|
||||
runtime: WxtRuntime & Omit<Chrome['runtime'], 'getURL'>;
|
||||
i18n: WxtI18n & Omit<Chrome['i18n'], 'getMessage'>;
|
||||
};
|
||||
|
||||
export const browser: WxtBrowser =
|
||||
// @ts-expect-error
|
||||
globalThis.browser?.runtime?.id == null
|
||||
? globalThis.chrome
|
||||
: // @ts-expect-error
|
||||
globalThis.browser;
|
||||
@@ -1,6 +1,9 @@
|
||||
/**
|
||||
* Includes the `browser` API and types when using `extensionApi: 'webextension-polyfill'` (the default).
|
||||
*
|
||||
* @module wxt/browser
|
||||
*/
|
||||
|
||||
import originalBrowser, { Browser, Runtime, I18n } from 'webextension-polyfill';
|
||||
|
||||
export interface AugmentedBrowser extends Browser {
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ContentScriptDefinition } from '../../types';
|
||||
import { browser } from '../../browser';
|
||||
import { browser } from 'wxt/browser';
|
||||
import { logger } from '../../sandbox/utils/logger';
|
||||
import { WxtLocationChangeEvent, getUniqueEventName } from './custom-events';
|
||||
import { createLocationWatcher } from './location-watcher';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { browser } from '../../browser';
|
||||
import { browser } from 'wxt/browser';
|
||||
|
||||
export class WxtLocationChangeEvent extends Event {
|
||||
static EVENT_NAME = getUniqueEventName('wxt:locationchange');
|
||||
@@ -22,5 +22,5 @@ export function getUniqueEventName(eventName: string): string {
|
||||
? 'build'
|
||||
: import.meta.env.ENTRYPOINT;
|
||||
|
||||
return `${browser.runtime.id}:${entrypointName}:${eventName}`;
|
||||
return `${browser?.runtime?.id}:${entrypointName}:${eventName}`;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { browser } from '../../../browser';
|
||||
import { browser } from 'wxt/browser';
|
||||
import { ContentScriptContext } from '..';
|
||||
import {
|
||||
ContentScriptAnchoredOptions,
|
||||
|
||||
@@ -66,7 +66,7 @@ export async function createViteBuilder(
|
||||
wxtPlugins.tsconfigPaths(wxtConfig),
|
||||
wxtPlugins.noopBackground(),
|
||||
wxtPlugins.globals(wxtConfig),
|
||||
wxtPlugins.excludeBrowserPolyfill(wxtConfig),
|
||||
wxtPlugins.resolveExtensionApi(wxtConfig),
|
||||
wxtPlugins.defineImportMeta(),
|
||||
wxtPlugins.wxtPluginLoader(wxtConfig),
|
||||
wxtPlugins.resolveAppConfig(wxtConfig),
|
||||
@@ -218,7 +218,7 @@ export async function createViteBuilder(
|
||||
const baseConfig = await getBaseConfig();
|
||||
const envConfig: vite.InlineConfig = {
|
||||
plugins: [
|
||||
wxtPlugins.webextensionPolyfillMock(wxtConfig),
|
||||
wxtPlugins.extensionApiMock(wxtConfig),
|
||||
wxtPlugins.removeEntrypointMainFunction(wxtConfig, path),
|
||||
],
|
||||
};
|
||||
@@ -238,7 +238,7 @@ export async function createViteBuilder(
|
||||
baseConfig.optimizeDeps.include = [];
|
||||
const envConfig: vite.InlineConfig = {
|
||||
plugins: [
|
||||
wxtPlugins.webextensionPolyfillMock(wxtConfig),
|
||||
wxtPlugins.extensionApiMock(wxtConfig),
|
||||
wxtPlugins.removeEntrypointMainFunction(wxtConfig, path),
|
||||
],
|
||||
};
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
import { ResolvedConfig } from '../../../../types';
|
||||
import type * as vite from 'vite';
|
||||
|
||||
/**
|
||||
* Apply the experimental config for disabling the polyfill. It works by aliasing the
|
||||
* `webextension-polyfill` module to a virtual module and exporting the `chrome` global from the
|
||||
* virtual module.
|
||||
*/
|
||||
export function excludeBrowserPolyfill(config: ResolvedConfig): vite.Plugin {
|
||||
const virtualId = 'virtual:wxt-webextension-polyfill-disabled';
|
||||
|
||||
return {
|
||||
name: 'wxt:exclude-browser-polyfill',
|
||||
config() {
|
||||
// Only apply the config if we're disabling the polyfill
|
||||
if (config.experimental.includeBrowserPolyfill) return;
|
||||
|
||||
return {
|
||||
resolve: {
|
||||
alias: {
|
||||
'webextension-polyfill': virtualId,
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
load(id) {
|
||||
if (id === virtualId) {
|
||||
// Use chrome instead of the polyfill when disabled.
|
||||
return 'export default chrome';
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import path from 'node:path';
|
||||
import type * as vite from 'vite';
|
||||
import { ResolvedConfig } from '../../../../types';
|
||||
|
||||
/**
|
||||
* Mock `webextension-polyfill`, `wxt/browser`, and `wxt/browser/*` by inlining
|
||||
* all dependencies that import them and adding a custom alias so that Vite
|
||||
* resolves to a mocked version of the module.
|
||||
*
|
||||
* TODO: Detect non-wxt dependencies (like `@webext-core/*`) that import `webextension-polyfill` via
|
||||
* `npm list` and inline them automatically.
|
||||
*/
|
||||
export function extensionApiMock(config: ResolvedConfig): vite.PluginOption {
|
||||
return {
|
||||
name: 'wxt:extension-api-mock',
|
||||
config() {
|
||||
const replacement = path.resolve(
|
||||
config.wxtModuleDir,
|
||||
'dist/virtual/mock-browser',
|
||||
);
|
||||
return {
|
||||
resolve: {
|
||||
alias: [
|
||||
{ find: 'webextension-polyfill', replacement },
|
||||
// wxt/browser, wxt/browser/...
|
||||
{ find: /^wxt\/browser.*/, replacement },
|
||||
],
|
||||
},
|
||||
ssr: {
|
||||
// Inline all WXT modules so vite processes them so the aliases can
|
||||
// be resolved
|
||||
noExternal: ['wxt'],
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -8,8 +8,8 @@ export * from './noopBackground';
|
||||
export * from './cssEntrypoints';
|
||||
export * from './bundleAnalysis';
|
||||
export * from './globals';
|
||||
export * from './webextensionPolyfillMock';
|
||||
export * from './excludeBrowserPolyfill';
|
||||
export * from './extensionApiMock';
|
||||
export * from './resolveExtensionApi';
|
||||
export * from './entrypointGroupGlobals';
|
||||
export * from './defineImportMeta';
|
||||
export * from './removeEntrypointMainFunction';
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import { ResolvedConfig } from '../../../../types';
|
||||
import type * as vite from 'vite';
|
||||
|
||||
/**
|
||||
* Apply the experimental config for which extension API is used. This only
|
||||
* effects the extension API included at RUNTIME - during development, types
|
||||
* depend on the import.
|
||||
*
|
||||
* NOTE: this only works if we import `wxt/browser` instead of using the relative path.
|
||||
*/
|
||||
export function resolveExtensionApi(config: ResolvedConfig): vite.Plugin {
|
||||
return {
|
||||
name: 'wxt:resolve-extension-api',
|
||||
config() {
|
||||
// Only apply the config if we're disabling the polyfill
|
||||
if (config.extensionApi === 'webextension-polyfill') return;
|
||||
|
||||
return {
|
||||
resolve: {
|
||||
alias: [
|
||||
{ find: /^wxt\/browser$/, replacement: 'wxt/browser/chrome' },
|
||||
],
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
import path from 'node:path';
|
||||
import type * as vite from 'vite';
|
||||
import { ResolvedConfig } from '../../../../types';
|
||||
|
||||
/**
|
||||
* Mock `webextension-polyfill` by inlining all dependencies that import it and adding a custom
|
||||
* alias so that Vite resolves to a mocked version of the module.
|
||||
*
|
||||
* There are two ways to mark a module as inline:
|
||||
* 1. Use partial file paths ("wxt/dist/browser.js") in the `test.server.deps.inline` option.
|
||||
* 2. Use module names ("wxt" or "@webext-core/messaging") in the `ssr.noExternalize` option.
|
||||
*
|
||||
* This plugin uses the second approach since it's a little more intuative to understand.
|
||||
*
|
||||
* TODO: Detect non-wxt dependencies (like `@webext-core/*`) that import `webextension-polyfill` via
|
||||
* `npm list` and inline them automatically.
|
||||
*/
|
||||
export function webextensionPolyfillMock(
|
||||
config: ResolvedConfig,
|
||||
): vite.PluginOption {
|
||||
return {
|
||||
name: 'wxt:testing-inline-deps',
|
||||
config() {
|
||||
return {
|
||||
resolve: {
|
||||
alias: {
|
||||
// Alias to use a mocked version of the polyfill
|
||||
'webextension-polyfill': path.resolve(
|
||||
config.wxtModuleDir,
|
||||
'dist/virtual/mock-browser',
|
||||
),
|
||||
},
|
||||
},
|
||||
ssr: {
|
||||
// Inline all WXT modules
|
||||
noExternal: ['wxt'],
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -42,6 +42,11 @@ export async function generateTypesDir(
|
||||
// import.meta.env.*
|
||||
entries.push(await getGlobalsDeclarationEntry());
|
||||
|
||||
// @types/chrome
|
||||
if (wxt.config.extensionApi === 'chrome') {
|
||||
entries.push({ module: '@types/chrome' });
|
||||
}
|
||||
|
||||
// tsconfig.json
|
||||
entries.push(await getTsConfigEntry());
|
||||
|
||||
@@ -85,13 +90,13 @@ async function getPathsDeclarationEntry(
|
||||
.join('\n');
|
||||
|
||||
const template = `// Generated by wxt
|
||||
import "wxt/browser";
|
||||
import "${wxt.config.browserModule}";
|
||||
|
||||
declare module "wxt/browser" {
|
||||
declare module "${wxt.config.browserModule}" {
|
||||
export type PublicPath =
|
||||
{{ union }}
|
||||
type HtmlPublicPath = Extract<PublicPath, \`\${string}.html\`>
|
||||
export interface WxtRuntime extends Runtime.Static {
|
||||
export interface WxtRuntime {
|
||||
getURL(path: PublicPath): string;
|
||||
getURL(path: \`\${HtmlPublicPath}\${string}\`): string;
|
||||
}
|
||||
@@ -108,9 +113,9 @@ declare module "wxt/browser" {
|
||||
async function getI18nDeclarationEntry(): Promise<WxtDirFileEntry> {
|
||||
const defaultLocale = wxt.config.manifest.default_locale;
|
||||
const template = `// Generated by wxt
|
||||
import "wxt/browser";
|
||||
import "${wxt.config.browserModule}";
|
||||
|
||||
declare module "wxt/browser" {
|
||||
declare module "${wxt.config.browserModule}" {
|
||||
/**
|
||||
* See https://developer.chrome.com/docs/extensions/reference/i18n/#method-getMessage
|
||||
*/
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Manifest } from '../../../browser';
|
||||
import type { Manifest } from 'wxt/browser';
|
||||
import { BuildOutput, Entrypoint, EntrypointGroup } from '../../../types';
|
||||
import { generateTypesDir } from './generate-wxt-dir';
|
||||
import { buildEntrypoints } from './build-entrypoints';
|
||||
|
||||
@@ -146,6 +146,8 @@ export async function resolveConfig(
|
||||
{},
|
||||
);
|
||||
|
||||
const extensionApi = mergedConfig.extensionApi ?? 'webextension-polyfill';
|
||||
|
||||
return {
|
||||
browser,
|
||||
command,
|
||||
@@ -155,7 +157,13 @@ export async function resolveConfig(
|
||||
filterEntrypoints,
|
||||
env,
|
||||
fsCache: createFsCache(wxtDir),
|
||||
imports: await getUnimportOptions(wxtDir, srcDir, logger, mergedConfig),
|
||||
imports: await getUnimportOptions(
|
||||
wxtDir,
|
||||
srcDir,
|
||||
logger,
|
||||
extensionApi,
|
||||
mergedConfig,
|
||||
),
|
||||
logger,
|
||||
manifest: await resolveManifestConfig(env, mergedConfig.manifest),
|
||||
manifestVersion,
|
||||
@@ -174,8 +182,10 @@ export async function resolveConfig(
|
||||
analysis: resolveAnalysisConfig(root, mergedConfig),
|
||||
userConfigMetadata: userConfigMetadata ?? {},
|
||||
alias,
|
||||
extensionApi,
|
||||
browserModule:
|
||||
extensionApi === 'chrome' ? 'wxt/browser/chrome' : 'wxt/browser',
|
||||
experimental: defu(mergedConfig.experimental, {
|
||||
includeBrowserPolyfill: true,
|
||||
entrypointImporter: 'jiti' as const,
|
||||
}),
|
||||
dev: {
|
||||
@@ -306,6 +316,7 @@ async function getUnimportOptions(
|
||||
wxtDir: string,
|
||||
srcDir: string,
|
||||
logger: Logger,
|
||||
extensionApi: ResolvedConfig['extensionApi'],
|
||||
config: InlineConfig,
|
||||
): Promise<WxtResolvedUnimportOptions | false> {
|
||||
if (config.imports === false) return false;
|
||||
@@ -324,7 +335,10 @@ async function getUnimportOptions(
|
||||
// ignored.
|
||||
ignore: ['options'],
|
||||
},
|
||||
{ package: 'wxt/browser' },
|
||||
{
|
||||
package:
|
||||
extensionApi === 'chrome' ? 'wxt/browser/chrome' : 'wxt/browser',
|
||||
},
|
||||
{ package: 'wxt/sandbox' },
|
||||
{ package: 'wxt/storage' },
|
||||
],
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Manifest, Scripting } from '../../browser';
|
||||
import type { Manifest, Scripting } from 'wxt/browser';
|
||||
import { ContentScriptEntrypoint, ResolvedConfig } from '../../types';
|
||||
import { getEntrypointBundlePath } from './entrypoints';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Manifest } from '../../browser';
|
||||
import type { Manifest } from 'wxt/browser';
|
||||
import {
|
||||
Entrypoint,
|
||||
BackgroundEntrypoint,
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import { resolve } from 'path';
|
||||
import { faker } from '@faker-js/faker';
|
||||
import merge from 'lodash.merge';
|
||||
import { Commands, type Manifest } from '../../../browser';
|
||||
import { Commands, type Manifest } from 'wxt/browser';
|
||||
import {
|
||||
FsCache,
|
||||
ResolvedConfig,
|
||||
@@ -296,8 +296,9 @@ export const fakeResolvedConfig = fakeObjectCreator<ResolvedConfig>(() => {
|
||||
transformManifest: () => {},
|
||||
userConfigMetadata: {},
|
||||
alias: {},
|
||||
extensionApi: 'webextension-polyfill',
|
||||
browserModule: 'wxt/browser',
|
||||
experimental: {
|
||||
includeBrowserPolyfill: true,
|
||||
entrypointImporter: 'jiti',
|
||||
},
|
||||
dev: {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*
|
||||
* @module wxt/storage
|
||||
*/
|
||||
import { Storage, browser } from './browser';
|
||||
import { Storage, browser } from 'wxt/browser';
|
||||
import { dequal } from 'dequal/lite';
|
||||
import { logger } from './sandbox/utils/logger';
|
||||
import { toArray } from './core/utils/arrays';
|
||||
|
||||
@@ -3,7 +3,7 @@ import {
|
||||
download,
|
||||
tsconfigPaths,
|
||||
globals,
|
||||
webextensionPolyfillMock,
|
||||
extensionApiMock,
|
||||
resolveAppConfig,
|
||||
} from '../core/builders/vite/plugins';
|
||||
import { resolveConfig } from '../core/utils/building';
|
||||
@@ -26,20 +26,23 @@ import { createUnimport } from 'unimport';
|
||||
*
|
||||
* @param inlineConfig Customize WXT's config for testing. Any config specified here overrides the config from your `wxt.config.ts` file.
|
||||
*/
|
||||
export function WxtVitest(inlineConfig?: InlineConfig): vite.PluginOption {
|
||||
return resolveConfig(inlineConfig ?? {}, 'serve').then(async (config) => {
|
||||
const plugins = [
|
||||
webextensionPolyfillMock(config),
|
||||
globals(config),
|
||||
download(config),
|
||||
tsconfigPaths(config),
|
||||
resolveAppConfig(config),
|
||||
];
|
||||
if (config.imports !== false) {
|
||||
const unimport = createUnimport(config.imports);
|
||||
await unimport.init();
|
||||
plugins.push(unimportPlugin(unimport));
|
||||
}
|
||||
return plugins;
|
||||
});
|
||||
export async function WxtVitest(
|
||||
inlineConfig?: InlineConfig,
|
||||
): Promise<vite.PluginOption[]> {
|
||||
const config = await resolveConfig(inlineConfig ?? {}, 'serve');
|
||||
|
||||
const plugins: vite.PluginOption[] = [
|
||||
globals(config),
|
||||
download(config),
|
||||
tsconfigPaths(config),
|
||||
resolveAppConfig(config),
|
||||
extensionApiMock(config),
|
||||
];
|
||||
if (config.imports !== false) {
|
||||
const unimport = createUnimport(config.imports);
|
||||
await unimport.init();
|
||||
plugins.push(unimportPlugin(unimport));
|
||||
}
|
||||
|
||||
return plugins;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import type * as vite from 'vite';
|
||||
import type { Manifest, Scripting } from '../browser';
|
||||
import type { Manifest, Scripting } from 'wxt/browser';
|
||||
import { UnimportOptions, Import } from 'unimport';
|
||||
import { LogLevel } from 'consola';
|
||||
import { ContentScriptContext } from '../client/content-scripts/content-script-context';
|
||||
import type { ContentScriptContext } from './client/content-scripts/content-script-context';
|
||||
import type { PluginVisualizerOptions } from '@aklinker1/rollup-plugin-visualizer';
|
||||
import type { FSWatcher } from 'chokidar';
|
||||
import { ResolvedConfig as C12ResolvedConfig } from 'c12';
|
||||
@@ -292,36 +292,25 @@ export interface InlineConfig {
|
||||
* }
|
||||
*/
|
||||
alias?: Record<string, string>;
|
||||
/**
|
||||
* Which extension API to use.
|
||||
*
|
||||
* - `"webextension-polyfill"`: Use `browser` and types from [`webextension-polyfill`](https://www.npmjs.com/package/webextension-polyfill).
|
||||
* - `"chrome"` (unstable): Use the regular `chrome` (or `browser` for Firefox/Safari) globals provided by the browser. Types provided by [`@types/chrome`](https://www.npmjs.com/package/@types/chrome), make sure to install the package or types won't work.
|
||||
*
|
||||
* @default "webextension-polyfill"
|
||||
*/
|
||||
extensionApi?: 'webextension-polyfill' | 'chrome';
|
||||
/**
|
||||
* Experimental settings - use with caution.
|
||||
*/
|
||||
experimental?: {
|
||||
/**
|
||||
* Whether to use [`webextension-polyfill`](https://www.npmjs.com/package/webextension-polyfill)
|
||||
* when importing `browser` from `wxt/browser`.
|
||||
*
|
||||
* When set to `false`, WXT will export the chrome global instead of the polyfill from
|
||||
* `wxt/browser`.
|
||||
*
|
||||
* You should use `browser` to access the web extension APIs.
|
||||
*
|
||||
* @experimental This option will remain experimental until Manifest V2 is dead.
|
||||
*
|
||||
* @default true
|
||||
* @example
|
||||
* export default defineConfig({
|
||||
* experimental: {
|
||||
* includeBrowserPolyfill: false
|
||||
* }
|
||||
* })
|
||||
*/
|
||||
includeBrowserPolyfill?: boolean;
|
||||
/**
|
||||
* Method used to import entrypoint files during the build process to extract their options.
|
||||
*
|
||||
* - "jiti": Simplest and fastest, but doesn't allow using any imported variables outside the entrypoint's main function
|
||||
* - "vite-runtime" (unstable): Uses Vite 5.3's new runtime API to import the entrypoints. Automatically includes vite config based on your wxt.config.ts file
|
||||
* - "vite-node" (unstable): Uses `vite-node` to import the entrypoints. Automatically includes vite config based on your wxt.config.ts file
|
||||
* - `"jiti"`: Simplest and fastest, but doesn't allow using any imported variables outside the entrypoint's main function
|
||||
* - `"vite-runtime"` (unstable): Uses Vite 5.3's new runtime API to import the entrypoints. Automatically includes vite config based on your wxt.config.ts file
|
||||
* - `"vite-node"` (unstable): Uses `vite-node` to import the entrypoints. Automatically includes vite config based on your wxt.config.ts file
|
||||
*
|
||||
* @see {@link https://wxt.dev/guide/go-further/entrypoint-side-effects.html|Entrypoint Side-effect Docs}
|
||||
*
|
||||
@@ -1202,8 +1191,9 @@ export interface ResolvedConfig {
|
||||
* Import aliases to absolute paths.
|
||||
*/
|
||||
alias: Record<string, string>;
|
||||
extensionApi: 'webextension-polyfill' | 'chrome';
|
||||
browserModule: 'wxt/browser' | 'wxt/browser/chrome';
|
||||
experimental: {
|
||||
includeBrowserPolyfill: boolean;
|
||||
entrypointImporter: 'jiti' | 'vite-runtime' | 'vite-node';
|
||||
};
|
||||
dev: {
|
||||
@@ -1,3 +1,4 @@
|
||||
import { fakeBrowser as mockBrowser } from 'wxt/testing';
|
||||
import { fakeBrowser } from 'wxt/testing';
|
||||
|
||||
export default mockBrowser;
|
||||
export const browser = fakeBrowser;
|
||||
export default fakeBrowser;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"extends": "../../../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"types": ["vite/client", "../types/globals.d.ts"]
|
||||
"types": ["vite/client", "../@types/globals.d.ts"]
|
||||
},
|
||||
"include": ["./*"]
|
||||
}
|
||||
|
||||
+4
-18
@@ -1,26 +1,22 @@
|
||||
// Types required to make the virtual modules happy.
|
||||
|
||||
declare module 'virtual:user-background-entrypoint' {
|
||||
const definition: { main: () => void };
|
||||
const definition: import('wxt').BackgroundDefinition;
|
||||
export default definition;
|
||||
}
|
||||
|
||||
declare module 'virtual:user-content-script-isolated-world-entrypoint' {
|
||||
const definition: {
|
||||
main: (
|
||||
ctx: import('wxt/client').ContentScriptContext,
|
||||
) => void | Promise<void>;
|
||||
};
|
||||
const definition: import('wxt').IsolatedWorldContentScriptDefinition;
|
||||
export default definition;
|
||||
}
|
||||
|
||||
declare module 'virtual:user-content-script-main-world-entrypoint' {
|
||||
const definition: { main: () => void | Promise<void> };
|
||||
const definition: import('wxt').MainWorldContentScriptDefinition;
|
||||
export default definition;
|
||||
}
|
||||
|
||||
declare module 'virtual:user-unlisted-script-entrypoint' {
|
||||
const definition: { main: () => void | Promise<void> };
|
||||
const definition: import('wxt').UnlistedScriptDefinition;
|
||||
export default definition;
|
||||
}
|
||||
|
||||
@@ -28,16 +24,6 @@ declare module 'wxt/browser' {
|
||||
export const browser: import('webextension-polyfill').Browser;
|
||||
}
|
||||
|
||||
declare module 'wxt/client' {
|
||||
export class ContentScriptContext {
|
||||
constructor(name: string, options: any);
|
||||
}
|
||||
}
|
||||
|
||||
declare module 'wxt/testing' {
|
||||
export const fakeBrowser: import('webextension-polyfill').Browser;
|
||||
}
|
||||
|
||||
declare module 'virtual:wxt-plugins' {
|
||||
export function initPlugins(): void;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
"src/client/index.ts",
|
||||
"src/testing/index.ts",
|
||||
"src/sandbox/index.ts",
|
||||
"src/browser.ts",
|
||||
"src/browser/index.ts",
|
||||
"src/browser/chrome.ts",
|
||||
"src/index.ts",
|
||||
"src/storage.ts",
|
||||
"src/modules.ts"
|
||||
|
||||
@@ -18,7 +18,10 @@ export default defineConfig({
|
||||
ignored: '**/dist/**',
|
||||
},
|
||||
},
|
||||
plugins: [RandomSeed()],
|
||||
plugins: [
|
||||
// @ts-expect-error: Vite version mismatch
|
||||
RandomSeed(),
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
'wxt/testing': path.resolve('src/testing'),
|
||||
|
||||
Generated
+28
-1
@@ -316,6 +316,9 @@ importers:
|
||||
'@faker-js/faker':
|
||||
specifier: ^8.4.1
|
||||
version: 8.4.1
|
||||
'@types/chrome':
|
||||
specifier: ^0.0.268
|
||||
version: 0.0.268
|
||||
'@types/fs-extra':
|
||||
specifier: ^11.0.4
|
||||
version: 11.0.4
|
||||
@@ -377,6 +380,9 @@ importers:
|
||||
specifier: ^18.3.1
|
||||
version: 18.3.1(react@18.3.1)
|
||||
devDependencies:
|
||||
'@types/chrome':
|
||||
specifier: ^0.0.268
|
||||
version: 0.0.268
|
||||
'@types/react':
|
||||
specifier: ^18.3.3
|
||||
version: 18.3.3
|
||||
@@ -1915,9 +1921,26 @@ packages:
|
||||
'@babel/types': 7.24.7
|
||||
dev: false
|
||||
|
||||
/@types/chrome@0.0.268:
|
||||
resolution: {integrity: sha512-7N1QH9buudSJ7sI8Pe4mBHJr5oZ48s0hcanI9w3wgijAlv1OZNUZve9JR4x42dn5lJ5Sm87V1JNfnoh10EnQlA==}
|
||||
dependencies:
|
||||
'@types/filesystem': 0.0.36
|
||||
'@types/har-format': 1.2.15
|
||||
dev: true
|
||||
|
||||
/@types/estree@1.0.5:
|
||||
resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
|
||||
|
||||
/@types/filesystem@0.0.36:
|
||||
resolution: {integrity: sha512-vPDXOZuannb9FZdxgHnqSwAG/jvdGM8Wq+6N4D/d80z+D4HWH+bItqsZaVRQykAn6WEVeEkLm2oQigyHtgb0RA==}
|
||||
dependencies:
|
||||
'@types/filewriter': 0.0.33
|
||||
dev: true
|
||||
|
||||
/@types/filewriter@0.0.33:
|
||||
resolution: {integrity: sha512-xFU8ZXTw4gd358lb2jw25nxY9QAgqn2+bKKjKOYfNCzN4DKCFetK7sPtrlpg66Ywe3vWY9FNxprZawAh9wfJ3g==}
|
||||
dev: true
|
||||
|
||||
/@types/fs-extra@11.0.4:
|
||||
resolution: {integrity: sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==}
|
||||
dependencies:
|
||||
@@ -1925,6 +1948,10 @@ packages:
|
||||
'@types/node': 20.10.3
|
||||
dev: true
|
||||
|
||||
/@types/har-format@1.2.15:
|
||||
resolution: {integrity: sha512-RpQH4rXLuvTXKR0zqHq3go0RVXYv/YVqv4TnPH95VbwUxZdQlK1EtcMvQvMpDngHbt13Csh9Z4qT9AbkiQH5BA==}
|
||||
dev: true
|
||||
|
||||
/@types/hast@3.0.4:
|
||||
resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==}
|
||||
dependencies:
|
||||
@@ -7239,7 +7266,7 @@ packages:
|
||||
peerDependencies:
|
||||
vite: ^4.0.0 || ^5.0.0
|
||||
dependencies:
|
||||
vite: 5.3.4(@types/node@20.14.11)
|
||||
vite: 5.3.4(sass@1.77.8)
|
||||
dev: true
|
||||
|
||||
/vitest@2.0.3:
|
||||
|
||||
Reference in New Issue
Block a user