diff --git a/demo/src/entrypoints/unlisted.ts b/demo/src/entrypoints/unlisted.ts new file mode 100644 index 00000000..d5b9214e --- /dev/null +++ b/demo/src/entrypoints/unlisted.ts @@ -0,0 +1,3 @@ +export default defineUnlistedScript(() => { + console.log('injected'); +}); diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index 9dd4265e..bb2cd55b 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -124,6 +124,7 @@ export default defineConfig({ { text: 'wxt', link: '/api/wxt.md' }, { text: 'wxt/browser', link: '/api/wxt-browser.md' }, { text: 'wxt/client', link: '/api/wxt-client.md' }, + { text: 'wxt/sandbox', link: '/api/wxt-sandbox.md' }, ], }, ], diff --git a/docs/api/wxt-sandbox.md b/docs/api/wxt-sandbox.md new file mode 100644 index 00000000..91b0438e --- /dev/null +++ b/docs/api/wxt-sandbox.md @@ -0,0 +1,12 @@ +# `wxt/sandbox` Reference + +The `wxt/sandbox` module contains exports that do not use the `browser` global (ie: a "sandboxed" environment). + +:::warning 🚧 Under construction +This documentation does not exist yet. All APIs are documented with JSDoc, so for now, you can view the documentation in your editor. + +```ts +import { defineUnlistedScript } from 'wxt/sandbox'; +``` + +::: diff --git a/docs/entrypoints/unlisted-scripts.md b/docs/entrypoints/unlisted-scripts.md index 3e054ca0..75aad219 100644 --- a/docs/entrypoints/unlisted-scripts.md +++ b/docs/entrypoints/unlisted-scripts.md @@ -2,6 +2,8 @@ TypeScript files that are built, but are not included in the manifest. +You are responsible for loading/running these scripts where needed. + ## Filenames { + // Executed when script is loaded +}); +``` + +or ```ts -// Code goes here +export default defineUnlistedScript({ + // Set include/exclude if the script should be removed from some builds + include: undefined | string[], + exclude: undefined | string[], + + // Executed when script is loaded + main() { + // ... + }, +}); ``` diff --git a/docs/guide/auto-imports.md b/docs/guide/auto-imports.md index b338a974..a8da83fa 100644 --- a/docs/guide/auto-imports.md +++ b/docs/guide/auto-imports.md @@ -14,6 +14,7 @@ Some WXT APIs can be used without importing them: - [`defineContentScript`](/api/wxt-client#defiencontentscript) from `wxt/client` - [`defineBackground`](/api/wxt-client#definebackground) from `wxt/client` - [`createContentScriptUi`](/api/wxt-client#createcontentscriptui) from `wxt/client` +- [`defineUnlistedScript`](/api/wxt-sandbox#defineunlistedscript) from `wxt/sandbox` And more. All [`wxt/client`](/api/wxt-client) APIs can be used without imports. diff --git a/e2e/tests/auto-imports.test.ts b/e2e/tests/auto-imports.test.ts index c9a6e648..953f9709 100644 --- a/e2e/tests/auto-imports.test.ts +++ b/e2e/tests/auto-imports.test.ts @@ -22,6 +22,7 @@ describe('Auto Imports', () => { const defineBackground: typeof import('wxt/client')['defineBackground'] const defineConfig: typeof import('wxt')['defineConfig'] const defineContentScript: typeof import('wxt/client')['defineContentScript'] + const defineUnlistedScript: typeof import('wxt/sandbox')['defineUnlistedScript'] } " `); diff --git a/e2e/tests/output-structure.test.ts b/e2e/tests/output-structure.test.ts index 5e3a04c3..e00f4451 100644 --- a/e2e/tests/output-structure.test.ts +++ b/e2e/tests/output-structure.test.ts @@ -172,7 +172,10 @@ describe('Output Directory Structure', () => { 'entrypoints/background.js', `export default defineBackground(() => {});`, ); - project.addFile('entrypoints/unlisted.js', ``); + project.addFile( + 'entrypoints/unlisted.js', + `export default defineUnlistedScript(() => {})`, + ); project.addFile( 'entrypoints/content.js', `export default defineContentScript({ diff --git a/e2e/tests/remote-code.test.ts b/e2e/tests/remote-code.test.ts index 321906e4..481a9e9c 100644 --- a/e2e/tests/remote-code.test.ts +++ b/e2e/tests/remote-code.test.ts @@ -5,7 +5,11 @@ describe('Remote Code', () => { it('should download "url:*" modules and include them in the final bundle', async () => { const url = 'https://code.jquery.com/jquery-3.7.1.slim.min.js'; const project = new TestProject(); - project.addFile('entrypoints/popup.ts', `import "url:${url}"`); + project.addFile( + 'entrypoints/popup.ts', + `import "url:${url}" + export default defineUnlistedScript(() => {})`, + ); await project.build(); diff --git a/package.json b/package.json index 5e94fc8d..43ac4814 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,10 @@ "import": "./dist/client.js", "types": "./dist/client.d.ts" }, + "./sandbox": { + "import": "./dist/sandbox.js", + "types": "./dist/sandbox.d.ts" + }, "./browser": { "import": "./dist/browser.js", "types": "./dist/browser.d.ts" diff --git a/scripts/build.ts b/scripts/build.ts index b3928ef6..cf5368a7 100644 --- a/scripts/build.ts +++ b/scripts/build.ts @@ -10,7 +10,7 @@ const spinner = ora('Building WXT').start(); const startTime = Date.now(); const outDir = 'dist'; -const virtualEntrypoints = ['background', 'content-script']; +const virtualEntrypoints = ['background', 'content-script', 'unlisted-script']; await fs.rm(outDir, { recursive: true, force: true }); @@ -48,6 +48,13 @@ await Promise.all([ silent: true, external: ['vite'], }), + tsup.build({ + entry: { sandbox: 'src/client/sandbox/index.ts' }, + format: ['esm'], + sourcemap: 'inline', + dts: true, + silent: true, + }), ...virtualEntrypoints.map((entryName) => tsup.build({ entry: { diff --git a/src/client/__tests__/defineBackground.test.ts b/src/client/__tests__/defineBackground.test.ts new file mode 100644 index 00000000..78007589 --- /dev/null +++ b/src/client/__tests__/defineBackground.test.ts @@ -0,0 +1,25 @@ +import { describe, expect, it, vi } from 'vitest'; +import { defineBackground } from '../defineBackground'; +import { BackgroundDefinition } from '../../core/types'; + +describe('defineBackground', () => { + it('should return the object definition when given an object', () => { + const definition: BackgroundDefinition = { + include: [''], + persistent: false, + main: vi.fn(), + }; + + const actual = defineBackground(definition); + + expect(actual).toEqual(definition); + }); + + it('should return the object definition when given a main function', () => { + const main = vi.fn(); + + const actual = defineBackground(main); + + expect(actual).toEqual({ main }); + }); +}); diff --git a/src/client/__tests__/defineContentScript.test.ts b/src/client/__tests__/defineContentScript.test.ts new file mode 100644 index 00000000..6647c355 --- /dev/null +++ b/src/client/__tests__/defineContentScript.test.ts @@ -0,0 +1,17 @@ +import { describe, expect, it, vi } from 'vitest'; +import { defineContentScript } from '../defineContentScript'; +import { ContentScriptDefinition } from '../../core/types'; + +describe('defineContentScript', () => { + it('should return the object passed in', () => { + const definition: ContentScriptDefinition = { + matches: [], + include: [''], + main: vi.fn(), + }; + + const actual = defineContentScript(definition); + + expect(actual).toEqual(definition); + }); +}); diff --git a/src/client/sandbox/__tests__/defineUnlistedScript.test.ts b/src/client/sandbox/__tests__/defineUnlistedScript.test.ts new file mode 100644 index 00000000..4c885da3 --- /dev/null +++ b/src/client/sandbox/__tests__/defineUnlistedScript.test.ts @@ -0,0 +1,24 @@ +import { describe, expect, it, vi } from 'vitest'; +import { defineUnlistedScript } from '../defineUnlistedScript'; +import { UnlistedScriptDefinition } from '../../../core/types'; + +describe('defineUnlistedScript', () => { + it('should return the object definition when given an object', () => { + const definition: UnlistedScriptDefinition = { + include: [''], + main: vi.fn(), + }; + + const actual = defineUnlistedScript(definition); + + expect(actual).toEqual(definition); + }); + + it('should return the object definition when given a main function', () => { + const main = vi.fn(); + + const actual = defineUnlistedScript(main); + + expect(actual).toEqual({ main }); + }); +}); diff --git a/src/client/sandbox/defineUnlistedScript.ts b/src/client/sandbox/defineUnlistedScript.ts new file mode 100644 index 00000000..bba82e58 --- /dev/null +++ b/src/client/sandbox/defineUnlistedScript.ts @@ -0,0 +1,14 @@ +import { UnlistedScriptDefinition } from '../../core/types'; + +export function defineUnlistedScript( + main: () => void, +): UnlistedScriptDefinition; +export function defineUnlistedScript( + definition: UnlistedScriptDefinition, +): UnlistedScriptDefinition; +export function defineUnlistedScript( + arg: (() => void) | UnlistedScriptDefinition, +): UnlistedScriptDefinition { + if (typeof arg === 'function') return { main: arg }; + return arg; +} diff --git a/src/client/sandbox/index.ts b/src/client/sandbox/index.ts new file mode 100644 index 00000000..c0bc0c9e --- /dev/null +++ b/src/client/sandbox/index.ts @@ -0,0 +1 @@ +export * from './defineUnlistedScript'; diff --git a/src/client/virtual-modules/background-entrypoint.ts b/src/client/virtual-modules/background-entrypoint.ts index 5b5d0bea..82d617a6 100644 --- a/src/client/virtual-modules/background-entrypoint.ts +++ b/src/client/virtual-modules/background-entrypoint.ts @@ -37,6 +37,6 @@ try { ); } } catch (err) { - logger.error('The background script crashed on startup!'); + logger.error('The background crashed on startup!'); throw err; } diff --git a/src/client/virtual-modules/content-script-entrypoint.ts b/src/client/virtual-modules/content-script-entrypoint.ts index 9e8c9cad..4ebfbd30 100644 --- a/src/client/virtual-modules/content-script-entrypoint.ts +++ b/src/client/virtual-modules/content-script-entrypoint.ts @@ -9,6 +9,9 @@ import { ContentScriptContext } from '../utils/ContentScriptContext'; await main(ctx); } catch (err) { - logger.error('The content script crashed on startup!', err); + logger.error( + `The content script "${__ENTRYPOINT__}" crashed on startup!`, + err, + ); } })(); diff --git a/src/client/virtual-modules/unlisted-script-entrypoint.ts b/src/client/virtual-modules/unlisted-script-entrypoint.ts new file mode 100644 index 00000000..da721e37 --- /dev/null +++ b/src/client/virtual-modules/unlisted-script-entrypoint.ts @@ -0,0 +1,13 @@ +import definition from 'virtual:user-unlisted-script'; +import { logger } from '../utils/logger'; + +(async () => { + try { + await definition.main(); + } catch (err) { + logger.error( + `The unlisted script "${__ENTRYPOINT__}" crashed on startup!`, + err, + ); + } +})(); diff --git a/src/client/virtual-modules/virtual-module-globals.d.ts b/src/client/virtual-modules/virtual-module-globals.d.ts index 2860f157..26152255 100644 --- a/src/client/virtual-modules/virtual-module-globals.d.ts +++ b/src/client/virtual-modules/virtual-module-globals.d.ts @@ -15,6 +15,11 @@ declare module 'virtual:user-content-script' { export default definition; } +declare module 'virtual:user-unlisted-script' { + const definition: import('../../').UnlistedScriptDefinition; + export default definition; +} + // Globals defined by the vite-plugins/devServerGlobals.ts and utils/globals.ts declare const __COMMAND__: 'build' | 'serve'; declare const __DEV_SERVER_PROTOCOL__: string; diff --git a/src/core/build/__tests__/findEntrypoints.test.ts b/src/core/build/__tests__/findEntrypoints.test.ts index b5142a8b..6724fe7b 100644 --- a/src/core/build/__tests__/findEntrypoints.test.ts +++ b/src/core/build/__tests__/findEntrypoints.test.ts @@ -261,6 +261,43 @@ describe('findEntrypoints', () => { }); }); + it.each<[string, Omit]>([ + [ + 'injected.ts', + { + type: 'unlisted-script', + name: 'injected', + inputPath: resolve(config.entrypointsDir, 'injected.ts'), + outputDir: config.outDir, + }, + ], + [ + 'injected/index.ts', + { + type: 'unlisted-script', + name: 'injected', + inputPath: resolve(config.entrypointsDir, 'injected/index.ts'), + outputDir: config.outDir, + }, + ], + ])( + 'should find and load unlisted-script entrypoint config from %s', + async (path, expected) => { + const options: GenericEntrypoint['options'] = {}; + globMock.mockResolvedValueOnce([path]); + importEntrypointFileMock.mockResolvedValue(options); + + const entrypoints = await findEntrypoints(config); + + expect(entrypoints).toHaveLength(1); + expect(entrypoints[0]).toEqual({ ...expected, options }); + expect(importEntrypointFileMock).toBeCalledWith( + expected.inputPath, + config, + ); + }, + ); + it.each<[string, GenericEntrypoint]>([ // Sandbox [ @@ -456,28 +493,6 @@ describe('findEntrypoints', () => { }, ], - // unlisted-script - [ - 'injected.ts', - { - type: 'unlisted-script', - name: 'injected', - inputPath: resolve(config.entrypointsDir, 'injected.ts'), - outputDir: config.outDir, - options: {}, - }, - ], - [ - 'injected/index.ts', - { - type: 'unlisted-script', - name: 'injected', - inputPath: resolve(config.entrypointsDir, 'injected/index.ts'), - outputDir: config.outDir, - options: {}, - }, - ], - // unlisted-style [ 'iframe.scss', diff --git a/src/core/build/buildEntrypoints.ts b/src/core/build/buildEntrypoints.ts index 1b0ee4e3..40a93adc 100644 --- a/src/core/build/buildEntrypoints.ts +++ b/src/core/build/buildEntrypoints.ts @@ -53,7 +53,11 @@ async function buildSingleEntrypoint( config: InternalConfig, ): Promise { // Should this entrypoint be wrapped by the vite-plugins/virtualEntrypoint plugin? - const isVirtual = ['background', 'content-script'].includes(entrypoint.type); + const isVirtual = [ + 'background', + 'content-script', + 'unlisted-script', + ].includes(entrypoint.type); const entry = isVirtual ? `virtual:wxt-${entrypoint.type}?${entrypoint.inputPath}` : entrypoint.inputPath; diff --git a/src/core/build/findEntrypoints.ts b/src/core/build/findEntrypoints.ts index ad7cecae..b9bafe41 100644 --- a/src/core/build/findEntrypoints.ts +++ b/src/core/build/findEntrypoints.ts @@ -10,6 +10,7 @@ import { InternalConfig, OptionsEntrypoint, PopupEntrypoint, + UnlistedScriptDefinition, } from '../types'; import fs from 'fs-extra'; import { minimatch } from 'minimatch'; @@ -74,15 +75,14 @@ export async function findEntrypoints( hasBackground = true; break; case 'content-script': - entrypoint = await getContentScriptEntrypoint( - config, - getEntrypointName(config.entrypointsDir, path), - path, - ); + entrypoint = await getContentScriptEntrypoint(config, path); break; case 'unlisted-page': entrypoint = await getUnlistedPageEntrypoint(config, path); break; + case 'unlisted-script': + entrypoint = await getUnlistedScriptEntrypoint(config, path); + break; case 'content-script-style': entrypoint = { type, @@ -288,6 +288,35 @@ async function getUnlistedPageEntrypoint( }; } +/** + * @param path Absolute path to the script's file. + * @param content String contents of the file at the path. + */ +async function getUnlistedScriptEntrypoint( + config: InternalConfig, + path: string, +): Promise { + const name = getEntrypointName(config.entrypointsDir, path); + const defaultExport = await importEntrypointFile( + path, + config, + ); + if (defaultExport == null) { + throw Error( + `${name}: Default export not found, did you forget to call "export default defineUnlistedScript(...)"?`, + ); + } + const { main: _, ...moduleOptions } = defaultExport; + const options: Omit = moduleOptions; + return { + type: 'unlisted-script', + name, + inputPath: path, + outputDir: config.outDir, + options, + }; +} + /** * @param path Absolute path to the background's TS file. */ @@ -295,6 +324,7 @@ async function getBackgroundEntrypoint( config: InternalConfig, path: string, ): Promise { + const name = 'background'; let options: Omit = {}; if (path !== VIRTUAL_NOOP_BACKGROUND_MODULE_ID) { const defaultExport = await importEntrypointFile( @@ -302,14 +332,16 @@ async function getBackgroundEntrypoint( config, ); if (defaultExport == null) { - throw Error('Background script does not have a default export'); + throw Error( + `${name}: Default export not found, did you forget to call "export default defineBackground(...)"?`, + ); } const { main: _, ...moduleOptions } = defaultExport; options = moduleOptions; } return { type: 'background', - name: 'background', + name, inputPath: path, outputDir: config.outDir, options: { @@ -325,17 +357,19 @@ async function getBackgroundEntrypoint( */ async function getContentScriptEntrypoint( config: InternalConfig, - name: string, path: string, ): Promise { + const name = getEntrypointName(config.entrypointsDir, path); const { main: _, ...options } = await importEntrypointFile(path, config); if (options == null) { - throw Error(`Content script ${name} does not have a default export`); + throw Error( + `${name}: Default export not found, did you forget to call "export default defineContentScript(...)"?`, + ); } return { type: 'content-script', - name: getEntrypointName(config.entrypointsDir, path), + name, inputPath: path, outputDir: resolve(config.outDir, CONTENT_SCRIPT_OUT_DIR), options, diff --git a/src/core/types/external.ts b/src/core/types/external.ts index 3c1b23f5..30056a0d 100644 --- a/src/core/types/external.ts +++ b/src/core/types/external.ts @@ -435,6 +435,13 @@ export interface BackgroundDefinition extends ExcludableEntrypoint { main(): void; } +export interface UnlistedScriptDefinition extends ExcludableEntrypoint { + /** + * Main function executed when the unlisted script is ran. + */ + main(): void | Promise; +} + export type PerBrowserOption = T | { [browser: TargetBrowser]: T }; export interface ExcludableEntrypoint { diff --git a/src/core/utils/__tests__/importEntrypointFile.test.ts b/src/core/utils/__tests__/importEntrypointFile.test.ts new file mode 100644 index 00000000..d61a2bc9 --- /dev/null +++ b/src/core/utils/__tests__/importEntrypointFile.test.ts @@ -0,0 +1,41 @@ +import { describe, expect, it } from 'vitest'; +import { importEntrypointFile } from '../importEntrypointFile'; +import { fakeInternalConfig } from '../../../testing/fake-objects'; +import { resolve } from 'node:path'; + +const entrypointPath = (filename: string) => + resolve('src/core/utils/__tests__/test-entrypoints', filename); + +const config = fakeInternalConfig({ + imports: false, + debug: false, + // Run inside the demo folder so that wxt is in the node_modules + // WXT must also be built for these tests to pass + root: 'demo', +}); + +describe('importEntrypointFile', () => { + it.each([ + ['background.ts', { main: expect.any(Function) }], + ['content.ts', { main: expect.any(Function), matches: [''] }], + ['unlisted.ts', { main: expect.any(Function) }], + ['react.tsx', { main: expect.any(Function) }], + ['with-named.ts', { main: expect.any(Function) }], + ])( + 'should return the default export of test-entrypoints/%s', + async (file, expected) => { + const actual = await importEntrypointFile(entrypointPath(file), config); + + expect(actual).toEqual(expected); + }, + ); + + it('should return undefined when there is no default export', async () => { + const actual = await importEntrypointFile( + entrypointPath('no-default-export.ts'), + config, + ); + + expect(actual).toBeUndefined(); + }); +}); diff --git a/src/core/utils/__tests__/test-entrypoints/background.ts b/src/core/utils/__tests__/test-entrypoints/background.ts new file mode 100644 index 00000000..bf0e9c5c --- /dev/null +++ b/src/core/utils/__tests__/test-entrypoints/background.ts @@ -0,0 +1,5 @@ +import { defineBackground } from '../../../../client'; + +export default defineBackground({ + main() {}, +}); diff --git a/src/core/utils/__tests__/test-entrypoints/content.ts b/src/core/utils/__tests__/test-entrypoints/content.ts new file mode 100644 index 00000000..905f6d1d --- /dev/null +++ b/src/core/utils/__tests__/test-entrypoints/content.ts @@ -0,0 +1,6 @@ +import { defineContentScript } from '../../../../client'; + +export default defineContentScript({ + matches: [''], + main() {}, +}); diff --git a/src/core/utils/__tests__/test-entrypoints/no-default-export.ts b/src/core/utils/__tests__/test-entrypoints/no-default-export.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/core/utils/__tests__/test-entrypoints/react.tsx b/src/core/utils/__tests__/test-entrypoints/react.tsx new file mode 100644 index 00000000..5c363c00 --- /dev/null +++ b/src/core/utils/__tests__/test-entrypoints/react.tsx @@ -0,0 +1,3 @@ +import { defineUnlistedScript } from '../../../../client/sandbox'; + +export default defineUnlistedScript(() => {}); diff --git a/src/core/utils/__tests__/test-entrypoints/unlisted.ts b/src/core/utils/__tests__/test-entrypoints/unlisted.ts new file mode 100644 index 00000000..5c363c00 --- /dev/null +++ b/src/core/utils/__tests__/test-entrypoints/unlisted.ts @@ -0,0 +1,3 @@ +import { defineUnlistedScript } from '../../../../client/sandbox'; + +export default defineUnlistedScript(() => {}); diff --git a/src/core/utils/__tests__/test-entrypoints/with-named.ts b/src/core/utils/__tests__/test-entrypoints/with-named.ts new file mode 100644 index 00000000..4901df9c --- /dev/null +++ b/src/core/utils/__tests__/test-entrypoints/with-named.ts @@ -0,0 +1,5 @@ +import { defineBackground } from '../../../../client'; + +export const a = {}; + +export default defineBackground(() => {}); diff --git a/src/core/utils/auto-imports.ts b/src/core/utils/auto-imports.ts index b521df58..d4c7e647 100644 --- a/src/core/utils/auto-imports.ts +++ b/src/core/utils/auto-imports.ts @@ -10,7 +10,11 @@ export function getUnimportOptions( const defaultOptions: Partial = { debugLog: config.logger.debug, imports: [{ name: 'defineConfig', from: 'wxt' }], - presets: [{ package: 'wxt/client' }, { package: 'wxt/browser' }], + presets: [ + { package: 'wxt/client' }, + { package: 'wxt/browser' }, + { package: 'wxt/sandbox' }, + ], warn: config.logger.warn, dirs: ['components', 'composables', 'hooks', 'utils'], }; diff --git a/src/core/utils/getInternalConfig.ts b/src/core/utils/getInternalConfig.ts index 39731d9b..e1add79e 100644 --- a/src/core/utils/getInternalConfig.ts +++ b/src/core/utils/getInternalConfig.ts @@ -237,10 +237,13 @@ async function resolveInternalViteConfig( internalVite.plugins.push(plugins.devHtmlPrerender(finalConfig)); internalVite.plugins.push(plugins.unimport(finalConfig)); internalVite.plugins.push( - plugins.virtualEntrypoin('background', finalConfig), + plugins.virtualEntrypoint('background', finalConfig), ); internalVite.plugins.push( - plugins.virtualEntrypoin('content-script', finalConfig), + plugins.virtualEntrypoint('content-script', finalConfig), + ); + internalVite.plugins.push( + plugins.virtualEntrypoint('unlisted-script', finalConfig), ); internalVite.plugins.push(plugins.devServerGlobals(finalConfig)); internalVite.plugins.push(plugins.tsconfigPaths(finalConfig)); diff --git a/src/core/utils/importEntrypointFile.ts b/src/core/utils/importEntrypointFile.ts index f4ffdf22..20f9f84d 100644 --- a/src/core/utils/importEntrypointFile.ts +++ b/src/core/utils/importEntrypointFile.ts @@ -49,7 +49,6 @@ export async function importEntrypointFile( cache: false, debug: config.debug, esmResolve: true, - interopDefault: true, alias: { 'webextension-polyfill': resolve( config.root, @@ -69,7 +68,8 @@ export async function importEntrypointFile( }); try { - return await jiti(path); + const res = await jiti(path); + return res.default; } catch (err) { config.logger.error(err); throw err; diff --git a/src/core/utils/strings.ts b/src/core/utils/strings.ts index d84f1c38..58f06bf4 100644 --- a/src/core/utils/strings.ts +++ b/src/core/utils/strings.ts @@ -23,6 +23,7 @@ export function removeProjectImportStatements(text: string): string { const noImports = removeImportStatements(text); return `import { defineContentScript, defineBackground } from 'wxt/client'; +import { defineUnlistedScript } from 'wxt/sandbox'; ${noImports}`; } diff --git a/src/core/vite-plugins/virtualEntrypoint.ts b/src/core/vite-plugins/virtualEntrypoint.ts index a6308896..2d41d78d 100644 --- a/src/core/vite-plugins/virtualEntrypoint.ts +++ b/src/core/vite-plugins/virtualEntrypoint.ts @@ -7,7 +7,7 @@ import { normalizePath } from '../utils/paths'; /** * Wraps a user's entrypoint with a vitual version with additional logic. */ -export function virtualEntrypoin( +export function virtualEntrypoint( type: Entrypoint['type'], config: InternalConfig, ): Plugin {