Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions demo/src/entrypoints/main-world.content.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export default defineContentScript({
matches: ['*://*/*'],
world: 'MAIN',

main() {
console.log(`Hello from ${location.hostname}!`);
},
});
8 changes: 4 additions & 4 deletions docs/guide/auto-imports.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ To setup your test environment for auto-imports, see [Testing](/guide/testing).
Some WXT APIs can be used without importing them:

- [`browser`](/api/wxt/browser/variables/browser) from `wxt/browser`, a small wrapper around `webextension-polyfill`
- [`defineContentScript`](/api/wxt/client/functions/defineContentScript) from `wxt/client`
- [`defineBackground`](/api/wxt/client/functions/defineBackground) from `wxt/client`
- [`createContentScriptUi`](/api/wxt/client/functions/createContentScriptUi) from `wxt/client`
- [`defineContentScript`](/api/wxt/sandbox/functions/defineContentScript) from `wxt/sandbox`
- [`defineBackground`](/api/wxt/sandbox/functions/defineBackground) from `wxt/sandbox`
- [`defineUnlistedScript`](/api/wxt/sandbox/functions/defineUnlistedScript) from `wxt/sandbox`
- [`createContentScriptUi`](/api/wxt/client/functions/createContentScriptUi) from `wxt/client`
- [`fakeBrowser`](/api/wxt/testing/variables/fakeBrowser) from `wxt/testing`

And more. All `wxt/*` APIs can be used without imports.
And more!

## Project Auto-imports

