#imports
+description: Learn how WXT's new #imports module works and how to use it.
+authors:
+ - name: Aaron Klinker
+ github: aklinker1
+date: 2024-12-06T14:39:00.000Z
+---
+
+WXT v0.20 introduced a new way of manually importing its APIs: **the `#imports` module**. This module was introduced to simplify import statements and provide more visibility into all the APIs WXT provides.
+
+
+```ts
+import { browser } from 'wxt/storage'; // [!code --]
+import { createShadowRootUi } from 'wxt/utils/content-script-ui/shadow-root'; // [!code --]
+import { defineContentScript } from 'wxt/utils/define-content-script'; // [!code --]
+import { injectScript } from 'wxt/utils/inject-script'; // [!code --]
+import { // [!code ++]
+ browser, createShadowRootUi, defineContentScript, injectScript // [!code ++]
+} from '#imports'; // [!code ++]
+```
+
+The `#imports` module is considered a "virtual module", because the file doesn't actually exist. At build-time, imports are split into individual statements for each API:
+
+:::code-group
+
+```ts [What you write]
+import { defineContentScript, injectScript } from '#imports';
+```
+
+```ts [What the bundler sees]
+import { defineContentScript } from 'wxt/utils/define-content-script';
+import { injectScript } from 'wxt/utils/inject-script';
+```
+
+:::
+
+Think of `#imports` as a convenient way to access all of WXT's APIs from one place, without impacting performance or bundle size.
+
+This enables better tree-shaking compared to v0.19 and below.
+
+:::tip Need to lookup the full import path of an API?
+Open up your project's `.wxt/types/imports-module.d.ts` file.
+:::
+
+## Mocking
+
+When writing tests, you might need to mock APIs from the `#imports` module. While mocking these APIs is very easy, it may not be immediately clear how to accomplish it.
+
+Let's look at an example using Vitest. When [configured with `wxt/testing`](/guide/essentials/unit-testing#vitest), Vitest sees the same transformed code as the bundler. That means to mock an API from `#imports`, you need to call `vi.mock` with the real import path, not `#imports`:
+
+```ts
+import { injectScript } from '#imports';
+import { vi } from 'vitest';
+
+vi.mock('wxt/utils/inject-script')
+const injectScriptMock = vi.mocked(injectScript);
+
+injectScriptMock.mockReturnValueOnce(...);
+```
+
+## Conclusion
+
+You don't have to use `#imports` if you don't like - you can continue importing APIs from their submodules. However, using `#imports` is the recommended approach moving forwards.
+
+- As more APIs are added, you won't have to memorize additional import paths.
+- If breaking changes are made to import paths in future major versions, `#imports` won't break.
+
+Happy Coding 😄
+
+> P.S. Yes, this is exactly how [Nuxt's `#imports`](https://nuxt.com/docs/guide/concepts/auto-imports#explicit-imports) works! We use the exact same library, [`unimport`](https://github.com/unjs/unimport).
diff --git a/package.json b/package.json
index 58e92881..ab221e04 100644
--- a/package.json
+++ b/package.json
@@ -26,6 +26,7 @@
"changelogen": "catalog:",
"consola": "catalog:",
"fast-glob": "catalog:",
+ "feed": "catalog:",
"fs-extra": "catalog:",
"lint-staged": "catalog:",
"markdown-it-footnote": "catalog:",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 1637026d..9dcf32f0 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -120,6 +120,9 @@ catalogs:
fast-glob:
specifier: ^3.3.2
version: 3.3.2
+ feed:
+ specifier: ^4.2.2
+ version: 4.2.2
filesize:
specifier: ^10.1.6
version: 10.1.6
@@ -328,6 +331,9 @@ importers:
fast-glob:
specifier: 'catalog:'
version: 3.3.2
+ feed:
+ specifier: 'catalog:'
+ version: 4.2.2
fs-extra:
specifier: 'catalog:'
version: 11.2.0
@@ -3304,6 +3310,10 @@ packages:
picomatch:
optional: true
+ feed@4.2.2:
+ resolution: {integrity: sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ==}
+ engines: {node: '>=0.4.0'}
+
filesize@10.1.6:
resolution: {integrity: sha512-sJslQKU2uM33qH5nqewAwVB2QgR6w1aMNsYUp3aN5rMRyXEwJGmZvaWzeJFNTOXWlHQyBFCWrdj3fV/fsTOX8w==}
engines: {node: '>= 10.4.0'}
@@ -5417,6 +5427,10 @@ packages:
resolution: {integrity: sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==}
engines: {node: '>=12'}
+ xml-js@1.6.11:
+ resolution: {integrity: sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==}
+ hasBin: true
+
xml2js@0.5.0:
resolution: {integrity: sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==}
engines: {node: '>=4.0.0'}
@@ -7865,6 +7879,10 @@ snapshots:
optionalDependencies:
picomatch: 4.0.2
+ feed@4.2.2:
+ dependencies:
+ xml-js: 1.6.11
+
filesize@10.1.6: {}
fill-range@7.1.1:
@@ -10128,6 +10146,10 @@ snapshots:
xdg-basedir@5.1.0: {}
+ xml-js@1.6.11:
+ dependencies:
+ sax: 1.2.4
+
xml2js@0.5.0:
dependencies:
sax: 1.2.4
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
index 43c62341..c2760417 100644
--- a/pnpm-workspace.yaml
+++ b/pnpm-workspace.yaml
@@ -48,6 +48,7 @@ catalog:
esbuild: ^0.25.0
extract-zip: ^2.0.1
fast-glob: ^3.3.2
+ feed: ^4.2.2
filesize: ^10.1.6
fs-extra: ^11.2.0
get-port-please: ^3.1.2