diff --git a/packages/wxt/e2e/tests/remote-code.test.ts b/packages/wxt/e2e/tests/remote-code.test.ts index 481a9e9c..f4ac9f93 100644 --- a/packages/wxt/e2e/tests/remote-code.test.ts +++ b/packages/wxt/e2e/tests/remote-code.test.ts @@ -3,7 +3,7 @@ import { TestProject } from '../utils'; 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 url = 'https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js'; const project = new TestProject(); project.addFile( 'entrypoints/popup.ts', @@ -16,7 +16,7 @@ describe('Remote Code', () => { const output = await project.serializeFile('.output/chrome-mv3/popup.js'); expect(output).toContain( // Some text that will hopefully be in future versions of this script - 'jQuery v3.7.1', + 'lodash.com', ); expect(output).not.toContain(url); expect( diff --git a/packages/wxt/package.json b/packages/wxt/package.json index 89ba57ae..271d3db0 100644 --- a/packages/wxt/package.json +++ b/packages/wxt/package.json @@ -1,7 +1,7 @@ { "name": "wxt", "type": "module", - "version": "0.19.0", + "version": "0.19.1-alpha2", "description": "Next gen framework for developing web extensions", "repository": { "type": "git", diff --git a/packages/wxt/src/core/builders/vite/index.ts b/packages/wxt/src/core/builders/vite/index.ts index a15a5530..1291eab8 100644 --- a/packages/wxt/src/core/builders/vite/index.ts +++ b/packages/wxt/src/core/builders/vite/index.ts @@ -230,10 +230,7 @@ export async function createViteBuilder( baseConfig.optimizeDeps.noDiscovery = true; baseConfig.optimizeDeps.include = []; const envConfig: vite.InlineConfig = { - plugins: [ - wxtPlugins.extensionApiMock(wxtConfig), - wxtPlugins.removeEntrypointMainFunction(wxtConfig, path), - ], + plugins: [wxtPlugins.removeEntrypointMainFunction(wxtConfig, path)], }; const config = vite.mergeConfig(baseConfig, envConfig); const server = await vite.createServer(config); diff --git a/packages/wxt/src/core/builders/vite/plugins/removeEntrypointMainFunction.ts b/packages/wxt/src/core/builders/vite/plugins/removeEntrypointMainFunction.ts index 979523c6..5146fe85 100644 --- a/packages/wxt/src/core/builders/vite/plugins/removeEntrypointMainFunction.ts +++ b/packages/wxt/src/core/builders/vite/plugins/removeEntrypointMainFunction.ts @@ -14,8 +14,11 @@ export function removeEntrypointMainFunction( const absPath = normalizePath(resolve(config.root, path)); return { name: 'wxt:remove-entrypoint-main-function', - transform(code, id) { - if (id === absPath) return removeMainFunctionCode(code); + transform: { + order: 'pre', + handler(code, id) { + if (id === absPath) return removeMainFunctionCode(code); + }, }, }; } diff --git a/packages/wxt/src/core/utils/building/find-entrypoints.ts b/packages/wxt/src/core/utils/building/find-entrypoints.ts index c023d422..2fd2f42f 100644 --- a/packages/wxt/src/core/utils/building/find-entrypoints.ts +++ b/packages/wxt/src/core/utils/building/find-entrypoints.ts @@ -28,6 +28,7 @@ import { VIRTUAL_NOOP_BACKGROUND_MODULE_ID } from '../../utils/constants'; import { CSS_EXTENSIONS_PATTERN } from '../../utils/paths'; import pc from 'picocolors'; import { wxt } from '../../wxt'; +import { createExtensionEnvironment } from '../environments'; /** * Return entrypoints and their configuration by looking through the project's files. @@ -72,47 +73,50 @@ export async function findEntrypoints(): Promise { // Import entrypoints to get their config let hasBackground = false; - const entrypoints: Entrypoint[] = await Promise.all( - entrypointInfos.map(async (info): Promise => { - const { type } = info; - switch (type) { - case 'popup': - return await getPopupEntrypoint(info); - case 'sidepanel': - return await getSidepanelEntrypoint(info); - case 'options': - return await getOptionsEntrypoint(info); - case 'background': - hasBackground = true; - return await getBackgroundEntrypoint(info); - case 'content-script': - return await getContentScriptEntrypoint(info); - case 'unlisted-page': - return await getUnlistedPageEntrypoint(info); - case 'unlisted-script': - return await getUnlistedScriptEntrypoint(info); - case 'content-script-style': - return { - ...info, - type, - outputDir: resolve(wxt.config.outDir, CONTENT_SCRIPT_OUT_DIR), - options: { - include: undefined, - exclude: undefined, - }, - }; - default: - return { - ...info, - type, - outputDir: wxt.config.outDir, - options: { - include: undefined, - exclude: undefined, - }, - }; - } - }), + const env = createExtensionEnvironment(); + const entrypoints: Entrypoint[] = await env.run(() => + Promise.all( + entrypointInfos.map(async (info): Promise => { + const { type } = info; + switch (type) { + case 'popup': + return await getPopupEntrypoint(info); + case 'sidepanel': + return await getSidepanelEntrypoint(info); + case 'options': + return await getOptionsEntrypoint(info); + case 'background': + hasBackground = true; + return await getBackgroundEntrypoint(info); + case 'content-script': + return await getContentScriptEntrypoint(info); + case 'unlisted-page': + return await getUnlistedPageEntrypoint(info); + case 'unlisted-script': + return await getUnlistedScriptEntrypoint(info); + case 'content-script-style': + return { + ...info, + type, + outputDir: resolve(wxt.config.outDir, CONTENT_SCRIPT_OUT_DIR), + options: { + include: undefined, + exclude: undefined, + }, + }; + default: + return { + ...info, + type, + outputDir: wxt.config.outDir, + options: { + include: undefined, + exclude: undefined, + }, + }; + } + }), + ), ); if (wxt.config.command === 'serve' && !hasBackground) { diff --git a/packages/wxt/src/core/utils/environments/browser-environment.ts b/packages/wxt/src/core/utils/environments/browser-environment.ts new file mode 100644 index 00000000..6b9d3d7b --- /dev/null +++ b/packages/wxt/src/core/utils/environments/browser-environment.ts @@ -0,0 +1,21 @@ +import { parseHTML } from 'linkedom'; +import { createEnvironment, Environment, EnvGlobals } from './environment'; + +export function createBrowserEnvironment(): Environment { + return createEnvironment(getBrowserEnvironmentGlobals); +} + +export function getBrowserEnvironmentGlobals(): EnvGlobals { + const { window, document, global } = parseHTML(` + + + + + `); + return { + ...global, + window, + document, + self: global, + }; +} diff --git a/packages/wxt/src/core/utils/environments/environment.ts b/packages/wxt/src/core/utils/environments/environment.ts new file mode 100644 index 00000000..8e62c9ce --- /dev/null +++ b/packages/wxt/src/core/utils/environments/environment.ts @@ -0,0 +1,49 @@ +export interface Environment { + setup: () => () => void; + run: (fn: () => Promise) => Promise; +} + +export function createEnvironment(getGlobals: () => EnvGlobals): Environment { + const setup = () => { + const envGlobals = getGlobals(); + const ogGlobals = getOgGlobals(envGlobals); + applyGlobals(envGlobals); + + return () => { + applyGlobals(ogGlobals); + }; + }; + const run = async (fn: () => any) => { + const teardown = setup(); + try { + return await fn(); + } finally { + teardown(); + } + }; + return { + setup, + run, + }; +} + +export type EnvGlobals = Record; + +export function getOgGlobals(envGlobals: EnvGlobals): EnvGlobals { + return Object.keys(envGlobals).reduce((acc, key) => { + // @ts-expect-error: Untyped key on globalThis + acc[key] = globalThis[key]; + return acc; + }, {}); +} + +export function applyGlobals(globals: EnvGlobals): void { + Object.entries(globals).forEach(([key, envValue]) => { + try { + // @ts-expect-error: Untyped key on globalThis + globalThis[key] = envValue; + } catch (err) { + // ignore any globals that can't be set + } + }); +} diff --git a/packages/wxt/src/core/utils/environments/extension-environment.ts b/packages/wxt/src/core/utils/environments/extension-environment.ts new file mode 100644 index 00000000..1f5644a4 --- /dev/null +++ b/packages/wxt/src/core/utils/environments/extension-environment.ts @@ -0,0 +1,15 @@ +import { fakeBrowser } from '@webext-core/fake-browser'; +import { getBrowserEnvironmentGlobals } from './browser-environment'; +import { createEnvironment, Environment } from './environment'; + +export function createExtensionEnvironment(): Environment { + return createEnvironment(getExtensionEnvironmentGlobals); +} + +export function getExtensionEnvironmentGlobals() { + return { + ...getBrowserEnvironmentGlobals(), + chrome: fakeBrowser, + browser: fakeBrowser, + }; +} diff --git a/packages/wxt/src/core/utils/environments/index.ts b/packages/wxt/src/core/utils/environments/index.ts new file mode 100644 index 00000000..ea141e0b --- /dev/null +++ b/packages/wxt/src/core/utils/environments/index.ts @@ -0,0 +1,2 @@ +export * from './browser-environment'; +export * from './extension-environment';