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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/wxt-demo/src/entrypoints/background.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export default defineBackground({
// type: 'module',
globalName: false,

main() {
console.log(browser.runtime.id);
Expand Down
373 changes: 373 additions & 0 deletions packages/wxt/e2e/tests/output-structure.test.ts

Large diffs are not rendered by default.

16 changes: 14 additions & 2 deletions packages/wxt/src/core/builders/vite/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@ export async function createViteBuilder(
const plugins: NonNullable<vite.UserConfig['plugins']> = [
wxtPlugins.entrypointGroupGlobals(entrypoint),
];
const iifeReturnValueName = safeVarName(entrypoint.name);

if (
entrypoint.type === 'content-script-style' ||
Expand All @@ -118,11 +117,24 @@ export async function createViteBuilder(
plugins.push(wxtPlugins.cssEntrypoints(entrypoint, wxtConfig));
}

let iifeReturnValueName: string;
if (typeof entrypoint.options.globalName === 'string') {
iifeReturnValueName = entrypoint.options.globalName;
} else if (typeof entrypoint.options.globalName === 'function') {
iifeReturnValueName = entrypoint.options.globalName(entrypoint);
} else {
iifeReturnValueName = safeVarName(entrypoint.name);
}

if (
entrypoint.type === 'content-script' ||
entrypoint.type === 'unlisted-script'
) {
plugins.push(wxtPlugins.iifeFooter(iifeReturnValueName));
if (entrypoint.options.globalName === false) {
plugins.push(wxtPlugins.iifeAnonymous(iifeReturnValueName));
} else {
plugins.push(wxtPlugins.iifeFooter(iifeReturnValueName));
}
}

return {
Expand Down
21 changes: 21 additions & 0 deletions packages/wxt/src/core/builders/vite/plugins/iifeAnonymous.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { Plugin } from 'vite';

/**
* Remove the `var name = ` prefix from the generated code so it becomes an anonymous IIFE.
* Handle both minified and non-minified cases.
*/
export function iifeAnonymous(iifeReturnValueName: string): Plugin {
return {
name: 'wxt:iife-anonymous',
generateBundle(_, bundle) {
for (const chunk of Object.values(bundle)) {
if (chunk.type === 'chunk' && chunk.isEntry) {
const namedIIFEPrefix = new RegExp(
`^var ${iifeReturnValueName}\\s*=\\s*(\\(function)`,
);
chunk.code = chunk.code.replace(namedIIFEPrefix, '$1');
}
}
},
};
}
1 change: 1 addition & 0 deletions packages/wxt/src/core/builders/vite/plugins/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ export * from './removeEntrypointMainFunction';
export * from './wxtPluginLoader';
export * from './resolveAppConfig';
export * from './iifeFooter';
export * from './iifeAnonymous';
1 change: 1 addition & 0 deletions packages/wxt/src/core/utils/building/find-entrypoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@ async function getUnlistedScriptEntrypoint(
{
include: options.include,
exclude: options.exclude,
globalName: options.globalName,
},
wxt.config.browser,
),
Expand Down
19 changes: 19 additions & 0 deletions packages/wxt/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,25 @@ export interface BaseEntrypointOptions {
* @default undefined
*/
exclude?: TargetBrowser[];
/**
* The variable name for the IIFE in the JS output bundle.
*
* This option is for content scripts with world=MAIN, and unlisted scripts.
* It's relevant for scripts that are inserted into the page context where the default IIFE
* variable name may conflict with an existing variable on the target page. This applies to content
* scripts with world=MAIN, and others, such as unlisted scripts, that could be dynamically injected
* into the page with a <script> tag.
*
* Available options:
* - `true`: automatically generate a name for the IIFE based on the entrypoint name
* - `false`: Output the IIFE without a variable name, making it anonymous. This is the safest option
* to avoid conflicts with existing variables on the page. This will become the default in a future version of WXT.
* - `string`: Use the provided string as the global variable name.
* - `function`: A function that receives the entrypoint and returns a string to use as the variable name.
*
* @default true
*/
globalName?: string | boolean | ((entrypoint: Entrypoint) => string);
}

export interface BackgroundEntrypointOptions extends BaseEntrypointOptions {
Expand Down