From 3cb2f5fbd249fd0390c1c5eb3b76393843581a67 Mon Sep 17 00:00:00 2001 From: Aaron Klinker Date: Tue, 20 Aug 2024 00:12:58 -0500 Subject: [PATCH] Create all files --- docs/{ => .old}/get-started/assets.md | 0 docs/{ => .old}/get-started/compare.md | 0 docs/{ => .old}/get-started/configuration.md | 0 docs/{ => .old}/get-started/entrypoints.md | 0 docs/{ => .old}/get-started/installation.md | 0 docs/{ => .old}/get-started/introduction.md | 0 docs/{ => .old}/get-started/migrate-to-wxt.md | 0 docs/{ => .old}/get-started/publishing.md | 0 .../guide/directory-structure/app-config.md | 0 .../guide/directory-structure/assets.md | 0 .../guide/directory-structure/components.md | 0 .../guide/directory-structure/composables.md | 0 .../guide/directory-structure/env.md | 0 .../guide/directory-structure/hooks.md | 0 .../guide/directory-structure/output.md | 0 .../guide/directory-structure/package.md | 0 .../guide/directory-structure/public/index.md | 0 .../directory-structure/public/locales.md | 0 .../guide/directory-structure/tsconfig.md | 0 .../guide/directory-structure/utils.md | 0 .../directory-structure/web-ext-config.md | 0 .../guide/directory-structure/wxt-config.md | 0 .../guide/directory-structure/wxt.md | 0 docs/.old/guide/extension-apis/i18n.md | 56 ++++ docs/.old/guide/extension-apis/messaging.md | 36 ++ .../{ => .old}/guide/extension-apis/others.md | 0 docs/.old/guide/extension-apis/scripting.md | 26 ++ docs/.old/guide/extension-apis/storage.md | 313 ++++++++++++++++++ .../guide/go-further/custom-events.md | 0 docs/{ => .old}/guide/go-further/debugging.md | 0 .../guide/go-further/entrypoint-loaders.md | 0 .../{ => .old}/guide/go-further/es-modules.md | 0 .../guide/go-further/handling-updates.md | 0 .../guide/go-further/how-wxt-works.md | 0 .../guide/go-further/remote-code.md | 0 .../guide/go-further/reusable-modules.md | 0 docs/{ => .old}/guide/go-further/testing.md | 0 docs/{ => .old}/guide/go-further/vite.md | 0 .../guide/i18n/build-integrations.md | 0 docs/{ => .old}/guide/i18n/editor-support.md | 0 docs/{ => .old}/guide/i18n/installation.md | 0 docs/{ => .old}/guide/i18n/introduction.md | 0 .../guide/i18n/messages-file-format.md | 0 .../guide/key-concepts/auto-imports.md | 0 .../guide/key-concepts/content-script-ui.md | 0 .../guide/key-concepts/frontend-frameworks.md | 0 .../{ => .old}/guide/key-concepts/manifest.md | 0 .../guide/key-concepts/multiple-browsers.md | 0 .../key-concepts/web-extension-polyfill.md | 0 .../guide/key-concepts/wxt-submit.md | 0 docs/{ => .old}/guide/upgrade-guide/wxt.md | 0 docs/.vitepress/config.ts | 164 ++++----- docs/.vitepress/utils/menus.ts | 15 +- docs/guide/assets/css.md | 0 docs/guide/assets/images.md | 0 docs/guide/assets/wasm.md | 0 docs/guide/config/browser-startup.md | 0 docs/guide/config/environment-variables.md | 0 docs/guide/config/frontend-frameworks.md | 0 docs/guide/config/main-file.md | 0 docs/guide/config/manifest.md | 0 docs/guide/config/runtime.md | 0 docs/guide/config/typescript.md | 0 docs/guide/content-scripts/context.md | 0 docs/guide/content-scripts/ui.md | 0 docs/guide/core-concepts/browser-support.md | 0 docs/guide/core-concepts/entrypoints.md | 0 docs/guide/core-concepts/project-structure.md | 0 docs/guide/core-concepts/vite.md | 0 .../background.md | 0 .../bookmarks.md | 0 .../content-scripts.md | 0 .../entrypoints => entrypoint-types}/css.md | 0 .../devtools.md | 0 .../history.md | 0 .../newtab.md | 0 .../options.md | 0 .../entrypoints => entrypoint-types}/popup.md | 0 .../sandbox.md | 0 .../sidepanel.md | 0 .../unlisted-pages.md | 0 .../unlisted-scripts.md | 0 docs/guide/extension-apis/action.md | 0 docs/guide/extension-apis/basic-usage.md | 0 docs/guide/extension-apis/i18n.md | 56 ---- docs/guide/extension-apis/messaging.md | 36 -- docs/guide/extension-apis/scripting.md | 26 -- docs/guide/extension-apis/storage.md | 313 ------------------ docs/guide/get-started/installation.md | 0 docs/guide/get-started/introduction.md | 0 docs/guide/get-started/migrate.md | 0 docs/guide/maintainence/debugging.md | 0 docs/guide/maintainence/e2e-testing.md | 0 docs/guide/maintainence/unit-testing.md | 0 docs/guide/maintainence/upgrading.md | 0 docs/guide/production/publishing.md | 0 docs/guide/production/remote-code.md | 0 docs/guide/production/testing-updates.md | 0 docs/guide/resources/compare.md | 0 docs/guide/resources/examples.md | 0 docs/guide/resources/how-wxt-works.md | 0 docs/guide/wxt-modules/recipes.md | 0 docs/guide/wxt-modules/using-modules.md | 0 docs/guide/wxt-modules/writing-modules.md | 0 docs/index.md | 4 +- 105 files changed, 535 insertions(+), 510 deletions(-) rename docs/{ => .old}/get-started/assets.md (100%) rename docs/{ => .old}/get-started/compare.md (100%) rename docs/{ => .old}/get-started/configuration.md (100%) rename docs/{ => .old}/get-started/entrypoints.md (100%) rename docs/{ => .old}/get-started/installation.md (100%) rename docs/{ => .old}/get-started/introduction.md (100%) rename docs/{ => .old}/get-started/migrate-to-wxt.md (100%) rename docs/{ => .old}/get-started/publishing.md (100%) rename docs/{ => .old}/guide/directory-structure/app-config.md (100%) rename docs/{ => .old}/guide/directory-structure/assets.md (100%) rename docs/{ => .old}/guide/directory-structure/components.md (100%) rename docs/{ => .old}/guide/directory-structure/composables.md (100%) rename docs/{ => .old}/guide/directory-structure/env.md (100%) rename docs/{ => .old}/guide/directory-structure/hooks.md (100%) rename docs/{ => .old}/guide/directory-structure/output.md (100%) rename docs/{ => .old}/guide/directory-structure/package.md (100%) rename docs/{ => .old}/guide/directory-structure/public/index.md (100%) rename docs/{ => .old}/guide/directory-structure/public/locales.md (100%) rename docs/{ => .old}/guide/directory-structure/tsconfig.md (100%) rename docs/{ => .old}/guide/directory-structure/utils.md (100%) rename docs/{ => .old}/guide/directory-structure/web-ext-config.md (100%) rename docs/{ => .old}/guide/directory-structure/wxt-config.md (100%) rename docs/{ => .old}/guide/directory-structure/wxt.md (100%) create mode 100644 docs/.old/guide/extension-apis/i18n.md create mode 100644 docs/.old/guide/extension-apis/messaging.md rename docs/{ => .old}/guide/extension-apis/others.md (100%) create mode 100644 docs/.old/guide/extension-apis/scripting.md create mode 100644 docs/.old/guide/extension-apis/storage.md rename docs/{ => .old}/guide/go-further/custom-events.md (100%) rename docs/{ => .old}/guide/go-further/debugging.md (100%) rename docs/{ => .old}/guide/go-further/entrypoint-loaders.md (100%) rename docs/{ => .old}/guide/go-further/es-modules.md (100%) rename docs/{ => .old}/guide/go-further/handling-updates.md (100%) rename docs/{ => .old}/guide/go-further/how-wxt-works.md (100%) rename docs/{ => .old}/guide/go-further/remote-code.md (100%) rename docs/{ => .old}/guide/go-further/reusable-modules.md (100%) rename docs/{ => .old}/guide/go-further/testing.md (100%) rename docs/{ => .old}/guide/go-further/vite.md (100%) rename docs/{ => .old}/guide/i18n/build-integrations.md (100%) rename docs/{ => .old}/guide/i18n/editor-support.md (100%) rename docs/{ => .old}/guide/i18n/installation.md (100%) rename docs/{ => .old}/guide/i18n/introduction.md (100%) rename docs/{ => .old}/guide/i18n/messages-file-format.md (100%) rename docs/{ => .old}/guide/key-concepts/auto-imports.md (100%) rename docs/{ => .old}/guide/key-concepts/content-script-ui.md (100%) rename docs/{ => .old}/guide/key-concepts/frontend-frameworks.md (100%) rename docs/{ => .old}/guide/key-concepts/manifest.md (100%) rename docs/{ => .old}/guide/key-concepts/multiple-browsers.md (100%) rename docs/{ => .old}/guide/key-concepts/web-extension-polyfill.md (100%) rename docs/{ => .old}/guide/key-concepts/wxt-submit.md (100%) rename docs/{ => .old}/guide/upgrade-guide/wxt.md (100%) create mode 100644 docs/guide/assets/css.md create mode 100644 docs/guide/assets/images.md create mode 100644 docs/guide/assets/wasm.md create mode 100644 docs/guide/config/browser-startup.md create mode 100644 docs/guide/config/environment-variables.md create mode 100644 docs/guide/config/frontend-frameworks.md create mode 100644 docs/guide/config/main-file.md create mode 100644 docs/guide/config/manifest.md create mode 100644 docs/guide/config/runtime.md create mode 100644 docs/guide/config/typescript.md create mode 100644 docs/guide/content-scripts/context.md create mode 100644 docs/guide/content-scripts/ui.md create mode 100644 docs/guide/core-concepts/browser-support.md create mode 100644 docs/guide/core-concepts/entrypoints.md create mode 100644 docs/guide/core-concepts/project-structure.md create mode 100644 docs/guide/core-concepts/vite.md rename docs/guide/{directory-structure/entrypoints => entrypoint-types}/background.md (100%) rename docs/guide/{directory-structure/entrypoints => entrypoint-types}/bookmarks.md (100%) rename docs/guide/{directory-structure/entrypoints => entrypoint-types}/content-scripts.md (100%) rename docs/guide/{directory-structure/entrypoints => entrypoint-types}/css.md (100%) rename docs/guide/{directory-structure/entrypoints => entrypoint-types}/devtools.md (100%) rename docs/guide/{directory-structure/entrypoints => entrypoint-types}/history.md (100%) rename docs/guide/{directory-structure/entrypoints => entrypoint-types}/newtab.md (100%) rename docs/guide/{directory-structure/entrypoints => entrypoint-types}/options.md (100%) rename docs/guide/{directory-structure/entrypoints => entrypoint-types}/popup.md (100%) rename docs/guide/{directory-structure/entrypoints => entrypoint-types}/sandbox.md (100%) rename docs/guide/{directory-structure/entrypoints => entrypoint-types}/sidepanel.md (100%) rename docs/guide/{directory-structure/entrypoints => entrypoint-types}/unlisted-pages.md (100%) rename docs/guide/{directory-structure/entrypoints => entrypoint-types}/unlisted-scripts.md (100%) create mode 100644 docs/guide/extension-apis/action.md create mode 100644 docs/guide/extension-apis/basic-usage.md create mode 100644 docs/guide/get-started/installation.md create mode 100644 docs/guide/get-started/introduction.md create mode 100644 docs/guide/get-started/migrate.md create mode 100644 docs/guide/maintainence/debugging.md create mode 100644 docs/guide/maintainence/e2e-testing.md create mode 100644 docs/guide/maintainence/unit-testing.md create mode 100644 docs/guide/maintainence/upgrading.md create mode 100644 docs/guide/production/publishing.md create mode 100644 docs/guide/production/remote-code.md create mode 100644 docs/guide/production/testing-updates.md create mode 100644 docs/guide/resources/compare.md create mode 100644 docs/guide/resources/examples.md create mode 100644 docs/guide/resources/how-wxt-works.md create mode 100644 docs/guide/wxt-modules/recipes.md create mode 100644 docs/guide/wxt-modules/using-modules.md create mode 100644 docs/guide/wxt-modules/writing-modules.md diff --git a/docs/get-started/assets.md b/docs/.old/get-started/assets.md similarity index 100% rename from docs/get-started/assets.md rename to docs/.old/get-started/assets.md diff --git a/docs/get-started/compare.md b/docs/.old/get-started/compare.md similarity index 100% rename from docs/get-started/compare.md rename to docs/.old/get-started/compare.md diff --git a/docs/get-started/configuration.md b/docs/.old/get-started/configuration.md similarity index 100% rename from docs/get-started/configuration.md rename to docs/.old/get-started/configuration.md diff --git a/docs/get-started/entrypoints.md b/docs/.old/get-started/entrypoints.md similarity index 100% rename from docs/get-started/entrypoints.md rename to docs/.old/get-started/entrypoints.md diff --git a/docs/get-started/installation.md b/docs/.old/get-started/installation.md similarity index 100% rename from docs/get-started/installation.md rename to docs/.old/get-started/installation.md diff --git a/docs/get-started/introduction.md b/docs/.old/get-started/introduction.md similarity index 100% rename from docs/get-started/introduction.md rename to docs/.old/get-started/introduction.md diff --git a/docs/get-started/migrate-to-wxt.md b/docs/.old/get-started/migrate-to-wxt.md similarity index 100% rename from docs/get-started/migrate-to-wxt.md rename to docs/.old/get-started/migrate-to-wxt.md diff --git a/docs/get-started/publishing.md b/docs/.old/get-started/publishing.md similarity index 100% rename from docs/get-started/publishing.md rename to docs/.old/get-started/publishing.md diff --git a/docs/guide/directory-structure/app-config.md b/docs/.old/guide/directory-structure/app-config.md similarity index 100% rename from docs/guide/directory-structure/app-config.md rename to docs/.old/guide/directory-structure/app-config.md diff --git a/docs/guide/directory-structure/assets.md b/docs/.old/guide/directory-structure/assets.md similarity index 100% rename from docs/guide/directory-structure/assets.md rename to docs/.old/guide/directory-structure/assets.md diff --git a/docs/guide/directory-structure/components.md b/docs/.old/guide/directory-structure/components.md similarity index 100% rename from docs/guide/directory-structure/components.md rename to docs/.old/guide/directory-structure/components.md diff --git a/docs/guide/directory-structure/composables.md b/docs/.old/guide/directory-structure/composables.md similarity index 100% rename from docs/guide/directory-structure/composables.md rename to docs/.old/guide/directory-structure/composables.md diff --git a/docs/guide/directory-structure/env.md b/docs/.old/guide/directory-structure/env.md similarity index 100% rename from docs/guide/directory-structure/env.md rename to docs/.old/guide/directory-structure/env.md diff --git a/docs/guide/directory-structure/hooks.md b/docs/.old/guide/directory-structure/hooks.md similarity index 100% rename from docs/guide/directory-structure/hooks.md rename to docs/.old/guide/directory-structure/hooks.md diff --git a/docs/guide/directory-structure/output.md b/docs/.old/guide/directory-structure/output.md similarity index 100% rename from docs/guide/directory-structure/output.md rename to docs/.old/guide/directory-structure/output.md diff --git a/docs/guide/directory-structure/package.md b/docs/.old/guide/directory-structure/package.md similarity index 100% rename from docs/guide/directory-structure/package.md rename to docs/.old/guide/directory-structure/package.md diff --git a/docs/guide/directory-structure/public/index.md b/docs/.old/guide/directory-structure/public/index.md similarity index 100% rename from docs/guide/directory-structure/public/index.md rename to docs/.old/guide/directory-structure/public/index.md diff --git a/docs/guide/directory-structure/public/locales.md b/docs/.old/guide/directory-structure/public/locales.md similarity index 100% rename from docs/guide/directory-structure/public/locales.md rename to docs/.old/guide/directory-structure/public/locales.md diff --git a/docs/guide/directory-structure/tsconfig.md b/docs/.old/guide/directory-structure/tsconfig.md similarity index 100% rename from docs/guide/directory-structure/tsconfig.md rename to docs/.old/guide/directory-structure/tsconfig.md diff --git a/docs/guide/directory-structure/utils.md b/docs/.old/guide/directory-structure/utils.md similarity index 100% rename from docs/guide/directory-structure/utils.md rename to docs/.old/guide/directory-structure/utils.md diff --git a/docs/guide/directory-structure/web-ext-config.md b/docs/.old/guide/directory-structure/web-ext-config.md similarity index 100% rename from docs/guide/directory-structure/web-ext-config.md rename to docs/.old/guide/directory-structure/web-ext-config.md diff --git a/docs/guide/directory-structure/wxt-config.md b/docs/.old/guide/directory-structure/wxt-config.md similarity index 100% rename from docs/guide/directory-structure/wxt-config.md rename to docs/.old/guide/directory-structure/wxt-config.md diff --git a/docs/guide/directory-structure/wxt.md b/docs/.old/guide/directory-structure/wxt.md similarity index 100% rename from docs/guide/directory-structure/wxt.md rename to docs/.old/guide/directory-structure/wxt.md diff --git a/docs/.old/guide/extension-apis/i18n.md b/docs/.old/guide/extension-apis/i18n.md new file mode 100644 index 000000000..e02e01345 --- /dev/null +++ b/docs/.old/guide/extension-apis/i18n.md @@ -0,0 +1,56 @@ +# Internationalization + +This guide is for using the vanilla, `browser.i18n` APIs. There are two other alternatives: + +1. [`@wxt-dev/i18n`](/guide/i18n/installation) - a wrapper around `browser.i18n` APIs with additional features, a simplified localization file format, and editor support +2. Third party packages - You can use any i18n package on NPM, most of which are more feature rich than `browser.i18n` and `@wxt-dev/i18n` + +:::info +Currently, using the `browser.i18n` APIs are the recommended approach. WXT has some built-in support for them and they work well enough. `@wxt-dev/i18n` was recently released, and it will become the recommended approach after some of the bugs have been worked out. Head over to [it's docs](/guide/i18n/introduction.md) to learn more. +::: + +## Setup + +First familiarize yourself with [Chrome's docs](https://developer.chrome.com/docs/extensions/reference/api/i18n). The only difference when using these APIs with WXT is where you put the localization files - in the [`public` directory](/guide/directory-structure/public/). + +``` +/ +└─ public/ + └─ _locales/ + ├─ en/ + │ └─ messages.json + ├─ de/ + │ └─ messages.json + └─ ko/ + └─ messages.json +``` + +Next, to set a `default_locale` on your manifest, add it to your `wxt.config.ts` file: + +```ts +// wxt.config.ts +export default defineConfig({ + manifest: { + default_locale: 'en', + name: '__MSG_extName__', + description: '__MSG_extDescription__', + }, +}); +``` + +> You can localize the `name` and `description` of your extension from the `manifest` config as well. + +Finally, to get a translation, call `browser.i18n.getMessage`: + +```ts +browser.i18n.getMessage('extName'); +browser.i18n.getMessage('extDescription'); +browser.i18n.getMessage(/* etc */); +``` + +## Examples + +See the official localization examples for more details: + +- [I18n](https://github.com/wxt-dev/wxt-examples/tree/main/examples/vanilla-i18n#readme) +- [Vue I18n](https://github.com/wxt-dev/wxt-examples/tree/main/examples/vue-i18n#readme) diff --git a/docs/.old/guide/extension-apis/messaging.md b/docs/.old/guide/extension-apis/messaging.md new file mode 100644 index 000000000..a55f1355c --- /dev/null +++ b/docs/.old/guide/extension-apis/messaging.md @@ -0,0 +1,36 @@ +# Messaging + +## Overview + +Follow [Chrome's message passing guide](https://developer.chrome.com/docs/extensions/mv3/messaging/) to understand how message passing works in web extensions. In Google's examples, just replace `chrome` with `browser`, and it will work in WXT. + +Here's a basic request/response example: + +```ts +// popup/main.ts +const res = await browser.runtime.sendMessage('ping'); + +console.log(res); // "pong" +``` + +```ts +// background.ts +export default defineBackground(() => { + browser.runtime.onMessage.addListener((message, sender, sendResponse) => { + console.log(message); // "ping" + + // Wait 1 second and respond with "pong" + setTimeout(() => sendResponse('pong'), 1000); + return true; + }); +}); +``` + +## Third Party Libraries + +There are a number of message passing libraries you can use to improve the message passing experience. + +- [`@webext-core/messaging`](https://webext-core.aklinker1.io/guide/messaging/) - "A light-weight, type-safe wrapper around the `browser.runtime` messaging APIs" +- [`@webext-core/proxy-service`](https://webext-core.aklinker1.io/guide/proxy-service/) - "Create RPC-like services that can be called from anywhere but run in the background" +- [`webext-bridge`](https://github.com/zikaari/webext-bridge) - "Messaging in Web Extensions made super easy. Out of the box." +- [`trpc-chrome`](https://www.npmjs.com/package/trpc-chrome) - "tRPC adapter for Web Extensions 🧩" diff --git a/docs/guide/extension-apis/others.md b/docs/.old/guide/extension-apis/others.md similarity index 100% rename from docs/guide/extension-apis/others.md rename to docs/.old/guide/extension-apis/others.md diff --git a/docs/.old/guide/extension-apis/scripting.md b/docs/.old/guide/extension-apis/scripting.md new file mode 100644 index 000000000..9565a739f --- /dev/null +++ b/docs/.old/guide/extension-apis/scripting.md @@ -0,0 +1,26 @@ +# `browser.scripting` + +[Chrome Docs](https://developer.chrome.com/docs/extensions/reference/api/scripting) • [Firefox Docs](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/scripting) + +Refer to the browser docs above for basics on how the API works. + +## Execute Script Return Values + +When using `browser.scripting.executeScript`, you can execute content scripts or unlisted scripts. To return a value, just return a value from the script's main function. + +```ts +// entrypoints/background.ts +const res = await browser.scripting.executeScript({ + target: { tabId }, + files: ['injected.js'], +}); +console.log(res); // "Hello John!" +``` + +```ts +// entrypoints/injected.js +export default defineContentScript(() => { + console.log('Script was injected!'); + return 'Hello John!'; +}); +``` diff --git a/docs/.old/guide/extension-apis/storage.md b/docs/.old/guide/extension-apis/storage.md new file mode 100644 index 000000000..9d593074d --- /dev/null +++ b/docs/.old/guide/extension-apis/storage.md @@ -0,0 +1,313 @@ +--- +outline: deep +--- + +# Storage API + +WXT provides a simplified API to replace the `browser.storage.*` APIs. Use the `storage` auto-import from `wxt/storage` or import it manually to get started: + +```ts +import { storage } from 'wxt/storage'; +``` + +:::warning +To use the `wxt/storage` API, the `"storage"` permission must be added to the manifest: + +```ts +// wxt.config.ts +export default defineConfig({ + manifest: { + permissions: ['storage'], + }, +}); +``` + +More info on permissions [here](/guide/key-concepts/manifest#permissions). +::: + +[[toc]] + +## Basic Usage + +All storage keys must be prefixed by their storage area. + +```ts +// ❌ This will throw an error +await storage.getItem('installDate'); + +// ✅ This is good +await storage.getItem('local:installDate'); +``` + +You can use `local:`, `session:`, `sync:`, or `managed:`. + +If you use TypeScript, you can add a type parameter to most methods to specify the expected type of the key's value: + +```ts +await storage.getItem('local:installDate'); +await storage.watch( + 'local:installDate', + (newInstallDate, oldInstallDate) => { + // ... + }, +); +await storage.getMeta<{ v: number }>('local:installDate'); +``` + +For a full list of methods available, see the [API reference](/api/reference/wxt/storage/interfaces/WxtStorage). + +## Watchers + +To listen for storage changes, use the `storage.watch` function. It lets you setup a listener for a single key: + +```ts +const unwatch = storage.watch('local:counter', (newCount, oldCount) => { + console.log('Count changed:', { newCount, oldCount }); +}); +``` + +To remove the listener, call the returned `unwatch` function: + +```ts +const unwatch = storage.watch(...); + +// Some time later... +unwatch(); +``` + +## Metadata + +`wxt/storage` also supports setting metadata for keys, stored at `key + "$"`. Metadata is a collection of properties associated with a key. It might be a version number, last modified date, etc. + +[Other than versioning](#versioning), you are responsible for managing a field's metadata: + +```ts +await Promise.all([ + storage.setItem('local:preference', true), + storage.setMeta('local:preference', { lastModified: Date.now() }), +]); +``` + +When setting different properties of metadata from multiple calls, the properties are combined instead of overwritten: + +```ts +await storage.setMeta('local:preference', { lastModified: Date.now() }); +await storage.setMeta('local:preference', { v: 2 }); + +await storage.getMeta('local:preference'); // { v: 2, lastModified: 1703690746007 } +``` + +You can remove all metadata associated with a key, or just specific properties: + +```ts +// Remove all properties +await storage.removeMeta('local:preference'); + +// Remove one property +await storage.removeMeta('local:preference', 'lastModified'); + +// Remove multiple properties +await storage.removeMeta('local:preference', ['lastModified', 'v']); +``` + +## Defining Storage Items + +Writing the key and type parameter for the same key over and over again can be annoying. As an alternative, you can use `storage.defineItem` to create a "storage item". + +Storage items contain the same APIs as the `storage` variable, but you can configure its type, default value, and more in a single place: + +```ts +// utils/storage.ts +const showChangelogOnUpdate = storage.defineItem( + 'local:showChangelogOnUpdate', + { + fallback: true, + }, +); +``` + +Now, instead of using the `storage` variable, you can use the helper functions on the storage item you created: + +```ts +await showChangelogOnUpdate.getValue(); +await showChangelogOnUpdate.setValue(false); +await showChangelogOnUpdate.removeValue(); +const unwatch = showChangelogOnUpdate.watch((newValue) => { + // ... +}); +``` + +For a full list of properties and methods available, see the [API reference](/api/reference/wxt/storage/interfaces/WxtStorageItem). + +### Versioning + +You can add versioning to storage items if you expect them to grow or change over time. When defining the first version of an item, start with version 1. + +For example, consider a storage item that stores a list of websites that are ignored by an extension. + +:::code-group + +```ts [v1] +type IgnoredWebsiteV1 = string; + +export const ignoredWebsites = storage.defineItem( + 'local:ignoredWebsites', + { + fallback: [], + version: 1, + }, +); +``` + + +```ts [v2] +import { nanoid } from 'nanoid'; // [!code ++] + +type IgnoredWebsiteV1 = string; +interface IgnoredWebsiteV2 { // [!code ++] + id: string; // [!code ++] + website: string; // [!code ++] +} // [!code ++] + +export const ignoredWebsites = storage.defineItem( // [!code --] +export const ignoredWebsites = storage.defineItem( // [!code ++] + 'local:ignoredWebsites', + { + fallback: [], + version: 1, // [!code --] + version: 2, // [!code ++] + migrations: { // [!code ++] + // Ran when migrating from v1 to v2 // [!code ++] + 2: (websites: IgnoredWebsiteV1[]): IgnoredWebsiteV2[] => { // [!code ++] + return websites.map((website) => ({ id: nanoid(), website })); // [!code ++] + }, // [!code ++] + }, // [!code ++] + }, +); +``` + + +```ts [v3] +import { nanoid } from 'nanoid'; + +type IgnoredWebsiteV1 = string; +interface IgnoredWebsiteV2 { + id: string; + website: string; +} +interface IgnoredWebsiteV3 { // [!code ++] + id: string; // [!code ++] + website: string; // [!code ++] + enabled: boolean; // [!code ++] +} // [!code ++] + +export const ignoredWebsites = storage.defineItem( // [!code --] +export const ignoredWebsites = storage.defineItem( // [!code ++] + 'local:ignoredWebsites', + { + fallback: [], + version: 2, // [!code --] + version: 3, // [!code ++] + migrations: { + // Ran when migrating from v1 to v2 + 2: (websites: IgnoredWebsiteV1[]): IgnoredWebsiteV2[] => { + return websites.map((website) => ({ id: nanoid(), website })); + }, + // Ran when migrating from v2 to v3 // [!code ++] + 3: (websites: IgnoredWebsiteV2[]): IgnoredWebsiteV3[] => { // [!code ++] + return websites.map((website) => ({ ...website, enabled: true })); // [!code ++] + }, // [!code ++] + }, + }, +); +``` + +::: + +:::info +Internally, this uses a metadata property called `v` to track the value's current version. +::: + +In this case, we thought that the ignored website list might change in the future, and were able to setup a versioned storage item from the start. + +Realistically, you won't know a item needs versioned until you need to change it's schema. Thankfully, it's simple to add versioning to an unversioned storage item. + +When a previous version isn't found, WXT assumes the version was `1`. That means you just need to set `version: 2` and add a migration for `2`, and it will just work! + +Lets look at the same ignored websites example from before, but start with an unversioned item this time: + +:::code-group + +```ts [Unversioned] +export const ignoredWebsites = storage.defineItem( + 'local:ignoredWebsites', + { + fallback: [], + }, +); +``` + + +```ts [v2] +import { nanoid } from 'nanoid'; // [!code ++] + +// Retroactively add a type for the first version // [!code ++] +type IgnoredWebsiteV1 = string; // [!code ++] +interface IgnoredWebsiteV2 { // [!code ++] + id: string; // [!code ++] + website: string; // [!code ++] +} // [!code ++] + +export const ignoredWebsites = storage.defineItem( // [!code --] +export const ignoredWebsites = storage.defineItem( // [!code ++] + 'local:ignoredWebsites', + { + fallback: [], + version: 2, // [!code ++] + migrations: { // [!code ++] + // Ran when migrating from v1 to v2 // [!code ++] + 2: (websites: IgnoredWebsiteV1[]): IgnoredWebsiteV2[] => { // [!code ++] + return websites.map((website) => ({ id: nanoid(), website })); // [!code ++] + }, // [!code ++] + }, // [!code ++] + }, +); +``` + +::: + +### Running Migrations + +As soon as `storage.defineItem` is called, WXT checks if migrations need to be ran, and if so, runs them. Calls to get or update the storage item's value or metadata (`getValue`, `setValue`, `removeValue`, `getMeta`, etc) will automatically wait for the migration process to finish before actually reading or writing values. + +### Default Values + +With `storage.defineItem`, there are multiple ways of defining default values: + +1. `fallback` - Return this value from `getValue` instead of `null` if the value is missing. + + This option is great for providing default values for settings: + + ```ts + const theme = storage.defineItem('local:theme', { + fallback: 'dark', + }); + const allowEditing = storage.defineItem('local:allow-editing', { + fallback: true, + }); + ``` + +2. `init` - Initialize and save a value in storage if it is not already saved. + + This is great for values that need to be initialized or set once: + + ```ts + const userId = storage.defineItem('local:user-id', { + init: () => globalThis.crypto.randomUUID(), + }); + const installDate = storage.defineItem('local:install-date', { + init: () => new Date().getTime(), + }); + ``` + + The value is initialized in storage immediately. diff --git a/docs/guide/go-further/custom-events.md b/docs/.old/guide/go-further/custom-events.md similarity index 100% rename from docs/guide/go-further/custom-events.md rename to docs/.old/guide/go-further/custom-events.md diff --git a/docs/guide/go-further/debugging.md b/docs/.old/guide/go-further/debugging.md similarity index 100% rename from docs/guide/go-further/debugging.md rename to docs/.old/guide/go-further/debugging.md diff --git a/docs/guide/go-further/entrypoint-loaders.md b/docs/.old/guide/go-further/entrypoint-loaders.md similarity index 100% rename from docs/guide/go-further/entrypoint-loaders.md rename to docs/.old/guide/go-further/entrypoint-loaders.md diff --git a/docs/guide/go-further/es-modules.md b/docs/.old/guide/go-further/es-modules.md similarity index 100% rename from docs/guide/go-further/es-modules.md rename to docs/.old/guide/go-further/es-modules.md diff --git a/docs/guide/go-further/handling-updates.md b/docs/.old/guide/go-further/handling-updates.md similarity index 100% rename from docs/guide/go-further/handling-updates.md rename to docs/.old/guide/go-further/handling-updates.md diff --git a/docs/guide/go-further/how-wxt-works.md b/docs/.old/guide/go-further/how-wxt-works.md similarity index 100% rename from docs/guide/go-further/how-wxt-works.md rename to docs/.old/guide/go-further/how-wxt-works.md diff --git a/docs/guide/go-further/remote-code.md b/docs/.old/guide/go-further/remote-code.md similarity index 100% rename from docs/guide/go-further/remote-code.md rename to docs/.old/guide/go-further/remote-code.md diff --git a/docs/guide/go-further/reusable-modules.md b/docs/.old/guide/go-further/reusable-modules.md similarity index 100% rename from docs/guide/go-further/reusable-modules.md rename to docs/.old/guide/go-further/reusable-modules.md diff --git a/docs/guide/go-further/testing.md b/docs/.old/guide/go-further/testing.md similarity index 100% rename from docs/guide/go-further/testing.md rename to docs/.old/guide/go-further/testing.md diff --git a/docs/guide/go-further/vite.md b/docs/.old/guide/go-further/vite.md similarity index 100% rename from docs/guide/go-further/vite.md rename to docs/.old/guide/go-further/vite.md diff --git a/docs/guide/i18n/build-integrations.md b/docs/.old/guide/i18n/build-integrations.md similarity index 100% rename from docs/guide/i18n/build-integrations.md rename to docs/.old/guide/i18n/build-integrations.md diff --git a/docs/guide/i18n/editor-support.md b/docs/.old/guide/i18n/editor-support.md similarity index 100% rename from docs/guide/i18n/editor-support.md rename to docs/.old/guide/i18n/editor-support.md diff --git a/docs/guide/i18n/installation.md b/docs/.old/guide/i18n/installation.md similarity index 100% rename from docs/guide/i18n/installation.md rename to docs/.old/guide/i18n/installation.md diff --git a/docs/guide/i18n/introduction.md b/docs/.old/guide/i18n/introduction.md similarity index 100% rename from docs/guide/i18n/introduction.md rename to docs/.old/guide/i18n/introduction.md diff --git a/docs/guide/i18n/messages-file-format.md b/docs/.old/guide/i18n/messages-file-format.md similarity index 100% rename from docs/guide/i18n/messages-file-format.md rename to docs/.old/guide/i18n/messages-file-format.md diff --git a/docs/guide/key-concepts/auto-imports.md b/docs/.old/guide/key-concepts/auto-imports.md similarity index 100% rename from docs/guide/key-concepts/auto-imports.md rename to docs/.old/guide/key-concepts/auto-imports.md diff --git a/docs/guide/key-concepts/content-script-ui.md b/docs/.old/guide/key-concepts/content-script-ui.md similarity index 100% rename from docs/guide/key-concepts/content-script-ui.md rename to docs/.old/guide/key-concepts/content-script-ui.md diff --git a/docs/guide/key-concepts/frontend-frameworks.md b/docs/.old/guide/key-concepts/frontend-frameworks.md similarity index 100% rename from docs/guide/key-concepts/frontend-frameworks.md rename to docs/.old/guide/key-concepts/frontend-frameworks.md diff --git a/docs/guide/key-concepts/manifest.md b/docs/.old/guide/key-concepts/manifest.md similarity index 100% rename from docs/guide/key-concepts/manifest.md rename to docs/.old/guide/key-concepts/manifest.md diff --git a/docs/guide/key-concepts/multiple-browsers.md b/docs/.old/guide/key-concepts/multiple-browsers.md similarity index 100% rename from docs/guide/key-concepts/multiple-browsers.md rename to docs/.old/guide/key-concepts/multiple-browsers.md diff --git a/docs/guide/key-concepts/web-extension-polyfill.md b/docs/.old/guide/key-concepts/web-extension-polyfill.md similarity index 100% rename from docs/guide/key-concepts/web-extension-polyfill.md rename to docs/.old/guide/key-concepts/web-extension-polyfill.md diff --git a/docs/guide/key-concepts/wxt-submit.md b/docs/.old/guide/key-concepts/wxt-submit.md similarity index 100% rename from docs/guide/key-concepts/wxt-submit.md rename to docs/.old/guide/key-concepts/wxt-submit.md diff --git a/docs/guide/upgrade-guide/wxt.md b/docs/.old/guide/upgrade-guide/wxt.md similarity index 100% rename from docs/guide/upgrade-guide/wxt.md rename to docs/.old/guide/upgrade-guide/wxt.md diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index 33a975369..4ea1303de 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -8,6 +8,8 @@ import { prepareTypedocSidebar, } from './utils/menus'; import { meta, script } from './utils/head'; +import { version as wxtVersion } from '../../packages/wxt/package.json'; +import { version as i18nVersion } from '../../packages/i18n/package.json'; const title = 'Next-gen Web Extension Framework'; const titleSuffix = ' – WXT'; @@ -64,92 +66,104 @@ export default defineConfig({ ], nav: [ - navItem('Get Started', '/get-started/introduction'), - navItem('Guide', '/guide/key-concepts/manifest'), - navItem('API', '/api/reference/wxt'), + navItem('Guide', '/guide/get-started/installation'), navItem('Examples', '/examples'), + navItem('API', '/api/reference/wxt'), + navItem('---', [ + navItem('wxt', [ + navItem(`v${wxtVersion}`, '/'), + navItem( + `Changelog`, + 'https://github.com/wxt-dev/wxt/blob/main/packages/wxt/CHANGELOG.md', + ), + ]), + navItem('@wxt-dev/i18n', [ + navItem(`v${i18nVersion}`, '/i18n'), + navItem( + `Changelog`, + 'https://github.com/wxt-dev/wxt/blob/main/packages/i18n/CHANGELOG.md', + ), + ]), + ]), ], sidebar: { - '/get-started/': menuRoot([ - menuGroup('Get Started', '/get-started/', [ - menuItem('Introduction', 'introduction'), - menuItem('Installation', 'installation'), - menuItem('Configuration', 'configuration'), - menuItem('Entrypoints', 'entrypoints'), - menuItem('Assets', 'assets'), - menuItem('Publishing', 'publishing'), - menuItem('Migrate to WXT', 'migrate-to-wxt'), - menuItem('Compare', 'compare'), - ]), - ]), '/guide/': menuRoot([ - menuGroup('Key Concepts', '/guide/key-concepts/', [ - menuItem('Manifest', 'manifest'), - menuItem('Auto-imports', 'auto-imports'), - menuItem('Web Extension Polyfill', 'web-extension-polyfill'), - menuItem('Frontend Frameworks', 'frontend-frameworks'), - menuItem('Content Script UI', 'content-script-ui'), + menuGroup('Get Started', '/guide/get-started/', [ + menuItem('Introduction', 'introduction.md'), + menuItem('Installation', 'installation.md'), + menuItem('Migrate to WXT', 'migrate.md'), ]), - menuGroup('Directory Structure', '/guide/directory-structure/', [ - // Folders - menuItem('.output/', 'output'), - menuItem('.wxt/', 'wxt'), - menuItem('assets/', 'assets'), - menuItem('components/', 'components'), - menuItem('composables/', 'composables'), - menuGroup('entrypoints/', '/guide/directory-structure/entrypoints/', [ - menuItem('background', 'background.md'), - menuItem('bookmarks', 'bookmarks.md'), - menuItem('*.content.ts', 'content-scripts.md'), - menuItem('*.css', 'css.md'), - menuItem('devtools', 'devtools.md'), - menuItem('history', 'history.md'), - menuItem('newtab', 'newtab.md'), - menuItem('options', 'options.md'), - menuItem('popup', 'popup.md'), - menuItem('sandbox', 'sandbox.md'), - menuItem('sidepanel', 'sidepanel.md'), - menuItem('*.html', 'unlisted-pages.md'), - menuItem('*.ts', 'unlisted-scripts.md'), - ]), - menuItem('hooks/', 'hooks'), - menuItem('public/', 'public/', [ - menuItem('_locales/', 'public/locales'), - ]), - menuItem('utils/', 'utils'), - - // Files - menuItem('.env', 'env'), - menuItem('app.config.ts', 'app-config'), - menuItem('package.json', 'package'), - menuItem('tsconfig.json', 'tsconfig'), - menuItem('web-ext.config.ts', 'web-ext-config'), - menuItem('wxt.config.ts', 'wxt-config'), + menuGroup('Core Concepts', '/guide/core-concepts/', [ + menuItem('Project Structure', 'project-structure.md'), + menuItem('Entrypoints', 'entrypoints.md'), + menuItem('Browser Support', 'browser-support.md'), + menuItem('Vite', 'vite.md'), + ]), + menuGroup('Configuration', '/guide/config/', [ + menuItem('Main Config File', 'main-file.md'), + menuItem('Manifest', 'manifest.md'), + menuItem('Frontend Frameworks', 'frontend-frameworks.md'), + menuItem('Browser Startup', 'browser-startup.md'), + menuItem('Environment Variables', 'environment-variables.md'), + menuItem('Runtime Config', 'runtime.md'), + menuItem('TypeScript', 'typescript.md'), ]), menuGroup('Extension APIs', '/guide/extension-apis/', [ - menuItem('Storage', 'storage'), - menuItem('Messaging', 'messaging'), - menuItem('I18n', 'i18n'), - menuItem('Scripting', 'scripting'), - menuItem('Others', 'others'), + menuItem('Basic Usage', 'basic-usage.md'), + menuItem('Action', 'action.md'), + menuItem('I18n', 'i18n.md'), + menuItem('Messaging', 'messaging.md'), + menuItem('Scripting', 'scripting.md'), + menuItem('Storage', 'storage.md'), + ]), + menuGroup('Assets', '/guide/assets/', [ + menuItem('Images', 'images.md'), + menuItem('CSS', 'css.md'), + menuItem('WASM', 'wasm.md'), + ]), + menuGroup('Content Scripts', '/guide/content-scripts/', [ + menuItem('UI', 'ui.md'), + menuItem('Content Script Context', 'context.md'), ]), - menuGroup('Go Further', '/guide/go-further/', [ - menuItem('Testing', 'testing'), - menuItem('ES Modules', 'es-modules'), - menuItem('Debugging', 'debugging'), - menuItem('Handling Updates', 'handling-updates'), - menuItem('Vite', 'vite'), - menuItem('Custom Events', 'custom-events'), - menuItem('Reusable Modules', 'reusable-modules'), - menuItem('Remote Code', 'remote-code'), - menuItem('Entrypoint Loaders', 'entrypoint-loaders'), - menuItem('How WXT Works', 'how-wxt-works'), + menuGroup('WXT Modules', '/guide/wxt-modules/', [ + menuItem('Using Modules', 'using-modules.md'), + menuItem('Writing Modules', 'writing-modules.md'), + menuItem('Recipes', 'recipes.md'), ]), - menuGroup('Upgrade Guide', '/guide/upgrade-guide/', [ - menuItem('wxt', 'wxt'), + menuGroup('Maintain Your Project', '/guide/maintainence/', [ + menuItem('Upgrading WXT', 'upgrading.md'), + menuItem('Unit Testing', 'unit-testing.md'), + menuItem('E2E Testing', 'e2e-testing.md'), + menuItem('Debugging', 'debugging.md'), ]), - menuGroup('@wxt-dev/i18n', '/guide/i18n/', [ + menuGroup('Going to Production', '/guide/production/', [ + menuItem('Publishing', 'publishing.md'), + menuItem('Bundle Remote Code', 'remote-code.md'), + menuItem('Testing Updates', 'testing-updates.md'), + ]), + menuGroup('Entrypoint Types', '/guide/entrypoint-types/', [ + menuItem('Background', 'background.md'), + menuItem('Bookmarks', 'bookmarks.md'), + menuItem('Content Script', 'content-scripts.md'), + menuItem('CSS', 'css.md'), + menuItem('Devtools', 'devtools.md'), + menuItem('History', 'history.md'), + menuItem('Newtab', 'newtab.md'), + menuItem('Options', 'options.md'), + menuItem('Popup', 'popup.md'), + menuItem('Sandbox', 'sandbox.md'), + menuItem('Sidepanel', 'sidepanel.md'), + menuItem('Unlisted HTML', 'unlisted-pages.md'), + menuItem('Unlisted Script', 'unlisted-scripts.md'), + ]), + menuGroup('Resources', '/guide/resources/', [ + menuItem('Compare', 'compare.md'), + menuItem('How WXT Works', 'how-wxt-works.md'), + ]), + ]), + '/i18n/': menuRoot([ + menuGroup('@wxt-dev/i18n', '/i18n/', [ menuItem('Introduction', 'introduction.md'), menuItem('Installation', 'installation.md'), menuItem('Messages File Format', 'messages-file-format.md'), diff --git a/docs/.vitepress/utils/menus.ts b/docs/.vitepress/utils/menus.ts index aad00c56b..b01d924ad 100644 --- a/docs/.vitepress/utils/menus.ts +++ b/docs/.vitepress/utils/menus.ts @@ -2,9 +2,20 @@ import { DefaultTheme } from 'vitepress'; type SidebarItem = DefaultTheme.SidebarItem; type NavItem = DefaultTheme.NavItem; +type NavItemWithLink = DefaultTheme.NavItemWithLink; +type NavItemWithChildren = DefaultTheme.NavItemWithChildren; +type NavItemChildren = DefaultTheme.NavItemChildren; -export function navItem(text: string, link: string): NavItem { - return { text, link }; +export function navItem(text: string): NavItemChildren; +export function navItem(text: string, link: string): NavItemChildren; +export function navItem(text: string, items: any[]): NavItemWithChildren; +export function navItem(text: string, arg2?: unknown): any { + if (typeof arg2 === 'string') { + return { text, link: arg2 }; + } else if (Array.isArray(arg2)) { + return { text, items: arg2 }; + } + return { text }; } export function menuRoot(items: SidebarItem[]) { diff --git a/docs/guide/assets/css.md b/docs/guide/assets/css.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/guide/assets/images.md b/docs/guide/assets/images.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/guide/assets/wasm.md b/docs/guide/assets/wasm.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/guide/config/browser-startup.md b/docs/guide/config/browser-startup.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/guide/config/environment-variables.md b/docs/guide/config/environment-variables.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/guide/config/frontend-frameworks.md b/docs/guide/config/frontend-frameworks.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/guide/config/main-file.md b/docs/guide/config/main-file.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/guide/config/manifest.md b/docs/guide/config/manifest.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/guide/config/runtime.md b/docs/guide/config/runtime.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/guide/config/typescript.md b/docs/guide/config/typescript.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/guide/content-scripts/context.md b/docs/guide/content-scripts/context.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/guide/content-scripts/ui.md b/docs/guide/content-scripts/ui.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/guide/core-concepts/browser-support.md b/docs/guide/core-concepts/browser-support.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/guide/core-concepts/entrypoints.md b/docs/guide/core-concepts/entrypoints.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/guide/core-concepts/project-structure.md b/docs/guide/core-concepts/project-structure.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/guide/core-concepts/vite.md b/docs/guide/core-concepts/vite.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/guide/directory-structure/entrypoints/background.md b/docs/guide/entrypoint-types/background.md similarity index 100% rename from docs/guide/directory-structure/entrypoints/background.md rename to docs/guide/entrypoint-types/background.md diff --git a/docs/guide/directory-structure/entrypoints/bookmarks.md b/docs/guide/entrypoint-types/bookmarks.md similarity index 100% rename from docs/guide/directory-structure/entrypoints/bookmarks.md rename to docs/guide/entrypoint-types/bookmarks.md diff --git a/docs/guide/directory-structure/entrypoints/content-scripts.md b/docs/guide/entrypoint-types/content-scripts.md similarity index 100% rename from docs/guide/directory-structure/entrypoints/content-scripts.md rename to docs/guide/entrypoint-types/content-scripts.md diff --git a/docs/guide/directory-structure/entrypoints/css.md b/docs/guide/entrypoint-types/css.md similarity index 100% rename from docs/guide/directory-structure/entrypoints/css.md rename to docs/guide/entrypoint-types/css.md diff --git a/docs/guide/directory-structure/entrypoints/devtools.md b/docs/guide/entrypoint-types/devtools.md similarity index 100% rename from docs/guide/directory-structure/entrypoints/devtools.md rename to docs/guide/entrypoint-types/devtools.md diff --git a/docs/guide/directory-structure/entrypoints/history.md b/docs/guide/entrypoint-types/history.md similarity index 100% rename from docs/guide/directory-structure/entrypoints/history.md rename to docs/guide/entrypoint-types/history.md diff --git a/docs/guide/directory-structure/entrypoints/newtab.md b/docs/guide/entrypoint-types/newtab.md similarity index 100% rename from docs/guide/directory-structure/entrypoints/newtab.md rename to docs/guide/entrypoint-types/newtab.md diff --git a/docs/guide/directory-structure/entrypoints/options.md b/docs/guide/entrypoint-types/options.md similarity index 100% rename from docs/guide/directory-structure/entrypoints/options.md rename to docs/guide/entrypoint-types/options.md diff --git a/docs/guide/directory-structure/entrypoints/popup.md b/docs/guide/entrypoint-types/popup.md similarity index 100% rename from docs/guide/directory-structure/entrypoints/popup.md rename to docs/guide/entrypoint-types/popup.md diff --git a/docs/guide/directory-structure/entrypoints/sandbox.md b/docs/guide/entrypoint-types/sandbox.md similarity index 100% rename from docs/guide/directory-structure/entrypoints/sandbox.md rename to docs/guide/entrypoint-types/sandbox.md diff --git a/docs/guide/directory-structure/entrypoints/sidepanel.md b/docs/guide/entrypoint-types/sidepanel.md similarity index 100% rename from docs/guide/directory-structure/entrypoints/sidepanel.md rename to docs/guide/entrypoint-types/sidepanel.md diff --git a/docs/guide/directory-structure/entrypoints/unlisted-pages.md b/docs/guide/entrypoint-types/unlisted-pages.md similarity index 100% rename from docs/guide/directory-structure/entrypoints/unlisted-pages.md rename to docs/guide/entrypoint-types/unlisted-pages.md diff --git a/docs/guide/directory-structure/entrypoints/unlisted-scripts.md b/docs/guide/entrypoint-types/unlisted-scripts.md similarity index 100% rename from docs/guide/directory-structure/entrypoints/unlisted-scripts.md rename to docs/guide/entrypoint-types/unlisted-scripts.md diff --git a/docs/guide/extension-apis/action.md b/docs/guide/extension-apis/action.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/guide/extension-apis/basic-usage.md b/docs/guide/extension-apis/basic-usage.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/guide/extension-apis/i18n.md b/docs/guide/extension-apis/i18n.md index e02e01345..e69de29bb 100644 --- a/docs/guide/extension-apis/i18n.md +++ b/docs/guide/extension-apis/i18n.md @@ -1,56 +0,0 @@ -# Internationalization - -This guide is for using the vanilla, `browser.i18n` APIs. There are two other alternatives: - -1. [`@wxt-dev/i18n`](/guide/i18n/installation) - a wrapper around `browser.i18n` APIs with additional features, a simplified localization file format, and editor support -2. Third party packages - You can use any i18n package on NPM, most of which are more feature rich than `browser.i18n` and `@wxt-dev/i18n` - -:::info -Currently, using the `browser.i18n` APIs are the recommended approach. WXT has some built-in support for them and they work well enough. `@wxt-dev/i18n` was recently released, and it will become the recommended approach after some of the bugs have been worked out. Head over to [it's docs](/guide/i18n/introduction.md) to learn more. -::: - -## Setup - -First familiarize yourself with [Chrome's docs](https://developer.chrome.com/docs/extensions/reference/api/i18n). The only difference when using these APIs with WXT is where you put the localization files - in the [`public` directory](/guide/directory-structure/public/). - -``` -/ -└─ public/ - └─ _locales/ - ├─ en/ - │ └─ messages.json - ├─ de/ - │ └─ messages.json - └─ ko/ - └─ messages.json -``` - -Next, to set a `default_locale` on your manifest, add it to your `wxt.config.ts` file: - -```ts -// wxt.config.ts -export default defineConfig({ - manifest: { - default_locale: 'en', - name: '__MSG_extName__', - description: '__MSG_extDescription__', - }, -}); -``` - -> You can localize the `name` and `description` of your extension from the `manifest` config as well. - -Finally, to get a translation, call `browser.i18n.getMessage`: - -```ts -browser.i18n.getMessage('extName'); -browser.i18n.getMessage('extDescription'); -browser.i18n.getMessage(/* etc */); -``` - -## Examples - -See the official localization examples for more details: - -- [I18n](https://github.com/wxt-dev/wxt-examples/tree/main/examples/vanilla-i18n#readme) -- [Vue I18n](https://github.com/wxt-dev/wxt-examples/tree/main/examples/vue-i18n#readme) diff --git a/docs/guide/extension-apis/messaging.md b/docs/guide/extension-apis/messaging.md index a55f1355c..e69de29bb 100644 --- a/docs/guide/extension-apis/messaging.md +++ b/docs/guide/extension-apis/messaging.md @@ -1,36 +0,0 @@ -# Messaging - -## Overview - -Follow [Chrome's message passing guide](https://developer.chrome.com/docs/extensions/mv3/messaging/) to understand how message passing works in web extensions. In Google's examples, just replace `chrome` with `browser`, and it will work in WXT. - -Here's a basic request/response example: - -```ts -// popup/main.ts -const res = await browser.runtime.sendMessage('ping'); - -console.log(res); // "pong" -``` - -```ts -// background.ts -export default defineBackground(() => { - browser.runtime.onMessage.addListener((message, sender, sendResponse) => { - console.log(message); // "ping" - - // Wait 1 second and respond with "pong" - setTimeout(() => sendResponse('pong'), 1000); - return true; - }); -}); -``` - -## Third Party Libraries - -There are a number of message passing libraries you can use to improve the message passing experience. - -- [`@webext-core/messaging`](https://webext-core.aklinker1.io/guide/messaging/) - "A light-weight, type-safe wrapper around the `browser.runtime` messaging APIs" -- [`@webext-core/proxy-service`](https://webext-core.aklinker1.io/guide/proxy-service/) - "Create RPC-like services that can be called from anywhere but run in the background" -- [`webext-bridge`](https://github.com/zikaari/webext-bridge) - "Messaging in Web Extensions made super easy. Out of the box." -- [`trpc-chrome`](https://www.npmjs.com/package/trpc-chrome) - "tRPC adapter for Web Extensions 🧩" diff --git a/docs/guide/extension-apis/scripting.md b/docs/guide/extension-apis/scripting.md index 9565a739f..e69de29bb 100644 --- a/docs/guide/extension-apis/scripting.md +++ b/docs/guide/extension-apis/scripting.md @@ -1,26 +0,0 @@ -# `browser.scripting` - -[Chrome Docs](https://developer.chrome.com/docs/extensions/reference/api/scripting) • [Firefox Docs](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/scripting) - -Refer to the browser docs above for basics on how the API works. - -## Execute Script Return Values - -When using `browser.scripting.executeScript`, you can execute content scripts or unlisted scripts. To return a value, just return a value from the script's main function. - -```ts -// entrypoints/background.ts -const res = await browser.scripting.executeScript({ - target: { tabId }, - files: ['injected.js'], -}); -console.log(res); // "Hello John!" -``` - -```ts -// entrypoints/injected.js -export default defineContentScript(() => { - console.log('Script was injected!'); - return 'Hello John!'; -}); -``` diff --git a/docs/guide/extension-apis/storage.md b/docs/guide/extension-apis/storage.md index 9d593074d..e69de29bb 100644 --- a/docs/guide/extension-apis/storage.md +++ b/docs/guide/extension-apis/storage.md @@ -1,313 +0,0 @@ ---- -outline: deep ---- - -# Storage API - -WXT provides a simplified API to replace the `browser.storage.*` APIs. Use the `storage` auto-import from `wxt/storage` or import it manually to get started: - -```ts -import { storage } from 'wxt/storage'; -``` - -:::warning -To use the `wxt/storage` API, the `"storage"` permission must be added to the manifest: - -```ts -// wxt.config.ts -export default defineConfig({ - manifest: { - permissions: ['storage'], - }, -}); -``` - -More info on permissions [here](/guide/key-concepts/manifest#permissions). -::: - -[[toc]] - -## Basic Usage - -All storage keys must be prefixed by their storage area. - -```ts -// ❌ This will throw an error -await storage.getItem('installDate'); - -// ✅ This is good -await storage.getItem('local:installDate'); -``` - -You can use `local:`, `session:`, `sync:`, or `managed:`. - -If you use TypeScript, you can add a type parameter to most methods to specify the expected type of the key's value: - -```ts -await storage.getItem('local:installDate'); -await storage.watch( - 'local:installDate', - (newInstallDate, oldInstallDate) => { - // ... - }, -); -await storage.getMeta<{ v: number }>('local:installDate'); -``` - -For a full list of methods available, see the [API reference](/api/reference/wxt/storage/interfaces/WxtStorage). - -## Watchers - -To listen for storage changes, use the `storage.watch` function. It lets you setup a listener for a single key: - -```ts -const unwatch = storage.watch('local:counter', (newCount, oldCount) => { - console.log('Count changed:', { newCount, oldCount }); -}); -``` - -To remove the listener, call the returned `unwatch` function: - -```ts -const unwatch = storage.watch(...); - -// Some time later... -unwatch(); -``` - -## Metadata - -`wxt/storage` also supports setting metadata for keys, stored at `key + "$"`. Metadata is a collection of properties associated with a key. It might be a version number, last modified date, etc. - -[Other than versioning](#versioning), you are responsible for managing a field's metadata: - -```ts -await Promise.all([ - storage.setItem('local:preference', true), - storage.setMeta('local:preference', { lastModified: Date.now() }), -]); -``` - -When setting different properties of metadata from multiple calls, the properties are combined instead of overwritten: - -```ts -await storage.setMeta('local:preference', { lastModified: Date.now() }); -await storage.setMeta('local:preference', { v: 2 }); - -await storage.getMeta('local:preference'); // { v: 2, lastModified: 1703690746007 } -``` - -You can remove all metadata associated with a key, or just specific properties: - -```ts -// Remove all properties -await storage.removeMeta('local:preference'); - -// Remove one property -await storage.removeMeta('local:preference', 'lastModified'); - -// Remove multiple properties -await storage.removeMeta('local:preference', ['lastModified', 'v']); -``` - -## Defining Storage Items - -Writing the key and type parameter for the same key over and over again can be annoying. As an alternative, you can use `storage.defineItem` to create a "storage item". - -Storage items contain the same APIs as the `storage` variable, but you can configure its type, default value, and more in a single place: - -```ts -// utils/storage.ts -const showChangelogOnUpdate = storage.defineItem( - 'local:showChangelogOnUpdate', - { - fallback: true, - }, -); -``` - -Now, instead of using the `storage` variable, you can use the helper functions on the storage item you created: - -```ts -await showChangelogOnUpdate.getValue(); -await showChangelogOnUpdate.setValue(false); -await showChangelogOnUpdate.removeValue(); -const unwatch = showChangelogOnUpdate.watch((newValue) => { - // ... -}); -``` - -For a full list of properties and methods available, see the [API reference](/api/reference/wxt/storage/interfaces/WxtStorageItem). - -### Versioning - -You can add versioning to storage items if you expect them to grow or change over time. When defining the first version of an item, start with version 1. - -For example, consider a storage item that stores a list of websites that are ignored by an extension. - -:::code-group - -```ts [v1] -type IgnoredWebsiteV1 = string; - -export const ignoredWebsites = storage.defineItem( - 'local:ignoredWebsites', - { - fallback: [], - version: 1, - }, -); -``` - - -```ts [v2] -import { nanoid } from 'nanoid'; // [!code ++] - -type IgnoredWebsiteV1 = string; -interface IgnoredWebsiteV2 { // [!code ++] - id: string; // [!code ++] - website: string; // [!code ++] -} // [!code ++] - -export const ignoredWebsites = storage.defineItem( // [!code --] -export const ignoredWebsites = storage.defineItem( // [!code ++] - 'local:ignoredWebsites', - { - fallback: [], - version: 1, // [!code --] - version: 2, // [!code ++] - migrations: { // [!code ++] - // Ran when migrating from v1 to v2 // [!code ++] - 2: (websites: IgnoredWebsiteV1[]): IgnoredWebsiteV2[] => { // [!code ++] - return websites.map((website) => ({ id: nanoid(), website })); // [!code ++] - }, // [!code ++] - }, // [!code ++] - }, -); -``` - - -```ts [v3] -import { nanoid } from 'nanoid'; - -type IgnoredWebsiteV1 = string; -interface IgnoredWebsiteV2 { - id: string; - website: string; -} -interface IgnoredWebsiteV3 { // [!code ++] - id: string; // [!code ++] - website: string; // [!code ++] - enabled: boolean; // [!code ++] -} // [!code ++] - -export const ignoredWebsites = storage.defineItem( // [!code --] -export const ignoredWebsites = storage.defineItem( // [!code ++] - 'local:ignoredWebsites', - { - fallback: [], - version: 2, // [!code --] - version: 3, // [!code ++] - migrations: { - // Ran when migrating from v1 to v2 - 2: (websites: IgnoredWebsiteV1[]): IgnoredWebsiteV2[] => { - return websites.map((website) => ({ id: nanoid(), website })); - }, - // Ran when migrating from v2 to v3 // [!code ++] - 3: (websites: IgnoredWebsiteV2[]): IgnoredWebsiteV3[] => { // [!code ++] - return websites.map((website) => ({ ...website, enabled: true })); // [!code ++] - }, // [!code ++] - }, - }, -); -``` - -::: - -:::info -Internally, this uses a metadata property called `v` to track the value's current version. -::: - -In this case, we thought that the ignored website list might change in the future, and were able to setup a versioned storage item from the start. - -Realistically, you won't know a item needs versioned until you need to change it's schema. Thankfully, it's simple to add versioning to an unversioned storage item. - -When a previous version isn't found, WXT assumes the version was `1`. That means you just need to set `version: 2` and add a migration for `2`, and it will just work! - -Lets look at the same ignored websites example from before, but start with an unversioned item this time: - -:::code-group - -```ts [Unversioned] -export const ignoredWebsites = storage.defineItem( - 'local:ignoredWebsites', - { - fallback: [], - }, -); -``` - - -```ts [v2] -import { nanoid } from 'nanoid'; // [!code ++] - -// Retroactively add a type for the first version // [!code ++] -type IgnoredWebsiteV1 = string; // [!code ++] -interface IgnoredWebsiteV2 { // [!code ++] - id: string; // [!code ++] - website: string; // [!code ++] -} // [!code ++] - -export const ignoredWebsites = storage.defineItem( // [!code --] -export const ignoredWebsites = storage.defineItem( // [!code ++] - 'local:ignoredWebsites', - { - fallback: [], - version: 2, // [!code ++] - migrations: { // [!code ++] - // Ran when migrating from v1 to v2 // [!code ++] - 2: (websites: IgnoredWebsiteV1[]): IgnoredWebsiteV2[] => { // [!code ++] - return websites.map((website) => ({ id: nanoid(), website })); // [!code ++] - }, // [!code ++] - }, // [!code ++] - }, -); -``` - -::: - -### Running Migrations - -As soon as `storage.defineItem` is called, WXT checks if migrations need to be ran, and if so, runs them. Calls to get or update the storage item's value or metadata (`getValue`, `setValue`, `removeValue`, `getMeta`, etc) will automatically wait for the migration process to finish before actually reading or writing values. - -### Default Values - -With `storage.defineItem`, there are multiple ways of defining default values: - -1. `fallback` - Return this value from `getValue` instead of `null` if the value is missing. - - This option is great for providing default values for settings: - - ```ts - const theme = storage.defineItem('local:theme', { - fallback: 'dark', - }); - const allowEditing = storage.defineItem('local:allow-editing', { - fallback: true, - }); - ``` - -2. `init` - Initialize and save a value in storage if it is not already saved. - - This is great for values that need to be initialized or set once: - - ```ts - const userId = storage.defineItem('local:user-id', { - init: () => globalThis.crypto.randomUUID(), - }); - const installDate = storage.defineItem('local:install-date', { - init: () => new Date().getTime(), - }); - ``` - - The value is initialized in storage immediately. diff --git a/docs/guide/get-started/installation.md b/docs/guide/get-started/installation.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/guide/get-started/introduction.md b/docs/guide/get-started/introduction.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/guide/get-started/migrate.md b/docs/guide/get-started/migrate.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/guide/maintainence/debugging.md b/docs/guide/maintainence/debugging.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/guide/maintainence/e2e-testing.md b/docs/guide/maintainence/e2e-testing.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/guide/maintainence/unit-testing.md b/docs/guide/maintainence/unit-testing.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/guide/maintainence/upgrading.md b/docs/guide/maintainence/upgrading.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/guide/production/publishing.md b/docs/guide/production/publishing.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/guide/production/remote-code.md b/docs/guide/production/remote-code.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/guide/production/testing-updates.md b/docs/guide/production/testing-updates.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/guide/resources/compare.md b/docs/guide/resources/compare.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/guide/resources/examples.md b/docs/guide/resources/examples.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/guide/resources/how-wxt-works.md b/docs/guide/resources/how-wxt-works.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/guide/wxt-modules/recipes.md b/docs/guide/wxt-modules/recipes.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/guide/wxt-modules/using-modules.md b/docs/guide/wxt-modules/using-modules.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/guide/wxt-modules/writing-modules.md b/docs/guide/wxt-modules/writing-modules.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/index.md b/docs/index.md index d0c15a8e7..5ec382ff7 100644 --- a/docs/index.md +++ b/docs/index.md @@ -13,10 +13,10 @@ hero: actions: - theme: brand text: Get Started - link: /get-started/installation + link: /guide/get-started/installation - theme: alt text: Learn More - link: /get-started/introduction + link: /guide/get-started/introduction features: - icon: 🌐