wxt 0.19.19 → 0.19.21
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.
- package/dist/client/content-scripts/ui/index.mjs +104 -6
- package/dist/client/content-scripts/ui/types.d.ts +34 -12
- package/dist/core/builders/vite/index.mjs +78 -34
- package/dist/core/create-server.mjs +3 -1
- package/dist/core/keyboard-shortcuts.d.ts +3 -1
- package/dist/core/keyboard-shortcuts.mjs +2 -2
- package/dist/core/runners/web-ext.mjs +3 -0
- package/dist/core/utils/building/find-entrypoints.mjs +161 -171
- package/dist/core/utils/entrypoints.d.ts +7 -1
- package/dist/core/utils/entrypoints.mjs +7 -2
- package/dist/core/utils/manifest.d.ts +1 -1
- package/dist/core/utils/manifest.mjs +2 -1
- package/dist/core/utils/testing/fake-objects.d.ts +3 -2
- package/dist/core/utils/testing/fake-objects.mjs +2 -2
- package/dist/types.d.ts +7 -1
- package/dist/version.mjs +1 -1
- package/package.json +2 -1
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import { browser } from "wxt/browser";
|
|
2
|
+
import { waitElement } from "@1natsu/wait-element";
|
|
3
|
+
import {
|
|
4
|
+
isExist as mountDetector,
|
|
5
|
+
isNotExist as removeDetector
|
|
6
|
+
} from "@1natsu/wait-element/detectors";
|
|
2
7
|
import { logger } from "../../../sandbox/utils/logger.mjs";
|
|
3
8
|
import { createIsolatedElement } from "@webext-core/isolated-element";
|
|
4
9
|
export * from "./types.mjs";
|
|
@@ -17,14 +22,20 @@ export function createIntegratedUi(ctx, options) {
|
|
|
17
22
|
wrapper.remove();
|
|
18
23
|
mounted = void 0;
|
|
19
24
|
};
|
|
25
|
+
const mountFunctions = createMountFunctions(
|
|
26
|
+
{
|
|
27
|
+
mount,
|
|
28
|
+
remove
|
|
29
|
+
},
|
|
30
|
+
options
|
|
31
|
+
);
|
|
20
32
|
ctx.onInvalidated(remove);
|
|
21
33
|
return {
|
|
22
34
|
get mounted() {
|
|
23
35
|
return mounted;
|
|
24
36
|
},
|
|
25
37
|
wrapper,
|
|
26
|
-
|
|
27
|
-
remove
|
|
38
|
+
...mountFunctions
|
|
28
39
|
};
|
|
29
40
|
}
|
|
30
41
|
export function createIframeUi(ctx, options) {
|
|
@@ -44,6 +55,13 @@ export function createIframeUi(ctx, options) {
|
|
|
44
55
|
wrapper.remove();
|
|
45
56
|
mounted = void 0;
|
|
46
57
|
};
|
|
58
|
+
const mountFunctions = createMountFunctions(
|
|
59
|
+
{
|
|
60
|
+
mount,
|
|
61
|
+
remove
|
|
62
|
+
},
|
|
63
|
+
options
|
|
64
|
+
);
|
|
47
65
|
ctx.onInvalidated(remove);
|
|
48
66
|
return {
|
|
49
67
|
get mounted() {
|
|
@@ -51,8 +69,7 @@ export function createIframeUi(ctx, options) {
|
|
|
51
69
|
},
|
|
52
70
|
iframe,
|
|
53
71
|
wrapper,
|
|
54
|
-
|
|
55
|
-
remove
|
|
72
|
+
...mountFunctions
|
|
56
73
|
};
|
|
57
74
|
}
|
|
58
75
|
export async function createShadowRootUi(ctx, options) {
|
|
@@ -87,13 +104,19 @@ export async function createShadowRootUi(ctx, options) {
|
|
|
87
104
|
uiContainer.removeChild(uiContainer.lastChild);
|
|
88
105
|
mounted = void 0;
|
|
89
106
|
};
|
|
107
|
+
const mountFunctions = createMountFunctions(
|
|
108
|
+
{
|
|
109
|
+
mount,
|
|
110
|
+
remove
|
|
111
|
+
},
|
|
112
|
+
options
|
|
113
|
+
);
|
|
90
114
|
ctx.onInvalidated(remove);
|
|
91
115
|
return {
|
|
92
116
|
shadow,
|
|
93
117
|
shadowHost,
|
|
94
118
|
uiContainer,
|
|
95
|
-
|
|
96
|
-
remove,
|
|
119
|
+
...mountFunctions,
|
|
97
120
|
get mounted() {
|
|
98
121
|
return mounted;
|
|
99
122
|
}
|
|
@@ -172,6 +195,81 @@ function mountUi(root, options) {
|
|
|
172
195
|
break;
|
|
173
196
|
}
|
|
174
197
|
}
|
|
198
|
+
function createMountFunctions(baseFunctions, options) {
|
|
199
|
+
let autoMountInstance = void 0;
|
|
200
|
+
const stopAutoMount = () => {
|
|
201
|
+
autoMountInstance?.stopAutoMount();
|
|
202
|
+
autoMountInstance = void 0;
|
|
203
|
+
};
|
|
204
|
+
const mount = () => {
|
|
205
|
+
baseFunctions.mount();
|
|
206
|
+
};
|
|
207
|
+
const unmount = baseFunctions.remove;
|
|
208
|
+
const remove = () => {
|
|
209
|
+
stopAutoMount();
|
|
210
|
+
baseFunctions.remove();
|
|
211
|
+
};
|
|
212
|
+
const autoMount = (autoMountOptions) => {
|
|
213
|
+
if (autoMountInstance) {
|
|
214
|
+
logger.warn("autoMount is already set.");
|
|
215
|
+
}
|
|
216
|
+
autoMountInstance = autoMountUi(
|
|
217
|
+
{ mount, unmount, stopAutoMount },
|
|
218
|
+
{
|
|
219
|
+
...options,
|
|
220
|
+
...autoMountOptions
|
|
221
|
+
}
|
|
222
|
+
);
|
|
223
|
+
};
|
|
224
|
+
return {
|
|
225
|
+
mount,
|
|
226
|
+
remove,
|
|
227
|
+
autoMount
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
function autoMountUi(uiCallbacks, options) {
|
|
231
|
+
const abortController = new AbortController();
|
|
232
|
+
const EXPLICIT_STOP_REASON = "explicit_stop_auto_mount";
|
|
233
|
+
const _stopAutoMount = () => {
|
|
234
|
+
abortController.abort(EXPLICIT_STOP_REASON);
|
|
235
|
+
options.onStop?.();
|
|
236
|
+
};
|
|
237
|
+
let resolvedAnchor = typeof options.anchor === "function" ? options.anchor() : options.anchor;
|
|
238
|
+
if (resolvedAnchor instanceof Element) {
|
|
239
|
+
throw Error(
|
|
240
|
+
"autoMount and Element anchor option cannot be combined. Avoid passing `Element` directly or `() => Element` to the anchor."
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
async function observeElement(selector) {
|
|
244
|
+
let isAnchorExist = !!getAnchor(options);
|
|
245
|
+
while (!abortController.signal.aborted) {
|
|
246
|
+
try {
|
|
247
|
+
const changedAnchor = await waitElement(selector ?? "body", {
|
|
248
|
+
customMatcher: () => getAnchor(options) ?? null,
|
|
249
|
+
detector: isAnchorExist ? removeDetector : mountDetector,
|
|
250
|
+
signal: abortController.signal
|
|
251
|
+
});
|
|
252
|
+
isAnchorExist = !!changedAnchor;
|
|
253
|
+
if (isAnchorExist) {
|
|
254
|
+
uiCallbacks.mount();
|
|
255
|
+
} else {
|
|
256
|
+
uiCallbacks.unmount();
|
|
257
|
+
if (options.once) {
|
|
258
|
+
uiCallbacks.stopAutoMount();
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
} catch (error) {
|
|
262
|
+
if (abortController.signal.aborted && abortController.signal.reason === EXPLICIT_STOP_REASON) {
|
|
263
|
+
break;
|
|
264
|
+
} else {
|
|
265
|
+
throw error;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
observeElement(resolvedAnchor);
|
|
271
|
+
return { stopAutoMount: _stopAutoMount };
|
|
272
|
+
}
|
|
175
273
|
async function loadCss() {
|
|
176
274
|
const url = browser.runtime.getURL(
|
|
177
275
|
`/content-scripts/${import.meta.env.ENTRYPOINT}.css`
|
|
@@ -30,18 +30,7 @@ export interface ShadowRootContentScriptUi<TMounted> extends ContentScriptUi<TMo
|
|
|
30
30
|
*/
|
|
31
31
|
shadow: ShadowRoot;
|
|
32
32
|
}
|
|
33
|
-
export interface ContentScriptUi<TMounted> {
|
|
34
|
-
/**
|
|
35
|
-
* Function that mounts or remounts the UI on the page.
|
|
36
|
-
*/
|
|
37
|
-
mount: () => void;
|
|
38
|
-
/**
|
|
39
|
-
* Function that removes the UI from the webpage.
|
|
40
|
-
*/
|
|
41
|
-
remove: () => void;
|
|
42
|
-
/**>
|
|
43
|
-
* Custom data returned from the `options.mount` function.
|
|
44
|
-
*/
|
|
33
|
+
export interface ContentScriptUi<TMounted> extends MountFunctions {
|
|
45
34
|
mounted: TMounted | undefined;
|
|
46
35
|
}
|
|
47
36
|
export type ContentScriptUiOptions<TMounted> = ContentScriptPositioningOptions & ContentScriptAnchoredOptions & {
|
|
@@ -172,3 +161,36 @@ export interface ContentScriptAnchoredOptions {
|
|
|
172
161
|
*/
|
|
173
162
|
append?: ContentScriptAppendMode | ((anchor: Element, ui: Element) => void);
|
|
174
163
|
}
|
|
164
|
+
export interface BaseMountFunctions {
|
|
165
|
+
/**
|
|
166
|
+
* Function that mounts or remounts the UI on the page.
|
|
167
|
+
*/
|
|
168
|
+
mount: () => void;
|
|
169
|
+
/**
|
|
170
|
+
* Function that removes the UI from the webpage.
|
|
171
|
+
*/
|
|
172
|
+
remove: () => void;
|
|
173
|
+
}
|
|
174
|
+
export interface MountFunctions extends BaseMountFunctions {
|
|
175
|
+
/**
|
|
176
|
+
* Call `ui.autoMount()` to automatically mount and remove the UI as the anchor is dynamically added/removed by the webpage.
|
|
177
|
+
*/
|
|
178
|
+
autoMount: (options?: AutoMountOptions) => void;
|
|
179
|
+
}
|
|
180
|
+
export type AutoMountOptions = {
|
|
181
|
+
/**
|
|
182
|
+
* When true, only mount and unmount a UI once.
|
|
183
|
+
*/
|
|
184
|
+
once?: boolean;
|
|
185
|
+
/**
|
|
186
|
+
* The callback triggered when `StopAutoMount` is called.
|
|
187
|
+
*/
|
|
188
|
+
onStop?: () => void;
|
|
189
|
+
};
|
|
190
|
+
export type StopAutoMount = () => void;
|
|
191
|
+
export interface AutoMount {
|
|
192
|
+
/**
|
|
193
|
+
* Stop watching the anchor element for changes, but keep the UI mounted.
|
|
194
|
+
*/
|
|
195
|
+
stopAutoMount: StopAutoMount;
|
|
196
|
+
}
|
|
@@ -9,6 +9,8 @@ import { importEntrypointFile } from "../../utils/building/index.mjs";
|
|
|
9
9
|
import { ViteNodeServer } from "vite-node/server";
|
|
10
10
|
import { ViteNodeRunner } from "vite-node/client";
|
|
11
11
|
import { installSourcemapsSupport } from "vite-node/source-map";
|
|
12
|
+
import { createExtensionEnvironment } from "../../utils/environments/index.mjs";
|
|
13
|
+
import { relative } from "node:path";
|
|
12
14
|
export async function createViteBuilder(wxtConfig, hooks, getWxtDevServer) {
|
|
13
15
|
const vite = await import("vite");
|
|
14
16
|
const getBaseConfig = async (baseConfigOptions) => {
|
|
@@ -161,54 +163,96 @@ export async function createViteBuilder(wxtConfig, hooks, getWxtDevServer) {
|
|
|
161
163
|
}
|
|
162
164
|
};
|
|
163
165
|
};
|
|
166
|
+
const createViteNodeImporter = async (paths) => {
|
|
167
|
+
const baseConfig = await getBaseConfig({
|
|
168
|
+
excludeAnalysisPlugin: true
|
|
169
|
+
});
|
|
170
|
+
baseConfig.optimizeDeps ??= {};
|
|
171
|
+
baseConfig.optimizeDeps.noDiscovery = true;
|
|
172
|
+
baseConfig.optimizeDeps.include = [];
|
|
173
|
+
const envConfig = {
|
|
174
|
+
plugins: paths.map(
|
|
175
|
+
(path) => wxtPlugins.removeEntrypointMainFunction(wxtConfig, path)
|
|
176
|
+
)
|
|
177
|
+
};
|
|
178
|
+
const config = vite.mergeConfig(baseConfig, envConfig);
|
|
179
|
+
const server = await vite.createServer(config);
|
|
180
|
+
await server.pluginContainer.buildStart({});
|
|
181
|
+
const node = new ViteNodeServer(
|
|
182
|
+
// @ts-ignore: Some weird type error...
|
|
183
|
+
server
|
|
184
|
+
);
|
|
185
|
+
installSourcemapsSupport({
|
|
186
|
+
getSourceMap: (source) => node.getSourceMap(source)
|
|
187
|
+
});
|
|
188
|
+
const runner = new ViteNodeRunner({
|
|
189
|
+
root: server.config.root,
|
|
190
|
+
base: server.config.base,
|
|
191
|
+
// when having the server and runner in a different context,
|
|
192
|
+
// you will need to handle the communication between them
|
|
193
|
+
// and pass to this function
|
|
194
|
+
fetchModule(id) {
|
|
195
|
+
return node.fetchModule(id);
|
|
196
|
+
},
|
|
197
|
+
resolveId(id, importer) {
|
|
198
|
+
return node.resolveId(id, importer);
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
return { runner, server };
|
|
202
|
+
};
|
|
203
|
+
const requireDefaultExport = (path, mod) => {
|
|
204
|
+
const relativePath = relative(wxtConfig.root, path);
|
|
205
|
+
if (mod?.default == null) {
|
|
206
|
+
const defineFn = relativePath.includes(".content") ? "defineContentScript" : relativePath.includes("background") ? "defineBackground" : "defineUnlistedScript";
|
|
207
|
+
throw Error(
|
|
208
|
+
`${relativePath}: Default export not found, did you forget to call "export default ${defineFn}(...)"?`
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
};
|
|
164
212
|
return {
|
|
165
213
|
name: "Vite",
|
|
166
214
|
version: vite.version,
|
|
167
215
|
async importEntrypoint(path) {
|
|
216
|
+
const env = createExtensionEnvironment();
|
|
168
217
|
switch (wxtConfig.entrypointLoader) {
|
|
169
218
|
default:
|
|
170
219
|
case "jiti": {
|
|
171
|
-
return await importEntrypointFile(path);
|
|
220
|
+
return await env.run(() => importEntrypointFile(path));
|
|
172
221
|
}
|
|
173
222
|
case "vite-node": {
|
|
174
|
-
const
|
|
175
|
-
|
|
176
|
-
});
|
|
177
|
-
baseConfig.optimizeDeps ??= {};
|
|
178
|
-
baseConfig.optimizeDeps.noDiscovery = true;
|
|
179
|
-
baseConfig.optimizeDeps.include = [];
|
|
180
|
-
const envConfig = {
|
|
181
|
-
plugins: [wxtPlugins.removeEntrypointMainFunction(wxtConfig, path)]
|
|
182
|
-
};
|
|
183
|
-
const config = vite.mergeConfig(baseConfig, envConfig);
|
|
184
|
-
const server = await vite.createServer(config);
|
|
185
|
-
await server.pluginContainer.buildStart({});
|
|
186
|
-
const node = new ViteNodeServer(
|
|
187
|
-
// @ts-ignore: Some weird type error...
|
|
188
|
-
server
|
|
189
|
-
);
|
|
190
|
-
installSourcemapsSupport({
|
|
191
|
-
getSourceMap: (source) => node.getSourceMap(source)
|
|
192
|
-
});
|
|
193
|
-
const runner = new ViteNodeRunner({
|
|
194
|
-
root: server.config.root,
|
|
195
|
-
base: server.config.base,
|
|
196
|
-
// when having the server and runner in a different context,
|
|
197
|
-
// you will need to handle the communication between them
|
|
198
|
-
// and pass to this function
|
|
199
|
-
fetchModule(id) {
|
|
200
|
-
return node.fetchModule(id);
|
|
201
|
-
},
|
|
202
|
-
resolveId(id, importer) {
|
|
203
|
-
return node.resolveId(id, importer);
|
|
204
|
-
}
|
|
205
|
-
});
|
|
206
|
-
const res = await runner.executeFile(path);
|
|
223
|
+
const { runner, server } = await createViteNodeImporter([path]);
|
|
224
|
+
const res = await env.run(() => runner.executeFile(path));
|
|
207
225
|
await server.close();
|
|
226
|
+
requireDefaultExport(path, res);
|
|
208
227
|
return res.default;
|
|
209
228
|
}
|
|
210
229
|
}
|
|
211
230
|
},
|
|
231
|
+
async importEntrypoints(paths) {
|
|
232
|
+
const env = createExtensionEnvironment();
|
|
233
|
+
switch (wxtConfig.entrypointLoader) {
|
|
234
|
+
default:
|
|
235
|
+
case "jiti": {
|
|
236
|
+
return await env.run(
|
|
237
|
+
() => Promise.all(paths.map(importEntrypointFile))
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
case "vite-node": {
|
|
241
|
+
const { runner, server } = await createViteNodeImporter(paths);
|
|
242
|
+
const res = await env.run(
|
|
243
|
+
() => Promise.all(
|
|
244
|
+
paths.map(async (path) => {
|
|
245
|
+
const mod = await runner.executeFile(path);
|
|
246
|
+
requireDefaultExport(path, mod);
|
|
247
|
+
return mod.default;
|
|
248
|
+
})
|
|
249
|
+
)
|
|
250
|
+
);
|
|
251
|
+
await server.close();
|
|
252
|
+
return res;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
},
|
|
212
256
|
async build(group) {
|
|
213
257
|
let entryConfig;
|
|
214
258
|
if (Array.isArray(group)) entryConfig = getMultiPageConfig(group);
|
|
@@ -76,7 +76,9 @@ async function createServerInternal() {
|
|
|
76
76
|
const reloadOnChange = createFileReloader(server);
|
|
77
77
|
server.watcher.on("all", reloadOnChange);
|
|
78
78
|
keyboardShortcuts.start();
|
|
79
|
-
keyboardShortcuts.printHelp(
|
|
79
|
+
keyboardShortcuts.printHelp({
|
|
80
|
+
canReopenBrowser: !wxt.config.runnerConfig.config.disabled && !!runner.canOpen?.()
|
|
81
|
+
});
|
|
80
82
|
},
|
|
81
83
|
async stop() {
|
|
82
84
|
wasStopped = true;
|
|
@@ -2,7 +2,9 @@ import { WxtDevServer } from '../types';
|
|
|
2
2
|
export interface KeyboardShortcutWatcher {
|
|
3
3
|
start(): void;
|
|
4
4
|
stop(): void;
|
|
5
|
-
printHelp(
|
|
5
|
+
printHelp(flags: {
|
|
6
|
+
canReopenBrowser: boolean;
|
|
7
|
+
}): void;
|
|
6
8
|
}
|
|
7
9
|
/**
|
|
8
10
|
* Function that creates a keyboard shortcut handler for the extension.
|
|
@@ -28,8 +28,8 @@ export function createKeyboardShortcuts(server) {
|
|
|
28
28
|
}
|
|
29
29
|
isWatching = false;
|
|
30
30
|
},
|
|
31
|
-
printHelp() {
|
|
32
|
-
if (
|
|
31
|
+
printHelp(flags) {
|
|
32
|
+
if (flags.canReopenBrowser) {
|
|
33
33
|
wxt.logger.info(
|
|
34
34
|
`${pc.dim("Press")} ${pc.bold("o + enter")} ${pc.dim("to reopen the browser")}`
|
|
35
35
|
);
|
|
@@ -4,6 +4,9 @@ import { wxt } from "../wxt.mjs";
|
|
|
4
4
|
export function createWebExtRunner() {
|
|
5
5
|
let runner;
|
|
6
6
|
return {
|
|
7
|
+
canOpen() {
|
|
8
|
+
return true;
|
|
9
|
+
},
|
|
7
10
|
async openBrowser() {
|
|
8
11
|
const startTime = Date.now();
|
|
9
12
|
if (wxt.config.browser === "firefox" && wxt.config.manifestVersion === 3) {
|
|
@@ -6,13 +6,15 @@ import JSON5 from "json5";
|
|
|
6
6
|
import glob from "fast-glob";
|
|
7
7
|
import {
|
|
8
8
|
getEntrypointName,
|
|
9
|
+
isHtmlEntrypoint,
|
|
10
|
+
isJsEntrypoint,
|
|
9
11
|
resolvePerBrowserOptions
|
|
10
12
|
} from "../../utils/entrypoints.mjs";
|
|
11
13
|
import { VIRTUAL_NOOP_BACKGROUND_MODULE_ID } from "../../utils/constants.mjs";
|
|
12
14
|
import { CSS_EXTENSIONS_PATTERN } from "../../utils/paths.mjs";
|
|
13
15
|
import pc from "picocolors";
|
|
14
16
|
import { wxt } from "../../wxt.mjs";
|
|
15
|
-
import {
|
|
17
|
+
import { camelCase } from "scule";
|
|
16
18
|
export async function findEntrypoints() {
|
|
17
19
|
await fs.mkdir(wxt.config.wxtDir, { recursive: true });
|
|
18
20
|
try {
|
|
@@ -46,58 +48,60 @@ export async function findEntrypoints() {
|
|
|
46
48
|
preventNoEntrypoints(entrypointInfos);
|
|
47
49
|
preventDuplicateEntrypointNames(entrypointInfos);
|
|
48
50
|
let hasBackground = false;
|
|
49
|
-
const
|
|
50
|
-
const entrypointsWithoutSkipped = await
|
|
51
|
-
() =>
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
)
|
|
51
|
+
const entrypointOptions = await importEntrypoints(entrypointInfos);
|
|
52
|
+
const entrypointsWithoutSkipped = await Promise.all(
|
|
53
|
+
entrypointInfos.map(async (info) => {
|
|
54
|
+
const { type } = info;
|
|
55
|
+
const options = entrypointOptions[info.inputPath] ?? {};
|
|
56
|
+
switch (type) {
|
|
57
|
+
case "popup":
|
|
58
|
+
return await getPopupEntrypoint(info, options);
|
|
59
|
+
case "sidepanel":
|
|
60
|
+
return await getSidepanelEntrypoint(info, options);
|
|
61
|
+
case "options":
|
|
62
|
+
return await getOptionsEntrypoint(info, options);
|
|
63
|
+
case "background":
|
|
64
|
+
hasBackground = true;
|
|
65
|
+
return await getBackgroundEntrypoint(info, options);
|
|
66
|
+
case "content-script":
|
|
67
|
+
return await getContentScriptEntrypoint(info, options);
|
|
68
|
+
case "unlisted-page":
|
|
69
|
+
return await getUnlistedPageEntrypoint(info, options);
|
|
70
|
+
case "unlisted-script":
|
|
71
|
+
return await getUnlistedScriptEntrypoint(info, options);
|
|
72
|
+
case "content-script-style":
|
|
73
|
+
return {
|
|
74
|
+
...info,
|
|
75
|
+
type,
|
|
76
|
+
outputDir: resolve(wxt.config.outDir, CONTENT_SCRIPT_OUT_DIR),
|
|
77
|
+
options: {
|
|
78
|
+
include: options.include,
|
|
79
|
+
exclude: options.exclude
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
default:
|
|
83
|
+
return {
|
|
84
|
+
...info,
|
|
85
|
+
type,
|
|
86
|
+
outputDir: wxt.config.outDir,
|
|
87
|
+
options: {
|
|
88
|
+
include: options.include,
|
|
89
|
+
exclude: options.exclude
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
})
|
|
93
94
|
);
|
|
94
95
|
if (wxt.config.command === "serve" && !hasBackground) {
|
|
95
96
|
entrypointsWithoutSkipped.push(
|
|
96
|
-
await getBackgroundEntrypoint(
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
97
|
+
await getBackgroundEntrypoint(
|
|
98
|
+
{
|
|
99
|
+
inputPath: VIRTUAL_NOOP_BACKGROUND_MODULE_ID,
|
|
100
|
+
name: "background",
|
|
101
|
+
type: "background"
|
|
102
|
+
},
|
|
103
|
+
{}
|
|
104
|
+
)
|
|
101
105
|
);
|
|
102
106
|
}
|
|
103
107
|
const entrypoints = entrypointsWithoutSkipped.map((entry) => ({
|
|
@@ -119,6 +123,48 @@ export async function findEntrypoints() {
|
|
|
119
123
|
await wxt.hooks.callHook("entrypoints:resolved", wxt, entrypoints);
|
|
120
124
|
return entrypoints;
|
|
121
125
|
}
|
|
126
|
+
async function importEntrypoints(infos) {
|
|
127
|
+
const resMap = {};
|
|
128
|
+
const htmlInfos = infos.filter((info) => isHtmlEntrypoint(info));
|
|
129
|
+
const jsInfos = infos.filter((info) => isJsEntrypoint(info));
|
|
130
|
+
await Promise.all([
|
|
131
|
+
// HTML
|
|
132
|
+
...htmlInfos.map(async (info) => {
|
|
133
|
+
const res = await importHtmlEntrypoint(info);
|
|
134
|
+
resMap[info.inputPath] = res;
|
|
135
|
+
}),
|
|
136
|
+
// JS
|
|
137
|
+
(async () => {
|
|
138
|
+
const res = await wxt.builder.importEntrypoints(
|
|
139
|
+
jsInfos.map((info) => info.inputPath)
|
|
140
|
+
);
|
|
141
|
+
res.forEach((res2, i) => {
|
|
142
|
+
resMap[jsInfos[i].inputPath] = res2;
|
|
143
|
+
});
|
|
144
|
+
})()
|
|
145
|
+
// CSS - never has options
|
|
146
|
+
]);
|
|
147
|
+
return resMap;
|
|
148
|
+
}
|
|
149
|
+
async function importHtmlEntrypoint(info) {
|
|
150
|
+
const content = await fs.readFile(info.inputPath, "utf-8");
|
|
151
|
+
const { document } = parseHTML(content);
|
|
152
|
+
const metaTags = document.querySelectorAll("meta");
|
|
153
|
+
const res = {
|
|
154
|
+
title: document.querySelector("title")?.textContent || void 0
|
|
155
|
+
};
|
|
156
|
+
metaTags.forEach((tag) => {
|
|
157
|
+
const name = tag.name;
|
|
158
|
+
if (!name.startsWith("manifest.")) return;
|
|
159
|
+
const key = camelCase(name.slice(9));
|
|
160
|
+
try {
|
|
161
|
+
res[key] = JSON5.parse(tag.content);
|
|
162
|
+
} catch {
|
|
163
|
+
res[key] = tag.content;
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
return res;
|
|
167
|
+
}
|
|
122
168
|
function preventDuplicateEntrypointNames(files) {
|
|
123
169
|
const namesToPaths = files.reduce(
|
|
124
170
|
(map, { name, inputPath }) => {
|
|
@@ -154,181 +200,125 @@ function preventNoEntrypoints(files) {
|
|
|
154
200
|
throw Error(`No entrypoints found in ${wxt.config.entrypointsDir}`);
|
|
155
201
|
}
|
|
156
202
|
}
|
|
157
|
-
async function getPopupEntrypoint(info) {
|
|
158
|
-
const
|
|
159
|
-
info,
|
|
203
|
+
async function getPopupEntrypoint(info, options) {
|
|
204
|
+
const stictOptions = resolvePerBrowserOptions(
|
|
160
205
|
{
|
|
161
|
-
browserStyle:
|
|
162
|
-
exclude:
|
|
163
|
-
include:
|
|
164
|
-
defaultIcon:
|
|
165
|
-
defaultTitle:
|
|
166
|
-
mv2Key:
|
|
206
|
+
browserStyle: options.browserStyle,
|
|
207
|
+
exclude: options.exclude,
|
|
208
|
+
include: options.include,
|
|
209
|
+
defaultIcon: options.defaultIcon,
|
|
210
|
+
defaultTitle: options.title,
|
|
211
|
+
mv2Key: options.type
|
|
167
212
|
},
|
|
168
|
-
|
|
169
|
-
defaultTitle: (document) => document.querySelector("title")?.textContent || void 0
|
|
170
|
-
},
|
|
171
|
-
{
|
|
172
|
-
defaultTitle: (content) => content,
|
|
173
|
-
mv2Key: (content) => content === "page_action" ? "page_action" : "browser_action"
|
|
174
|
-
}
|
|
213
|
+
wxt.config.browser
|
|
175
214
|
);
|
|
215
|
+
if (stictOptions.mv2Key && stictOptions.mv2Key !== "page_action")
|
|
216
|
+
stictOptions.mv2Key = "browser_action";
|
|
176
217
|
return {
|
|
177
218
|
type: "popup",
|
|
178
219
|
name: "popup",
|
|
179
|
-
options:
|
|
220
|
+
options: stictOptions,
|
|
180
221
|
inputPath: info.inputPath,
|
|
181
222
|
outputDir: wxt.config.outDir
|
|
182
223
|
};
|
|
183
224
|
}
|
|
184
|
-
async function getOptionsEntrypoint(info) {
|
|
185
|
-
const options = await getHtmlEntrypointOptions(
|
|
186
|
-
info,
|
|
187
|
-
{
|
|
188
|
-
browserStyle: "browser_style",
|
|
189
|
-
chromeStyle: "chrome_style",
|
|
190
|
-
exclude: "exclude",
|
|
191
|
-
include: "include",
|
|
192
|
-
openInTab: "open_in_tab"
|
|
193
|
-
}
|
|
194
|
-
);
|
|
225
|
+
async function getOptionsEntrypoint(info, options) {
|
|
195
226
|
return {
|
|
196
227
|
type: "options",
|
|
197
228
|
name: "options",
|
|
198
|
-
options: resolvePerBrowserOptions(
|
|
229
|
+
options: resolvePerBrowserOptions(
|
|
230
|
+
{
|
|
231
|
+
browserStyle: options.browserStyle,
|
|
232
|
+
chromeStyle: options.chromeStyle,
|
|
233
|
+
exclude: options.exclude,
|
|
234
|
+
include: options.include,
|
|
235
|
+
openInTab: options.openInTab
|
|
236
|
+
},
|
|
237
|
+
wxt.config.browser
|
|
238
|
+
),
|
|
199
239
|
inputPath: info.inputPath,
|
|
200
240
|
outputDir: wxt.config.outDir
|
|
201
241
|
};
|
|
202
242
|
}
|
|
203
|
-
async function getUnlistedPageEntrypoint(info) {
|
|
204
|
-
const options = await getHtmlEntrypointOptions(info, {
|
|
205
|
-
exclude: "exclude",
|
|
206
|
-
include: "include"
|
|
207
|
-
});
|
|
243
|
+
async function getUnlistedPageEntrypoint(info, options) {
|
|
208
244
|
return {
|
|
209
245
|
type: "unlisted-page",
|
|
210
246
|
name: info.name,
|
|
211
247
|
inputPath: info.inputPath,
|
|
212
248
|
outputDir: wxt.config.outDir,
|
|
213
|
-
options
|
|
249
|
+
options: {
|
|
250
|
+
include: options.include,
|
|
251
|
+
exclude: options.exclude
|
|
252
|
+
}
|
|
214
253
|
};
|
|
215
254
|
}
|
|
216
|
-
async function getUnlistedScriptEntrypoint({
|
|
217
|
-
inputPath,
|
|
218
|
-
name
|
|
219
|
-
}) {
|
|
220
|
-
const defaultExport = await wxt.builder.importEntrypoint(inputPath);
|
|
221
|
-
if (defaultExport == null) {
|
|
222
|
-
throw Error(
|
|
223
|
-
`${name}: Default export not found, did you forget to call "export default defineUnlistedScript(...)"?`
|
|
224
|
-
);
|
|
225
|
-
}
|
|
226
|
-
const { main: _, ...options } = defaultExport;
|
|
255
|
+
async function getUnlistedScriptEntrypoint({ inputPath, name }, options) {
|
|
227
256
|
return {
|
|
228
257
|
type: "unlisted-script",
|
|
229
258
|
name,
|
|
230
259
|
inputPath,
|
|
231
260
|
outputDir: wxt.config.outDir,
|
|
232
|
-
options: resolvePerBrowserOptions(
|
|
261
|
+
options: resolvePerBrowserOptions(
|
|
262
|
+
{
|
|
263
|
+
include: options.include,
|
|
264
|
+
exclude: options.exclude
|
|
265
|
+
},
|
|
266
|
+
wxt.config.browser
|
|
267
|
+
)
|
|
233
268
|
};
|
|
234
269
|
}
|
|
235
|
-
async function getBackgroundEntrypoint({
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
);
|
|
246
|
-
}
|
|
247
|
-
const { main: _, ...moduleOptions } = defaultExport;
|
|
248
|
-
options = moduleOptions;
|
|
249
|
-
}
|
|
270
|
+
async function getBackgroundEntrypoint({ inputPath, name }, options) {
|
|
271
|
+
const strictOptions = resolvePerBrowserOptions(
|
|
272
|
+
{
|
|
273
|
+
include: options.include,
|
|
274
|
+
exclude: options.exclude,
|
|
275
|
+
persistent: options.persistent,
|
|
276
|
+
type: options.type
|
|
277
|
+
},
|
|
278
|
+
wxt.config.browser
|
|
279
|
+
);
|
|
250
280
|
if (wxt.config.manifestVersion !== 3) {
|
|
251
|
-
delete
|
|
281
|
+
delete strictOptions.type;
|
|
252
282
|
}
|
|
253
283
|
return {
|
|
254
284
|
type: "background",
|
|
255
285
|
name,
|
|
256
286
|
inputPath,
|
|
257
287
|
outputDir: wxt.config.outDir,
|
|
258
|
-
options:
|
|
288
|
+
options: strictOptions
|
|
259
289
|
};
|
|
260
290
|
}
|
|
261
|
-
async function getContentScriptEntrypoint({
|
|
262
|
-
inputPath,
|
|
263
|
-
name
|
|
264
|
-
}) {
|
|
265
|
-
const defaultExport = await wxt.builder.importEntrypoint(inputPath);
|
|
266
|
-
if (defaultExport == null) {
|
|
267
|
-
throw Error(
|
|
268
|
-
`${name}: Default export not found, did you forget to call "export default defineContentScript(...)"?`
|
|
269
|
-
);
|
|
270
|
-
}
|
|
271
|
-
const { main: _, ...options } = defaultExport;
|
|
272
|
-
if (options == null) {
|
|
273
|
-
throw Error(
|
|
274
|
-
`${name}: Default export not found, did you forget to call "export default defineContentScript(...)"?`
|
|
275
|
-
);
|
|
276
|
-
}
|
|
291
|
+
async function getContentScriptEntrypoint({ inputPath, name }, options) {
|
|
277
292
|
return {
|
|
278
293
|
type: "content-script",
|
|
279
294
|
name,
|
|
280
295
|
inputPath,
|
|
281
296
|
outputDir: resolve(wxt.config.outDir, CONTENT_SCRIPT_OUT_DIR),
|
|
282
|
-
options: resolvePerBrowserOptions(
|
|
297
|
+
options: resolvePerBrowserOptions(
|
|
298
|
+
options,
|
|
299
|
+
wxt.config.browser
|
|
300
|
+
)
|
|
283
301
|
};
|
|
284
302
|
}
|
|
285
|
-
async function getSidepanelEntrypoint(info) {
|
|
286
|
-
const options = await getHtmlEntrypointOptions(
|
|
287
|
-
info,
|
|
288
|
-
{
|
|
289
|
-
browserStyle: "browser_style",
|
|
290
|
-
exclude: "exclude",
|
|
291
|
-
include: "include",
|
|
292
|
-
defaultIcon: "default_icon",
|
|
293
|
-
defaultTitle: "default_title",
|
|
294
|
-
openAtInstall: "open_at_install"
|
|
295
|
-
},
|
|
296
|
-
{
|
|
297
|
-
defaultTitle: (document) => document.querySelector("title")?.textContent || void 0
|
|
298
|
-
},
|
|
299
|
-
{
|
|
300
|
-
defaultTitle: (content) => content
|
|
301
|
-
}
|
|
302
|
-
);
|
|
303
|
+
async function getSidepanelEntrypoint(info, options) {
|
|
303
304
|
return {
|
|
304
305
|
type: "sidepanel",
|
|
305
306
|
name: info.name,
|
|
306
|
-
options: resolvePerBrowserOptions(
|
|
307
|
+
options: resolvePerBrowserOptions(
|
|
308
|
+
{
|
|
309
|
+
browserStyle: options.browserStyle,
|
|
310
|
+
exclude: options.exclude,
|
|
311
|
+
include: options.include,
|
|
312
|
+
defaultIcon: options.defaultIcon,
|
|
313
|
+
defaultTitle: options.title,
|
|
314
|
+
openAtInstall: options.openAtInstall
|
|
315
|
+
},
|
|
316
|
+
wxt.config.browser
|
|
317
|
+
),
|
|
307
318
|
inputPath: info.inputPath,
|
|
308
319
|
outputDir: wxt.config.outDir
|
|
309
320
|
};
|
|
310
321
|
}
|
|
311
|
-
async function getHtmlEntrypointOptions(info, keyMap, queries, parsers) {
|
|
312
|
-
const content = await fs.readFile(info.inputPath, "utf-8");
|
|
313
|
-
const { document } = parseHTML(content);
|
|
314
|
-
const options = {};
|
|
315
|
-
const defaultQuery = (manifestKey) => document.querySelector(`meta[name='manifest.${manifestKey}']`)?.getAttribute("content");
|
|
316
|
-
Object.entries(keyMap).forEach(([_key, manifestKey]) => {
|
|
317
|
-
const key = _key;
|
|
318
|
-
const content2 = queries?.[key] ? queries[key](document, manifestKey) : defaultQuery(manifestKey);
|
|
319
|
-
if (content2) {
|
|
320
|
-
try {
|
|
321
|
-
options[key] = (parsers?.[key] ?? JSON5.parse)(content2);
|
|
322
|
-
} catch (err) {
|
|
323
|
-
wxt.logger.fatal(
|
|
324
|
-
`Failed to parse meta tag content. Usually this means you have invalid JSON5 content (content=${content2})`,
|
|
325
|
-
err
|
|
326
|
-
);
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
});
|
|
330
|
-
return options;
|
|
331
|
-
}
|
|
332
322
|
function isEntrypointSkipped(entry) {
|
|
333
323
|
if (wxt.config.filterEntrypoints != null) {
|
|
334
324
|
return !wxt.config.filterEntrypoints.has(entry.name);
|
|
@@ -22,4 +22,10 @@ export declare function resolvePerBrowserOptions<T extends Record<string, any>,
|
|
|
22
22
|
*
|
|
23
23
|
* Naively just checking the file extension of the input path.
|
|
24
24
|
*/
|
|
25
|
-
export declare function isHtmlEntrypoint(entrypoint: Entrypoint): boolean;
|
|
25
|
+
export declare function isHtmlEntrypoint(entrypoint: Pick<Entrypoint, 'inputPath'>): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Returns true when the entrypoint is a JS entrypoint.
|
|
28
|
+
*
|
|
29
|
+
* Naively just checking the file extension of the input path.
|
|
30
|
+
*/
|
|
31
|
+
export declare function isJsEntrypoint(entrypoint: Pick<Entrypoint, 'inputPath'>): boolean;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import path, { relative, resolve } from "node:path";
|
|
1
|
+
import path, { relative, resolve, extname } from "node:path";
|
|
2
2
|
import { normalizePath } from "./paths.mjs";
|
|
3
3
|
export function getEntrypointName(entrypointsDir, inputPath) {
|
|
4
4
|
const relativePath = path.relative(entrypointsDir, inputPath);
|
|
@@ -27,5 +27,10 @@ export function resolvePerBrowserOptions(options, browser) {
|
|
|
27
27
|
);
|
|
28
28
|
}
|
|
29
29
|
export function isHtmlEntrypoint(entrypoint) {
|
|
30
|
-
|
|
30
|
+
const ext = extname(entrypoint.inputPath);
|
|
31
|
+
return [".html"].includes(ext);
|
|
32
|
+
}
|
|
33
|
+
export function isJsEntrypoint(entrypoint) {
|
|
34
|
+
const ext = extname(entrypoint.inputPath);
|
|
35
|
+
return [".js", ".jsx", ".ts", ".tsx"].includes(ext);
|
|
31
36
|
}
|
|
@@ -7,7 +7,7 @@ export declare function writeManifest(manifest: Manifest.WebExtensionManifest, o
|
|
|
7
7
|
/**
|
|
8
8
|
* Generates the manifest based on the config and entrypoints.
|
|
9
9
|
*/
|
|
10
|
-
export declare function generateManifest(
|
|
10
|
+
export declare function generateManifest(allEntrypoints: Entrypoint[], buildOutput: Omit<BuildOutput, 'manifest'>): Promise<{
|
|
11
11
|
manifest: Manifest.WebExtensionManifest;
|
|
12
12
|
warnings: any[][];
|
|
13
13
|
}>;
|
|
@@ -20,7 +20,8 @@ export async function writeManifest(manifest, output) {
|
|
|
20
20
|
fileName: "manifest.json"
|
|
21
21
|
});
|
|
22
22
|
}
|
|
23
|
-
export async function generateManifest(
|
|
23
|
+
export async function generateManifest(allEntrypoints, buildOutput) {
|
|
24
|
+
const entrypoints = allEntrypoints.filter((entry) => !entry.skipped);
|
|
24
25
|
const warnings = [];
|
|
25
26
|
const pkg = await getPackageJson();
|
|
26
27
|
let versionName = wxt.config.manifest.version_name ?? wxt.config.manifest.version ?? pkg?.version;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { Manifest } from 'wxt/browser';
|
|
2
|
-
import { ResolvedConfig, WxtDevServer, BackgroundEntrypoint, ContentScriptEntrypoint, GenericEntrypoint, OptionsEntrypoint, PopupEntrypoint, OutputChunk, OutputFile, OutputAsset, BuildOutput, BuildStepOutput, UserManifest, Wxt, SidepanelEntrypoint } from '../../../types';
|
|
2
|
+
import { ResolvedConfig, WxtDevServer, BackgroundEntrypoint, ContentScriptEntrypoint, GenericEntrypoint, OptionsEntrypoint, PopupEntrypoint, OutputChunk, OutputFile, OutputAsset, BuildOutput, BuildStepOutput, UserManifest, Wxt, SidepanelEntrypoint, BaseEntrypoint } from '../../../types';
|
|
3
3
|
type DeepPartial<T> = T extends object ? {
|
|
4
4
|
[P in keyof T]?: DeepPartial<T[P]>;
|
|
5
5
|
} : T;
|
|
6
6
|
export declare function fakeFileName(): string;
|
|
7
7
|
export declare function fakeFile(root?: string): string;
|
|
8
8
|
export declare function fakeDir(root?: string): string;
|
|
9
|
-
export declare const fakeEntrypoint: () => GenericEntrypoint | BackgroundEntrypoint | ContentScriptEntrypoint | PopupEntrypoint | OptionsEntrypoint;
|
|
9
|
+
export declare const fakeEntrypoint: (options?: DeepPartial<BaseEntrypoint>) => GenericEntrypoint | BackgroundEntrypoint | ContentScriptEntrypoint | PopupEntrypoint | OptionsEntrypoint;
|
|
10
10
|
export declare const fakeContentScriptEntrypoint: (overrides?: {
|
|
11
11
|
type?: "content-script" | undefined;
|
|
12
12
|
options?: {
|
|
@@ -8104,6 +8104,7 @@ export declare const fakeWxt: (overrides?: {
|
|
|
8104
8104
|
name?: string | undefined;
|
|
8105
8105
|
version?: string | undefined;
|
|
8106
8106
|
importEntrypoint?: {} | undefined;
|
|
8107
|
+
importEntrypoints?: {} | undefined;
|
|
8107
8108
|
build?: {} | undefined;
|
|
8108
8109
|
createServer?: {} | undefined;
|
|
8109
8110
|
} | undefined;
|
|
@@ -17,14 +17,14 @@ export function fakeFile(root = process.cwd()) {
|
|
|
17
17
|
export function fakeDir(root = process.cwd()) {
|
|
18
18
|
return resolve(root, faker.string.alphanumeric());
|
|
19
19
|
}
|
|
20
|
-
export const fakeEntrypoint = () => faker.helpers.arrayElement([
|
|
20
|
+
export const fakeEntrypoint = (options) => faker.helpers.arrayElement([
|
|
21
21
|
fakePopupEntrypoint,
|
|
22
22
|
fakeGenericEntrypoint,
|
|
23
23
|
fakeOptionsEntrypoint,
|
|
24
24
|
fakeBackgroundEntrypoint,
|
|
25
25
|
fakeContentScriptEntrypoint,
|
|
26
26
|
fakeUnlistedScriptEntrypoint
|
|
27
|
-
])();
|
|
27
|
+
])(options);
|
|
28
28
|
export const fakeContentScriptEntrypoint = fakeObjectCreator(() => ({
|
|
29
29
|
type: "content-script",
|
|
30
30
|
inputPath: fakeFile("src"),
|
package/dist/types.d.ts
CHANGED
|
@@ -927,9 +927,13 @@ export interface WxtBuilder {
|
|
|
927
927
|
*/
|
|
928
928
|
version: string;
|
|
929
929
|
/**
|
|
930
|
-
* Import
|
|
930
|
+
* Import a JS entrypoint file, returning the default export containing the options.
|
|
931
931
|
*/
|
|
932
932
|
importEntrypoint<T>(path: string): Promise<T>;
|
|
933
|
+
/**
|
|
934
|
+
* Import a list of JS entrypoint files, returning their options.
|
|
935
|
+
*/
|
|
936
|
+
importEntrypoints(paths: string[]): Promise<Record<string, unknown>[]>;
|
|
933
937
|
/**
|
|
934
938
|
* Build a single entrypoint group. This is effectively one of the multiple "steps" during the
|
|
935
939
|
* build process.
|
|
@@ -1288,6 +1292,8 @@ export interface FsCache {
|
|
|
1288
1292
|
export interface ExtensionRunner {
|
|
1289
1293
|
openBrowser(): Promise<void>;
|
|
1290
1294
|
closeBrowser(): Promise<void>;
|
|
1295
|
+
/** Whether or not this runner actually opens the browser. */
|
|
1296
|
+
canOpen?(): boolean;
|
|
1291
1297
|
}
|
|
1292
1298
|
export type EslintGlobalsPropValue = boolean | 'readonly' | 'readable' | 'writable' | 'writeable';
|
|
1293
1299
|
export interface Eslintrc {
|
package/dist/version.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = "0.19.
|
|
1
|
+
export const version = "0.19.21";
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wxt",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.19.
|
|
4
|
+
"version": "0.19.21",
|
|
5
5
|
"description": "Next gen framework for developing web extensions",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -70,6 +70,7 @@
|
|
|
70
70
|
}
|
|
71
71
|
},
|
|
72
72
|
"dependencies": {
|
|
73
|
+
"@1natsu/wait-element": "^4.1.2",
|
|
73
74
|
"@aklinker1/rollup-plugin-visualizer": "5.12.0",
|
|
74
75
|
"@types/chrome": "^0.0.280",
|
|
75
76
|
"@types/webextension-polyfill": "^0.12.1",
|