Expand Down
4 changes: 2 additions & 2 deletions e2e/tests/auto-imports.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ describe('Auto Imports', () => {
const createContentScriptIframe: typeof import('wxt/client')['createContentScriptIframe']
const createContentScriptUi: typeof import('wxt/client')['createContentScriptUi']
const createStorage: typeof import('wxt/storage')['createStorage']
const defineBackground: typeof import('wxt/client')['defineBackground']
const defineBackground: typeof import('wxt/sandbox')['defineBackground']
const defineConfig: typeof import('wxt')['defineConfig']
const defineContentScript: typeof import('wxt/client')['defineContentScript']
const defineContentScript: typeof import('wxt/sandbox')['defineContentScript']
const defineDriver: typeof import('wxt/storage')['defineDriver']
const defineUnlistedScript: typeof import('wxt/sandbox')['defineUnlistedScript']
const fakeBrowser: typeof import('wxt/testing')['fakeBrowser']
Expand Down
9 changes: 6 additions & 3 deletions scripts/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ const preset: tsup.Options = {
external: [
'vite',
'virtual:user-unlisted-script',
'virtual:user-content-script',
'virtual:user-content-script-isolated-world',
'virtual:user-content-script-main-world',
'virtual:user-background',
],
};
Expand Down Expand Up @@ -76,8 +77,10 @@ const config: tsup.Options[] = [
...preset,
entry: {
'virtual/background-entrypoint': 'src/virtual/background-entrypoint.ts',
'virtual/content-script-entrypoint':
'src/virtual/content-script-entrypoint.ts',
'virtual/content-script-isolated-world-entrypoint':
'src/virtual/content-script-isolated-world-entrypoint.ts',
'virtual/content-script-main-world-entrypoint':
'src/virtual/content-script-main-world-entrypoint.ts',
'virtual/mock-browser': 'src/virtual/mock-browser.ts',
'virtual/reload-html': 'src/virtual/reload-html.ts',
'virtual/unlisted-script-entrypoint':
Expand Down
1 change: 0 additions & 1 deletion src/client/content-scripts/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
export * from './content-script-context';
export * from './content-script-ui';
export * from './content-script-iframe';
export * from './define-content-script';
3 changes: 2 additions & 1 deletion src/client/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
/**
* Any runtime APIs that use the web extension APIs.
*
* @module wxt/client
*/
export * from './define-background';
export * from './content-scripts';
export {
ContentScriptOverlayAlignment,
Expand Down
26 changes: 18 additions & 8 deletions src/core/builders/vite/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
InlineConfig,
InternalConfig,
UserConfig,
VirtualEntrypointType,
WxtBuilder,
WxtBuilderServer,
} from '~/types';
Expand Down Expand Up @@ -46,7 +47,8 @@ export async function craeteViteBuilder(
wxtPlugins.devHtmlPrerender(wxtConfig),
wxtPlugins.unimport(wxtConfig),
wxtPlugins.virtualEntrypoint('background', wxtConfig),
wxtPlugins.virtualEntrypoint('content-script', wxtConfig),
wxtPlugins.virtualEntrypoint('content-script-isolated-world', wxtConfig),
wxtPlugins.virtualEntrypoint('content-script-main-world', wxtConfig),
wxtPlugins.virtualEntrypoint('unlisted-script', wxtConfig),
wxtPlugins.devServerGlobals(wxtConfig),
wxtPlugins.tsconfigPaths(wxtConfig),
Expand All @@ -65,13 +67,21 @@ export async function craeteViteBuilder(
* 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 isVirtual = [
'background',
'content-script',
'unlisted-script',
].includes(entrypoint.type);
const entry = isVirtual
? `virtual:wxt-${entrypoint.type}?${entrypoint.inputPath}`
let virtualEntrypointType: VirtualEntrypointType | undefined;
switch (entrypoint.type) {
case 'background':
case 'unlisted-script':
virtualEntrypointType = entrypoint.type;
break;
case 'content-script':
virtualEntrypointType =
entrypoint.options.world === 'MAIN'
? 'content-script-main-world'
: 'content-script-isolated-world';
break;
}
const entry = virtualEntrypointType
? `virtual:wxt-${virtualEntrypointType}?${entrypoint.inputPath}`
: entrypoint.inputPath;

const plugins: NonNullable<vite.UserConfig['plugins']> = [
Expand Down
4 changes: 2 additions & 2 deletions src/core/builders/vite/plugins/virtualEntrypoint.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Plugin } from 'vite';
import { Entrypoint, InternalConfig } from '~/types';
import { InternalConfig, VirtualEntrypointType } from '~/types';
import fs from 'fs-extra';
import { resolve } from 'path';
import { normalizePath } from '~/core/utils/paths';
Expand All @@ -8,7 +8,7 @@ import { normalizePath } from '~/core/utils/paths';
* Wraps a user's entrypoint with a vitual version with additional logic.
*/
export function virtualEntrypoint(
type: Entrypoint['type'],
type: VirtualEntrypointType,
config: Omit<InternalConfig, 'builder'>,
): Plugin {
const virtualId = `virtual:wxt-${type}?`;
Expand Down
2 changes: 1 addition & 1 deletion src/core/utils/__tests__/test-entrypoints/background.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { defineBackground } from '~/client';
import { defineBackground } from '~/sandbox';

export default defineBackground({
main() {},
Expand Down
2 changes: 1 addition & 1 deletion src/core/utils/__tests__/test-entrypoints/content.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { defineContentScript } from '~/client';
import { defineContentScript } from '~/sandbox';

export default defineContentScript({
matches: ['<all_urls>'],
Expand Down
2 changes: 1 addition & 1 deletion src/core/utils/__tests__/test-entrypoints/with-named.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { defineBackground } from '~/client';
import { defineBackground } from '~/sandbox';

export const a = {};

Expand Down
3 changes: 1 addition & 2 deletions src/core/utils/strings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ export function removeImportStatements(text: string): string {
export function removeProjectImportStatements(text: string): string {
const noImports = removeImportStatements(text);

return `import { defineContentScript, defineBackground } from 'wxt/client';
import { defineUnlistedScript } from 'wxt/sandbox';
return `import { defineUnlistedScript, defineContentScript, defineBackground } from 'wxt/sandbox';

${noImports}`;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describe, expect, it, vi } from 'vitest';
import { defineBackground } from '~/client/define-background';
import { defineBackground } from '~/sandbox/define-background';
import { BackgroundDefinition } from '~/types';

describe('defineBackground', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describe, expect, it, vi } from 'vitest';
import { defineContentScript } from '~/client/content-scripts/define-content-script';
import { defineContentScript } from '~/sandbox/define-content-script';
import { ContentScriptDefinition } from '~/types';

describe('defineContentScript', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BackgroundDefinition } from '~/types';
import type { BackgroundDefinition } from '~/types';

export function defineBackground(main: () => void): BackgroundDefinition;
export function defineBackground(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ContentScriptDefinition } from '~/types';
import type { ContentScriptDefinition } from '~/types';

export function defineContentScript(
definition: ContentScriptDefinition,
Expand Down
2 changes: 1 addition & 1 deletion src/sandbox/define-unlisted-script.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { UnlistedScriptDefinition } from '~/types';
import type { UnlistedScriptDefinition } from '~/types';

export function defineUnlistedScript(
main: () => void,
Expand Down
4 changes: 4 additions & 0 deletions src/sandbox/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
/**
* Any runtime APIs that don't use the web extension APIs.
*
* @module wxt/sandbox
*/
export * from './define-unlisted-script';
export * from './define-background';
export * from './define-content-script';
40 changes: 30 additions & 10 deletions src/types/external.ts
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,36 @@ export type EntrypointGroup = Entrypoint | Entrypoint[];

export type OnContentScriptStopped = (cb: () => void) => void;

export interface ContentScriptDefinition extends ExcludableEntrypoint {
export type ContentScriptDefinition =
| ContentScriptIsolatedWorldDefinition
| ContentScriptMainWorldDefinition;

export interface ContentScriptIsolatedWorldDefinition
extends ContentScriptBaseDefinition {
/**
* See https://developer.chrome.com/docs/extensions/develop/concepts/content-scripts#isolated_world
* @default "ISOLATED"
*/
world?: 'ISOLATED';
/**
* Main function executed when the content script is loaded.
*/
main(ctx: ContentScriptContext): void | Promise<void>;
}

export interface ContentScriptMainWorldDefinition
extends ContentScriptBaseDefinition {
/**
* See https://developer.chrome.com/docs/extensions/develop/concepts/content-scripts#isolated_world
*/
world: 'MAIN';
/**
* Main function executed when the content script is loaded.
*/
main(): void | Promise<void>;
}

export interface ContentScriptBaseDefinition extends ExcludableEntrypoint {
matches: PerBrowserOption<Manifest.ContentScript['matches']>;
/**
* See https://developer.chrome.com/docs/extensions/mv3/content_scripts/
Expand Down Expand Up @@ -478,11 +507,6 @@ export interface ContentScriptDefinition extends ExcludableEntrypoint {
* @default false
*/
matchOriginAsFallback?: PerBrowserOption<boolean>;
/**
* See https://developer.chrome.com/docs/extensions/mv3/content_scripts/
* @default "ISOLATED"
*/
world?: PerBrowserOption<'ISOLATED' | 'MAIN'>;
/**
* Customize how imported/generated styles are injected with the content script. Regardless of the
* mode selected, CSS will always be built and included in the output directory.
Expand All @@ -497,10 +521,6 @@ export interface ContentScriptDefinition extends ExcludableEntrypoint {
* @default "manifest"
*/
cssInjectionMode?: PerBrowserOption<'manifest' | 'manual' | 'ui'>;
/**
* Main function executed when the content script is loaded.
*/
main(ctx: ContentScriptContext): void | Promise<void>;
}

export interface BackgroundDefinition extends ExcludableEntrypoint {
Expand Down
6 changes: 6 additions & 0 deletions src/types/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,9 @@ export interface ExtensionRunner {
openBrowser(config: InternalConfig): Promise<void>;
closeBrowser(): Promise<void>;
}

export type VirtualEntrypointType =
| 'content-script-main-world'
| 'content-script-isolated-world'
| 'background'
| 'unlisted-script';
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import definition from 'virtual:user-content-script';
import definition from 'virtual:user-content-script-isolated-world';
import { logger } from '~/client/utils/logger';
import { ContentScriptContext } from '~/client/content-scripts/content-script-context';

Expand Down
14 changes: 14 additions & 0 deletions src/virtual/content-script-main-world-entrypoint.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import definition from 'virtual:user-content-script-main-world';
import { logger } from '~/client/utils/logger';

(async () => {
try {
const { main } = definition;
await main();
} catch (err) {
logger.error(
`The content script "${__ENTRYPOINT__}" crashed on startup!`,
err,
);
}
})();
9 changes: 7 additions & 2 deletions src/virtual/virtual-module-globals.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,13 @@ declare module 'virtual:user-background' {
export default definition;
}

declare module 'virtual:user-content-script' {
const definition: import('~/types').ContentScriptDefinition;
declare module 'virtual:user-content-script-isolated-world' {
const definition: import('~/types').ContentScriptIsolatedWorldDefinition;
export default definition;
}

declare module 'virtual:user-content-script-main-world' {
const definition: import('~/types').ContentScriptMainWorldDefinition;
export default definition;
}

Expand Down