wxt 0.20.17 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,4 +4,4 @@
4
4
  * `publish-browser-extension` as a direct dependency (like for PNPM, which doesn't link
5
5
  * sub-dependency binaries to "node_modules/.bin")
6
6
  */
7
- import 'publish-browser-extension/cli';
7
+ await import('publish-browser-extension/cli');
@@ -1,3 +1,4 @@
1
+ import { ScriptPublicPath } from "./utils/inject-script.mjs";
1
2
  import { Browser, browser as browser$1 } from "@wxt-dev/browser";
2
3
 
3
4
  //#region src/browser.d.ts
@@ -11,10 +12,26 @@ interface WxtRuntime {}
11
12
  * - `.wxt/types/i18n.d.ts`
12
13
  */
13
14
  interface WxtI18n {}
14
- type WxtBrowser = Omit<typeof browser$1, 'runtime' | 'i18n'> & {
15
+ type ScriptInjection<Args extends any[], Result> = Browser.scripting.ScriptInjection<Args, Result> extends infer T ? T extends {
16
+ files: string[];
17
+ } ? Omit<T, 'files'> & {
18
+ files: ScriptPublicPath[];
19
+ } : T : never;
20
+ type InjectionResult<Result> = Array<Browser.scripting.InjectionResult<Awaited<Result>>>;
21
+ interface WxtScripting {
22
+ executeScript: {
23
+ /**
24
+ * @see {@link Browser.scripting.executeScript}
25
+ */
26
+ <Args extends any[], Result>(injection: ScriptInjection<Args, Result>): Promise<InjectionResult<Result>>;
27
+ <Args extends any[], Result>(injection: ScriptInjection<Args, Result>, callback: (results: InjectionResult<Result>) => void): void;
28
+ };
29
+ }
30
+ type WxtBrowser = Omit<typeof browser$1, 'runtime' | 'i18n' | 'scripting'> & {
15
31
  runtime: WxtRuntime & Omit<(typeof browser$1)['runtime'], 'getURL'>;
16
32
  i18n: WxtI18n & Omit<(typeof browser$1)['i18n'], 'getMessage'>;
33
+ scripting: WxtScripting & Omit<(typeof browser$1)['scripting'], 'executeScript'>;
17
34
  };
18
35
  declare const browser: WxtBrowser;
19
36
  //#endregion
20
- export { Browser, WxtBrowser, WxtI18n, WxtRuntime, browser };
37
+ export { Browser, WxtBrowser, WxtI18n, WxtRuntime, WxtScripting, browser };
@@ -16,6 +16,7 @@ import { removeEntrypointMainFunction } from "./plugins/removeEntrypointMainFunc
16
16
  import { wxtPluginLoader } from "./plugins/wxtPluginLoader.mjs";
17
17
  import { resolveAppConfig } from "./plugins/resolveAppConfig.mjs";
18
18
  import { iifeFooter } from "./plugins/iifeFooter.mjs";
19
+ import { iifeAnonymous } from "./plugins/iifeAnonymous.mjs";
19
20
  import "./plugins/index.mjs";
20
21
  import { toArray } from "../../utils/arrays.mjs";
21
22
  import { safeVarName } from "../../utils/strings.mjs";
@@ -63,9 +64,14 @@ async function createViteBuilder(wxtConfig, hooks, getWxtDevServer) {
63
64
  const getLibModeConfig = (entrypoint) => {
64
65
  const entry = getRollupEntry(entrypoint);
65
66
  const plugins = [entrypointGroupGlobals(entrypoint)];
66
- const iifeReturnValueName = safeVarName(entrypoint.name);
67
+ let iifeReturnValueName = safeVarName(entrypoint.name);
67
68
  if (entrypoint.type === "content-script-style" || entrypoint.type === "unlisted-style") plugins.push(cssEntrypoints(entrypoint, wxtConfig));
68
- if (entrypoint.type === "content-script" || entrypoint.type === "unlisted-script") plugins.push(iifeFooter(iifeReturnValueName));
69
+ if (entrypoint.type === "content-script" || entrypoint.type === "unlisted-script") {
70
+ if (typeof entrypoint.options.globalName === "string") iifeReturnValueName = entrypoint.options.globalName;
71
+ else if (typeof entrypoint.options.globalName === "function") iifeReturnValueName = entrypoint.options.globalName(entrypoint);
72
+ if (entrypoint.options.globalName === false) plugins.push(iifeAnonymous(iifeReturnValueName));
73
+ else plugins.push(iifeFooter(iifeReturnValueName));
74
+ }
69
75
  return {
70
76
  mode: wxtConfig.mode,
71
77
  plugins,
@@ -0,0 +1,15 @@
1
+ //#region src/core/builders/vite/plugins/iifeAnonymous.ts
2
+ function iifeAnonymous(iifeReturnValueName) {
3
+ return {
4
+ name: "wxt:iife-anonymous",
5
+ generateBundle(_, bundle) {
6
+ for (const chunk of Object.values(bundle)) if (chunk.type === "chunk" && chunk.isEntry) {
7
+ const namedIIFEPrefix = new RegExp(`^var ${iifeReturnValueName}\\s*=\\s*(\\(function)`);
8
+ chunk.code = chunk.code.replace(namedIIFEPrefix, "$1");
9
+ }
10
+ }
11
+ };
12
+ }
13
+
14
+ //#endregion
15
+ export { iifeAnonymous };
@@ -14,5 +14,6 @@ import { removeEntrypointMainFunction } from "./removeEntrypointMainFunction.mjs
14
14
  import { wxtPluginLoader } from "./wxtPluginLoader.mjs";
15
15
  import { resolveAppConfig } from "./resolveAppConfig.mjs";
16
16
  import { iifeFooter } from "./iifeFooter.mjs";
17
+ import { iifeAnonymous } from "./iifeAnonymous.mjs";
17
18
 
18
19
  export { };
@@ -34,7 +34,7 @@ async function generateWxtDir(entrypoints) {
34
34
  }));
35
35
  }
36
36
  async function getPathsDeclarationEntry(entrypoints) {
37
- const paths = entrypoints.map((entry) => getEntrypointBundlePath(entry, wxt.config.outDir, isHtmlEntrypoint(entry) ? ".html" : ".js")).concat(await getPublicFiles());
37
+ const paths = entrypoints.map((entry) => getEntrypointBundlePath(entry, wxt.config.outDir, getEntrypointPublicExt(entry))).concat(await getPublicFiles());
38
38
  await wxt.hooks.callHook("prepare:publicPaths", wxt, paths);
39
39
  const unions = [
40
40
  ` | ""`,
@@ -59,6 +59,14 @@ declare module "wxt/browser" {
59
59
  tsReference: true
60
60
  };
61
61
  }
62
+ function getEntrypointPublicExt(entry) {
63
+ if (isHtmlEntrypoint(entry)) return ".html";
64
+ switch (entry.type) {
65
+ case "content-script-style":
66
+ case "unlisted-style": return ".css";
67
+ default: return ".js";
68
+ }
69
+ }
62
70
  async function getI18nDeclarationEntry() {
63
71
  const defaultLocale = wxt.config.manifest.default_locale;
64
72
  const template = `// Generated by wxt
@@ -246,7 +246,7 @@ async function getUnimportOptions(wxtDir, srcDir, logger, config) {
246
246
  },
247
247
  {
248
248
  from: "wxt/utils/app-config",
249
- imports: defineImportsAndTypes(["useAppConfig"], [])
249
+ imports: defineImportsAndTypes(["getAppConfig", "useAppConfig"], [])
250
250
  },
251
251
  {
252
252
  from: "wxt/utils/content-script-context",
@@ -14,7 +14,6 @@ function createWebExtRunner() {
14
14
  },
15
15
  async openBrowser() {
16
16
  const startTime = Date.now();
17
- if (wxt.config.browser === "firefox" && wxt.config.manifestVersion === 3) throw Error("Dev mode does not support Firefox MV3. For alternatives, see https://github.com/wxt-dev/wxt/issues/230#issuecomment-1806881653");
18
17
  const webExtLogger = await import("web-ext-run/util/logger");
19
18
  webExtLogger.consoleStream.write = ({ level, msg, name }) => {
20
19
  if (level >= ERROR_LOG_LEVEL) wxt.logger.error(name, msg);
@@ -65,19 +65,13 @@ async function findEntrypoints() {
65
65
  ...info,
66
66
  type,
67
67
  outputDir: resolve(wxt.config.outDir, CONTENT_SCRIPT_OUT_DIR),
68
- options: {
69
- include: options.include,
70
- exclude: options.exclude
71
- }
68
+ options
72
69
  };
73
70
  default: return {
74
71
  ...info,
75
72
  type,
76
73
  outputDir: wxt.config.outDir,
77
- options: {
78
- include: options.include,
79
- exclude: options.exclude
80
- }
74
+ options
81
75
  };
82
76
  }
83
77
  }));
@@ -110,15 +104,17 @@ async function importEntrypoints(infos) {
110
104
  })()]);
111
105
  return resMap;
112
106
  }
113
- /** Extract `manifest.` options from meta tags, converting snake_case keys to camelCase */
107
+ /** Extract `manifest.` and `wxt.` options from meta tags, converting snake_case keys to camelCase */
114
108
  async function importHtmlEntrypoint(info) {
115
109
  const { document } = parseHTML(await fs.readFile(info.inputPath, "utf-8"));
116
110
  const metaTags = document.querySelectorAll("meta");
117
111
  const res = { title: document.querySelector("title")?.textContent || void 0 };
118
112
  metaTags.forEach((tag) => {
119
113
  const name = tag.name;
120
- if (!name.startsWith("manifest.")) return;
121
- const key = camelCase(name.slice(9));
114
+ let key;
115
+ if (name.startsWith("manifest.")) key = camelCase(name.slice(9));
116
+ else if (name.startsWith("wxt.")) key = camelCase(name.slice(4));
117
+ else return;
122
118
  try {
123
119
  res[key] = JSON5.parse(tag.content);
124
120
  } catch {
@@ -151,17 +147,13 @@ function preventNoEntrypoints(files) {
151
147
  if (files.length === 0) throw Error(`No entrypoints found in ${wxt.config.entrypointsDir}`);
152
148
  }
153
149
  async function getPopupEntrypoint(info, options) {
150
+ const { themeIcons, title, type, ...perBrowserOptions } = options;
154
151
  const strictOptions = resolvePerBrowserOptions({
155
- browserStyle: options.browserStyle,
156
- exclude: options.exclude,
157
- include: options.include,
158
- defaultIcon: options.defaultIcon,
159
- defaultTitle: options.title,
160
- mv2Key: options.type,
161
- defaultArea: options.defaultArea
152
+ ...perBrowserOptions,
153
+ defaultTitle: title,
154
+ mv2Key: type
162
155
  }, wxt.config.browser);
163
156
  if (strictOptions.mv2Key && strictOptions.mv2Key !== "page_action") strictOptions.mv2Key = "browser_action";
164
- const themeIcons = options.themeIcons;
165
157
  return {
166
158
  type: "popup",
167
159
  name: "popup",
@@ -177,13 +169,7 @@ async function getOptionsEntrypoint(info, options) {
177
169
  return {
178
170
  type: "options",
179
171
  name: "options",
180
- options: resolvePerBrowserOptions({
181
- browserStyle: options.browserStyle,
182
- chromeStyle: options.chromeStyle,
183
- exclude: options.exclude,
184
- include: options.include,
185
- openInTab: options.openInTab
186
- }, wxt.config.browser),
172
+ options: resolvePerBrowserOptions(options, wxt.config.browser),
187
173
  inputPath: info.inputPath,
188
174
  outputDir: wxt.config.outDir
189
175
  };
@@ -194,10 +180,7 @@ async function getUnlistedPageEntrypoint(info, options) {
194
180
  name: info.name,
195
181
  inputPath: info.inputPath,
196
182
  outputDir: wxt.config.outDir,
197
- options: {
198
- include: options.include,
199
- exclude: options.exclude
200
- }
183
+ options
201
184
  };
202
185
  }
203
186
  async function getUnlistedScriptEntrypoint({ inputPath, name }, options) {
@@ -206,19 +189,11 @@ async function getUnlistedScriptEntrypoint({ inputPath, name }, options) {
206
189
  name,
207
190
  inputPath,
208
191
  outputDir: wxt.config.outDir,
209
- options: resolvePerBrowserOptions({
210
- include: options.include,
211
- exclude: options.exclude
212
- }, wxt.config.browser)
192
+ options: resolvePerBrowserOptions(options, wxt.config.browser)
213
193
  };
214
194
  }
215
195
  async function getBackgroundEntrypoint({ inputPath, name }, options) {
216
- const strictOptions = resolvePerBrowserOptions({
217
- include: options.include,
218
- exclude: options.exclude,
219
- persistent: options.persistent,
220
- type: options.type
221
- }, wxt.config.browser);
196
+ const strictOptions = resolvePerBrowserOptions(options, wxt.config.browser);
222
197
  if (wxt.config.manifestVersion !== 3) delete strictOptions.type;
223
198
  return {
224
199
  type: "background",
@@ -238,16 +213,13 @@ async function getContentScriptEntrypoint({ inputPath, name }, options) {
238
213
  };
239
214
  }
240
215
  async function getSidepanelEntrypoint(info, options) {
216
+ const { title, ...perBrowserOptions } = options;
241
217
  return {
242
218
  type: "sidepanel",
243
219
  name: info.name,
244
220
  options: resolvePerBrowserOptions({
245
- browserStyle: options.browserStyle,
246
- exclude: options.exclude,
247
- include: options.include,
248
- defaultIcon: options.defaultIcon,
249
- defaultTitle: options.title,
250
- openAtInstall: options.openAtInstall
221
+ ...perBrowserOptions,
222
+ defaultTitle: title
251
223
  }, wxt.config.browser),
252
224
  inputPath: info.inputPath,
253
225
  outputDir: wxt.config.outDir
@@ -1,11 +1,17 @@
1
1
  import { withTimeout } from "./time.mjs";
2
+ import consola from "consola";
2
3
  import dns from "node:dns";
3
4
 
4
5
  //#region src/core/utils/network.ts
5
- function isOffline() {
6
- return withTimeout(new Promise((res) => {
7
- dns.resolve("google.com", (err) => res(err != null));
8
- }), 1e3).catch(() => true);
6
+ async function isOffline() {
7
+ try {
8
+ return await withTimeout(new Promise((res) => {
9
+ dns.resolve("google.com", (err) => res(err != null));
10
+ }), 1e3);
11
+ } catch (error) {
12
+ consola.error("Error checking offline status:", error);
13
+ return true;
14
+ }
9
15
  }
10
16
  async function isOnline() {
11
17
  return !await isOffline();
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { BackgroundDefinition, BackgroundEntrypoint, BackgroundEntrypointOptions, BaseContentScriptEntrypointOptions, BaseEntrypoint, BaseEntrypointOptions, BuildOutput, BuildStepOutput, ConfigEnv, ContentScriptDefinition, ContentScriptEntrypoint, CopiedPublicFile, Dependency, Entrypoint, EntrypointGroup, EntrypointInfo, EslintGlobalsPropValue, Eslintrc, ExtensionRunner, ExtensionRunnerConfig, FsCache, GeneratedPublicFile, GenericEntrypoint, HookResult, InlineConfig, IsolatedWorldContentScriptDefinition, IsolatedWorldContentScriptEntrypointOptions, Logger, MainWorldContentScriptDefinition, MainWorldContentScriptEntrypointOptions, OnContentScriptStopped, OptionsEntrypoint, OptionsEntrypointOptions, OutputAsset, OutputChunk, OutputFile, PerBrowserMap, PerBrowserOption, PopupEntrypoint, PopupEntrypointOptions, ReloadContentScriptPayload, ResolvedBasePublicFile, ResolvedConfig, ResolvedEslintrc, ResolvedPerBrowserOptions, ResolvedPublicFile, ServerInfo, SidepanelEntrypoint, SidepanelEntrypointOptions, TargetBrowser, TargetManifestVersion, ThemeIcon, UnlistedScriptDefinition, UserConfig, UserManifest, UserManifestFn, WebExtConfig, Wxt, WxtBuilder, WxtBuilderServer, WxtCommand, WxtDevServer, WxtDirEntry, WxtDirFileEntry, WxtDirTypeReferenceEntry, WxtHooks, WxtModule, WxtModuleOptions, WxtModuleSetup, WxtModuleWithMetadata, WxtPackageManager, WxtPlugin, WxtResolvedUnimportOptions, WxtUnimportOptions, WxtViteConfig } from "./types.mjs";
1
+ import { BackgroundDefinition, BackgroundEntrypoint, BackgroundEntrypointOptions, BaseContentScriptEntrypointOptions, BaseEntrypoint, BaseEntrypointOptions, BaseScriptEntrypointOptions, BuildOutput, BuildStepOutput, ConfigEnv, ContentScriptDefinition, ContentScriptEntrypoint, CopiedPublicFile, Dependency, Entrypoint, EntrypointGroup, EntrypointInfo, EslintGlobalsPropValue, Eslintrc, ExtensionRunner, ExtensionRunnerConfig, FsCache, GeneratedPublicFile, GenericEntrypoint, HookResult, InlineConfig, IsolatedWorldContentScriptDefinition, IsolatedWorldContentScriptEntrypointOptions, Logger, MainWorldContentScriptDefinition, MainWorldContentScriptEntrypointOptions, OnContentScriptStopped, OptionsEntrypoint, OptionsEntrypointOptions, OutputAsset, OutputChunk, OutputFile, PerBrowserMap, PerBrowserOption, PopupEntrypoint, PopupEntrypointOptions, ReloadContentScriptPayload, ResolvedBasePublicFile, ResolvedConfig, ResolvedEslintrc, ResolvedPerBrowserOptions, ResolvedPublicFile, ServerInfo, SidepanelEntrypoint, SidepanelEntrypointOptions, TargetBrowser, TargetManifestVersion, ThemeIcon, UnlistedScriptDefinition, UnlistedScriptEntrypoint, UserConfig, UserManifest, UserManifestFn, WebExtConfig, Wxt, WxtBuilder, WxtBuilderServer, WxtCommand, WxtDevServer, WxtDirEntry, WxtDirFileEntry, WxtDirTypeReferenceEntry, WxtHooks, WxtModule, WxtModuleOptions, WxtModuleSetup, WxtModuleWithMetadata, WxtPackageManager, WxtPlugin, WxtResolvedUnimportOptions, WxtUnimportOptions, WxtViteConfig } from "./types.mjs";
2
2
  import { build } from "./core/build.mjs";
3
3
  import { clean } from "./core/clean.mjs";
4
4
  import { defineConfig } from "./core/define-config.mjs";
@@ -10,4 +10,4 @@ import { zip } from "./core/zip.mjs";
10
10
  import { normalizePath } from "./core/utils/paths.mjs";
11
11
  import "./core/index.mjs";
12
12
  import { version } from "./version.mjs";
13
- export { BackgroundDefinition, BackgroundEntrypoint, BackgroundEntrypointOptions, BaseContentScriptEntrypointOptions, BaseEntrypoint, BaseEntrypointOptions, BuildOutput, BuildStepOutput, ConfigEnv, ContentScriptDefinition, ContentScriptEntrypoint, CopiedPublicFile, Dependency, Entrypoint, EntrypointGroup, EntrypointInfo, EslintGlobalsPropValue, Eslintrc, ExtensionRunner, ExtensionRunnerConfig, FsCache, GeneratedPublicFile, GenericEntrypoint, HookResult, InlineConfig, IsolatedWorldContentScriptDefinition, IsolatedWorldContentScriptEntrypointOptions, Logger, MainWorldContentScriptDefinition, MainWorldContentScriptEntrypointOptions, OnContentScriptStopped, OptionsEntrypoint, OptionsEntrypointOptions, OutputAsset, OutputChunk, OutputFile, PerBrowserMap, PerBrowserOption, PopupEntrypoint, PopupEntrypointOptions, ReloadContentScriptPayload, ResolvedBasePublicFile, ResolvedConfig, ResolvedEslintrc, ResolvedPerBrowserOptions, ResolvedPublicFile, ServerInfo, SidepanelEntrypoint, SidepanelEntrypointOptions, TargetBrowser, TargetManifestVersion, ThemeIcon, UnlistedScriptDefinition, UserConfig, UserManifest, UserManifestFn, WebExtConfig, Wxt, WxtBuilder, WxtBuilderServer, WxtCommand, WxtDevServer, WxtDirEntry, WxtDirFileEntry, WxtDirTypeReferenceEntry, WxtHooks, WxtModule, WxtModuleOptions, WxtModuleSetup, WxtModuleWithMetadata, WxtPackageManager, WxtPlugin, WxtResolvedUnimportOptions, WxtUnimportOptions, WxtViteConfig, build, clean, createServer, defineConfig, defineRunnerConfig, defineWebExtConfig, initialize, normalizePath, prepare, version, zip };
13
+ export { BackgroundDefinition, BackgroundEntrypoint, BackgroundEntrypointOptions, BaseContentScriptEntrypointOptions, BaseEntrypoint, BaseEntrypointOptions, BaseScriptEntrypointOptions, BuildOutput, BuildStepOutput, ConfigEnv, ContentScriptDefinition, ContentScriptEntrypoint, CopiedPublicFile, Dependency, Entrypoint, EntrypointGroup, EntrypointInfo, EslintGlobalsPropValue, Eslintrc, ExtensionRunner, ExtensionRunnerConfig, FsCache, GeneratedPublicFile, GenericEntrypoint, HookResult, InlineConfig, IsolatedWorldContentScriptDefinition, IsolatedWorldContentScriptEntrypointOptions, Logger, MainWorldContentScriptDefinition, MainWorldContentScriptEntrypointOptions, OnContentScriptStopped, OptionsEntrypoint, OptionsEntrypointOptions, OutputAsset, OutputChunk, OutputFile, PerBrowserMap, PerBrowserOption, PopupEntrypoint, PopupEntrypointOptions, ReloadContentScriptPayload, ResolvedBasePublicFile, ResolvedConfig, ResolvedEslintrc, ResolvedPerBrowserOptions, ResolvedPublicFile, ServerInfo, SidepanelEntrypoint, SidepanelEntrypointOptions, TargetBrowser, TargetManifestVersion, ThemeIcon, UnlistedScriptDefinition, UnlistedScriptEntrypoint, UserConfig, UserManifest, UserManifestFn, WebExtConfig, Wxt, WxtBuilder, WxtBuilderServer, WxtCommand, WxtDevServer, WxtDirEntry, WxtDirFileEntry, WxtDirTypeReferenceEntry, WxtHooks, WxtModule, WxtModuleOptions, WxtModuleSetup, WxtModuleWithMetadata, WxtPackageManager, WxtPlugin, WxtResolvedUnimportOptions, WxtUnimportOptions, WxtViteConfig, build, clean, createServer, defineConfig, defineRunnerConfig, defineWebExtConfig, initialize, normalizePath, prepare, version, zip };
package/dist/types.d.mts CHANGED
@@ -560,7 +560,27 @@ interface BackgroundEntrypointOptions extends BaseEntrypointOptions {
560
560
  */
561
561
  type?: PerBrowserOption<'module'>;
562
562
  }
563
- interface BaseContentScriptEntrypointOptions extends BaseEntrypointOptions {
563
+ interface BaseScriptEntrypointOptions extends BaseEntrypointOptions {
564
+ /**
565
+ * The variable name for the IIFE in the output bundle.
566
+ *
567
+ * This option is relevant for scripts inserted into the page context where the default IIFE
568
+ * variable name may conflict with an existing variable on the target page. This applies to content
569
+ * scripts with world=MAIN, and others, such as unlisted scripts, that could be dynamically injected
570
+ * into the page with a <script> tag.
571
+ *
572
+ * Available options:
573
+ * - `true`: automatically generate a name for the IIFE based on the entrypoint name
574
+ * - `false`: Output the IIFE without a variable name, making it anonymous. This is the safest option
575
+ * to avoid conflicts with existing variables on the page. This will become the default in a future version of WXT.
576
+ * - `string`: Use the provided string as the global variable name.
577
+ * - `function`: A function that receives the entrypoint and returns a string to use as the variable name.
578
+ *
579
+ * @default true
580
+ */
581
+ globalName?: string | boolean | ((entrypoint: Entrypoint) => string);
582
+ }
583
+ interface BaseContentScriptEntrypointOptions extends BaseScriptEntrypointOptions {
564
584
  matches?: PerBrowserOption<NonNullable<ManifestContentScript['matches']>>;
565
585
  /**
566
586
  * See https://developer.chrome.com/docs/extensions/mv3/content_scripts/
@@ -669,6 +689,7 @@ interface PopupEntrypointOptions extends BaseEntrypointOptions {
669
689
  themeIcons?: ThemeIcon[];
670
690
  }
671
691
  interface OptionsEntrypointOptions extends BaseEntrypointOptions {
692
+ title?: string;
672
693
  openInTab?: PerBrowserOption<boolean>;
673
694
  browserStyle?: PerBrowserOption<boolean>;
674
695
  chromeStyle?: PerBrowserOption<boolean>;
@@ -723,9 +744,13 @@ interface BaseEntrypoint {
723
744
  skipped?: boolean;
724
745
  }
725
746
  interface GenericEntrypoint extends BaseEntrypoint {
726
- type: 'sandbox' | 'bookmarks' | 'history' | 'newtab' | 'devtools' | 'unlisted-page' | 'unlisted-script' | 'unlisted-style' | 'content-script-style';
747
+ type: 'sandbox' | 'bookmarks' | 'history' | 'newtab' | 'devtools' | 'unlisted-page' | 'unlisted-style' | 'content-script-style';
727
748
  options: ResolvedPerBrowserOptions<BaseEntrypointOptions>;
728
749
  }
750
+ interface UnlistedScriptEntrypoint extends BaseEntrypoint {
751
+ type: 'unlisted-script';
752
+ options: ResolvedPerBrowserOptions<BaseScriptEntrypointOptions>;
753
+ }
729
754
  interface BackgroundEntrypoint extends BaseEntrypoint {
730
755
  type: 'background';
731
756
  options: ResolvedPerBrowserOptions<BackgroundEntrypointOptions>;
@@ -746,7 +771,7 @@ interface SidepanelEntrypoint extends BaseEntrypoint {
746
771
  type: 'sidepanel';
747
772
  options: ResolvedPerBrowserOptions<SidepanelEntrypointOptions, 'defaultIcon'>;
748
773
  }
749
- type Entrypoint = GenericEntrypoint | BackgroundEntrypoint | ContentScriptEntrypoint | PopupEntrypoint | OptionsEntrypoint | SidepanelEntrypoint;
774
+ type Entrypoint = GenericEntrypoint | BackgroundEntrypoint | UnlistedScriptEntrypoint | ContentScriptEntrypoint | PopupEntrypoint | OptionsEntrypoint | SidepanelEntrypoint;
750
775
  interface EntrypointInfo {
751
776
  name: string;
752
777
  /** Absolute path to the entrypoint file. */
@@ -782,7 +807,7 @@ interface BackgroundDefinition extends BackgroundEntrypointOptions {
782
807
  */
783
808
  main(): void;
784
809
  }
785
- interface UnlistedScriptDefinition extends BaseEntrypointOptions {
810
+ interface UnlistedScriptDefinition extends BaseScriptEntrypointOptions {
786
811
  /**
787
812
  * Main function executed when the unlisted script is ran.
788
813
  *
@@ -1472,4 +1497,4 @@ interface WxtDirFileEntry {
1472
1497
  tsReference?: boolean;
1473
1498
  }
1474
1499
  //#endregion
1475
- export { BackgroundDefinition, BackgroundEntrypoint, BackgroundEntrypointOptions, BaseContentScriptEntrypointOptions, BaseEntrypoint, BaseEntrypointOptions, BuildOutput, BuildStepOutput, ConfigEnv, ContentScriptDefinition, ContentScriptEntrypoint, CopiedPublicFile, Dependency, Entrypoint, EntrypointGroup, EntrypointInfo, EslintGlobalsPropValue, Eslintrc, ExtensionRunner, ExtensionRunnerConfig, FsCache, GeneratedPublicFile, GenericEntrypoint, HookResult, InlineConfig, IsolatedWorldContentScriptDefinition, IsolatedWorldContentScriptEntrypointOptions, Logger, MainWorldContentScriptDefinition, MainWorldContentScriptEntrypointOptions, OnContentScriptStopped, OptionsEntrypoint, OptionsEntrypointOptions, OutputAsset, OutputChunk, OutputFile, PerBrowserMap, PerBrowserOption, PopupEntrypoint, PopupEntrypointOptions, ReloadContentScriptPayload, ResolvedBasePublicFile, ResolvedConfig$1 as ResolvedConfig, ResolvedEslintrc, ResolvedPerBrowserOptions, ResolvedPublicFile, ServerInfo, SidepanelEntrypoint, SidepanelEntrypointOptions, TargetBrowser, TargetManifestVersion, ThemeIcon, UnlistedScriptDefinition, UserConfig, UserManifest, UserManifestFn, WebExtConfig, Wxt, WxtBuilder, WxtBuilderServer, WxtCommand, WxtDevServer, WxtDirEntry, WxtDirFileEntry, WxtDirTypeReferenceEntry, WxtHooks, WxtModule, WxtModuleOptions, WxtModuleSetup, WxtModuleWithMetadata, WxtPackageManager, WxtPlugin, WxtResolvedUnimportOptions, WxtUnimportOptions, WxtViteConfig };
1500
+ export { BackgroundDefinition, BackgroundEntrypoint, BackgroundEntrypointOptions, BaseContentScriptEntrypointOptions, BaseEntrypoint, BaseEntrypointOptions, BaseScriptEntrypointOptions, BuildOutput, BuildStepOutput, ConfigEnv, ContentScriptDefinition, ContentScriptEntrypoint, CopiedPublicFile, Dependency, Entrypoint, EntrypointGroup, EntrypointInfo, EslintGlobalsPropValue, Eslintrc, ExtensionRunner, ExtensionRunnerConfig, FsCache, GeneratedPublicFile, GenericEntrypoint, HookResult, InlineConfig, IsolatedWorldContentScriptDefinition, IsolatedWorldContentScriptEntrypointOptions, Logger, MainWorldContentScriptDefinition, MainWorldContentScriptEntrypointOptions, OnContentScriptStopped, OptionsEntrypoint, OptionsEntrypointOptions, OutputAsset, OutputChunk, OutputFile, PerBrowserMap, PerBrowserOption, PopupEntrypoint, PopupEntrypointOptions, ReloadContentScriptPayload, ResolvedBasePublicFile, ResolvedConfig$1 as ResolvedConfig, ResolvedEslintrc, ResolvedPerBrowserOptions, ResolvedPublicFile, ServerInfo, SidepanelEntrypoint, SidepanelEntrypointOptions, TargetBrowser, TargetManifestVersion, ThemeIcon, UnlistedScriptDefinition, UnlistedScriptEntrypoint, UserConfig, UserManifest, UserManifestFn, WebExtConfig, Wxt, WxtBuilder, WxtBuilderServer, WxtCommand, WxtDevServer, WxtDirEntry, WxtDirFileEntry, WxtDirTypeReferenceEntry, WxtHooks, WxtModule, WxtModuleOptions, WxtModuleSetup, WxtModuleWithMetadata, WxtPackageManager, WxtPlugin, WxtResolvedUnimportOptions, WxtUnimportOptions, WxtViteConfig };
@@ -1,6 +1,17 @@
1
1
  import { WxtAppConfig } from "./define-app-config.mjs";
2
2
 
3
3
  //#region src/utils/app-config.d.ts
4
+ /**
5
+ * Get runtime config defined in `<srcDir>/app.config.ts`
6
+ *
7
+ * @see https://wxt.dev/guide/essentials/config/runtime.html
8
+ */
9
+ declare function getAppConfig(): WxtAppConfig;
10
+ /**
11
+ * Alias for {@link getAppConfig}.
12
+ *
13
+ * @see https://wxt.dev/guide/essentials/config/runtime.html
14
+ */
4
15
  declare function useAppConfig(): WxtAppConfig;
5
16
  //#endregion
6
- export { useAppConfig };
17
+ export { getAppConfig, useAppConfig };
@@ -2,9 +2,22 @@ import appConfig from "virtual:app-config";
2
2
 
3
3
  //#region src/utils/app-config.ts
4
4
  /** @module wxt/utils/app-config */
5
- function useAppConfig() {
5
+ /**
6
+ * Get runtime config defined in `<srcDir>/app.config.ts`
7
+ *
8
+ * @see https://wxt.dev/guide/essentials/config/runtime.html
9
+ */
10
+ function getAppConfig() {
6
11
  return appConfig;
7
12
  }
13
+ /**
14
+ * Alias for {@link getAppConfig}.
15
+ *
16
+ * @see https://wxt.dev/guide/essentials/config/runtime.html
17
+ */
18
+ function useAppConfig() {
19
+ return getAppConfig();
20
+ }
8
21
 
9
22
  //#endregion
10
- export { useAppConfig };
23
+ export { getAppConfig, useAppConfig };
@@ -1,21 +1,30 @@
1
1
  import { WxtLocationChangeEvent } from "./custom-events.mjs";
2
2
 
3
3
  //#region src/utils/internal/location-watcher.ts
4
+ const supportsNavigationApi = typeof globalThis.navigation?.addEventListener === "function";
4
5
  /**
5
6
  * Create a util that watches for URL changes, dispatching the custom event when detected. Stops
6
- * watching when content script is invalidated.
7
+ * watching when content script is invalidated. Uses Navigation API when available, otherwise
8
+ * falls back to polling.
7
9
  */
8
10
  function createLocationWatcher(ctx) {
9
- let interval;
10
- let oldUrl;
11
+ let lastUrl;
12
+ let watching = false;
11
13
  return { run() {
12
- if (interval != null) return;
13
- oldUrl = new URL(location.href);
14
- interval = ctx.setInterval(() => {
15
- let newUrl = new URL(location.href);
16
- if (newUrl.href !== oldUrl.href) {
17
- window.dispatchEvent(new WxtLocationChangeEvent(newUrl, oldUrl));
18
- oldUrl = newUrl;
14
+ if (watching) return;
15
+ watching = true;
16
+ lastUrl = new URL(location.href);
17
+ if (supportsNavigationApi) globalThis.navigation.addEventListener("navigate", (event) => {
18
+ const newUrl = new URL(event.destination.url);
19
+ if (newUrl.href === lastUrl.href) return;
20
+ window.dispatchEvent(new WxtLocationChangeEvent(newUrl, lastUrl));
21
+ lastUrl = newUrl;
22
+ }, { signal: ctx.signal });
23
+ else ctx.setInterval(() => {
24
+ const newUrl = new URL(location.href);
25
+ if (newUrl.href !== lastUrl.href) {
26
+ window.dispatchEvent(new WxtLocationChangeEvent(newUrl, lastUrl));
27
+ lastUrl = newUrl;
19
28
  }
20
29
  }, 1e3);
21
30
  } };
package/dist/version.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  //#region src/version.ts
2
- const version = "0.20.17";
2
+ const version = "0.21.0";
3
3
 
4
4
  //#endregion
5
5
  export { version };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "wxt",
3
3
  "type": "module",
4
- "version": "0.20.17",
4
+ "version": "0.21.0",
5
5
  "description": "⚡ Next-gen Web Extension Framework",
6
6
  "license": "MIT",
7
7
  "dependencies": {
@@ -43,13 +43,13 @@
43
43
  "perfect-debounce": "^2.1.0",
44
44
  "picocolors": "^1.1.1",
45
45
  "prompts": "^2.4.2",
46
- "publish-browser-extension": "^2.3.0 || ^3.0.2 || ^4.0.0",
46
+ "publish-browser-extension": "^2.3.0 || ^3.0.2 || ^4.0.4",
47
47
  "scule": "^1.3.0",
48
48
  "unimport": "^3.13.1 || ^4.0.0 || ^5.0.0",
49
49
  "vite": "^5.4.19 || ^6.3.4 || ^7.0.0",
50
50
  "vite-node": "^3.2.4 || ^5.0.0",
51
51
  "web-ext-run": "^0.2.4",
52
- "@wxt-dev/browser": "^0.1.36"
52
+ "@wxt-dev/browser": "^0.1.37"
53
53
  },
54
54
  "peerDependencies": {
55
55
  "eslint": "^8.57.0 || ^9.0.0"