wxt icon indicating copy to clipboard operation
wxt copied to clipboard

feat: Add iifeName option

Open jviney opened this issue 4 months ago • 6 comments

Overview

The IIFE name is not currently configurable, and can be important when inserting content scripts with world=MAIN to ensure there is no conflict with the page where the script is being inserted.

Manual Testing

When specifying an iifeName option in the config, the return value of this function is used as the IIFE name in the built JS files.

jviney avatar Sep 16 '25 05:09 jviney

Deploy Preview for creative-fairy-df92c4 ready!

Name Link
Latest commit 97a4fb99a649e1605c0f44dca0dc901965a7a2df
Latest deploy log https://app.netlify.com/projects/creative-fairy-df92c4/deploys/68c92b5f1d6bfa0008c49dec
Deploy Preview https://deploy-preview-1897--creative-fairy-df92c4.netlify.app
Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

netlify[bot] avatar Sep 16 '25 05:09 netlify[bot]

I like this idea, I am willing to merge this as-is.

Before that, I want to run an alternative by you: would it make more sense to add this to defineContentScript (as an option like cssInjectionMode, matches, etc) instead of wxt.config.ts?

export default defineContentScript({
  iffeName: "example",
  // OR `globalName: string | boolean`, letting people disable the iffe name in the  output as well as give it a different name.

  main() {
    // ...
  }
})

In this version, it would default to true and the name would be generated based on the content script name, but in the next major version would could change the default to false so a name isn't even generated in the first place.

Great - thank you. Yes that idea could work too, and does offer more flexibility.

My only hesitation is that on a team it's easy for someone to forget to add this option, so having a way to globally ensure the IIFE name is unique (or unnamed) would still be valuable. Our extension inserts world=MAIN content scripts and we need a strong guarantee that we're not going to interfere with a variable on the site.

jviney avatar Oct 27 '25 22:10 jviney

If we go with that approach, forgetting to override the name would be resolved in the next major version by changing the default value to false and not even storing the IIFE result in a variable for all content scripts unless a name is set.

I don't really want to introduce a feature now that would only be removed in the next major version. I know that sucks for you now, but an alternative would be to patch WXT and add a prefix to all IIFE global names by default.

aklinker1 avatar Oct 27 '25 22:10 aklinker1

If we go with that approach, forgetting to override the name would be resolved in the next major version by changing the default value to false and not even storing the IIFE result in a variable for all content scripts unless a name is set.

I don't really want to introduce a feature now that would only be removed in the next major version. I know that sucks for you now, but an alternative would be to patch WXT and add a prefix to all IIFE global names by default.

Sounds fine to me - we can add something to our build tests that ensure the value has been set to false.

jviney avatar Oct 28 '25 02:10 jviney

You could validate it via a WXT module:

// modules/iife-global-name-validation.ts
import { defineWxtModule } from 'wxt/modules';

export default defineWxtModules({
  name: "iife-global-name-validation",
  setup(wxt) {
    wxt.hook('entrypoints:resolved', (entrypoints) => {
      for (const entrypoint of entrpoints) {
        // I believe entrypoint.options contains the fully resolved options, with defaults applied.
        if (entrypoint.type === "content" && entrypoint.options.globalName !== false) {
          throw Error("ERROR: All content scripts must have `globalName: false` set in the options")
          // or log a warning with wxt.logger.warn,
          // or look at wxt.config.command and decide to throw an error or warn based on the command being ran,
          // or build a list of invalid content scripts and do either of the above for all content scripts that are invalid
        }
      }
    }
  }
})

It would run on wxt prepare, wxt and wxt build, basically any WXT command that actually builds/runs the project.

aklinker1 avatar Oct 28 '25 23:10 aklinker1

You could validate it via a WXT module:

// modules/iife-global-name-validation.ts
import { defineWxtModule } from 'wxt/modules';

export default defineWxtModules({
  name: "iife-global-name-validation",
  setup(wxt) {
    wxt.hook('entrypoints:resolved', (entrypoints) => {
      for (const entrypoint of entrpoints) {
        // I believe entrypoint.options contains the fully resolved options, with defaults applied.
        if (entrypoint.type === "content" && entrypoint.options.globalName !== false) {
          throw Error("ERROR: All content scripts must have `globalName: false` set in the options")
          // or log a warning with wxt.logger.warn,
          // or look at wxt.config.command and decide to throw an error or warn based on the command being ran,
          // or build a list of invalid content scripts and do either of the above for all content scripts that are invalid
        }
      }
    }
  }
})

It would run on wxt prepare, wxt and wxt build, basically any WXT command that actually builds/runs the project.

Great - that's even better. Shall I do a PR to add this new option?

jviney avatar Oct 29 '25 00:10 jviney