diff --git a/docs/guide/essentials/config/entrypoint-loaders.md b/docs/guide/essentials/config/entrypoint-loaders.md index c33c870ad..23a85d19d 100644 --- a/docs/guide/essentials/config/entrypoint-loaders.md +++ b/docs/guide/essentials/config/entrypoint-loaders.md @@ -10,7 +10,7 @@ WXT does several pre-processing steps to try and prevent errors during this proc 2. Use `@webext-core/fake-browser` to create a fake version of the `chrome` and `browser` globals expected by extensions. 3. Pre-process the JS/TS code, stripping out the `main` function then tree-shaking unused code from the file -However, this process is not perfect. It doesn't setup all the globals found in the browser and the APIs may behave differently. As such, **_you should avoid using browser or extension APIs outside the `main` function of your entrypoints!_** +However, this process is not perfect. It doesn't setup all the globals found in the browser and the APIs may behave differently. As such, **_you should avoid using browser or extension APIs outside the `main` function of your entrypoints!_** See [Entrypoint Limitations](/guide/essentials/extension-apis#entrypoint-limitations) for more details. :::tip If you're running into errors while importing entrypoints, run `wxt prepare --debug` to see more details about this process. When debugging, WXT will print out the pre-processed code to help you identify issues. diff --git a/docs/guide/essentials/extension-apis.md b/docs/guide/essentials/extension-apis.md index 6397acf96..15439d8c6 100644 --- a/docs/guide/essentials/extension-apis.md +++ b/docs/guide/essentials/extension-apis.md @@ -75,3 +75,63 @@ Alternatively, if you're trying to use similar APIs under different names (to su // }); ``` + +## Entrypoint Limitations + +Because WXT imports your entrypoint files into a NodeJS, non-extension environment, the `chrome`/`browser` variables provided to extensions by the browser **will not be available**. + +To prevent some basic errors, WXT polyfills these globals with the same in-memory, fake implementation it uses for testing: [`@webext-core/fake-browser`](https://webext-core.aklinker1.io/fake-browser/installation/). However, not all the APIs have been implemented. + +So it is extremely important to NEVER use `browser.*` extension APIs outside the main function of any JS/TS entrypoints (background, content scripts, and unlisted scripts). If you do, you'll see an error like this: + +```plaintext +✖ Command failed after 440 ms + + ERROR Browser.action.onClicked.addListener not implemented. +``` + +The fix is simple, just move your API usage into the entrypoint's main function: + +:::code-group + +```ts [background.ts] +browser.action.onClicked.addListener(() => { + /* ... */ +}); // [!code --] + +export default defineBackground(() => { + browser.action.onClicked.addListener(() => { + /* ... */ + }); // [!code ++] +}); +``` + +```ts [content.ts] +browser.runtime.onMessage.addListener(() => { + /* ... */ +}); // [!code --] + +export default defineContentScript({ + main() { + browser.runtime.onMessage.addListener(() => { + /* ... */ + }); // [!code ++] + }, +}); +``` + +```ts [unlisted.ts] +browser.runtime.onMessage.addListener(() => { + /* ... */ +}); // [!code --] + +export default defineUnlistedScript(() => { + browser.runtime.onMessage.addListener(() => { + /* ... */ + }); // [!code ++] +}); +``` + +::: + +Read [Entrypoint Loaders](/guide/essentials/config/entrypoint-loaders) for more technical details about this limitation.