@multiplatform.one/vite-plugin-webext 6.2.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.
- package/LICENSE +201 -0
- package/lib/index.cjs +336 -0
- package/lib/index.mjs +296 -0
- package/package.json +68 -0
- package/src/index.ts +412 -0
- package/types/index.d.ts +75 -0
- package/types/index.d.ts.map +1 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
// Vite config factories for the web-extension target of a One platform app.
|
|
2
|
+
//
|
|
3
|
+
// The target lives INSIDE the product app (apps/<name>/webext/) — the same
|
|
4
|
+
// pattern as the GNOME target's vite.config.gnome*.ts — and produces a
|
|
5
|
+
// loadable MV3 extension staging dir:
|
|
6
|
+
//
|
|
7
|
+
// <stagingDir>/manifest.json
|
|
8
|
+
// <stagingDir>/dist/views/<view>/index.html (popup/options/sidepanel/…)
|
|
9
|
+
// <stagingDir>/dist/background/index.mjs (service worker / bg script)
|
|
10
|
+
// <stagingDir>/dist/contentScripts/index.global.js
|
|
11
|
+
//
|
|
12
|
+
// Three vite builds cover the three JS worlds (DOM views, worker, injected
|
|
13
|
+
// content script); `runWebextPrepare` writes the manifest and the dev-mode
|
|
14
|
+
// HMR scaffolding. Hard-won workarounds (workspace source aliases, the
|
|
15
|
+
// one-server-only browser stub, expo type-declaration stubs) come from
|
|
16
|
+
// @multiplatform.one/utils/dev so every product app shares one copy.
|
|
17
|
+
|
|
18
|
+
import fs from "node:fs";
|
|
19
|
+
import path from "node:path";
|
|
20
|
+
import {
|
|
21
|
+
lookupTamaguiModules,
|
|
22
|
+
oneServerOnlyBrowserStub,
|
|
23
|
+
stubExpoTypeDeclarations,
|
|
24
|
+
workspaceSourceAliases,
|
|
25
|
+
lookupProjectRoot,
|
|
26
|
+
} from "@multiplatform.one/utils/dev";
|
|
27
|
+
import react from "@vitejs/plugin-react";
|
|
28
|
+
import type { Alias, Plugin, UserConfig } from "vite";
|
|
29
|
+
|
|
30
|
+
export interface WebextPackageInfo {
|
|
31
|
+
name: string;
|
|
32
|
+
displayName?: string;
|
|
33
|
+
version: string;
|
|
34
|
+
description?: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface WebextTargetOptions {
|
|
38
|
+
/** Absolute path of the webext target source dir (contains views/,
|
|
39
|
+
* background/, content_scripts/). */
|
|
40
|
+
targetDir: string;
|
|
41
|
+
/** Absolute path of the loadable-extension staging dir (manifest.json +
|
|
42
|
+
* dist/). Keep it under the app's dist/ so tree-clean stays green. */
|
|
43
|
+
stagingDir: string;
|
|
44
|
+
/** Absolute path to the Tamagui config compiled into the views. */
|
|
45
|
+
tamaguiConfig: string;
|
|
46
|
+
/** Package identity for defines and bundle names. */
|
|
47
|
+
packageInfo: WebextPackageInfo;
|
|
48
|
+
/** Workspace root (defaults to the git toplevel). */
|
|
49
|
+
workspaceRoot?: string;
|
|
50
|
+
/** Views dev-server port. */
|
|
51
|
+
port?: number;
|
|
52
|
+
/** Development mode (watch + HMR scaffolding). Defaults to
|
|
53
|
+
* NODE_ENV !== "production". */
|
|
54
|
+
isDev?: boolean;
|
|
55
|
+
/** Extra defines merged over the factory defaults. */
|
|
56
|
+
define?: Record<string, unknown>;
|
|
57
|
+
/** Extra resolve aliases appended after the factory's. */
|
|
58
|
+
aliases?: Alias[];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const WEBEXT_EXTENSIONS = [
|
|
62
|
+
".webext.ts",
|
|
63
|
+
".webext.tsx",
|
|
64
|
+
".webext.js",
|
|
65
|
+
".webext.jsx",
|
|
66
|
+
".web.ts",
|
|
67
|
+
".web.tsx",
|
|
68
|
+
".web.js",
|
|
69
|
+
".web.jsx",
|
|
70
|
+
".ts",
|
|
71
|
+
".tsx",
|
|
72
|
+
".js",
|
|
73
|
+
".jsx",
|
|
74
|
+
];
|
|
75
|
+
|
|
76
|
+
const OPTIMIZE_INCLUDE = [
|
|
77
|
+
"react",
|
|
78
|
+
"react-dom",
|
|
79
|
+
"webextension-polyfill",
|
|
80
|
+
"@tamagui/core",
|
|
81
|
+
"@tamagui/web",
|
|
82
|
+
"tamagui",
|
|
83
|
+
"react-native-web",
|
|
84
|
+
"@multiplatform.one/components",
|
|
85
|
+
];
|
|
86
|
+
|
|
87
|
+
/** shiki's chunk graph (wasm/TLA) can't fold into the single-file iife a
|
|
88
|
+
* content script requires. Stub it with an empty module —
|
|
89
|
+
* @multiplatform.one/components' highlightCode() catches the missing
|
|
90
|
+
* codeToTokens and falls back to plain text. */
|
|
91
|
+
export function shikiStubPlugin(): Plugin {
|
|
92
|
+
const VIRTUAL_ID = "\0webext-shiki-stub";
|
|
93
|
+
return {
|
|
94
|
+
name: "webext-shiki-stub",
|
|
95
|
+
enforce: "pre",
|
|
96
|
+
resolveId(id: string) {
|
|
97
|
+
if (/^shiki(\/.*)?$/.test(id)) return VIRTUAL_ID;
|
|
98
|
+
},
|
|
99
|
+
load(id: string) {
|
|
100
|
+
if (id === VIRTUAL_ID) return "export {}";
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function resolveDefaults(options: WebextTargetOptions) {
|
|
106
|
+
const workspaceRoot = options.workspaceRoot ?? lookupProjectRoot();
|
|
107
|
+
const isDev = options.isDev ?? process.env.NODE_ENV !== "production";
|
|
108
|
+
const port = options.port ?? (Number(process.env.PORT) || 3303);
|
|
109
|
+
return { workspaceRoot, isDev, port };
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function baseDefine(options: WebextTargetOptions, isDev: boolean): Record<string, unknown> {
|
|
113
|
+
return {
|
|
114
|
+
__DEV__: isDev,
|
|
115
|
+
__NAME__: JSON.stringify(options.packageInfo.name),
|
|
116
|
+
"process.env.NODE_ENV": JSON.stringify(isDev ? "development" : "production"),
|
|
117
|
+
global: "globalThis",
|
|
118
|
+
...options.define,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function baseResolve(options: WebextTargetOptions, workspaceRoot: string) {
|
|
123
|
+
return {
|
|
124
|
+
alias: [
|
|
125
|
+
...Object.entries(workspaceSourceAliases(workspaceRoot)).map(([find, replacement]) => ({
|
|
126
|
+
find,
|
|
127
|
+
replacement,
|
|
128
|
+
})),
|
|
129
|
+
{ find: "react-native", replacement: "react-native-web" },
|
|
130
|
+
{ find: "@", replacement: options.targetDir },
|
|
131
|
+
...(options.aliases ?? []),
|
|
132
|
+
],
|
|
133
|
+
extensions: WEBEXT_EXTENSIONS,
|
|
134
|
+
mainFields: ["browser", "module", "main"],
|
|
135
|
+
} satisfies UserConfig["resolve"];
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function baseOptimizeDeps(): UserConfig["optimizeDeps"] {
|
|
139
|
+
return {
|
|
140
|
+
include: OPTIMIZE_INCLUDE,
|
|
141
|
+
esbuildOptions: {
|
|
142
|
+
resolveExtensions: WEBEXT_EXTENSIONS,
|
|
143
|
+
mainFields: ["module", "main"],
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** Discover view names — every directory under <targetDir>/views with an
|
|
149
|
+
* index.html becomes an extension page (popup, options, sidepanel, …). */
|
|
150
|
+
export function listWebextViews(targetDir: string): string[] {
|
|
151
|
+
const viewsDir = path.join(targetDir, "views");
|
|
152
|
+
if (!fs.existsSync(viewsDir)) return [];
|
|
153
|
+
return fs
|
|
154
|
+
.readdirSync(viewsDir)
|
|
155
|
+
.filter((file) => fs.statSync(path.join(viewsDir, file)).isDirectory())
|
|
156
|
+
.filter((view) => fs.existsSync(path.join(viewsDir, view, "index.html")));
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/** The extension pages build (popup/options/sidepanel/devtools…). */
|
|
160
|
+
export async function createWebextViewsConfig(options: WebextTargetOptions): Promise<UserConfig> {
|
|
161
|
+
const { workspaceRoot, isDev, port } = resolveDefaults(options);
|
|
162
|
+
const { tamaguiPlugin } = await import("@tamagui/vite-plugin");
|
|
163
|
+
const views = listWebextViews(options.targetDir);
|
|
164
|
+
return {
|
|
165
|
+
root: options.targetDir,
|
|
166
|
+
base: isDev ? `http://localhost:${port}/` : "/dist/",
|
|
167
|
+
plugins: [
|
|
168
|
+
stubExpoTypeDeclarations(),
|
|
169
|
+
oneServerOnlyBrowserStub(workspaceRoot),
|
|
170
|
+
react({ jsxRuntime: "automatic" }),
|
|
171
|
+
tamaguiPlugin({
|
|
172
|
+
components: lookupTamaguiModules([options.targetDir]),
|
|
173
|
+
config: options.tamaguiConfig,
|
|
174
|
+
outputCSS: path.join(options.targetDir, "tamagui.css"),
|
|
175
|
+
}) as Plugin,
|
|
176
|
+
],
|
|
177
|
+
define: baseDefine(options, isDev),
|
|
178
|
+
optimizeDeps: baseOptimizeDeps(),
|
|
179
|
+
esbuild: {
|
|
180
|
+
jsx: "automatic",
|
|
181
|
+
target: "esnext",
|
|
182
|
+
},
|
|
183
|
+
resolve: baseResolve(options, workspaceRoot),
|
|
184
|
+
server: {
|
|
185
|
+
port,
|
|
186
|
+
hmr: {
|
|
187
|
+
host: "localhost",
|
|
188
|
+
protocol: "ws",
|
|
189
|
+
clientPort: port,
|
|
190
|
+
},
|
|
191
|
+
origin: `http://localhost:${port}`,
|
|
192
|
+
cors: true,
|
|
193
|
+
headers: {
|
|
194
|
+
"Access-Control-Allow-Origin": "*",
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
build: {
|
|
198
|
+
watch: isDev ? {} : undefined,
|
|
199
|
+
outDir: path.join(options.stagingDir, "dist"),
|
|
200
|
+
emptyOutDir: false,
|
|
201
|
+
sourcemap: isDev ? "inline" : false,
|
|
202
|
+
terserOptions: {
|
|
203
|
+
mangle: false,
|
|
204
|
+
},
|
|
205
|
+
rollupOptions: {
|
|
206
|
+
input: Object.fromEntries(
|
|
207
|
+
views.map((view) => [view, path.join(options.targetDir, "views", view, "index.html")]),
|
|
208
|
+
),
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/** The background service-worker (chromium) / background-script (firefox)
|
|
215
|
+
* build — a single-file iife, no DOM. */
|
|
216
|
+
export function createWebextBackgroundConfig(options: WebextTargetOptions): UserConfig {
|
|
217
|
+
const { workspaceRoot, isDev } = resolveDefaults(options);
|
|
218
|
+
return {
|
|
219
|
+
root: options.targetDir,
|
|
220
|
+
plugins: [oneServerOnlyBrowserStub(workspaceRoot)],
|
|
221
|
+
define: baseDefine(options, isDev),
|
|
222
|
+
optimizeDeps: baseOptimizeDeps(),
|
|
223
|
+
esbuild: {
|
|
224
|
+
jsx: "automatic",
|
|
225
|
+
target: "esnext",
|
|
226
|
+
},
|
|
227
|
+
resolve: baseResolve(options, workspaceRoot),
|
|
228
|
+
build: {
|
|
229
|
+
watch: isDev ? {} : undefined,
|
|
230
|
+
outDir: path.join(options.stagingDir, "dist/background"),
|
|
231
|
+
cssCodeSplit: false,
|
|
232
|
+
emptyOutDir: false,
|
|
233
|
+
sourcemap: isDev ? "inline" : false,
|
|
234
|
+
lib: {
|
|
235
|
+
entry: path.join(options.targetDir, "background/main.ts"),
|
|
236
|
+
name: options.packageInfo.name,
|
|
237
|
+
formats: ["iife"],
|
|
238
|
+
},
|
|
239
|
+
rollupOptions: {
|
|
240
|
+
output: {
|
|
241
|
+
entryFileNames: "index.mjs",
|
|
242
|
+
extend: true,
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/** The content-script build — a single-file iife injected into pages, with
|
|
250
|
+
* Tamagui CSS extracted separately (webext.css web-accessible resource). */
|
|
251
|
+
export async function createWebextContentConfig(options: WebextTargetOptions): Promise<UserConfig> {
|
|
252
|
+
const { workspaceRoot, isDev } = resolveDefaults(options);
|
|
253
|
+
const { tamaguiPlugin } = await import("@tamagui/vite-plugin");
|
|
254
|
+
return {
|
|
255
|
+
root: options.targetDir,
|
|
256
|
+
plugins: [
|
|
257
|
+
stubExpoTypeDeclarations(),
|
|
258
|
+
oneServerOnlyBrowserStub(workspaceRoot),
|
|
259
|
+
shikiStubPlugin(),
|
|
260
|
+
tamaguiPlugin({
|
|
261
|
+
components: lookupTamaguiModules([options.targetDir]),
|
|
262
|
+
config: options.tamaguiConfig,
|
|
263
|
+
outputCSS: path.join(options.targetDir, "tamagui.content.css"),
|
|
264
|
+
}) as Plugin,
|
|
265
|
+
],
|
|
266
|
+
define: {
|
|
267
|
+
...baseDefine(options, isDev),
|
|
268
|
+
process: {
|
|
269
|
+
env: {
|
|
270
|
+
NODE_ENV: JSON.stringify(isDev ? "development" : "production"),
|
|
271
|
+
},
|
|
272
|
+
},
|
|
273
|
+
},
|
|
274
|
+
optimizeDeps: baseOptimizeDeps(),
|
|
275
|
+
esbuild: {
|
|
276
|
+
jsx: "automatic",
|
|
277
|
+
target: "esnext",
|
|
278
|
+
},
|
|
279
|
+
resolve: baseResolve(options, workspaceRoot),
|
|
280
|
+
build: {
|
|
281
|
+
watch: isDev ? {} : undefined,
|
|
282
|
+
outDir: path.join(options.stagingDir, "dist/contentScripts"),
|
|
283
|
+
cssCodeSplit: false,
|
|
284
|
+
emptyOutDir: false,
|
|
285
|
+
sourcemap: isDev ? "inline" : false,
|
|
286
|
+
lib: {
|
|
287
|
+
entry: path.join(options.targetDir, "content_scripts/index.tsx"),
|
|
288
|
+
name: options.packageInfo.name,
|
|
289
|
+
formats: ["iife"],
|
|
290
|
+
},
|
|
291
|
+
rollupOptions: {
|
|
292
|
+
output: {
|
|
293
|
+
entryFileNames: "index.global.js",
|
|
294
|
+
extend: true,
|
|
295
|
+
},
|
|
296
|
+
},
|
|
297
|
+
},
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// ── prepare pipeline (manifest + dev HMR scaffolding) ─────────────
|
|
302
|
+
|
|
303
|
+
export interface WebextPrepareOptions {
|
|
304
|
+
targetDir: string;
|
|
305
|
+
stagingDir: string;
|
|
306
|
+
/** Produces the manifest object (app-owned — permissions, views, icons).
|
|
307
|
+
* Typed `object` so interface-typed manifests (webextension-polyfill's
|
|
308
|
+
* WebExtensionManifest has no index signature) assign cleanly. */
|
|
309
|
+
getManifest: () => Promise<object> | object;
|
|
310
|
+
/** Static files (icons, …) copied verbatim into the staging root.
|
|
311
|
+
* Defaults to `<targetDir>/static` when it exists. */
|
|
312
|
+
staticDir?: string;
|
|
313
|
+
isDev?: boolean;
|
|
314
|
+
port?: number;
|
|
315
|
+
/** Watch manifest/html sources and rewrite on change (dev loop). */
|
|
316
|
+
watch?: boolean;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/** Copy static extension files (icons, …) into the staging root — the
|
|
320
|
+
* staging dir is build output (gitignored), so committed assets live in
|
|
321
|
+
* the target source tree instead. */
|
|
322
|
+
export async function copyWebextStatic(options: WebextPrepareOptions): Promise<void> {
|
|
323
|
+
const staticDir = options.staticDir ?? path.join(options.targetDir, "static");
|
|
324
|
+
if (!fs.existsSync(staticDir)) return;
|
|
325
|
+
await fs.promises.mkdir(options.stagingDir, { recursive: true });
|
|
326
|
+
await fs.promises.cp(staticDir, options.stagingDir, { recursive: true });
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
export async function writeWebextManifest(options: WebextPrepareOptions): Promise<void> {
|
|
330
|
+
const manifestPath = path.join(options.stagingDir, "manifest.json");
|
|
331
|
+
await fs.promises.mkdir(path.dirname(manifestPath), { recursive: true });
|
|
332
|
+
await fs.promises.writeFile(
|
|
333
|
+
manifestPath,
|
|
334
|
+
JSON.stringify(await options.getManifest(), null, 2),
|
|
335
|
+
"utf-8",
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/** Dev mode: emit view HTML that loads main.tsx from the vite dev server
|
|
340
|
+
* (extension pages can't be served BY vite — the html on disk must point
|
|
341
|
+
* at it) plus the react-refresh preamble shim. */
|
|
342
|
+
export async function stubWebextIndexHtml(options: WebextPrepareOptions): Promise<void> {
|
|
343
|
+
const port = options.port ?? 3303;
|
|
344
|
+
for (const view of listWebextViews(options.targetDir)) {
|
|
345
|
+
let data = await fs.promises.readFile(
|
|
346
|
+
path.join(options.targetDir, "views", view, "index.html"),
|
|
347
|
+
"utf-8",
|
|
348
|
+
);
|
|
349
|
+
data = data.replace(
|
|
350
|
+
"</head>",
|
|
351
|
+
` <script type="module" src="http://localhost:${port}/@vite/client"></script>
|
|
352
|
+
<script type="module" src="/dist/refresh.js"></script>
|
|
353
|
+
</head>`,
|
|
354
|
+
);
|
|
355
|
+
data = data
|
|
356
|
+
.replace(
|
|
357
|
+
'<script type="module" src="./main.tsx"></script>',
|
|
358
|
+
`<script type="module" src="http://localhost:${port}/views/${view}/main.tsx"></script>`,
|
|
359
|
+
)
|
|
360
|
+
.replace('<div id="app"></div>', '<div id="app">vite server did not start</div>');
|
|
361
|
+
const outPath = path.join(options.stagingDir, "dist/views", view, "index.html");
|
|
362
|
+
await fs.promises.mkdir(path.dirname(outPath), { recursive: true });
|
|
363
|
+
await fs.promises.writeFile(outPath, data, "utf-8");
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
export async function writeWebextRefreshScript(options: WebextPrepareOptions): Promise<void> {
|
|
368
|
+
const port = options.port ?? 3303;
|
|
369
|
+
const refreshPath = path.join(options.stagingDir, "dist/refresh.js");
|
|
370
|
+
await fs.promises.mkdir(path.dirname(refreshPath), { recursive: true });
|
|
371
|
+
await fs.promises.writeFile(
|
|
372
|
+
refreshPath,
|
|
373
|
+
`window.__vite_plugin_react_preamble_installed__ = true;
|
|
374
|
+
window.$RefreshReg$ = () => {};
|
|
375
|
+
window.$RefreshSig$ = () => (type) => type;
|
|
376
|
+
window.addEventListener('load', () => {
|
|
377
|
+
import("http://localhost:${port}/@react-refresh")
|
|
378
|
+
.then((RefreshRuntime) => {
|
|
379
|
+
if (RefreshRuntime && typeof RefreshRuntime.injectIntoGlobalHook === 'function') {
|
|
380
|
+
RefreshRuntime.injectIntoGlobalHook(window);
|
|
381
|
+
}
|
|
382
|
+
})
|
|
383
|
+
.catch(console.error);
|
|
384
|
+
});
|
|
385
|
+
`,
|
|
386
|
+
"utf-8",
|
|
387
|
+
);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/** One-shot (prod) or watching (dev) prepare: manifest + static assets +
|
|
391
|
+
* dev scaffolding. */
|
|
392
|
+
export async function runWebextPrepare(options: WebextPrepareOptions): Promise<void> {
|
|
393
|
+
const isDev = options.isDev ?? process.env.NODE_ENV !== "production";
|
|
394
|
+
if (!isDev) {
|
|
395
|
+
await copyWebextStatic(options);
|
|
396
|
+
await writeWebextManifest(options);
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
await copyWebextStatic(options);
|
|
400
|
+
await stubWebextIndexHtml(options);
|
|
401
|
+
await writeWebextRefreshScript(options);
|
|
402
|
+
await writeWebextManifest(options);
|
|
403
|
+
if (options.watch) {
|
|
404
|
+
const { watch } = await import("chokidar");
|
|
405
|
+
watch(path.join(options.targetDir, "**/*.html")).on("change", () =>
|
|
406
|
+
stubWebextIndexHtml(options).catch(console.error),
|
|
407
|
+
);
|
|
408
|
+
watch(path.join(options.targetDir, "manifest.ts")).on("change", () =>
|
|
409
|
+
writeWebextManifest(options).catch(console.error),
|
|
410
|
+
);
|
|
411
|
+
}
|
|
412
|
+
}
|
package/types/index.d.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { Alias, Plugin, UserConfig } from "vite";
|
|
2
|
+
export interface WebextPackageInfo {
|
|
3
|
+
name: string;
|
|
4
|
+
displayName?: string;
|
|
5
|
+
version: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface WebextTargetOptions {
|
|
9
|
+
/** Absolute path of the webext target source dir (contains views/,
|
|
10
|
+
* background/, content_scripts/). */
|
|
11
|
+
targetDir: string;
|
|
12
|
+
/** Absolute path of the loadable-extension staging dir (manifest.json +
|
|
13
|
+
* dist/). Keep it under the app's dist/ so tree-clean stays green. */
|
|
14
|
+
stagingDir: string;
|
|
15
|
+
/** Absolute path to the Tamagui config compiled into the views. */
|
|
16
|
+
tamaguiConfig: string;
|
|
17
|
+
/** Package identity for defines and bundle names. */
|
|
18
|
+
packageInfo: WebextPackageInfo;
|
|
19
|
+
/** Workspace root (defaults to the git toplevel). */
|
|
20
|
+
workspaceRoot?: string;
|
|
21
|
+
/** Views dev-server port. */
|
|
22
|
+
port?: number;
|
|
23
|
+
/** Development mode (watch + HMR scaffolding). Defaults to
|
|
24
|
+
* NODE_ENV !== "production". */
|
|
25
|
+
isDev?: boolean;
|
|
26
|
+
/** Extra defines merged over the factory defaults. */
|
|
27
|
+
define?: Record<string, unknown>;
|
|
28
|
+
/** Extra resolve aliases appended after the factory's. */
|
|
29
|
+
aliases?: Alias[];
|
|
30
|
+
}
|
|
31
|
+
/** shiki's chunk graph (wasm/TLA) can't fold into the single-file iife a
|
|
32
|
+
* content script requires. Stub it with an empty module —
|
|
33
|
+
* @multiplatform.one/components' highlightCode() catches the missing
|
|
34
|
+
* codeToTokens and falls back to plain text. */
|
|
35
|
+
export declare function shikiStubPlugin(): Plugin;
|
|
36
|
+
/** Discover view names — every directory under <targetDir>/views with an
|
|
37
|
+
* index.html becomes an extension page (popup, options, sidepanel, …). */
|
|
38
|
+
export declare function listWebextViews(targetDir: string): string[];
|
|
39
|
+
/** The extension pages build (popup/options/sidepanel/devtools…). */
|
|
40
|
+
export declare function createWebextViewsConfig(options: WebextTargetOptions): Promise<UserConfig>;
|
|
41
|
+
/** The background service-worker (chromium) / background-script (firefox)
|
|
42
|
+
* build — a single-file iife, no DOM. */
|
|
43
|
+
export declare function createWebextBackgroundConfig(options: WebextTargetOptions): UserConfig;
|
|
44
|
+
/** The content-script build — a single-file iife injected into pages, with
|
|
45
|
+
* Tamagui CSS extracted separately (webext.css web-accessible resource). */
|
|
46
|
+
export declare function createWebextContentConfig(options: WebextTargetOptions): Promise<UserConfig>;
|
|
47
|
+
export interface WebextPrepareOptions {
|
|
48
|
+
targetDir: string;
|
|
49
|
+
stagingDir: string;
|
|
50
|
+
/** Produces the manifest object (app-owned — permissions, views, icons).
|
|
51
|
+
* Typed `object` so interface-typed manifests (webextension-polyfill's
|
|
52
|
+
* WebExtensionManifest has no index signature) assign cleanly. */
|
|
53
|
+
getManifest: () => Promise<object> | object;
|
|
54
|
+
/** Static files (icons, …) copied verbatim into the staging root.
|
|
55
|
+
* Defaults to `<targetDir>/static` when it exists. */
|
|
56
|
+
staticDir?: string;
|
|
57
|
+
isDev?: boolean;
|
|
58
|
+
port?: number;
|
|
59
|
+
/** Watch manifest/html sources and rewrite on change (dev loop). */
|
|
60
|
+
watch?: boolean;
|
|
61
|
+
}
|
|
62
|
+
/** Copy static extension files (icons, …) into the staging root — the
|
|
63
|
+
* staging dir is build output (gitignored), so committed assets live in
|
|
64
|
+
* the target source tree instead. */
|
|
65
|
+
export declare function copyWebextStatic(options: WebextPrepareOptions): Promise<void>;
|
|
66
|
+
export declare function writeWebextManifest(options: WebextPrepareOptions): Promise<void>;
|
|
67
|
+
/** Dev mode: emit view HTML that loads main.tsx from the vite dev server
|
|
68
|
+
* (extension pages can't be served BY vite — the html on disk must point
|
|
69
|
+
* at it) plus the react-refresh preamble shim. */
|
|
70
|
+
export declare function stubWebextIndexHtml(options: WebextPrepareOptions): Promise<void>;
|
|
71
|
+
export declare function writeWebextRefreshScript(options: WebextPrepareOptions): Promise<void>;
|
|
72
|
+
/** One-shot (prod) or watching (dev) prepare: manifest + static assets +
|
|
73
|
+
* dev scaffolding. */
|
|
74
|
+
export declare function runWebextPrepare(options: WebextPrepareOptions): Promise<void>;
|
|
75
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAEtD,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC;0CACsC;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB;2EACuE;IACvE,UAAU,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,aAAa,EAAE,MAAM,CAAC;IACtB,qDAAqD;IACrD,WAAW,EAAE,iBAAiB,CAAC;IAC/B,qDAAqD;IACrD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,6BAA6B;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;qCACiC;IACjC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,sDAAsD;IACtD,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,0DAA0D;IAC1D,OAAO,CAAC,EAAE,KAAK,EAAE,CAAC;CACnB;AA4BD;;;iDAGiD;AACjD,wBAAgB,eAAe,IAAI,MAAM,CAYxC;AA6CD;2EAC2E;AAC3E,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAO3D;AAED,qEAAqE;AACrE,wBAAsB,uBAAuB,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,UAAU,CAAC,CAoD/F;AAED;0CAC0C;AAC1C,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,mBAAmB,GAAG,UAAU,CA+BrF;AAED;6EAC6E;AAC7E,wBAAsB,yBAAyB,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,UAAU,CAAC,CAgDjG;AAID,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB;;uEAEmE;IACnE,WAAW,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;IAC5C;2DACuD;IACvD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oEAAoE;IACpE,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;sCAEsC;AACtC,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAKnF;AAED,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAQtF;AAED;;mDAEmD;AACnD,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAuBtF;AAED,wBAAsB,wBAAwB,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAqB3F;AAED;uBACuB;AACvB,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAoBnF"}
|