wxt 0.18.15 → 0.19.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.
Files changed (257) hide show
  1. package/bin/wxt.mjs +1 -1
  2. package/dist/browser/chrome.d.ts +17 -0
  3. package/dist/browser/chrome.mjs +7 -0
  4. package/dist/browser/index.d.ts +18 -0
  5. package/dist/browser/index.mjs +2 -0
  6. package/dist/builtin-modules/index.d.ts +2 -0
  7. package/dist/builtin-modules/index.mjs +2 -0
  8. package/dist/builtin-modules/unimport.d.ts +8 -0
  9. package/dist/builtin-modules/unimport.mjs +99 -0
  10. package/dist/cli/cli-utils.d.ts +25 -0
  11. package/dist/cli/cli-utils.mjs +58 -0
  12. package/dist/cli/commands.d.ts +2 -0
  13. package/dist/cli/commands.mjs +104 -0
  14. package/dist/cli/index.d.ts +1 -0
  15. package/dist/cli/index.mjs +11 -0
  16. package/dist/client/app-config.d.ts +2 -0
  17. package/dist/client/app-config.mjs +4 -0
  18. package/dist/client/content-scripts/content-script-context.d.ts +114 -0
  19. package/dist/client/content-scripts/content-script-context.mjs +169 -0
  20. package/dist/client/content-scripts/custom-events.d.ts +10 -0
  21. package/dist/client/content-scripts/custom-events.mjs +13 -0
  22. package/dist/client/content-scripts/index.d.ts +2 -0
  23. package/dist/client/content-scripts/index.mjs +2 -0
  24. package/dist/client/content-scripts/location-watcher.d.ts +12 -0
  25. package/dist/client/content-scripts/location-watcher.mjs +22 -0
  26. package/dist/client/content-scripts/ui/index.d.ts +23 -0
  27. package/dist/client/content-scripts/ui/index.mjs +188 -0
  28. package/dist/{client.d.ts → client/content-scripts/ui/types.d.ts} +17 -45
  29. package/dist/client/content-scripts/ui/types.mjs +0 -0
  30. package/dist/client/index.d.ts +7 -0
  31. package/dist/client/index.mjs +2 -0
  32. package/dist/core/build.d.ts +15 -0
  33. package/dist/core/build.mjs +6 -0
  34. package/dist/core/builders/vite/index.d.ts +3 -0
  35. package/dist/core/builders/vite/index.mjs +285 -0
  36. package/dist/core/builders/vite/plugins/bundleAnalysis.d.ts +7 -0
  37. package/dist/core/builders/vite/plugins/bundleAnalysis.mjs +15 -0
  38. package/dist/core/builders/vite/plugins/cssEntrypoints.d.ts +13 -0
  39. package/dist/core/builders/vite/plugins/cssEntrypoints.mjs +22 -0
  40. package/dist/core/builders/vite/plugins/defineImportMeta.d.ts +14 -0
  41. package/dist/core/builders/vite/plugins/defineImportMeta.mjs +13 -0
  42. package/dist/core/builders/vite/plugins/devHtmlPrerender.d.ts +7 -0
  43. package/dist/core/builders/vite/plugins/devHtmlPrerender.mjs +140 -0
  44. package/dist/core/builders/vite/plugins/devServerGlobals.d.ts +6 -0
  45. package/dist/core/builders/vite/plugins/devServerGlobals.mjs +15 -0
  46. package/dist/core/builders/vite/plugins/download.d.ts +10 -0
  47. package/dist/core/builders/vite/plugins/download.mjs +14 -0
  48. package/dist/core/builders/vite/plugins/entrypointGroupGlobals.d.ts +6 -0
  49. package/dist/core/builders/vite/plugins/entrypointGroupGlobals.mjs +16 -0
  50. package/dist/core/builders/vite/plugins/extensionApiMock.d.ts +11 -0
  51. package/dist/core/builders/vite/plugins/extensionApiMock.mjs +26 -0
  52. package/dist/core/builders/vite/plugins/globals.d.ts +3 -0
  53. package/dist/core/builders/vite/plugins/globals.mjs +15 -0
  54. package/dist/core/builders/vite/plugins/index.d.ts +17 -0
  55. package/dist/core/builders/vite/plugins/index.mjs +17 -0
  56. package/dist/core/builders/vite/plugins/multipageMove.d.ts +20 -0
  57. package/dist/core/builders/vite/plugins/multipageMove.mjs +59 -0
  58. package/dist/core/builders/vite/plugins/noopBackground.d.ts +6 -0
  59. package/dist/core/builders/vite/plugins/noopBackground.mjs +17 -0
  60. package/dist/core/builders/vite/plugins/removeEntrypointMainFunction.d.ts +6 -0
  61. package/dist/core/builders/vite/plugins/removeEntrypointMainFunction.mjs +12 -0
  62. package/dist/core/builders/vite/plugins/resolveAppConfig.d.ts +6 -0
  63. package/dist/core/builders/vite/plugins/resolveAppConfig.mjs +26 -0
  64. package/dist/core/builders/vite/plugins/resolveExtensionApi.d.ts +10 -0
  65. package/dist/core/builders/vite/plugins/resolveExtensionApi.mjs +15 -0
  66. package/dist/core/builders/vite/plugins/resolveVirtualModules.d.ts +6 -0
  67. package/dist/core/builders/vite/plugins/resolveVirtualModules.mjs +30 -0
  68. package/dist/core/builders/vite/plugins/tsconfigPaths.d.ts +3 -0
  69. package/dist/core/builders/vite/plugins/tsconfigPaths.mjs +12 -0
  70. package/dist/core/builders/vite/plugins/wxtPluginLoader.d.ts +6 -0
  71. package/dist/core/builders/vite/plugins/wxtPluginLoader.mjs +56 -0
  72. package/dist/core/clean.d.ts +21 -0
  73. package/dist/core/clean.mjs +38 -0
  74. package/dist/core/create-server.d.ts +11 -0
  75. package/dist/core/create-server.mjs +206 -0
  76. package/dist/core/define-config.d.ts +2 -0
  77. package/dist/core/define-config.mjs +3 -0
  78. package/dist/core/define-runner-config.d.ts +2 -0
  79. package/dist/core/define-runner-config.mjs +3 -0
  80. package/dist/core/index.d.ts +8 -0
  81. package/dist/core/index.mjs +8 -0
  82. package/dist/core/initialize.d.ts +5 -0
  83. package/dist/core/initialize.mjs +128 -0
  84. package/dist/core/package-managers/bun.d.ts +2 -0
  85. package/dist/core/package-managers/bun.mjs +19 -0
  86. package/dist/core/package-managers/index.d.ts +2 -0
  87. package/dist/core/package-managers/index.mjs +65 -0
  88. package/dist/core/package-managers/npm.d.ts +17 -0
  89. package/dist/core/package-managers/npm.mjs +58 -0
  90. package/dist/core/package-managers/pnpm.d.ts +2 -0
  91. package/dist/core/package-managers/pnpm.mjs +21 -0
  92. package/dist/core/package-managers/types.d.ts +2 -0
  93. package/dist/core/package-managers/types.mjs +0 -0
  94. package/dist/core/package-managers/yarn.d.ts +2 -0
  95. package/dist/core/package-managers/yarn.mjs +31 -0
  96. package/dist/core/prepare.d.ts +2 -0
  97. package/dist/core/prepare.mjs +8 -0
  98. package/dist/core/runners/index.d.ts +2 -0
  99. package/dist/core/runners/index.mjs +12 -0
  100. package/dist/core/runners/manual.d.ts +5 -0
  101. package/dist/core/runners/manual.mjs +16 -0
  102. package/dist/core/runners/safari.d.ts +5 -0
  103. package/dist/core/runners/safari.mjs +16 -0
  104. package/dist/core/runners/web-ext.d.ts +5 -0
  105. package/dist/core/runners/web-ext.mjs +78 -0
  106. package/dist/core/runners/wsl.d.ts +5 -0
  107. package/dist/core/runners/wsl.mjs +16 -0
  108. package/dist/core/utils/arrays.d.ts +13 -0
  109. package/dist/{chunk-BERPNPEZ.js → core/utils/arrays.mjs} +6 -10
  110. package/dist/core/utils/building/build-entrypoints.d.ts +3 -0
  111. package/dist/core/utils/building/build-entrypoints.mjs +47 -0
  112. package/dist/core/utils/building/detect-dev-changes.d.ts +57 -0
  113. package/dist/core/utils/building/detect-dev-changes.mjs +93 -0
  114. package/dist/core/utils/building/find-entrypoints.d.ts +5 -0
  115. package/dist/core/utils/building/find-entrypoints.mjs +385 -0
  116. package/dist/core/utils/building/generate-wxt-dir.d.ts +5 -0
  117. package/dist/core/utils/building/generate-wxt-dir.mjs +192 -0
  118. package/dist/core/utils/building/group-entrypoints.d.ts +8 -0
  119. package/dist/core/utils/building/group-entrypoints.mjs +37 -0
  120. package/dist/core/utils/building/import-entrypoint.d.ts +16 -0
  121. package/dist/core/utils/building/import-entrypoint.mjs +97 -0
  122. package/dist/core/utils/building/index.d.ts +9 -0
  123. package/dist/core/utils/building/index.mjs +9 -0
  124. package/dist/core/utils/building/internal-build.d.ts +12 -0
  125. package/dist/core/utils/building/internal-build.mjs +112 -0
  126. package/dist/core/utils/building/rebuild.d.ts +23 -0
  127. package/dist/core/utils/building/rebuild.mjs +39 -0
  128. package/dist/core/utils/building/resolve-config.d.ts +11 -0
  129. package/dist/core/utils/building/resolve-config.mjs +364 -0
  130. package/dist/core/utils/cache.d.ts +8 -0
  131. package/dist/core/utils/cache.mjs +21 -0
  132. package/dist/core/utils/cli.d.ts +3 -0
  133. package/dist/core/utils/cli.mjs +26 -0
  134. package/dist/core/utils/constants.d.ts +5 -0
  135. package/dist/core/utils/constants.mjs +1 -0
  136. package/dist/core/utils/content-scripts.d.ts +11 -0
  137. package/dist/core/utils/content-scripts.mjs +60 -0
  138. package/dist/core/utils/content-security-policy.d.ts +14 -0
  139. package/dist/core/utils/content-security-policy.mjs +39 -0
  140. package/dist/core/utils/entrypoints.d.ts +25 -0
  141. package/dist/core/utils/entrypoints.mjs +31 -0
  142. package/dist/core/utils/eslint.d.ts +1 -0
  143. package/dist/core/utils/eslint.mjs +11 -0
  144. package/dist/core/utils/fs.d.ts +13 -0
  145. package/dist/core/utils/fs.mjs +15 -0
  146. package/dist/core/utils/globals.d.ts +11 -0
  147. package/dist/core/utils/globals.mjs +53 -0
  148. package/dist/core/utils/i18n.d.ts +11 -0
  149. package/dist/core/utils/i18n.mjs +35 -0
  150. package/dist/core/utils/log/index.d.ts +4 -0
  151. package/dist/core/utils/log/index.mjs +4 -0
  152. package/dist/core/utils/log/printBuildSummary.d.ts +2 -0
  153. package/dist/core/utils/log/printBuildSummary.mjs +32 -0
  154. package/dist/core/utils/log/printFileList.d.ts +1 -0
  155. package/dist/core/utils/log/printFileList.mjs +42 -0
  156. package/dist/core/utils/log/printHeader.d.ts +1 -0
  157. package/dist/core/utils/log/printHeader.mjs +7 -0
  158. package/dist/core/utils/log/printTable.d.ts +1 -0
  159. package/dist/core/utils/log/printTable.mjs +22 -0
  160. package/dist/core/utils/manifest.d.ts +44 -0
  161. package/dist/core/utils/manifest.mjs +512 -0
  162. package/dist/core/utils/network.d.ts +7 -0
  163. package/dist/core/utils/network.mjs +38 -0
  164. package/dist/core/utils/package.d.ts +6 -0
  165. package/dist/core/utils/package.mjs +14 -0
  166. package/dist/core/utils/paths.d.ts +11 -0
  167. package/dist/core/utils/paths.mjs +10 -0
  168. package/dist/core/utils/strings.d.ts +14 -0
  169. package/dist/core/utils/strings.mjs +18 -0
  170. package/dist/core/utils/testing/fake-objects.d.ts +4556 -0
  171. package/dist/core/utils/testing/fake-objects.mjs +322 -0
  172. package/dist/core/utils/time.d.ts +9 -0
  173. package/dist/core/utils/time.mjs +17 -0
  174. package/dist/core/utils/transform.d.ts +9 -0
  175. package/dist/core/utils/transform.mjs +17 -0
  176. package/dist/core/utils/types.d.ts +10 -0
  177. package/dist/core/utils/types.mjs +0 -0
  178. package/dist/core/utils/validation.d.ts +15 -0
  179. package/dist/core/utils/validation.mjs +55 -0
  180. package/dist/core/utils/virtual-modules.d.ts +22 -0
  181. package/dist/core/utils/virtual-modules.mjs +14 -0
  182. package/dist/core/utils/wsl.d.ts +4 -0
  183. package/dist/core/utils/wsl.mjs +4 -0
  184. package/dist/core/wxt.d.ts +19 -0
  185. package/dist/core/wxt.mjs +41 -0
  186. package/dist/core/zip.d.ts +7 -0
  187. package/dist/core/zip.mjs +137 -0
  188. package/dist/index.d.ts +4 -79
  189. package/dist/index.mjs +3 -0
  190. package/dist/modules.d.ts +10 -20
  191. package/dist/{chunk-6XSIWUWF.js → modules.mjs} +7 -16
  192. package/dist/sandbox/define-app-config.d.ts +19 -0
  193. package/dist/sandbox/define-app-config.mjs +3 -0
  194. package/dist/sandbox/define-background.d.ts +3 -0
  195. package/dist/sandbox/define-background.mjs +4 -0
  196. package/dist/sandbox/define-content-script.d.ts +2 -0
  197. package/dist/sandbox/define-content-script.mjs +3 -0
  198. package/dist/sandbox/define-unlisted-script.d.ts +3 -0
  199. package/dist/sandbox/define-unlisted-script.mjs +4 -0
  200. package/dist/sandbox/define-wxt-plugin.d.ts +2 -0
  201. package/dist/sandbox/define-wxt-plugin.mjs +3 -0
  202. package/dist/sandbox/dev-server-websocket.d.ts +21 -0
  203. package/dist/sandbox/dev-server-websocket.mjs +37 -0
  204. package/dist/sandbox/index.d.ts +11 -0
  205. package/dist/sandbox/index.mjs +6 -0
  206. package/dist/sandbox/utils/logger.d.ts +9 -0
  207. package/dist/sandbox/utils/logger.mjs +15 -0
  208. package/dist/storage.d.ts +39 -16
  209. package/dist/{storage.js → storage.mjs} +30 -41
  210. package/dist/testing/fake-browser.d.ts +1 -0
  211. package/dist/testing/fake-browser.mjs +1 -0
  212. package/dist/testing/index.d.ts +5 -0
  213. package/dist/testing/index.mjs +2 -0
  214. package/dist/{testing.d.ts → testing/wxt-vitest-plugin.d.ts} +3 -15
  215. package/dist/testing/wxt-vitest-plugin.mjs +26 -0
  216. package/dist/{index-nWRfwAJi.d.cts → types.d.ts} +150 -264
  217. package/dist/types.mjs +0 -0
  218. package/dist/version.d.ts +1 -0
  219. package/dist/version.mjs +1 -0
  220. package/dist/virtual/{background-entrypoint.js → background-entrypoint.mjs} +31 -40
  221. package/dist/virtual/{content-script-isolated-world-entrypoint.js → content-script-isolated-world-entrypoint.mjs} +9 -13
  222. package/dist/virtual/{content-script-main-world-entrypoint.js → content-script-main-world-entrypoint.mjs} +9 -14
  223. package/dist/virtual/mock-browser.mjs +6 -0
  224. package/dist/virtual/{reload-html.js → reload-html.mjs} +8 -9
  225. package/dist/virtual/{unlisted-script-entrypoint.js → unlisted-script-entrypoint.mjs} +8 -12
  226. package/package.json +47 -57
  227. package/dist/browser.d.ts +0 -18
  228. package/dist/browser.js +0 -6
  229. package/dist/chunk-BM6QYGAW.js +0 -1063
  230. package/dist/chunk-FNTE2L27.js +0 -7
  231. package/dist/chunk-FP7RYLVL.js +0 -3617
  232. package/dist/chunk-KPD5J7PZ.js +0 -1065
  233. package/dist/chunk-QGM4M3NI.js +0 -37
  234. package/dist/chunk-SGKCDMVR.js +0 -38
  235. package/dist/cli.d.ts +0 -2
  236. package/dist/cli.js +0 -4438
  237. package/dist/client.js +0 -424
  238. package/dist/define-app-config-bg54F_lV.d.ts +0 -294
  239. package/dist/execa-4UBDUBJZ.js +0 -7244
  240. package/dist/execa-QLUM2B3W.js +0 -7245
  241. package/dist/index-nWRfwAJi.d.ts +0 -1401
  242. package/dist/index.cjs +0 -14473
  243. package/dist/index.d.cts +0 -81
  244. package/dist/index.js +0 -696
  245. package/dist/modules.cjs +0 -96
  246. package/dist/modules.d.cts +0 -119
  247. package/dist/modules.js +0 -17
  248. package/dist/prompt-25QIVJDC.js +0 -755
  249. package/dist/prompt-7BMKNSWS.js +0 -754
  250. package/dist/sandbox.d.ts +0 -16
  251. package/dist/sandbox.js +0 -36
  252. package/dist/storage.cjs +0 -439
  253. package/dist/storage.d.cts +0 -200
  254. package/dist/testing.cjs +0 -2815
  255. package/dist/testing.d.cts +0 -30
  256. package/dist/testing.js +0 -40
  257. package/dist/virtual/mock-browser.js +0 -6
@@ -1,3617 +0,0 @@
1
- import {
2
- every,
3
- some,
4
- toArray
5
- } from "./chunk-BERPNPEZ.js";
6
- import {
7
- addViteConfig,
8
- defineWxtModule
9
- } from "./chunk-6XSIWUWF.js";
10
- import {
11
- LogLevels,
12
- consola
13
- } from "./chunk-BM6QYGAW.js";
14
- import {
15
- __require
16
- } from "./chunk-QGM4M3NI.js";
17
-
18
- // package.json
19
- var version = "0.18.14";
20
-
21
- // src/core/utils/paths.ts
22
- import systemPath from "node:path";
23
- import normalize from "normalize-path";
24
- function normalizePath(path8) {
25
- return normalize(path8);
26
- }
27
- function unnormalizePath(path8) {
28
- return systemPath.normalize(path8);
29
- }
30
- var CSS_EXTENSIONS = ["css", "scss", "sass", "less", "styl", "stylus"];
31
- var CSS_EXTENSIONS_PATTERN = `+(${CSS_EXTENSIONS.join("|")})`;
32
-
33
- // src/core/utils/entrypoints.ts
34
- import path, { relative, resolve } from "node:path";
35
- function getEntrypointName(entrypointsDir, inputPath) {
36
- const relativePath = path.relative(entrypointsDir, inputPath);
37
- const name = relativePath.split(/[\.\/\\]/, 2)[0];
38
- return name;
39
- }
40
- function getEntrypointOutputFile(entrypoint, ext) {
41
- return resolve(entrypoint.outputDir, `${entrypoint.name}${ext}`);
42
- }
43
- function getEntrypointBundlePath(entrypoint, outDir, ext) {
44
- return normalizePath(
45
- relative(outDir, getEntrypointOutputFile(entrypoint, ext))
46
- );
47
- }
48
- function resolvePerBrowserOption(option, browser) {
49
- if (typeof option === "object" && !Array.isArray(option))
50
- return option[browser];
51
- return option;
52
- }
53
- function resolvePerBrowserOptions(options, browser) {
54
- return Object.fromEntries(
55
- Object.entries(options).map(([key, value]) => [
56
- key,
57
- key === "defaultIcon" ? value : resolvePerBrowserOption(value, browser)
58
- ])
59
- );
60
- }
61
- function isHtmlEntrypoint(entrypoint) {
62
- return entrypoint.inputPath.endsWith(".html");
63
- }
64
-
65
- // src/core/utils/time.ts
66
- function formatDuration(duration) {
67
- if (duration < 1e3) return `${duration} ms`;
68
- if (duration < 1e4) return `${(duration / 1e3).toFixed(3)} s`;
69
- if (duration < 6e4) return `${(duration / 1e3).toFixed(1)} s`;
70
- return `${(duration / 1e3).toFixed(0)} s`;
71
- }
72
- function withTimeout(promise, duration) {
73
- return new Promise((res, rej) => {
74
- const timeout = setTimeout(() => {
75
- rej(`Promise timed out after ${duration}ms`);
76
- }, duration);
77
- promise.then(res).catch(rej).finally(() => clearTimeout(timeout));
78
- });
79
- }
80
-
81
- // src/core/utils/network.ts
82
- import dns from "node:dns";
83
- function isOffline() {
84
- const isOffline2 = new Promise((res) => {
85
- dns.resolve("google.com", (err) => {
86
- if (err == null) {
87
- res(false);
88
- } else {
89
- res(true);
90
- }
91
- });
92
- });
93
- return withTimeout(isOffline2, 1e3).catch(() => true);
94
- }
95
- async function isOnline() {
96
- const offline = await isOffline();
97
- return !offline;
98
- }
99
- async function fetchCached(url, config) {
100
- let content = "";
101
- if (await isOnline()) {
102
- const res = await fetch(url);
103
- if (res.status < 300) {
104
- content = await res.text();
105
- await config.fsCache.set(url, content);
106
- } else {
107
- config.logger.debug(
108
- `Failed to download "${url}", falling back to cache...`
109
- );
110
- }
111
- }
112
- if (!content) content = await config.fsCache.get(url) ?? "";
113
- if (!content)
114
- throw Error(
115
- `Offline and "${url}" has not been cached. Try again when online.`
116
- );
117
- return content;
118
- }
119
-
120
- // src/core/builders/vite/plugins/download.ts
121
- function download(config) {
122
- return {
123
- name: "wxt:download",
124
- resolveId(id) {
125
- if (id.startsWith("url:")) return "\0" + id;
126
- },
127
- async load(id) {
128
- if (!id.startsWith("\0url:")) return;
129
- const url = id.replace("\0url:", "");
130
- return await fetchCached(url, config);
131
- }
132
- };
133
- }
134
-
135
- // src/core/builders/vite/plugins/tsconfigPaths.ts
136
- function tsconfigPaths(config) {
137
- return {
138
- name: "wxt:aliases",
139
- async config() {
140
- return {
141
- resolve: {
142
- alias: config.alias
143
- }
144
- };
145
- }
146
- };
147
- }
148
-
149
- // src/core/utils/globals.ts
150
- function getGlobals(config) {
151
- return [
152
- {
153
- name: "MANIFEST_VERSION",
154
- value: config.manifestVersion,
155
- type: `2 | 3`
156
- },
157
- {
158
- name: "BROWSER",
159
- value: config.browser,
160
- type: `string`
161
- },
162
- {
163
- name: "CHROME",
164
- value: config.browser === "chrome",
165
- type: `boolean`
166
- },
167
- {
168
- name: "FIREFOX",
169
- value: config.browser === "firefox",
170
- type: `boolean`
171
- },
172
- {
173
- name: "SAFARI",
174
- value: config.browser === "safari",
175
- type: `boolean`
176
- },
177
- {
178
- name: "EDGE",
179
- value: config.browser === "edge",
180
- type: `boolean`
181
- },
182
- {
183
- name: "OPERA",
184
- value: config.browser === "opera",
185
- type: `boolean`
186
- },
187
- {
188
- name: "COMMAND",
189
- value: config.command,
190
- type: `"build" | "serve"`
191
- }
192
- ];
193
- }
194
- function getEntrypointGlobals(entrypointName) {
195
- return [
196
- {
197
- name: "ENTRYPOINT",
198
- value: entrypointName,
199
- type: `string`
200
- }
201
- ];
202
- }
203
-
204
- // src/core/builders/vite/plugins/globals.ts
205
- function globals(config) {
206
- return {
207
- name: "wxt:globals",
208
- config() {
209
- const define = {};
210
- for (const global of getGlobals(config)) {
211
- define[`import.meta.env.${global.name}`] = JSON.stringify(global.value);
212
- }
213
- return {
214
- define
215
- };
216
- }
217
- };
218
- }
219
-
220
- // src/core/builders/vite/plugins/webextensionPolyfillMock.ts
221
- import path2 from "node:path";
222
- function webextensionPolyfillMock(config) {
223
- return {
224
- name: "wxt:testing-inline-deps",
225
- config() {
226
- return {
227
- resolve: {
228
- alias: {
229
- // Alias to use a mocked version of the polyfill
230
- "webextension-polyfill": path2.resolve(
231
- config.wxtModuleDir,
232
- "dist/virtual/mock-browser"
233
- )
234
- }
235
- },
236
- ssr: {
237
- // Inline all WXT modules
238
- noExternal: ["wxt"]
239
- }
240
- };
241
- }
242
- };
243
- }
244
-
245
- // src/core/builders/vite/plugins/resolveAppConfig.ts
246
- import { exists } from "fs-extra";
247
- import { resolve as resolve2 } from "node:path";
248
- function resolveAppConfig(config) {
249
- const virtualModuleId = "virtual:app-config";
250
- const resolvedVirtualModuleId = "\0" + virtualModuleId;
251
- const appConfigFile = resolve2(config.srcDir, "app.config.ts");
252
- return {
253
- name: "wxt:resolve-app-config",
254
- config() {
255
- return {
256
- optimizeDeps: {
257
- // Prevent ESBuild from attempting to resolve the virtual module
258
- // while optimizing WXT.
259
- exclude: [virtualModuleId]
260
- }
261
- };
262
- },
263
- async resolveId(id) {
264
- if (id !== virtualModuleId) return;
265
- return await exists(appConfigFile) ? appConfigFile : resolvedVirtualModuleId;
266
- },
267
- load(id) {
268
- if (id === resolvedVirtualModuleId) return `export default {}`;
269
- }
270
- };
271
- }
272
-
273
- // src/core/builders/vite/plugins/devHtmlPrerender.ts
274
- import { parseHTML } from "linkedom";
275
- import { dirname, relative as relative2, resolve as resolve3 } from "node:path";
276
- import { murmurHash } from "ohash";
277
- var inlineScriptContents = {};
278
- function devHtmlPrerender(config, server) {
279
- const htmlReloadId = "@wxt/reload-html";
280
- const resolvedHtmlReloadId = resolve3(
281
- config.wxtModuleDir,
282
- "dist/virtual/reload-html.js"
283
- );
284
- const virtualInlineScript = "virtual:wxt-inline-script";
285
- const resolvedVirtualInlineScript = "\0" + virtualInlineScript;
286
- return [
287
- {
288
- apply: "build",
289
- name: "wxt:dev-html-prerender",
290
- config() {
291
- return {
292
- resolve: {
293
- alias: {
294
- [htmlReloadId]: resolvedHtmlReloadId
295
- }
296
- }
297
- };
298
- },
299
- // Convert scripts like src="./main.tsx" -> src="http://localhost:3000/entrypoints/popup/main.tsx"
300
- // before the paths are replaced with their bundled path
301
- transform(code, id) {
302
- if (config.command !== "serve" || server == null || !id.endsWith(".html"))
303
- return;
304
- const { document } = parseHTML(code);
305
- const _pointToDevServer = (querySelector, attr) => pointToDevServer(config, server, id, document, querySelector, attr);
306
- _pointToDevServer("script[type=module]", "src");
307
- _pointToDevServer("link[rel=stylesheet]", "href");
308
- const reloader = document.createElement("script");
309
- reloader.src = htmlReloadId;
310
- reloader.type = "module";
311
- document.head.appendChild(reloader);
312
- const newHtml = document.toString();
313
- config.logger.debug("transform " + id);
314
- config.logger.debug("Old HTML:\n" + code);
315
- config.logger.debug("New HTML:\n" + newHtml);
316
- return newHtml;
317
- },
318
- // Pass the HTML through the dev server to add dev-mode specific code
319
- async transformIndexHtml(html, ctx) {
320
- if (config.command !== "serve" || server == null) return;
321
- const originalUrl = `${server.origin}${ctx.path}`;
322
- const name = getEntrypointName(config.entrypointsDir, ctx.filename);
323
- const url = `${server.origin}/${name}.html`;
324
- const serverHtml = await server.transformHtml(url, html, originalUrl);
325
- const { document } = parseHTML(serverHtml);
326
- const inlineScripts = document.querySelectorAll("script:not([src])");
327
- inlineScripts.forEach((script) => {
328
- const textContent = script.textContent ?? "";
329
- const hash = murmurHash(textContent);
330
- inlineScriptContents[hash] = textContent;
331
- const virtualScript = document.createElement("script");
332
- virtualScript.type = "module";
333
- virtualScript.src = `${server.origin}/@id/${virtualInlineScript}?${hash}`;
334
- script.replaceWith(virtualScript);
335
- });
336
- const viteClientScript = document.querySelector(
337
- "script[src='/@vite/client']"
338
- );
339
- if (viteClientScript) {
340
- viteClientScript.src = `${server.origin}${viteClientScript.src}`;
341
- }
342
- const newHtml = document.toString();
343
- config.logger.debug("transformIndexHtml " + ctx.filename);
344
- config.logger.debug("Old HTML:\n" + html);
345
- config.logger.debug("New HTML:\n" + newHtml);
346
- return newHtml;
347
- }
348
- },
349
- {
350
- name: "wxt:virtualize-react-refresh",
351
- apply: "serve",
352
- resolveId(id) {
353
- if (id.startsWith(virtualInlineScript)) {
354
- return "\0" + id;
355
- }
356
- if (id.startsWith("/chunks/")) {
357
- return "\0noop";
358
- }
359
- },
360
- load(id) {
361
- if (id.startsWith(resolvedVirtualInlineScript)) {
362
- const hash = Number(id.substring(id.indexOf("?") + 1));
363
- return inlineScriptContents[hash];
364
- }
365
- if (id === "\0noop") {
366
- return "";
367
- }
368
- }
369
- }
370
- ];
371
- }
372
- function pointToDevServer(config, server, id, document, querySelector, attr) {
373
- document.querySelectorAll(querySelector).forEach((element) => {
374
- const src = element.getAttribute(attr);
375
- if (!src || isUrl(src)) return;
376
- let resolvedAbsolutePath;
377
- const matchingAlias = Object.entries(config.alias).find(
378
- ([key]) => src.startsWith(key)
379
- );
380
- if (matchingAlias) {
381
- const [alias, replacement] = matchingAlias;
382
- resolvedAbsolutePath = resolve3(
383
- config.root,
384
- src.replace(alias, replacement)
385
- );
386
- } else {
387
- resolvedAbsolutePath = resolve3(dirname(id), src);
388
- }
389
- if (resolvedAbsolutePath) {
390
- const relativePath = normalizePath(
391
- relative2(config.root, resolvedAbsolutePath)
392
- );
393
- if (relativePath.startsWith(".")) {
394
- let path8 = normalizePath(resolvedAbsolutePath);
395
- if (!path8.startsWith("/")) path8 = "/" + path8;
396
- element.setAttribute(attr, `${server.origin}/@fs${path8}`);
397
- } else {
398
- const url = new URL(relativePath, server.origin);
399
- element.setAttribute(attr, url.href);
400
- }
401
- }
402
- });
403
- }
404
- function isUrl(str) {
405
- try {
406
- new URL(str);
407
- return true;
408
- } catch {
409
- return false;
410
- }
411
- }
412
-
413
- // src/core/builders/vite/plugins/devServerGlobals.ts
414
- function devServerGlobals(config, server) {
415
- return {
416
- name: "wxt:dev-server-globals",
417
- config() {
418
- if (server == null || config.command == "build") return;
419
- return {
420
- define: {
421
- __DEV_SERVER_PROTOCOL__: JSON.stringify("ws:"),
422
- __DEV_SERVER_HOSTNAME__: JSON.stringify(server.hostname),
423
- __DEV_SERVER_PORT__: JSON.stringify(server.port)
424
- }
425
- };
426
- }
427
- };
428
- }
429
-
430
- // src/core/builders/vite/plugins/multipageMove.ts
431
- import { dirname as dirname2, extname, resolve as resolve4, join } from "node:path";
432
- import fs, { ensureDir } from "fs-extra";
433
- function multipageMove(entrypoints, config) {
434
- return {
435
- name: "wxt:multipage-move",
436
- async writeBundle(_, bundle) {
437
- for (const oldBundlePath in bundle) {
438
- const entrypoint = entrypoints.find(
439
- (entry) => !!normalizePath(entry.inputPath).endsWith(oldBundlePath)
440
- );
441
- if (entrypoint == null) {
442
- config.logger.debug(
443
- `No entrypoint found for ${oldBundlePath}, leaving in chunks directory`
444
- );
445
- continue;
446
- }
447
- const newBundlePath = getEntrypointBundlePath(
448
- entrypoint,
449
- config.outDir,
450
- extname(oldBundlePath)
451
- );
452
- if (newBundlePath === oldBundlePath) {
453
- config.logger.debug(
454
- "HTML file is already in the correct location",
455
- oldBundlePath
456
- );
457
- continue;
458
- }
459
- const oldAbsPath = resolve4(config.outDir, oldBundlePath);
460
- const newAbsPath = resolve4(config.outDir, newBundlePath);
461
- await ensureDir(dirname2(newAbsPath));
462
- await fs.move(oldAbsPath, newAbsPath, { overwrite: true });
463
- const renamedChunk = {
464
- ...bundle[oldBundlePath],
465
- fileName: newBundlePath
466
- };
467
- delete bundle[oldBundlePath];
468
- bundle[newBundlePath] = renamedChunk;
469
- }
470
- removeEmptyDirs(config.outDir);
471
- }
472
- };
473
- }
474
- async function removeEmptyDirs(dir) {
475
- const files = await fs.readdir(dir);
476
- for (const file of files) {
477
- const filePath = join(dir, file);
478
- const stats = await fs.stat(filePath);
479
- if (stats.isDirectory()) {
480
- await removeEmptyDirs(filePath);
481
- }
482
- }
483
- try {
484
- await fs.rmdir(dir);
485
- } catch {
486
- }
487
- }
488
-
489
- // src/core/utils/virtual-modules.ts
490
- var virtualEntrypointTypes = [
491
- "content-script-main-world",
492
- "content-script-isolated-world",
493
- "background",
494
- "unlisted-script"
495
- ];
496
- var virtualEntrypointModuleNames = virtualEntrypointTypes.map(
497
- (name) => `${name}-entrypoint`
498
- );
499
- var virtualModuleNames = [
500
- ...virtualEntrypointModuleNames,
501
- "mock-browser",
502
- "reload-html"
503
- ];
504
-
505
- // src/core/builders/vite/plugins/resolveVirtualModules.ts
506
- import fs2 from "fs-extra";
507
- import { resolve as resolve5 } from "path";
508
- function resolveVirtualModules(config) {
509
- return virtualModuleNames.map((name) => {
510
- const virtualId = `virtual:wxt-${name}?`;
511
- const resolvedVirtualId = "\0" + virtualId;
512
- return {
513
- name: `wxt:resolve-virtual-${name}`,
514
- resolveId(id) {
515
- const index = id.indexOf(virtualId);
516
- if (index === -1) return;
517
- const inputPath = normalizePath(id.substring(index + virtualId.length));
518
- return resolvedVirtualId + inputPath;
519
- },
520
- async load(id) {
521
- if (!id.startsWith(resolvedVirtualId)) return;
522
- const inputPath = id.replace(resolvedVirtualId, "");
523
- const template = await fs2.readFile(
524
- resolve5(config.wxtModuleDir, `dist/virtual/${name}.js`),
525
- "utf-8"
526
- );
527
- return template.replace(`virtual:user-${name}`, inputPath);
528
- }
529
- };
530
- });
531
- }
532
-
533
- // src/core/utils/constants.ts
534
- var VIRTUAL_NOOP_BACKGROUND_MODULE_ID = "virtual:user-background";
535
-
536
- // src/core/builders/vite/plugins/noopBackground.ts
537
- function noopBackground() {
538
- const virtualModuleId = VIRTUAL_NOOP_BACKGROUND_MODULE_ID;
539
- const resolvedVirtualModuleId = "\0" + virtualModuleId;
540
- return {
541
- name: "wxt:noop-background",
542
- resolveId(id) {
543
- if (id === virtualModuleId) return resolvedVirtualModuleId;
544
- },
545
- load(id) {
546
- if (id === resolvedVirtualModuleId) {
547
- return `import { defineBackground } from 'wxt/sandbox';
548
- export default defineBackground(() => void 0)`;
549
- }
550
- }
551
- };
552
- }
553
-
554
- // src/core/builders/vite/plugins/cssEntrypoints.ts
555
- function cssEntrypoints(entrypoint, config) {
556
- return {
557
- name: "wxt:css-entrypoint",
558
- config() {
559
- return {
560
- build: {
561
- rollupOptions: {
562
- output: {
563
- assetFileNames: () => getEntrypointBundlePath(entrypoint, config.outDir, ".css")
564
- }
565
- }
566
- }
567
- };
568
- },
569
- generateBundle(_, bundle) {
570
- Object.keys(bundle).forEach((file) => {
571
- if (file.endsWith(".js")) delete bundle[file];
572
- });
573
- }
574
- };
575
- }
576
-
577
- // src/core/builders/vite/plugins/bundleAnalysis.ts
578
- import { visualizer } from "@aklinker1/rollup-plugin-visualizer";
579
- import path3 from "node:path";
580
- var increment = 0;
581
- function bundleAnalysis(config) {
582
- return visualizer({
583
- template: "raw-data",
584
- filename: path3.resolve(
585
- config.analysis.outputDir,
586
- `${config.analysis.outputName}-${increment++}.json`
587
- )
588
- });
589
- }
590
-
591
- // src/core/builders/vite/plugins/excludeBrowserPolyfill.ts
592
- function excludeBrowserPolyfill(config) {
593
- const virtualId = "virtual:wxt-webextension-polyfill-disabled";
594
- return {
595
- name: "wxt:exclude-browser-polyfill",
596
- config() {
597
- if (config.experimental.includeBrowserPolyfill) return;
598
- return {
599
- resolve: {
600
- alias: {
601
- "webextension-polyfill": virtualId
602
- }
603
- }
604
- };
605
- },
606
- load(id) {
607
- if (id === virtualId) {
608
- return "export default chrome";
609
- }
610
- }
611
- };
612
- }
613
-
614
- // src/core/builders/vite/plugins/entrypointGroupGlobals.ts
615
- function entrypointGroupGlobals(entrypointGroup) {
616
- return {
617
- name: "wxt:entrypoint-group-globals",
618
- config() {
619
- const define = {};
620
- let name = Array.isArray(entrypointGroup) ? "html" : entrypointGroup.name;
621
- for (const global of getEntrypointGlobals(name)) {
622
- define[`import.meta.env.${global.name}`] = JSON.stringify(global.value);
623
- }
624
- return {
625
- define
626
- };
627
- }
628
- };
629
- }
630
-
631
- // src/core/builders/vite/plugins/defineImportMeta.ts
632
- function defineImportMeta() {
633
- return {
634
- name: "wxt:define",
635
- config() {
636
- return {
637
- define: {
638
- // This works for all extension contexts, including background service worker
639
- "import.meta.url": "self.location.href"
640
- }
641
- };
642
- }
643
- };
644
- }
645
-
646
- // src/core/utils/transform.ts
647
- import { parseModule } from "magicast";
648
- function removeMainFunctionCode(code) {
649
- const mod = parseModule(code);
650
- emptyMainFunction(mod);
651
- return mod.generate();
652
- }
653
- function emptyMainFunction(mod) {
654
- if (mod.exports?.default?.$type === "function-call") {
655
- if (mod.exports.default.$ast?.arguments?.[0]?.body) {
656
- mod.exports.default.$ast.arguments[0].body.body = [];
657
- } else if (mod.exports.default.$ast?.arguments?.[0]?.properties) {
658
- mod.exports.default.$ast.arguments[0].properties = mod.exports.default.$ast.arguments[0].properties.filter(
659
- (prop) => prop.key.name !== "main"
660
- );
661
- }
662
- }
663
- }
664
-
665
- // src/core/builders/vite/plugins/removeEntrypointMainFunction.ts
666
- import { resolve as resolve6 } from "node:path";
667
- function removeEntrypointMainFunction(config, path8) {
668
- const absPath = normalizePath(resolve6(config.root, path8));
669
- return {
670
- name: "wxt:remove-entrypoint-main-function",
671
- transform(code, id) {
672
- if (id === absPath) return removeMainFunctionCode(code);
673
- }
674
- };
675
- }
676
-
677
- // src/core/builders/vite/plugins/wxtPluginLoader.ts
678
- import { parseHTML as parseHTML2 } from "linkedom";
679
- function wxtPluginLoader(config) {
680
- const virtualModuleId = "virtual:wxt-plugins";
681
- const resolvedVirtualModuleId = "\0" + virtualModuleId;
682
- const virtualHtmlModuleId = "virtual:wxt-html-plugins";
683
- const resolvedVirtualHtmlModuleId = "\0" + virtualHtmlModuleId;
684
- return {
685
- name: "wxt:plugin-loader",
686
- resolveId(id) {
687
- if (id === virtualModuleId) return resolvedVirtualModuleId;
688
- if (id === virtualHtmlModuleId) return resolvedVirtualHtmlModuleId;
689
- },
690
- load(id) {
691
- if (id === resolvedVirtualModuleId) {
692
- const imports = config.plugins.map(
693
- (plugin, i) => `import initPlugin${i} from '${normalizePath(plugin)}';`
694
- ).join("\n");
695
- const initCalls = config.plugins.map((_, i) => ` initPlugin${i}();`).join("\n");
696
- return `${imports}
697
-
698
- export function initPlugins() {
699
- ${initCalls}
700
- }`;
701
- }
702
- if (id === resolvedVirtualHtmlModuleId) {
703
- return `import { initPlugins } from '${virtualModuleId}';
704
-
705
- try {
706
- initPlugins();
707
- } catch (err) {
708
- console.error("[wxt] Failed to initialize plugins", err);
709
- }`;
710
- }
711
- },
712
- transformIndexHtml: {
713
- // Use "pre" so the new script is added before vite bundles all the scripts
714
- order: "pre",
715
- handler(html, _ctx) {
716
- const src = config.command === "serve" ? `http://${config.dev.server?.hostname}:${config.dev.server?.port}/@id/${virtualHtmlModuleId}` : virtualHtmlModuleId;
717
- const { document } = parseHTML2(html);
718
- const existing = document.querySelector(`script[src='${src}']`);
719
- if (existing) return;
720
- const script = document.createElement("script");
721
- script.type = "module";
722
- script.src = src;
723
- if (document.head == null) {
724
- const newHead = document.createElement("head");
725
- document.documentElement.prepend(newHead);
726
- }
727
- document.head.prepend(script);
728
- return document.toString();
729
- }
730
- }
731
- };
732
- }
733
-
734
- // src/core/utils/strings.ts
735
- function kebabCaseAlphanumeric(str) {
736
- return str.toLowerCase().replace(/[^a-z0-9-\s]/g, "").replace(/\s+/g, "-");
737
- }
738
- function safeVarName(str) {
739
- return "_" + kebabCaseAlphanumeric(str.trim()).replace("-", "_");
740
- }
741
- function removeImportStatements(text) {
742
- return text.replace(
743
- /(import\s?[\s\S]*?from\s?["'][\s\S]*?["'];?|import\s?["'][\s\S]*?["'];?)/gm,
744
- ""
745
- );
746
- }
747
- function removeProjectImportStatements(text) {
748
- const noImports = removeImportStatements(text);
749
- return `import { defineUnlistedScript, defineContentScript, defineBackground } from 'wxt/sandbox';
750
-
751
- ${noImports}`;
752
- }
753
-
754
- // src/builtin-modules/unimport.ts
755
- import { createUnimport } from "unimport";
756
- import { extname as extname2 } from "node:path";
757
- var unimport_default = defineWxtModule({
758
- name: "wxt:built-in:unimport",
759
- setup(wxt2) {
760
- const options = wxt2.config.imports;
761
- if (options === false) return;
762
- let unimport;
763
- wxt2.hooks.hook("ready", () => {
764
- const addModuleImports = (module) => {
765
- if (!module.imports) return;
766
- options.imports ??= [];
767
- options.imports.push(...module.imports);
768
- };
769
- wxt2.config.builtinModules.forEach(addModuleImports);
770
- wxt2.config.userModules.forEach(addModuleImports);
771
- });
772
- wxt2.hooks.afterEach((event) => {
773
- if (event.name === "ready") {
774
- unimport = createUnimport(options);
775
- }
776
- });
777
- wxt2.hooks.hook("prepare:types", async (_, entries) => {
778
- await unimport.init();
779
- entries.push(await getImportsDeclarationEntry(unimport));
780
- if (options.eslintrc.enabled === false) return;
781
- entries.push(
782
- await getEslintConfigEntry(unimport, options.eslintrc.enabled, options)
783
- );
784
- });
785
- addViteConfig(wxt2, () => ({
786
- plugins: [vitePlugin(unimport)]
787
- }));
788
- }
789
- });
790
- function vitePlugin(unimport) {
791
- const ENABLED_EXTENSIONS = /* @__PURE__ */ new Set([
792
- ".js",
793
- ".jsx",
794
- ".ts",
795
- ".tsx",
796
- ".vue",
797
- ".svelte"
798
- ]);
799
- return {
800
- name: "wxt:unimport",
801
- async transform(code, id) {
802
- if (id.includes("node_modules")) return;
803
- if (!ENABLED_EXTENSIONS.has(extname2(id))) return;
804
- const injected = await unimport.injectImports(code, id);
805
- return {
806
- code: injected.code,
807
- map: injected.s.generateMap({ hires: "boundary", source: id })
808
- };
809
- }
810
- };
811
- }
812
- async function getImportsDeclarationEntry(unimport) {
813
- await unimport.init();
814
- return {
815
- path: "types/imports.d.ts",
816
- text: [
817
- "// Generated by wxt",
818
- await unimport.generateTypeDeclarations(),
819
- ""
820
- ].join("\n"),
821
- tsReference: true
822
- };
823
- }
824
- async function getEslintConfigEntry(unimport, version2, options) {
825
- const globals2 = (await unimport.getImports()).map((i) => i.as ?? i.name).filter(Boolean).sort().reduce((globals3, name) => {
826
- globals3[name] = options.eslintrc.globalsPropValue;
827
- return globals3;
828
- }, {});
829
- if (version2 <= 8) return getEslint8ConfigEntry(options, globals2);
830
- else return getEslint9ConfigEntry(options, globals2);
831
- }
832
- function getEslint8ConfigEntry(options, globals2) {
833
- return {
834
- path: options.eslintrc.filePath,
835
- text: JSON.stringify({ globals: globals2 }, null, 2) + "\n"
836
- };
837
- }
838
- function getEslint9ConfigEntry(options, globals2) {
839
- return {
840
- path: options.eslintrc.filePath,
841
- text: `const globals = ${JSON.stringify(globals2, null, 2)}
842
-
843
- export default {
844
- name: "wxt/auto-imports",
845
- languageOptions: {
846
- globals,
847
- sourceType: "module",
848
- },
849
- };
850
- `
851
- };
852
- }
853
-
854
- // src/core/utils/fs.ts
855
- import fs3 from "fs-extra";
856
- import glob from "fast-glob";
857
- async function writeFileIfDifferent(file, newContents) {
858
- const existingContents = await fs3.readFile(file, "utf-8").catch(() => void 0);
859
- if (existingContents !== newContents) {
860
- await fs3.writeFile(file, newContents);
861
- }
862
- }
863
- async function getPublicFiles() {
864
- if (!await fs3.exists(wxt.config.publicDir)) return [];
865
- const files = await glob("**/*", { cwd: wxt.config.publicDir });
866
- return files.map(unnormalizePath);
867
- }
868
-
869
- // src/core/utils/building/build-entrypoints.ts
870
- import fs4 from "fs-extra";
871
- import { dirname as dirname3, resolve as resolve7 } from "path";
872
- import pc from "picocolors";
873
- async function buildEntrypoints(groups, spinner) {
874
- const steps = [];
875
- for (let i = 0; i < groups.length; i++) {
876
- const group = groups[i];
877
- const groupNames = toArray(group).map((e) => e.name);
878
- const groupNameColored = groupNames.join(pc.dim(", "));
879
- spinner.text = pc.dim(`[${i + 1}/${groups.length}]`) + ` ${groupNameColored}`;
880
- try {
881
- steps.push(await wxt.builder.build(group));
882
- } catch (err) {
883
- spinner.stop().clear();
884
- wxt.logger.error(err);
885
- throw Error(`Failed to build ${groupNames.join(", ")}`, { cause: err });
886
- }
887
- }
888
- const publicAssets = await copyPublicDirectory();
889
- return { publicAssets, steps };
890
- }
891
- async function copyPublicDirectory() {
892
- const files = (await getPublicFiles()).map((file) => ({
893
- absoluteSrc: resolve7(wxt.config.publicDir, file),
894
- relativeDest: file
895
- }));
896
- await wxt.hooks.callHook("build:publicAssets", wxt, files);
897
- if (files.length === 0) return [];
898
- const publicAssets = [];
899
- for (const file of files) {
900
- const absoluteDest = resolve7(wxt.config.outDir, file.relativeDest);
901
- await fs4.ensureDir(dirname3(absoluteDest));
902
- if ("absoluteSrc" in file) {
903
- await fs4.copyFile(file.absoluteSrc, absoluteDest);
904
- } else {
905
- await fs4.writeFile(absoluteDest, file.contents, "utf8");
906
- }
907
- publicAssets.push({
908
- type: "asset",
909
- fileName: file.relativeDest
910
- });
911
- }
912
- return publicAssets;
913
- }
914
-
915
- // src/core/utils/building/detect-dev-changes.ts
916
- function detectDevChanges(changedFiles, currentOutput) {
917
- const isConfigChange = some(
918
- changedFiles,
919
- (file) => file === wxt.config.userConfigMetadata.configFile
920
- );
921
- if (isConfigChange) return { type: "full-restart" };
922
- const isRunnerChange = some(
923
- changedFiles,
924
- (file) => file === wxt.config.runnerConfig.configFile
925
- );
926
- if (isRunnerChange) return { type: "browser-restart" };
927
- const changedSteps = new Set(
928
- changedFiles.flatMap(
929
- (changedFile) => findEffectedSteps(changedFile, currentOutput)
930
- )
931
- );
932
- if (changedSteps.size === 0) {
933
- const hasPublicChange = some(
934
- changedFiles,
935
- (file) => file.startsWith(wxt.config.publicDir)
936
- );
937
- if (hasPublicChange) {
938
- return {
939
- type: "extension-reload",
940
- rebuildGroups: [],
941
- cachedOutput: currentOutput
942
- };
943
- } else {
944
- return { type: "no-change" };
945
- }
946
- }
947
- const unchangedOutput = {
948
- manifest: currentOutput.manifest,
949
- steps: [],
950
- publicAssets: [...currentOutput.publicAssets]
951
- };
952
- const changedOutput = {
953
- manifest: currentOutput.manifest,
954
- steps: [],
955
- publicAssets: []
956
- };
957
- for (const step of currentOutput.steps) {
958
- if (changedSteps.has(step)) {
959
- changedOutput.steps.push(step);
960
- } else {
961
- unchangedOutput.steps.push(step);
962
- }
963
- }
964
- const isOnlyHtmlChanges = changedFiles.length > 0 && every(changedFiles, (file) => file.endsWith(".html"));
965
- if (isOnlyHtmlChanges) {
966
- return {
967
- type: "html-reload",
968
- cachedOutput: unchangedOutput,
969
- rebuildGroups: changedOutput.steps.map((step) => step.entrypoints)
970
- };
971
- }
972
- const isOnlyContentScripts = changedOutput.steps.length > 0 && every(
973
- changedOutput.steps.flatMap((step) => step.entrypoints),
974
- (entry) => entry.type === "content-script"
975
- );
976
- if (isOnlyContentScripts) {
977
- return {
978
- type: "content-script-reload",
979
- cachedOutput: unchangedOutput,
980
- changedSteps: changedOutput.steps,
981
- rebuildGroups: changedOutput.steps.map((step) => step.entrypoints)
982
- };
983
- }
984
- return {
985
- type: "extension-reload",
986
- cachedOutput: unchangedOutput,
987
- rebuildGroups: changedOutput.steps.map((step) => step.entrypoints)
988
- };
989
- }
990
- function findEffectedSteps(changedFile, currentOutput) {
991
- const changes = [];
992
- const changedPath = normalizePath(changedFile);
993
- const isChunkEffected = (chunk) => (
994
- // If it's an HTML file with the same path, is is effected because HTML files need to be re-rendered
995
- // - fileName is normalized, relative bundle path, "<entrypoint-name>.html"
996
- chunk.type === "asset" && changedPath.replace("/index.html", ".html").endsWith(chunk.fileName) || // If it's a chunk that depends on the changed file, it is effected
997
- // - moduleIds are absolute, normalized paths
998
- chunk.type === "chunk" && chunk.moduleIds.includes(changedPath)
999
- );
1000
- for (const step of currentOutput.steps) {
1001
- const effectedChunk = step.chunks.find((chunk) => isChunkEffected(chunk));
1002
- if (effectedChunk) changes.push(step);
1003
- }
1004
- return changes;
1005
- }
1006
-
1007
- // src/core/utils/building/find-entrypoints.ts
1008
- import { relative as relative3, resolve as resolve8 } from "path";
1009
- import fs5 from "fs-extra";
1010
- import { minimatch } from "minimatch";
1011
- import { parseHTML as parseHTML3 } from "linkedom";
1012
- import JSON5 from "json5";
1013
- import glob2 from "fast-glob";
1014
- import pc2 from "picocolors";
1015
- async function findEntrypoints() {
1016
- await fs5.mkdir(wxt.config.wxtDir, { recursive: true });
1017
- await fs5.writeJson(resolve8(wxt.config.wxtDir, "tsconfig.json"), {});
1018
- const relativePaths = await glob2(Object.keys(PATH_GLOB_TO_TYPE_MAP), {
1019
- cwd: wxt.config.entrypointsDir
1020
- });
1021
- relativePaths.sort();
1022
- const pathGlobs = Object.keys(PATH_GLOB_TO_TYPE_MAP);
1023
- const entrypointInfos = relativePaths.reduce((results, relativePath) => {
1024
- const inputPath = resolve8(wxt.config.entrypointsDir, relativePath);
1025
- const name = getEntrypointName(wxt.config.entrypointsDir, inputPath);
1026
- const matchingGlob = pathGlobs.find(
1027
- (glob5) => minimatch(relativePath, glob5)
1028
- );
1029
- if (matchingGlob) {
1030
- const type = PATH_GLOB_TO_TYPE_MAP[matchingGlob];
1031
- results.push({
1032
- name,
1033
- inputPath,
1034
- type,
1035
- skipped: wxt.config.filterEntrypoints != null && !wxt.config.filterEntrypoints.has(name)
1036
- });
1037
- }
1038
- return results;
1039
- }, []);
1040
- preventNoEntrypoints(entrypointInfos);
1041
- preventDuplicateEntrypointNames(entrypointInfos);
1042
- let hasBackground = false;
1043
- const entrypoints = await Promise.all(
1044
- entrypointInfos.map(async (info) => {
1045
- const { type } = info;
1046
- switch (type) {
1047
- case "popup":
1048
- return await getPopupEntrypoint(info);
1049
- case "sidepanel":
1050
- return await getSidepanelEntrypoint(info);
1051
- case "options":
1052
- return await getOptionsEntrypoint(info);
1053
- case "background":
1054
- hasBackground = true;
1055
- return await getBackgroundEntrypoint(info);
1056
- case "content-script":
1057
- return await getContentScriptEntrypoint(info);
1058
- case "unlisted-page":
1059
- return await getUnlistedPageEntrypoint(info);
1060
- case "unlisted-script":
1061
- return await getUnlistedScriptEntrypoint(info);
1062
- case "content-script-style":
1063
- return {
1064
- ...info,
1065
- type,
1066
- outputDir: resolve8(wxt.config.outDir, CONTENT_SCRIPT_OUT_DIR),
1067
- options: {
1068
- include: void 0,
1069
- exclude: void 0
1070
- }
1071
- };
1072
- default:
1073
- return {
1074
- ...info,
1075
- type,
1076
- outputDir: wxt.config.outDir,
1077
- options: {
1078
- include: void 0,
1079
- exclude: void 0
1080
- }
1081
- };
1082
- }
1083
- })
1084
- );
1085
- if (wxt.config.command === "serve" && !hasBackground) {
1086
- entrypoints.push(
1087
- await getBackgroundEntrypoint({
1088
- inputPath: VIRTUAL_NOOP_BACKGROUND_MODULE_ID,
1089
- name: "background",
1090
- type: "background",
1091
- skipped: false
1092
- })
1093
- );
1094
- }
1095
- wxt.logger.debug("All entrypoints:", entrypoints);
1096
- const skippedEntrypointNames = entrypointInfos.filter((item) => item.skipped).map((item) => item.name);
1097
- if (skippedEntrypointNames.length) {
1098
- wxt.logger.warn(
1099
- `Filter excluded the following entrypoints:
1100
- ${skippedEntrypointNames.map((item) => `${pc2.dim("-")} ${pc2.cyan(item)}`).join("\n")}`
1101
- );
1102
- }
1103
- const targetEntrypoints = entrypoints.filter((entry) => {
1104
- const { include, exclude } = entry.options;
1105
- if (include?.length && exclude?.length) {
1106
- wxt.logger.warn(
1107
- `The ${entry.name} entrypoint lists both include and exclude, but only one can be used per entrypoint. Entrypoint ignored.`
1108
- );
1109
- return false;
1110
- }
1111
- if (exclude?.length && !include?.length) {
1112
- return !exclude.includes(wxt.config.browser);
1113
- }
1114
- if (include?.length && !exclude?.length) {
1115
- return include.includes(wxt.config.browser);
1116
- }
1117
- if (skippedEntrypointNames.includes(entry.name)) {
1118
- return false;
1119
- }
1120
- return true;
1121
- });
1122
- wxt.logger.debug(`${wxt.config.browser} entrypoints:`, targetEntrypoints);
1123
- await wxt.hooks.callHook("entrypoints:resolved", wxt, targetEntrypoints);
1124
- return targetEntrypoints;
1125
- }
1126
- function preventDuplicateEntrypointNames(files) {
1127
- const namesToPaths = files.reduce(
1128
- (map, { name, inputPath }) => {
1129
- map[name] ??= [];
1130
- map[name].push(inputPath);
1131
- return map;
1132
- },
1133
- {}
1134
- );
1135
- const errorLines = Object.entries(namesToPaths).reduce(
1136
- (lines, [name, absolutePaths]) => {
1137
- if (absolutePaths.length > 1) {
1138
- lines.push(`- ${name}`);
1139
- absolutePaths.forEach((absolutePath) => {
1140
- lines.push(` - ${relative3(wxt.config.root, absolutePath)}`);
1141
- });
1142
- }
1143
- return lines;
1144
- },
1145
- []
1146
- );
1147
- if (errorLines.length > 0) {
1148
- const errorContent = errorLines.join("\n");
1149
- throw Error(
1150
- `Multiple entrypoints with the same name detected, only one entrypoint for each name is allowed.
1151
-
1152
- ${errorContent}`
1153
- );
1154
- }
1155
- }
1156
- function preventNoEntrypoints(files) {
1157
- if (files.length === 0) {
1158
- throw Error(`No entrypoints found in ${wxt.config.entrypointsDir}`);
1159
- }
1160
- }
1161
- async function getPopupEntrypoint(info) {
1162
- const options = await getHtmlEntrypointOptions(
1163
- info,
1164
- {
1165
- browserStyle: "browse_style",
1166
- exclude: "exclude",
1167
- include: "include",
1168
- defaultIcon: "default_icon",
1169
- defaultTitle: "default_title",
1170
- mv2Key: "type"
1171
- },
1172
- {
1173
- defaultTitle: (document) => document.querySelector("title")?.textContent || void 0
1174
- },
1175
- {
1176
- defaultTitle: (content) => content,
1177
- mv2Key: (content) => content === "page_action" ? "page_action" : "browser_action"
1178
- }
1179
- );
1180
- return {
1181
- type: "popup",
1182
- name: "popup",
1183
- options: resolvePerBrowserOptions(options, wxt.config.browser),
1184
- inputPath: info.inputPath,
1185
- outputDir: wxt.config.outDir,
1186
- skipped: info.skipped
1187
- };
1188
- }
1189
- async function getOptionsEntrypoint(info) {
1190
- const options = await getHtmlEntrypointOptions(
1191
- info,
1192
- {
1193
- browserStyle: "browse_style",
1194
- chromeStyle: "chrome_style",
1195
- exclude: "exclude",
1196
- include: "include",
1197
- openInTab: "open_in_tab"
1198
- }
1199
- );
1200
- return {
1201
- type: "options",
1202
- name: "options",
1203
- options: resolvePerBrowserOptions(options, wxt.config.browser),
1204
- inputPath: info.inputPath,
1205
- outputDir: wxt.config.outDir,
1206
- skipped: info.skipped
1207
- };
1208
- }
1209
- async function getUnlistedPageEntrypoint(info) {
1210
- const options = await getHtmlEntrypointOptions(info, {
1211
- exclude: "exclude",
1212
- include: "include"
1213
- });
1214
- return {
1215
- type: "unlisted-page",
1216
- name: info.name,
1217
- inputPath: info.inputPath,
1218
- outputDir: wxt.config.outDir,
1219
- options,
1220
- skipped: info.skipped
1221
- };
1222
- }
1223
- async function getUnlistedScriptEntrypoint({
1224
- inputPath,
1225
- name,
1226
- skipped
1227
- }) {
1228
- const defaultExport = await wxt.builder.importEntrypoint(inputPath);
1229
- if (defaultExport == null) {
1230
- throw Error(
1231
- `${name}: Default export not found, did you forget to call "export default defineUnlistedScript(...)"?`
1232
- );
1233
- }
1234
- const { main: _, ...options } = defaultExport;
1235
- return {
1236
- type: "unlisted-script",
1237
- name,
1238
- inputPath,
1239
- outputDir: wxt.config.outDir,
1240
- options: resolvePerBrowserOptions(options, wxt.config.browser),
1241
- skipped
1242
- };
1243
- }
1244
- async function getBackgroundEntrypoint({
1245
- inputPath,
1246
- name,
1247
- skipped
1248
- }) {
1249
- let options = {};
1250
- if (inputPath !== VIRTUAL_NOOP_BACKGROUND_MODULE_ID) {
1251
- const defaultExport = await wxt.builder.importEntrypoint(inputPath);
1252
- if (defaultExport == null) {
1253
- throw Error(
1254
- `${name}: Default export not found, did you forget to call "export default defineBackground(...)"?`
1255
- );
1256
- }
1257
- const { main: _, ...moduleOptions } = defaultExport;
1258
- options = moduleOptions;
1259
- }
1260
- if (wxt.config.manifestVersion !== 3) {
1261
- delete options.type;
1262
- }
1263
- return {
1264
- type: "background",
1265
- name,
1266
- inputPath,
1267
- outputDir: wxt.config.outDir,
1268
- options: resolvePerBrowserOptions(options, wxt.config.browser),
1269
- skipped
1270
- };
1271
- }
1272
- async function getContentScriptEntrypoint({
1273
- inputPath,
1274
- name,
1275
- skipped
1276
- }) {
1277
- const defaultExport = await wxt.builder.importEntrypoint(inputPath);
1278
- if (defaultExport == null) {
1279
- throw Error(
1280
- `${name}: Default export not found, did you forget to call "export default defineContentScript(...)"?`
1281
- );
1282
- }
1283
- const { main: _, ...options } = defaultExport;
1284
- if (options == null) {
1285
- throw Error(
1286
- `${name}: Default export not found, did you forget to call "export default defineContentScript(...)"?`
1287
- );
1288
- }
1289
- return {
1290
- type: "content-script",
1291
- name,
1292
- inputPath,
1293
- outputDir: resolve8(wxt.config.outDir, CONTENT_SCRIPT_OUT_DIR),
1294
- options: resolvePerBrowserOptions(options, wxt.config.browser),
1295
- skipped
1296
- };
1297
- }
1298
- async function getSidepanelEntrypoint(info) {
1299
- const options = await getHtmlEntrypointOptions(
1300
- info,
1301
- {
1302
- browserStyle: "browse_style",
1303
- exclude: "exclude",
1304
- include: "include",
1305
- defaultIcon: "default_icon",
1306
- defaultTitle: "default_title",
1307
- openAtInstall: "open_at_install"
1308
- },
1309
- {
1310
- defaultTitle: (document) => document.querySelector("title")?.textContent || void 0
1311
- },
1312
- {
1313
- defaultTitle: (content) => content
1314
- }
1315
- );
1316
- return {
1317
- type: "sidepanel",
1318
- name: info.name,
1319
- options: resolvePerBrowserOptions(options, wxt.config.browser),
1320
- inputPath: info.inputPath,
1321
- outputDir: wxt.config.outDir,
1322
- skipped: info.skipped
1323
- };
1324
- }
1325
- async function getHtmlEntrypointOptions(info, keyMap, queries, parsers) {
1326
- const content = await fs5.readFile(info.inputPath, "utf-8");
1327
- const { document } = parseHTML3(content);
1328
- const options = {};
1329
- const defaultQuery = (manifestKey) => document.querySelector(`meta[name='manifest.${manifestKey}']`)?.getAttribute("content");
1330
- Object.entries(keyMap).forEach(([_key, manifestKey]) => {
1331
- const key = _key;
1332
- const content2 = queries?.[key] ? queries[key](document, manifestKey) : defaultQuery(manifestKey);
1333
- if (content2) {
1334
- try {
1335
- options[key] = (parsers?.[key] ?? JSON5.parse)(content2);
1336
- } catch (err) {
1337
- wxt.logger.fatal(
1338
- `Failed to parse meta tag content. Usually this means you have invalid JSON5 content (content=${content2})`,
1339
- err
1340
- );
1341
- }
1342
- }
1343
- });
1344
- return options;
1345
- }
1346
- var PATH_GLOB_TO_TYPE_MAP = {
1347
- "sandbox.html": "sandbox",
1348
- "sandbox/index.html": "sandbox",
1349
- "*.sandbox.html": "sandbox",
1350
- "*.sandbox/index.html": "sandbox",
1351
- "bookmarks.html": "bookmarks",
1352
- "bookmarks/index.html": "bookmarks",
1353
- "history.html": "history",
1354
- "history/index.html": "history",
1355
- "newtab.html": "newtab",
1356
- "newtab/index.html": "newtab",
1357
- "sidepanel.html": "sidepanel",
1358
- "sidepanel/index.html": "sidepanel",
1359
- "*.sidepanel.html": "sidepanel",
1360
- "*.sidepanel/index.html": "sidepanel",
1361
- "devtools.html": "devtools",
1362
- "devtools/index.html": "devtools",
1363
- "background.[jt]s": "background",
1364
- "background/index.[jt]s": "background",
1365
- [VIRTUAL_NOOP_BACKGROUND_MODULE_ID]: "background",
1366
- "content.[jt]s?(x)": "content-script",
1367
- "content/index.[jt]s?(x)": "content-script",
1368
- "*.content.[jt]s?(x)": "content-script",
1369
- "*.content/index.[jt]s?(x)": "content-script",
1370
- [`content.${CSS_EXTENSIONS_PATTERN}`]: "content-script-style",
1371
- [`*.content.${CSS_EXTENSIONS_PATTERN}`]: "content-script-style",
1372
- [`content/index.${CSS_EXTENSIONS_PATTERN}`]: "content-script-style",
1373
- [`*.content/index.${CSS_EXTENSIONS_PATTERN}`]: "content-script-style",
1374
- "popup.html": "popup",
1375
- "popup/index.html": "popup",
1376
- "options.html": "options",
1377
- "options/index.html": "options",
1378
- "*.html": "unlisted-page",
1379
- "*/index.html": "unlisted-page",
1380
- "*.[jt]s?(x)": "unlisted-script",
1381
- "*/index.[jt]s?(x)": "unlisted-script",
1382
- [`*.${CSS_EXTENSIONS_PATTERN}`]: "unlisted-style",
1383
- [`*/index.${CSS_EXTENSIONS_PATTERN}`]: "unlisted-style"
1384
- };
1385
- var CONTENT_SCRIPT_OUT_DIR = "content-scripts";
1386
-
1387
- // src/core/utils/building/generate-wxt-dir.ts
1388
- import fs6 from "fs-extra";
1389
- import { dirname as dirname4, relative as relative4, resolve as resolve9 } from "node:path";
1390
- import path4 from "node:path";
1391
-
1392
- // src/core/utils/i18n.ts
1393
- var predefinedMessages = {
1394
- "@@extension_id": {
1395
- message: "<browser.runtime.id>",
1396
- description: "The extension or app ID; you might use this string to construct URLs for resources inside the extension. Even unlocalized extensions can use this message.\nNote: You can't use this message in a manifest file."
1397
- },
1398
- "@@ui_locale": {
1399
- message: "<browser.i18n.getUiLocale()>",
1400
- description: ""
1401
- },
1402
- "@@bidi_dir": {
1403
- message: "<ltr|rtl>",
1404
- description: 'The text direction for the current locale, either "ltr" for left-to-right languages such as English or "rtl" for right-to-left languages such as Japanese.'
1405
- },
1406
- "@@bidi_reversed_dir": {
1407
- message: "<rtl|ltr>",
1408
- description: `If the @@bidi_dir is "ltr", then this is "rtl"; otherwise, it's "ltr".`
1409
- },
1410
- "@@bidi_start_edge": {
1411
- message: "<left|right>",
1412
- description: `If the @@bidi_dir is "ltr", then this is "left"; otherwise, it's "right".`
1413
- },
1414
- "@@bidi_end_edge": {
1415
- message: "<right|left>",
1416
- description: `If the @@bidi_dir is "ltr", then this is "right"; otherwise, it's "left".`
1417
- }
1418
- };
1419
- function parseI18nMessages(messagesJson) {
1420
- return Object.entries({
1421
- ...predefinedMessages,
1422
- ...messagesJson
1423
- }).map(([name, details]) => ({
1424
- name,
1425
- ...details
1426
- }));
1427
- }
1428
-
1429
- // src/core/utils/building/generate-wxt-dir.ts
1430
- async function generateTypesDir(entrypoints) {
1431
- await fs6.ensureDir(wxt.config.typesDir);
1432
- const entries = [
1433
- // Hard-coded entries
1434
- { module: "wxt/vite-builder-env" }
1435
- ];
1436
- wxt.config.userModules.forEach((module) => {
1437
- if (module.type === "node_module") entries.push({ module: module.id });
1438
- });
1439
- entries.push(await getPathsDeclarationEntry(entrypoints));
1440
- entries.push(await getI18nDeclarationEntry());
1441
- entries.push(await getGlobalsDeclarationEntry());
1442
- entries.push(await getTsConfigEntry());
1443
- await wxt.hooks.callHook("prepare:types", wxt, entries);
1444
- entries.push(getMainDeclarationEntry(entries));
1445
- const absoluteFileEntries = entries.filter((entry) => "path" in entry).map((entry) => ({
1446
- ...entry,
1447
- path: resolve9(wxt.config.wxtDir, entry.path)
1448
- }));
1449
- await Promise.all(
1450
- absoluteFileEntries.map(async (file) => {
1451
- await fs6.ensureDir(dirname4(file.path));
1452
- await writeFileIfDifferent(file.path, file.text);
1453
- })
1454
- );
1455
- }
1456
- async function getPathsDeclarationEntry(entrypoints) {
1457
- const unions = entrypoints.map(
1458
- (entry) => getEntrypointBundlePath(
1459
- entry,
1460
- wxt.config.outDir,
1461
- isHtmlEntrypoint(entry) ? ".html" : ".js"
1462
- )
1463
- ).concat(await getPublicFiles()).map(normalizePath).map((path8) => ` | "/${path8}"`).sort().join("\n");
1464
- const template = `// Generated by wxt
1465
- import "wxt/browser";
1466
-
1467
- declare module "wxt/browser" {
1468
- export type PublicPath =
1469
- {{ union }}
1470
- type HtmlPublicPath = Extract<PublicPath, \`\${string}.html\`>
1471
- export interface WxtRuntime extends Runtime.Static {
1472
- getURL(path: PublicPath): string;
1473
- getURL(path: \`\${HtmlPublicPath}\${string}\`): string;
1474
- }
1475
- }
1476
- `;
1477
- return {
1478
- path: "types/paths.d.ts",
1479
- text: template.replace("{{ union }}", unions || " | never"),
1480
- tsReference: true
1481
- };
1482
- }
1483
- async function getI18nDeclarationEntry() {
1484
- const defaultLocale = wxt.config.manifest.default_locale;
1485
- const template = `// Generated by wxt
1486
- import "wxt/browser";
1487
-
1488
- declare module "wxt/browser" {
1489
- /**
1490
- * See https://developer.chrome.com/docs/extensions/reference/i18n/#method-getMessage
1491
- */
1492
- interface GetMessageOptions {
1493
- /**
1494
- * See https://developer.chrome.com/docs/extensions/reference/i18n/#method-getMessage
1495
- */
1496
- escapeLt?: boolean
1497
- }
1498
-
1499
- export interface WxtI18n extends I18n.Static {
1500
- {{ overrides }}
1501
- }
1502
- }
1503
- `;
1504
- const defaultLocalePath = path4.resolve(
1505
- wxt.config.publicDir,
1506
- "_locales",
1507
- defaultLocale ?? "",
1508
- "messages.json"
1509
- );
1510
- let messages;
1511
- if (await fs6.exists(defaultLocalePath)) {
1512
- const content = JSON.parse(await fs6.readFile(defaultLocalePath, "utf-8"));
1513
- messages = parseI18nMessages(content);
1514
- } else {
1515
- messages = parseI18nMessages({});
1516
- }
1517
- const overrides = messages.map((message) => {
1518
- return ` /**
1519
- * ${message.description || "No message description."}
1520
- *
1521
- * "${message.message}"
1522
- */
1523
- getMessage(
1524
- messageName: "${message.name}",
1525
- substitutions?: string | string[],
1526
- options?: GetMessageOptions,
1527
- ): string;`;
1528
- });
1529
- return {
1530
- path: "types/i18n.d.ts",
1531
- text: template.replace("{{ overrides }}", overrides.join("\n")),
1532
- tsReference: true
1533
- };
1534
- }
1535
- async function getGlobalsDeclarationEntry() {
1536
- const globals2 = [...getGlobals(wxt.config), ...getEntrypointGlobals("")];
1537
- return {
1538
- path: "types/globals.d.ts",
1539
- text: [
1540
- "// Generated by wxt",
1541
- "export {}",
1542
- "interface ImportMetaEnv {",
1543
- ...globals2.map((global) => ` readonly ${global.name}: ${global.type};`),
1544
- "}",
1545
- "interface ImportMeta {",
1546
- " readonly env: ImportMetaEnv",
1547
- "}",
1548
- ""
1549
- ].join("\n"),
1550
- tsReference: true
1551
- };
1552
- }
1553
- function getMainDeclarationEntry(references) {
1554
- const lines = ["// Generated by wxt"];
1555
- references.forEach((ref) => {
1556
- if ("module" in ref) {
1557
- return lines.push(`/// <reference types="${ref.module}" />`);
1558
- } else if (ref.tsReference) {
1559
- const absolutePath = resolve9(wxt.config.wxtDir, ref.path);
1560
- const relativePath = relative4(wxt.config.wxtDir, absolutePath);
1561
- lines.push(`/// <reference types="./${normalizePath(relativePath)}" />`);
1562
- }
1563
- });
1564
- return {
1565
- path: "wxt.d.ts",
1566
- text: lines.join("\n") + "\n"
1567
- };
1568
- }
1569
- async function getTsConfigEntry() {
1570
- const dir = wxt.config.wxtDir;
1571
- const getTsconfigPath = (path8) => normalizePath(relative4(dir, path8));
1572
- const paths = Object.entries(wxt.config.alias).flatMap(([alias, absolutePath]) => {
1573
- const aliasPath = getTsconfigPath(absolutePath);
1574
- return [
1575
- ` "${alias}": ["${aliasPath}"]`,
1576
- ` "${alias}/*": ["${aliasPath}/*"]`
1577
- ];
1578
- }).join(",\n");
1579
- const text = `{
1580
- "compilerOptions": {
1581
- "target": "ESNext",
1582
- "module": "ESNext",
1583
- "moduleResolution": "Bundler",
1584
- "noEmit": true,
1585
- "esModuleInterop": true,
1586
- "forceConsistentCasingInFileNames": true,
1587
- "resolveJsonModule": true,
1588
- "strict": true,
1589
- "skipLibCheck": true,
1590
- "paths": {
1591
- ${paths}
1592
- }
1593
- },
1594
- "include": [
1595
- "${getTsconfigPath(wxt.config.root)}/**/*",
1596
- "./wxt.d.ts"
1597
- ],
1598
- "exclude": ["${getTsconfigPath(wxt.config.outBaseDir)}"]
1599
- }`;
1600
- return {
1601
- path: "tsconfig.json",
1602
- text
1603
- };
1604
- }
1605
-
1606
- // src/core/utils/building/resolve-config.ts
1607
- import { loadConfig } from "c12";
1608
- import path5 from "node:path";
1609
-
1610
- // src/core/utils/cache.ts
1611
- import fs7, { ensureDir as ensureDir2 } from "fs-extra";
1612
- import { dirname as dirname5, resolve as resolve10 } from "path";
1613
- function createFsCache(wxtDir) {
1614
- const getPath = (key) => resolve10(wxtDir, "cache", encodeURIComponent(key));
1615
- return {
1616
- async set(key, value) {
1617
- const path8 = getPath(key);
1618
- await ensureDir2(dirname5(path8));
1619
- await writeFileIfDifferent(path8, value);
1620
- },
1621
- async get(key) {
1622
- const path8 = getPath(key);
1623
- try {
1624
- return await fs7.readFile(path8, "utf-8");
1625
- } catch {
1626
- return void 0;
1627
- }
1628
- }
1629
- };
1630
- }
1631
-
1632
- // src/core/utils/building/resolve-config.ts
1633
- import defu from "defu";
1634
- import fs8 from "fs-extra";
1635
- import glob3 from "fast-glob";
1636
-
1637
- // src/builtin-modules/index.ts
1638
- var builtinModules = [unimport_default];
1639
-
1640
- // src/core/utils/eslint.ts
1641
- async function getEslintVersion() {
1642
- try {
1643
- const require2 = (await import("node:module")).default.createRequire(
1644
- import.meta.url
1645
- );
1646
- const { ESLint } = require2("eslint");
1647
- return ESLint.version?.split(".") ?? [];
1648
- } catch (error) {
1649
- return [];
1650
- }
1651
- }
1652
-
1653
- // src/core/utils/building/resolve-config.ts
1654
- async function resolveConfig(inlineConfig, command) {
1655
- let userConfig = {};
1656
- let userConfigMetadata;
1657
- if (inlineConfig.configFile !== false) {
1658
- const { config: loadedConfig, ...metadata } = await loadConfig({
1659
- configFile: inlineConfig.configFile,
1660
- name: "wxt",
1661
- cwd: inlineConfig.root ?? process.cwd(),
1662
- rcFile: false,
1663
- jitiOptions: {
1664
- esmResolve: true
1665
- }
1666
- });
1667
- userConfig = loadedConfig ?? {};
1668
- userConfigMetadata = metadata;
1669
- }
1670
- const mergedConfig = await mergeInlineConfig(inlineConfig, userConfig);
1671
- const debug = mergedConfig.debug ?? false;
1672
- const logger = mergedConfig.logger ?? consola;
1673
- if (debug) logger.level = LogLevels.debug;
1674
- const browser = mergedConfig.browser ?? "chrome";
1675
- const manifestVersion = mergedConfig.manifestVersion ?? (browser === "firefox" || browser === "safari" ? 2 : 3);
1676
- const mode = mergedConfig.mode ?? COMMAND_MODES[command];
1677
- const env = { browser, command, manifestVersion, mode };
1678
- const root = path5.resolve(
1679
- inlineConfig.root ?? userConfig.root ?? process.cwd()
1680
- );
1681
- const wxtDir = path5.resolve(root, ".wxt");
1682
- const wxtModuleDir = await resolveWxtModuleDir();
1683
- const srcDir = path5.resolve(root, mergedConfig.srcDir ?? root);
1684
- const entrypointsDir = path5.resolve(
1685
- srcDir,
1686
- mergedConfig.entrypointsDir ?? "entrypoints"
1687
- );
1688
- const modulesDir = path5.resolve(srcDir, mergedConfig.modulesDir ?? "modules");
1689
- if (await isDirMissing(entrypointsDir)) {
1690
- logMissingDir(logger, "Entrypoints", entrypointsDir);
1691
- }
1692
- const filterEntrypoints = !!mergedConfig.filterEntrypoints?.length ? new Set(mergedConfig.filterEntrypoints) : void 0;
1693
- const publicDir = path5.resolve(srcDir, mergedConfig.publicDir ?? "public");
1694
- if (await isDirMissing(publicDir)) {
1695
- logMissingDir(logger, "Public", publicDir);
1696
- }
1697
- const typesDir = path5.resolve(wxtDir, "types");
1698
- const outBaseDir = path5.resolve(root, mergedConfig.outDir ?? ".output");
1699
- const outDir = path5.resolve(outBaseDir, `${browser}-mv${manifestVersion}`);
1700
- const reloadCommand = mergedConfig.dev?.reloadCommand ?? "Alt+R";
1701
- const runnerConfig = await loadConfig({
1702
- name: "web-ext",
1703
- cwd: root,
1704
- globalRc: true,
1705
- rcFile: ".webextrc",
1706
- overrides: inlineConfig.runner,
1707
- defaults: userConfig.runner
1708
- });
1709
- const alias = Object.fromEntries(
1710
- Object.entries({
1711
- ...mergedConfig.alias,
1712
- "@": srcDir,
1713
- "~": srcDir,
1714
- "@@": root,
1715
- "~~": root
1716
- }).map(([key, value]) => [key, path5.resolve(root, value)])
1717
- );
1718
- let devServerConfig;
1719
- if (command === "serve") {
1720
- let port = mergedConfig.dev?.server?.port;
1721
- if (port == null || !isFinite(port)) {
1722
- const { default: getPort, portNumbers } = await import("get-port");
1723
- port = await getPort({ port: portNumbers(3e3, 3010) });
1724
- }
1725
- devServerConfig = {
1726
- port,
1727
- hostname: mergedConfig.dev?.server?.hostname ?? "localhost"
1728
- };
1729
- }
1730
- const userModules = await resolveWxtUserModules(
1731
- modulesDir,
1732
- mergedConfig.modules
1733
- );
1734
- const moduleOptions = userModules.reduce(
1735
- (map, module) => {
1736
- if (module.configKey) {
1737
- map[module.configKey] = // @ts-expect-error
1738
- mergedConfig[module.configKey];
1739
- }
1740
- return map;
1741
- },
1742
- {}
1743
- );
1744
- return {
1745
- browser,
1746
- command,
1747
- debug,
1748
- entrypointsDir,
1749
- modulesDir,
1750
- filterEntrypoints,
1751
- env,
1752
- fsCache: createFsCache(wxtDir),
1753
- imports: await getUnimportOptions(wxtDir, srcDir, logger, mergedConfig),
1754
- logger,
1755
- manifest: await resolveManifestConfig(env, mergedConfig.manifest),
1756
- manifestVersion,
1757
- mode,
1758
- outBaseDir,
1759
- outDir,
1760
- publicDir,
1761
- wxtModuleDir,
1762
- root,
1763
- runnerConfig,
1764
- srcDir,
1765
- typesDir,
1766
- wxtDir,
1767
- zip: resolveZipConfig(root, outBaseDir, mergedConfig),
1768
- transformManifest: mergedConfig.transformManifest,
1769
- analysis: resolveAnalysisConfig(root, mergedConfig),
1770
- userConfigMetadata: userConfigMetadata ?? {},
1771
- alias,
1772
- experimental: defu(mergedConfig.experimental, {
1773
- includeBrowserPolyfill: true,
1774
- entrypointImporter: "jiti"
1775
- }),
1776
- dev: {
1777
- server: devServerConfig,
1778
- reloadCommand
1779
- },
1780
- hooks: mergedConfig.hooks ?? {},
1781
- vite: mergedConfig.vite ?? (() => ({})),
1782
- builtinModules,
1783
- userModules,
1784
- plugins: [],
1785
- ...moduleOptions
1786
- };
1787
- }
1788
- async function resolveManifestConfig(env, manifest) {
1789
- return await (typeof manifest === "function" ? manifest(env) : manifest ?? {});
1790
- }
1791
- async function mergeInlineConfig(inlineConfig, userConfig) {
1792
- const imports = inlineConfig.imports === false || userConfig.imports === false ? false : userConfig.imports == null && inlineConfig.imports == null ? void 0 : defu(inlineConfig.imports ?? {}, userConfig.imports ?? {});
1793
- const manifest = async (env) => {
1794
- const user = await resolveManifestConfig(env, userConfig.manifest);
1795
- const inline = await resolveManifestConfig(env, inlineConfig.manifest);
1796
- return defu(inline, user);
1797
- };
1798
- const transformManifest = (manifest2) => {
1799
- userConfig.transformManifest?.(manifest2);
1800
- inlineConfig.transformManifest?.(manifest2);
1801
- };
1802
- const merged = defu(inlineConfig, userConfig);
1803
- const builderConfig = await mergeBuilderConfig(
1804
- merged.logger ?? consola,
1805
- inlineConfig,
1806
- userConfig
1807
- );
1808
- return {
1809
- ...merged,
1810
- // Custom merge values
1811
- transformManifest,
1812
- imports,
1813
- manifest,
1814
- ...builderConfig
1815
- };
1816
- }
1817
- function resolveZipConfig(root, outBaseDir, mergedConfig) {
1818
- const downloadedPackagesDir = path5.resolve(root, ".wxt/local_modules");
1819
- return {
1820
- name: void 0,
1821
- sourcesTemplate: "{{name}}-{{version}}-sources.zip",
1822
- artifactTemplate: "{{name}}-{{version}}-{{browser}}.zip",
1823
- sourcesRoot: root,
1824
- includeSources: [],
1825
- compressionLevel: 9,
1826
- ...mergedConfig.zip,
1827
- excludeSources: [
1828
- "**/node_modules",
1829
- // WXT files
1830
- "**/web-ext.config.ts",
1831
- // Hidden files
1832
- "**/.*",
1833
- // Tests
1834
- "**/__tests__/**",
1835
- "**/*.+(test|spec).?(c|m)+(j|t)s?(x)",
1836
- // Output directory
1837
- `${path5.relative(root, outBaseDir)}/**`,
1838
- // From user
1839
- ...mergedConfig.zip?.excludeSources ?? []
1840
- ],
1841
- downloadPackages: mergedConfig.zip?.downloadPackages ?? [],
1842
- downloadedPackagesDir
1843
- };
1844
- }
1845
- function resolveAnalysisConfig(root, mergedConfig) {
1846
- const analysisOutputFile = path5.resolve(
1847
- root,
1848
- mergedConfig.analysis?.outputFile ?? "stats.html"
1849
- );
1850
- const analysisOutputDir = path5.dirname(analysisOutputFile);
1851
- const analysisOutputName = path5.parse(analysisOutputFile).name;
1852
- return {
1853
- enabled: mergedConfig.analysis?.enabled ?? false,
1854
- open: mergedConfig.analysis?.open ?? false,
1855
- template: mergedConfig.analysis?.template ?? "treemap",
1856
- outputFile: analysisOutputFile,
1857
- outputDir: analysisOutputDir,
1858
- outputName: analysisOutputName,
1859
- keepArtifacts: mergedConfig.analysis?.keepArtifacts ?? false
1860
- };
1861
- }
1862
- async function getUnimportOptions(wxtDir, srcDir, logger, config) {
1863
- if (config.imports === false) return false;
1864
- const defaultOptions = {
1865
- debugLog: logger.debug,
1866
- imports: [
1867
- { name: "defineConfig", from: "wxt" },
1868
- { name: "fakeBrowser", from: "wxt/testing" }
1869
- ],
1870
- presets: [
1871
- { package: "wxt/client" },
1872
- { package: "wxt/browser" },
1873
- { package: "wxt/sandbox" },
1874
- { package: "wxt/storage" }
1875
- ],
1876
- warn: logger.warn,
1877
- dirs: ["components", "composables", "hooks", "utils"],
1878
- dirsScanOptions: {
1879
- cwd: srcDir
1880
- },
1881
- eslintrc: await getUnimportEslintOptions(wxtDir, config.imports?.eslintrc)
1882
- };
1883
- return defu(
1884
- config.imports ?? {},
1885
- defaultOptions
1886
- );
1887
- }
1888
- async function getUnimportEslintOptions(wxtDir, options) {
1889
- const rawEslintEnabled = options?.enabled ?? "auto";
1890
- let eslintEnabled;
1891
- switch (rawEslintEnabled) {
1892
- case "auto":
1893
- const version2 = await getEslintVersion();
1894
- let major = parseInt(version2[0]);
1895
- if (major <= 8) eslintEnabled = 8;
1896
- else if (major >= 9) eslintEnabled = 9;
1897
- else eslintEnabled = 8;
1898
- break;
1899
- case true:
1900
- eslintEnabled = 8;
1901
- break;
1902
- default:
1903
- eslintEnabled = rawEslintEnabled;
1904
- }
1905
- return {
1906
- enabled: eslintEnabled,
1907
- filePath: path5.resolve(
1908
- wxtDir,
1909
- eslintEnabled === 9 ? "eslint-auto-imports.mjs" : "eslintrc-auto-import.json"
1910
- ),
1911
- globalsPropValue: true
1912
- };
1913
- }
1914
- async function resolveWxtModuleDir() {
1915
- const requireResolve = __require?.resolve ?? (await import("node:module")).default.createRequire(import.meta.url).resolve;
1916
- return path5.resolve(requireResolve("wxt"), "../..");
1917
- }
1918
- async function isDirMissing(dir) {
1919
- return !await fs8.exists(dir);
1920
- }
1921
- function logMissingDir(logger, name, expected) {
1922
- logger.warn(
1923
- `${name} directory not found: ./${normalizePath(
1924
- path5.relative(process.cwd(), expected)
1925
- )}`
1926
- );
1927
- }
1928
- var COMMAND_MODES = {
1929
- build: "production",
1930
- serve: "development"
1931
- };
1932
- async function mergeBuilderConfig(logger, inlineConfig, userConfig) {
1933
- const vite = await import("vite").catch((err) => {
1934
- logger.debug("Failed to import vite:", err);
1935
- });
1936
- if (vite) {
1937
- return {
1938
- vite: async (env) => {
1939
- const resolvedInlineConfig = await inlineConfig.vite?.(env) ?? {};
1940
- const resolvedUserConfig = await userConfig.vite?.(env) ?? {};
1941
- return vite.mergeConfig(resolvedUserConfig, resolvedInlineConfig);
1942
- }
1943
- };
1944
- }
1945
- throw Error("Builder not found. Make sure vite is installed.");
1946
- }
1947
- async function resolveWxtUserModules(modulesDir, modules = []) {
1948
- const npmModules = await Promise.all(
1949
- modules.map(async (moduleId) => {
1950
- const mod = await import(
1951
- /* @vite-ignore */
1952
- moduleId
1953
- );
1954
- if (mod.default == null) {
1955
- throw Error("Module missing default export: " + moduleId);
1956
- }
1957
- return {
1958
- ...mod.default,
1959
- type: "node_module",
1960
- id: moduleId
1961
- };
1962
- })
1963
- );
1964
- const localModulePaths = await glob3(["*.[tj]s", "*/index.[tj]s"], {
1965
- cwd: modulesDir,
1966
- onlyFiles: true
1967
- }).catch(() => []);
1968
- const localModules = await Promise.all(
1969
- localModulePaths.map(async (file) => {
1970
- const absolutePath = normalizePath(path5.resolve(modulesDir, file));
1971
- const { config } = await loadConfig({
1972
- configFile: absolutePath,
1973
- globalRc: false,
1974
- rcFile: false,
1975
- packageJson: false,
1976
- envName: false,
1977
- dotenv: false
1978
- });
1979
- if (config == null)
1980
- throw Error(
1981
- `No config found for ${file}. Did you forget to add a default export?`
1982
- );
1983
- config.name ??= file;
1984
- return {
1985
- ...config,
1986
- type: "local",
1987
- id: absolutePath
1988
- };
1989
- })
1990
- );
1991
- return [...npmModules, ...localModules];
1992
- }
1993
-
1994
- // src/core/utils/building/group-entrypoints.ts
1995
- function groupEntrypoints(entrypoints) {
1996
- const groupIndexMap = {};
1997
- const groups = [];
1998
- for (const entry of entrypoints) {
1999
- let group = ENTRY_TYPE_TO_GROUP_MAP[entry.type];
2000
- if (entry.type === "background" && entry.options.type === "module") {
2001
- group = "esm";
2002
- }
2003
- if (group === "individual") {
2004
- groups.push(entry);
2005
- } else {
2006
- let groupIndex = groupIndexMap[group];
2007
- if (groupIndex == null) {
2008
- groupIndex = groups.push([]) - 1;
2009
- groupIndexMap[group] = groupIndex;
2010
- }
2011
- groups[groupIndex].push(entry);
2012
- }
2013
- }
2014
- return groups;
2015
- }
2016
- var ENTRY_TYPE_TO_GROUP_MAP = {
2017
- sandbox: "sandboxed-esm",
2018
- popup: "esm",
2019
- newtab: "esm",
2020
- history: "esm",
2021
- options: "esm",
2022
- devtools: "esm",
2023
- bookmarks: "esm",
2024
- sidepanel: "esm",
2025
- "unlisted-page": "esm",
2026
- background: "individual",
2027
- "content-script": "individual",
2028
- "unlisted-script": "individual",
2029
- "unlisted-style": "individual",
2030
- "content-script-style": "individual"
2031
- };
2032
-
2033
- // src/core/utils/building/import-entrypoint.ts
2034
- import createJITI from "jiti";
2035
- import { createUnimport as createUnimport2 } from "unimport";
2036
- import fs9 from "fs-extra";
2037
- import { relative as relative5, resolve as resolve11 } from "node:path";
2038
- import { transformSync } from "esbuild";
2039
- import { fileURLToPath } from "node:url";
2040
- async function importEntrypointFile(path8) {
2041
- wxt.logger.debug("Loading file metadata:", path8);
2042
- const normalPath = normalizePath(path8);
2043
- const unimport = createUnimport2({
2044
- ...wxt.config.imports,
2045
- // Only allow specific imports, not all from the project
2046
- dirs: []
2047
- });
2048
- await unimport.init();
2049
- const text = await fs9.readFile(path8, "utf-8");
2050
- const textNoImports = removeProjectImportStatements(text);
2051
- const { code } = await unimport.injectImports(textNoImports);
2052
- wxt.logger.debug(
2053
- ["Text:", text, "No imports:", textNoImports, "Code:", code].join("\n")
2054
- );
2055
- const jiti = createJITI(
2056
- typeof __filename !== "undefined" ? __filename : fileURLToPath(import.meta.url),
2057
- {
2058
- cache: false,
2059
- debug: wxt.config.debug,
2060
- esmResolve: true,
2061
- alias: {
2062
- "webextension-polyfill": resolve11(
2063
- wxt.config.wxtModuleDir,
2064
- "dist/virtual/mock-browser.js"
2065
- ),
2066
- // TODO: Resolve this virtual module to some file with
2067
- // `export default {}` instead of this hack of using another file with
2068
- // a default export.
2069
- "virtual:app-config": resolve11(
2070
- wxt.config.wxtModuleDir,
2071
- "dist/virtual/mock-browser.js"
2072
- )
2073
- },
2074
- // Continue using node to load TS files even if `bun run --bun` is detected. Jiti does not
2075
- // respect the custom transform function when using it's native bun option.
2076
- experimentalBun: false,
2077
- // List of extensions to transform with esbuild
2078
- extensions: [
2079
- ".ts",
2080
- ".cts",
2081
- ".mts",
2082
- ".tsx",
2083
- ".js",
2084
- ".cjs",
2085
- ".mjs",
2086
- ".jsx"
2087
- ],
2088
- transform(opts) {
2089
- const isEntrypoint = opts.filename === normalPath;
2090
- return transformSync(
2091
- // Use modified source code for entrypoints
2092
- isEntrypoint ? code : opts.source,
2093
- getEsbuildOptions(opts)
2094
- );
2095
- }
2096
- }
2097
- );
2098
- try {
2099
- const res = await jiti(path8);
2100
- return res.default;
2101
- } catch (err) {
2102
- const filePath = relative5(wxt.config.root, path8);
2103
- if (err instanceof ReferenceError) {
2104
- const variableName = err.message.replace(" is not defined", "");
2105
- throw Error(
2106
- `${filePath}: Cannot use imported variable "${variableName}" outside the main function. See https://wxt.dev/guide/go-further/entrypoint-side-effects.html`,
2107
- { cause: err }
2108
- );
2109
- } else {
2110
- wxt.logger.error(err);
2111
- throw Error(`Failed to load entrypoint: ${filePath}`, { cause: err });
2112
- }
2113
- }
2114
- }
2115
- function getEsbuildOptions(opts) {
2116
- const isJsx = opts.filename?.endsWith("x");
2117
- return {
2118
- format: "cjs",
2119
- loader: isJsx ? "tsx" : "ts",
2120
- ...isJsx ? {
2121
- // `h` and `Fragment` are undefined, but that's OK because JSX is never evaluated while
2122
- // grabbing the entrypoint's options.
2123
- jsxFactory: "h",
2124
- jsxFragment: "Fragment"
2125
- } : void 0
2126
- };
2127
- }
2128
-
2129
- // src/core/utils/building/internal-build.ts
2130
- import pc5 from "picocolors";
2131
- import fs13 from "fs-extra";
2132
-
2133
- // src/core/utils/log/printBuildSummary.ts
2134
- import { resolve as resolve12 } from "path";
2135
-
2136
- // src/core/utils/log/printFileList.ts
2137
- import path6 from "node:path";
2138
- import pc3 from "picocolors";
2139
- import fs10 from "fs-extra";
2140
- import { filesize } from "filesize";
2141
-
2142
- // src/core/utils/log/printTable.ts
2143
- function printTable(log, header, rows, gap = 2) {
2144
- if (rows.length === 0) return;
2145
- const columnWidths = rows.reduce(
2146
- (widths, row) => {
2147
- for (let i = 0; i < Math.max(widths.length, row.length); i++) {
2148
- widths[i] = Math.max(row[i]?.length ?? 0, widths[i] ?? 0);
2149
- }
2150
- return widths;
2151
- },
2152
- rows[0].map((column) => column.length)
2153
- );
2154
- let str = "";
2155
- rows.forEach((row, i) => {
2156
- row.forEach((col, j) => {
2157
- str += col.padEnd(columnWidths[j], " ");
2158
- if (j !== row.length - 1) str += "".padEnd(gap, " ");
2159
- });
2160
- if (i !== rows.length - 1) str += "\n";
2161
- });
2162
- log(`${header}
2163
- ${str}`);
2164
- }
2165
-
2166
- // src/core/utils/log/printFileList.ts
2167
- async function printFileList(log, header, baseDir, files) {
2168
- let totalSize = 0;
2169
- const fileRows = await Promise.all(
2170
- files.map(async (file, i) => {
2171
- const parts = [
2172
- path6.relative(process.cwd(), baseDir) + path6.sep,
2173
- path6.relative(baseDir, file)
2174
- ];
2175
- const prefix = i === files.length - 1 ? " \u2514\u2500" : " \u251C\u2500";
2176
- const color = getChunkColor(file);
2177
- const stats = await fs10.lstat(file);
2178
- totalSize += stats.size;
2179
- const size = String(filesize(stats.size));
2180
- return [
2181
- `${pc3.gray(prefix)} ${pc3.dim(parts[0])}${color(parts[1])}`,
2182
- pc3.dim(size)
2183
- ];
2184
- })
2185
- );
2186
- fileRows.push([`${pc3.cyan("\u03A3 Total size:")} ${String(filesize(totalSize))}`]);
2187
- printTable(log, header, fileRows);
2188
- }
2189
- var DEFAULT_COLOR = pc3.blue;
2190
- var CHUNK_COLORS = {
2191
- ".js.map": pc3.gray,
2192
- ".cjs.map": pc3.gray,
2193
- ".mjs.map": pc3.gray,
2194
- ".html": pc3.green,
2195
- ".css": pc3.magenta,
2196
- ".js": pc3.cyan,
2197
- ".cjs": pc3.cyan,
2198
- ".mjs": pc3.cyan,
2199
- ".zip": pc3.yellow
2200
- };
2201
- function getChunkColor(filename) {
2202
- return Object.entries(CHUNK_COLORS).find(([key]) => filename.endsWith(key))?.[1] ?? DEFAULT_COLOR;
2203
- }
2204
-
2205
- // src/core/utils/log/printBuildSummary.ts
2206
- async function printBuildSummary(log, header, output) {
2207
- const chunks = [
2208
- ...output.steps.flatMap((step) => step.chunks),
2209
- ...output.publicAssets
2210
- ].sort((l, r) => {
2211
- const lWeight = getChunkSortWeight(l.fileName);
2212
- const rWeight = getChunkSortWeight(r.fileName);
2213
- const diff = lWeight - rWeight;
2214
- if (diff !== 0) return diff;
2215
- return l.fileName.localeCompare(r.fileName);
2216
- });
2217
- const files = chunks.map(
2218
- (chunk) => resolve12(wxt.config.outDir, chunk.fileName)
2219
- );
2220
- await printFileList(log, header, wxt.config.outDir, files);
2221
- }
2222
- var DEFAULT_SORT_WEIGHT = 100;
2223
- var CHUNK_SORT_WEIGHTS = {
2224
- "manifest.json": 0,
2225
- ".html": 1,
2226
- ".js.map": 2,
2227
- ".js": 2,
2228
- ".css": 3
2229
- };
2230
- function getChunkSortWeight(filename) {
2231
- return Object.entries(CHUNK_SORT_WEIGHTS).find(
2232
- ([key]) => filename.endsWith(key)
2233
- )?.[1] ?? DEFAULT_SORT_WEIGHT;
2234
- }
2235
-
2236
- // src/core/utils/log/printHeader.ts
2237
- import pc4 from "picocolors";
2238
-
2239
- // src/core/utils/building/internal-build.ts
2240
- import glob4 from "fast-glob";
2241
-
2242
- // src/core/utils/manifest.ts
2243
- import fs12 from "fs-extra";
2244
- import { resolve as resolve14 } from "path";
2245
-
2246
- // src/core/utils/content-security-policy.ts
2247
- var ContentSecurityPolicy = class _ContentSecurityPolicy {
2248
- static DIRECTIVE_ORDER = {
2249
- "default-src": 0,
2250
- "script-src": 1,
2251
- "object-src": 2
2252
- };
2253
- data;
2254
- constructor(csp) {
2255
- if (csp) {
2256
- const sections = csp.split(";").map((section) => section.trim());
2257
- this.data = sections.reduce((data, section) => {
2258
- const [key, ...values] = section.split(" ").map((item) => item.trim());
2259
- if (key) data[key] = values;
2260
- return data;
2261
- }, {});
2262
- } else {
2263
- this.data = {};
2264
- }
2265
- }
2266
- /**
2267
- * Ensure a set of values are listed under a directive.
2268
- */
2269
- add(directive, ...newValues) {
2270
- const values = this.data[directive] ?? [];
2271
- newValues.forEach((newValue) => {
2272
- if (!values.includes(newValue)) values.push(newValue);
2273
- });
2274
- this.data[directive] = values;
2275
- return this;
2276
- }
2277
- toString() {
2278
- const directives = Object.entries(this.data).sort(([l], [r]) => {
2279
- const lo = _ContentSecurityPolicy.DIRECTIVE_ORDER[l] ?? 2;
2280
- const ro = _ContentSecurityPolicy.DIRECTIVE_ORDER[r] ?? 2;
2281
- return lo - ro;
2282
- });
2283
- return directives.map((entry) => entry.flat().join(" ")).join("; ") + ";";
2284
- }
2285
- };
2286
-
2287
- // src/core/utils/content-scripts.ts
2288
- function hashContentScriptOptions(options) {
2289
- const simplifiedOptions = mapWxtOptionsToContentScript(
2290
- options,
2291
- void 0,
2292
- void 0
2293
- );
2294
- Object.keys(simplifiedOptions).forEach((key) => {
2295
- if (simplifiedOptions[key] == null) delete simplifiedOptions[key];
2296
- });
2297
- const withDefaults = {
2298
- exclude_globs: [],
2299
- exclude_matches: [],
2300
- include_globs: [],
2301
- match_about_blank: false,
2302
- run_at: "document_idle",
2303
- all_frames: false,
2304
- // @ts-expect-error - not in type
2305
- match_origin_as_fallback: false,
2306
- world: "ISOLATED",
2307
- ...simplifiedOptions
2308
- };
2309
- return JSON.stringify(
2310
- Object.entries(withDefaults).map(([key, value]) => {
2311
- if (Array.isArray(value)) return [key, value.sort()];
2312
- else return [key, value];
2313
- }).sort((l, r) => l[0].localeCompare(r[0]))
2314
- );
2315
- }
2316
- function mapWxtOptionsToContentScript(options, js, css) {
2317
- return {
2318
- matches: options.matches,
2319
- all_frames: options.allFrames,
2320
- match_about_blank: options.matchAboutBlank,
2321
- exclude_globs: options.excludeGlobs,
2322
- exclude_matches: options.excludeMatches,
2323
- include_globs: options.includeGlobs,
2324
- run_at: options.runAt,
2325
- css,
2326
- js,
2327
- // @ts-expect-error: untyped chrome options
2328
- match_origin_as_fallback: options.matchOriginAsFallback,
2329
- world: options.world
2330
- };
2331
- }
2332
- function mapWxtOptionsToRegisteredContentScript(options, js, css) {
2333
- return {
2334
- allFrames: options.allFrames,
2335
- excludeMatches: options.excludeMatches,
2336
- matches: options.matches,
2337
- runAt: options.runAt,
2338
- js,
2339
- css,
2340
- // @ts-expect-error: Chrome accepts this, not typed in webextension-polyfill (https://developer.chrome.com/docs/extensions/reference/scripting/#type-RegisteredContentScript)
2341
- world: options.world
2342
- };
2343
- }
2344
- function getContentScriptJs(config, entrypoint) {
2345
- return [getEntrypointBundlePath(entrypoint, config.outDir, ".js")];
2346
- }
2347
-
2348
- // src/core/utils/package.ts
2349
- import { resolve as resolve13 } from "node:path";
2350
- import fs11 from "fs-extra";
2351
- async function getPackageJson() {
2352
- const file = resolve13(wxt.config.root, "package.json");
2353
- try {
2354
- return await fs11.readJson(file);
2355
- } catch (err) {
2356
- wxt.logger.debug(
2357
- `Failed to read package.json at: ${file}. Returning undefined.`
2358
- );
2359
- return {};
2360
- }
2361
- }
2362
-
2363
- // src/core/utils/manifest.ts
2364
- import defu2 from "defu";
2365
- async function writeManifest(manifest, output) {
2366
- const str = wxt.config.mode === "production" ? JSON.stringify(manifest) : JSON.stringify(manifest, null, 2);
2367
- await fs12.ensureDir(wxt.config.outDir);
2368
- await writeFileIfDifferent(resolve14(wxt.config.outDir, "manifest.json"), str);
2369
- output.publicAssets.unshift({
2370
- type: "asset",
2371
- fileName: "manifest.json"
2372
- });
2373
- }
2374
- async function generateManifest(entrypoints, buildOutput) {
2375
- const warnings = [];
2376
- const pkg = await getPackageJson();
2377
- let versionName = wxt.config.manifest.version_name ?? wxt.config.manifest.version ?? pkg?.version;
2378
- if (versionName == null) {
2379
- versionName = "0.0.0";
2380
- wxt.logger.warn(
2381
- 'Extension version not found, defaulting to "0.0.0". Add a version to your `package.json` or `wxt.config.ts` file. For more details, see: https://wxt.dev/guide/key-concepts/manifest.html#version-and-version-name'
2382
- );
2383
- }
2384
- const version2 = wxt.config.manifest.version ?? simplifyVersion(versionName);
2385
- const baseManifest = {
2386
- manifest_version: wxt.config.manifestVersion,
2387
- name: pkg?.name,
2388
- description: pkg?.description,
2389
- version: version2,
2390
- short_name: pkg?.shortName,
2391
- icons: discoverIcons(buildOutput)
2392
- };
2393
- const userManifest = wxt.config.manifest;
2394
- let manifest = defu2(
2395
- userManifest,
2396
- baseManifest
2397
- );
2398
- if (wxt.config.command === "serve" && wxt.config.dev.reloadCommand) {
2399
- if (manifest.commands && Object.keys(manifest.commands).length >= 4) {
2400
- warnings.push([
2401
- "Extension already has 4 registered commands, WXT's reload command is disabled"
2402
- ]);
2403
- } else {
2404
- manifest.commands ??= {};
2405
- manifest.commands["wxt:reload-extension"] = {
2406
- description: "Reload the extension during development",
2407
- suggested_key: {
2408
- default: wxt.config.dev.reloadCommand
2409
- }
2410
- };
2411
- }
2412
- }
2413
- manifest.version = version2;
2414
- manifest.version_name = // Firefox doesn't support version_name
2415
- wxt.config.browser === "firefox" || versionName === version2 ? void 0 : versionName;
2416
- addEntrypoints(manifest, entrypoints, buildOutput);
2417
- if (wxt.config.command === "serve") addDevModeCsp(manifest);
2418
- if (wxt.config.command === "serve") addDevModePermissions(manifest);
2419
- wxt.config.transformManifest?.(manifest);
2420
- await wxt.hooks.callHook("build:manifestGenerated", wxt, manifest);
2421
- if (wxt.config.manifestVersion === 2) {
2422
- convertWebAccessibleResourcesToMv2(manifest);
2423
- convertActionToMv2(manifest);
2424
- moveHostPermissionsToPermissions(manifest);
2425
- }
2426
- if (wxt.config.manifestVersion === 3) {
2427
- validateMv3WebAccessbileResources(manifest);
2428
- }
2429
- stripKeys(manifest);
2430
- if (manifest.name == null)
2431
- throw Error(
2432
- "Manifest 'name' is missing. Either:\n1. Set the name in your <rootDir>/package.json\n2. Set a name via the manifest option in your wxt.config.ts"
2433
- );
2434
- if (manifest.version == null) {
2435
- throw Error(
2436
- "Manifest 'version' is missing. Either:\n1. Add a version in your <rootDir>/package.json\n2. Pass the version via the manifest option in your wxt.config.ts"
2437
- );
2438
- }
2439
- return {
2440
- manifest,
2441
- warnings
2442
- };
2443
- }
2444
- function simplifyVersion(versionName) {
2445
- const version2 = /^((0|[1-9][0-9]{0,8})([.](0|[1-9][0-9]{0,8})){0,3}).*$/.exec(
2446
- versionName
2447
- )?.[1];
2448
- if (version2 == null)
2449
- throw Error(
2450
- `Cannot simplify package.json version "${versionName}" to a valid extension version, "X.Y.Z"`
2451
- );
2452
- return version2;
2453
- }
2454
- function addEntrypoints(manifest, entrypoints, buildOutput) {
2455
- const entriesByType = entrypoints.reduce((map, entrypoint) => {
2456
- map[entrypoint.type] ??= [];
2457
- map[entrypoint.type]?.push(entrypoint);
2458
- return map;
2459
- }, {});
2460
- const background = entriesByType["background"]?.[0];
2461
- const bookmarks = entriesByType["bookmarks"]?.[0];
2462
- const contentScripts = entriesByType["content-script"];
2463
- const devtools = entriesByType["devtools"]?.[0];
2464
- const history = entriesByType["history"]?.[0];
2465
- const newtab = entriesByType["newtab"]?.[0];
2466
- const options = entriesByType["options"]?.[0];
2467
- const popup = entriesByType["popup"]?.[0];
2468
- const sandboxes = entriesByType["sandbox"];
2469
- const sidepanels = entriesByType["sidepanel"];
2470
- if (background) {
2471
- const script = getEntrypointBundlePath(
2472
- background,
2473
- wxt.config.outDir,
2474
- ".js"
2475
- );
2476
- if (wxt.config.browser === "firefox" && wxt.config.manifestVersion === 3) {
2477
- manifest.background = {
2478
- type: background.options.type,
2479
- scripts: [script]
2480
- };
2481
- } else if (wxt.config.manifestVersion === 3) {
2482
- manifest.background = {
2483
- type: background.options.type,
2484
- service_worker: script
2485
- };
2486
- } else {
2487
- manifest.background = {
2488
- persistent: background.options.persistent,
2489
- scripts: [script]
2490
- };
2491
- }
2492
- }
2493
- if (bookmarks) {
2494
- if (wxt.config.browser === "firefox") {
2495
- wxt.logger.warn(
2496
- "Bookmarks are not supported by Firefox. chrome_url_overrides.bookmarks was not added to the manifest"
2497
- );
2498
- } else {
2499
- manifest.chrome_url_overrides ??= {};
2500
- manifest.chrome_url_overrides.bookmarks = getEntrypointBundlePath(
2501
- bookmarks,
2502
- wxt.config.outDir,
2503
- ".html"
2504
- );
2505
- }
2506
- }
2507
- if (history) {
2508
- if (wxt.config.browser === "firefox") {
2509
- wxt.logger.warn(
2510
- "Bookmarks are not supported by Firefox. chrome_url_overrides.history was not added to the manifest"
2511
- );
2512
- } else {
2513
- manifest.chrome_url_overrides ??= {};
2514
- manifest.chrome_url_overrides.history = getEntrypointBundlePath(
2515
- history,
2516
- wxt.config.outDir,
2517
- ".html"
2518
- );
2519
- }
2520
- }
2521
- if (newtab) {
2522
- manifest.chrome_url_overrides ??= {};
2523
- manifest.chrome_url_overrides.newtab = getEntrypointBundlePath(
2524
- newtab,
2525
- wxt.config.outDir,
2526
- ".html"
2527
- );
2528
- }
2529
- if (popup) {
2530
- const default_popup = getEntrypointBundlePath(
2531
- popup,
2532
- wxt.config.outDir,
2533
- ".html"
2534
- );
2535
- const options2 = {};
2536
- if (popup.options.defaultIcon)
2537
- options2.default_icon = popup.options.defaultIcon;
2538
- if (popup.options.defaultTitle)
2539
- options2.default_title = popup.options.defaultTitle;
2540
- if (popup.options.browserStyle)
2541
- options2.browser_style = popup.options.browserStyle;
2542
- if (manifest.manifest_version === 3) {
2543
- manifest.action = {
2544
- ...manifest.action ?? {},
2545
- ...options2,
2546
- default_popup
2547
- };
2548
- } else {
2549
- const key = popup.options.mv2Key ?? "browser_action";
2550
- manifest[key] = {
2551
- ...manifest[key] ?? {},
2552
- ...options2,
2553
- default_popup
2554
- };
2555
- }
2556
- }
2557
- if (devtools) {
2558
- manifest.devtools_page = getEntrypointBundlePath(
2559
- devtools,
2560
- wxt.config.outDir,
2561
- ".html"
2562
- );
2563
- }
2564
- if (options) {
2565
- const page = getEntrypointBundlePath(options, wxt.config.outDir, ".html");
2566
- manifest.options_ui = {
2567
- open_in_tab: options.options.openInTab,
2568
- browser_style: wxt.config.browser === "firefox" ? options.options.browserStyle : void 0,
2569
- chrome_style: wxt.config.browser !== "firefox" ? options.options.chromeStyle : void 0,
2570
- page
2571
- };
2572
- }
2573
- if (sandboxes?.length) {
2574
- if (wxt.config.browser === "firefox") {
2575
- wxt.logger.warn(
2576
- "Sandboxed pages not supported by Firefox. sandbox.pages was not added to the manifest"
2577
- );
2578
- } else {
2579
- manifest.sandbox = {
2580
- pages: sandboxes.map(
2581
- (entry) => getEntrypointBundlePath(entry, wxt.config.outDir, ".html")
2582
- )
2583
- };
2584
- }
2585
- }
2586
- if (sidepanels?.length) {
2587
- const defaultSidepanel = sidepanels.find((entry) => entry.name === "sidepanel") ?? sidepanels[0];
2588
- const page = getEntrypointBundlePath(
2589
- defaultSidepanel,
2590
- wxt.config.outDir,
2591
- ".html"
2592
- );
2593
- if (wxt.config.browser === "firefox") {
2594
- manifest.sidebar_action = {
2595
- default_panel: page,
2596
- browser_style: defaultSidepanel.options.browserStyle,
2597
- default_icon: defaultSidepanel.options.defaultIcon,
2598
- default_title: defaultSidepanel.options.defaultTitle,
2599
- open_at_install: defaultSidepanel.options.openAtInstall
2600
- };
2601
- } else if (wxt.config.manifestVersion === 3) {
2602
- manifest.side_panel = {
2603
- default_path: page
2604
- };
2605
- addPermission(manifest, "sidePanel");
2606
- } else {
2607
- wxt.logger.warn(
2608
- "Side panel not supported by Chromium using MV2. side_panel.default_path was not added to the manifest"
2609
- );
2610
- }
2611
- }
2612
- if (contentScripts?.length) {
2613
- const cssMap = getContentScriptsCssMap(buildOutput, contentScripts);
2614
- if (wxt.config.command === "serve" && wxt.config.manifestVersion === 3) {
2615
- contentScripts.forEach((script) => {
2616
- script.options.matches.forEach((matchPattern) => {
2617
- addHostPermission(manifest, matchPattern);
2618
- });
2619
- });
2620
- } else {
2621
- const hashToEntrypointsMap = contentScripts.filter((cs) => cs.options.registration !== "runtime").reduce((map, script) => {
2622
- const hash = hashContentScriptOptions(script.options);
2623
- if (map.has(hash)) map.get(hash)?.push(script);
2624
- else map.set(hash, [script]);
2625
- return map;
2626
- }, /* @__PURE__ */ new Map());
2627
- const manifestContentScripts = Array.from(
2628
- hashToEntrypointsMap.values()
2629
- ).map(
2630
- (scripts) => mapWxtOptionsToContentScript(
2631
- scripts[0].options,
2632
- scripts.map(
2633
- (entry) => getEntrypointBundlePath(entry, wxt.config.outDir, ".js")
2634
- ),
2635
- getContentScriptCssFiles(scripts, cssMap)
2636
- )
2637
- );
2638
- if (manifestContentScripts.length >= 0) {
2639
- manifest.content_scripts ??= [];
2640
- manifest.content_scripts.push(...manifestContentScripts);
2641
- }
2642
- const runtimeContentScripts = contentScripts.filter(
2643
- (cs) => cs.options.registration === "runtime"
2644
- );
2645
- if (runtimeContentScripts.length > 0 && wxt.config.manifestVersion === 2) {
2646
- throw Error(
2647
- 'Cannot use `registration: "runtime"` with MV2 content scripts, it is a MV3-only feature.'
2648
- );
2649
- }
2650
- runtimeContentScripts.forEach((script) => {
2651
- script.options.matches.forEach((matchPattern) => {
2652
- addHostPermission(manifest, matchPattern);
2653
- });
2654
- });
2655
- }
2656
- const contentScriptCssResources = getContentScriptCssWebAccessibleResources(
2657
- contentScripts,
2658
- cssMap
2659
- );
2660
- if (contentScriptCssResources.length > 0) {
2661
- manifest.web_accessible_resources ??= [];
2662
- manifest.web_accessible_resources.push(...contentScriptCssResources);
2663
- }
2664
- }
2665
- }
2666
- function discoverIcons(buildOutput) {
2667
- const icons = [];
2668
- const iconRegex = [
2669
- /^icon-([0-9]+)\.png$/,
2670
- // icon-16.png
2671
- /^icon-([0-9]+)x[0-9]+\.png$/,
2672
- // icon-16x16.png
2673
- /^icon@([0-9]+)w\.png$/,
2674
- // icon@16w.png
2675
- /^icon@([0-9]+)h\.png$/,
2676
- // icon@16h.png
2677
- /^icon@([0-9]+)\.png$/,
2678
- // icon@16.png
2679
- /^icons?[\/\\]([0-9]+)\.png$/,
2680
- // icon/16.png | icons/16.png
2681
- /^icons?[\/\\]([0-9]+)x[0-9]+\.png$/
2682
- // icon/16x16.png | icons/16x16.png
2683
- ];
2684
- buildOutput.publicAssets.forEach((asset) => {
2685
- let size;
2686
- for (const regex of iconRegex) {
2687
- const match = asset.fileName.match(regex);
2688
- if (match?.[1] != null) {
2689
- size = match[1];
2690
- break;
2691
- }
2692
- }
2693
- if (size == null) return;
2694
- icons.push([size, normalizePath(asset.fileName)]);
2695
- });
2696
- return icons.length > 0 ? Object.fromEntries(icons) : void 0;
2697
- }
2698
- function addDevModeCsp(manifest) {
2699
- const permission = `http://${wxt.server?.hostname ?? ""}/*`;
2700
- const allowedCsp = wxt.server?.origin ?? "http://localhost:*";
2701
- if (manifest.manifest_version === 3) {
2702
- addHostPermission(manifest, permission);
2703
- } else {
2704
- addPermission(manifest, permission);
2705
- }
2706
- const extensionPagesCsp = new ContentSecurityPolicy(
2707
- manifest.manifest_version === 3 ? (
2708
- // @ts-expect-error: extension_pages is not typed
2709
- manifest.content_security_policy?.extension_pages ?? "script-src 'self' 'wasm-unsafe-eval'; object-src 'self';"
2710
- ) : manifest.content_security_policy ?? "script-src 'self'; object-src 'self';"
2711
- // default CSP for MV2
2712
- );
2713
- const sandboxCsp = new ContentSecurityPolicy(
2714
- // @ts-expect-error: sandbox is not typed
2715
- manifest.content_security_policy?.sandbox ?? "sandbox allow-scripts allow-forms allow-popups allow-modals; script-src 'self' 'unsafe-inline' 'unsafe-eval'; child-src 'self';"
2716
- // default sandbox CSP for MV3
2717
- );
2718
- if (wxt.server) {
2719
- extensionPagesCsp.add("script-src", allowedCsp);
2720
- sandboxCsp.add("script-src", allowedCsp);
2721
- }
2722
- if (manifest.manifest_version === 3) {
2723
- manifest.content_security_policy ??= {};
2724
- manifest.content_security_policy.extension_pages = extensionPagesCsp.toString();
2725
- manifest.content_security_policy.sandbox = sandboxCsp.toString();
2726
- } else {
2727
- manifest.content_security_policy = extensionPagesCsp.toString();
2728
- }
2729
- }
2730
- function addDevModePermissions(manifest) {
2731
- addPermission(manifest, "tabs");
2732
- if (wxt.config.manifestVersion === 3) addPermission(manifest, "scripting");
2733
- }
2734
- function getContentScriptCssFiles(contentScripts, contentScriptCssMap) {
2735
- const css = [];
2736
- contentScripts.forEach((script) => {
2737
- if (script.options.cssInjectionMode === "manual" || script.options.cssInjectionMode === "ui")
2738
- return;
2739
- const cssFile = contentScriptCssMap[script.name];
2740
- if (cssFile == null) return;
2741
- if (cssFile) css.push(cssFile);
2742
- });
2743
- if (css.length > 0) return css;
2744
- return void 0;
2745
- }
2746
- function getContentScriptCssWebAccessibleResources(contentScripts, contentScriptCssMap) {
2747
- const resources = [];
2748
- contentScripts.forEach((script) => {
2749
- if (script.options.cssInjectionMode !== "ui") return;
2750
- const cssFile = contentScriptCssMap[script.name];
2751
- if (cssFile == null) return;
2752
- resources.push({
2753
- resources: [cssFile],
2754
- matches: script.options.matches.map(
2755
- (matchPattern) => stripPathFromMatchPattern(matchPattern)
2756
- )
2757
- });
2758
- });
2759
- return resources;
2760
- }
2761
- function getContentScriptsCssMap(buildOutput, scripts) {
2762
- const map = {};
2763
- const allChunks = buildOutput.steps.flatMap((step) => step.chunks);
2764
- scripts.forEach((script) => {
2765
- const relatedCss = allChunks.find(
2766
- (chunk) => chunk.fileName === `content-scripts/${script.name}.css`
2767
- );
2768
- if (relatedCss != null) map[script.name] = relatedCss.fileName;
2769
- });
2770
- return map;
2771
- }
2772
- function addPermission(manifest, permission) {
2773
- manifest.permissions ??= [];
2774
- if (manifest.permissions.includes(permission)) return;
2775
- manifest.permissions.push(permission);
2776
- }
2777
- function addHostPermission(manifest, hostPermission) {
2778
- manifest.host_permissions ??= [];
2779
- if (manifest.host_permissions.includes(hostPermission)) return;
2780
- manifest.host_permissions.push(hostPermission);
2781
- }
2782
- function stripPathFromMatchPattern(pattern) {
2783
- const protocolSepIndex = pattern.indexOf("://");
2784
- if (protocolSepIndex === -1) return pattern;
2785
- const startOfPath = pattern.indexOf("/", protocolSepIndex + 3);
2786
- return pattern.substring(0, startOfPath) + "/*";
2787
- }
2788
- function convertWebAccessibleResourcesToMv2(manifest) {
2789
- if (manifest.web_accessible_resources == null) return;
2790
- manifest.web_accessible_resources = Array.from(
2791
- new Set(
2792
- manifest.web_accessible_resources.flatMap((item) => {
2793
- if (typeof item === "string") return item;
2794
- return item.resources;
2795
- })
2796
- )
2797
- );
2798
- }
2799
- function moveHostPermissionsToPermissions(manifest) {
2800
- if (!manifest.host_permissions?.length) return;
2801
- manifest.host_permissions.forEach(
2802
- (permission) => addPermission(manifest, permission)
2803
- );
2804
- delete manifest.host_permissions;
2805
- }
2806
- function convertActionToMv2(manifest) {
2807
- if (manifest.action == null || manifest.browser_action != null || manifest.page_action != null)
2808
- return;
2809
- manifest.browser_action = manifest.action;
2810
- }
2811
- function validateMv3WebAccessbileResources(manifest) {
2812
- if (manifest.web_accessible_resources == null) return;
2813
- const stringResources = manifest.web_accessible_resources.filter(
2814
- (item) => typeof item === "string"
2815
- );
2816
- if (stringResources.length > 0) {
2817
- throw Error(
2818
- `Non-MV3 web_accessible_resources detected: ${JSON.stringify(
2819
- stringResources
2820
- )}. When manually defining web_accessible_resources, define them as MV3 objects ({ matches: [...], resources: [...] }), and WXT will automatically convert them to MV2 when necessary.`
2821
- );
2822
- }
2823
- }
2824
- function stripKeys(manifest) {
2825
- let keysToRemove = [];
2826
- if (wxt.config.manifestVersion === 2) {
2827
- keysToRemove.push(...mv3OnlyKeys);
2828
- if (wxt.config.browser === "firefox")
2829
- keysToRemove.push(...firefoxMv3OnlyKeys);
2830
- } else {
2831
- keysToRemove.push(...mv2OnlyKeys);
2832
- }
2833
- keysToRemove.forEach((key) => {
2834
- delete manifest[key];
2835
- });
2836
- }
2837
- var mv2OnlyKeys = [
2838
- "page_action",
2839
- "browser_action",
2840
- "automation",
2841
- "content_capabilities",
2842
- "converted_from_user_script",
2843
- "current_locale",
2844
- "differential_fingerprint",
2845
- "event_rules",
2846
- "file_browser_handlers",
2847
- "file_system_provider_capabilities",
2848
- "input_components",
2849
- "nacl_modules",
2850
- "natively_connectable",
2851
- "offline_enabled",
2852
- "platforms",
2853
- "replacement_web_app",
2854
- "system_indicator",
2855
- "user_scripts"
2856
- ];
2857
- var mv3OnlyKeys = [
2858
- "action",
2859
- "export",
2860
- "optional_host_permissions",
2861
- "side_panel"
2862
- ];
2863
- var firefoxMv3OnlyKeys = ["host_permissions"];
2864
-
2865
- // src/core/utils/building/rebuild.ts
2866
- async function rebuild(allEntrypoints, entrypointGroups, existingOutput = {
2867
- steps: [],
2868
- publicAssets: []
2869
- }) {
2870
- const { default: ora } = await import("ora");
2871
- const spinner = ora(`Preparing...`).start();
2872
- await generateTypesDir(allEntrypoints).catch((err) => {
2873
- wxt.logger.warn("Failed to update .wxt directory:", err);
2874
- if (wxt.config.command === "build") throw err;
2875
- });
2876
- const newOutput = await buildEntrypoints(entrypointGroups, spinner);
2877
- const mergedOutput = {
2878
- steps: [...existingOutput.steps, ...newOutput.steps],
2879
- publicAssets: [...existingOutput.publicAssets, ...newOutput.publicAssets]
2880
- };
2881
- const { manifest: newManifest, warnings: manifestWarnings } = await generateManifest(allEntrypoints, mergedOutput);
2882
- const finalOutput = {
2883
- manifest: newManifest,
2884
- ...newOutput
2885
- };
2886
- await writeManifest(newManifest, finalOutput);
2887
- spinner.clear().stop();
2888
- return {
2889
- output: {
2890
- manifest: newManifest,
2891
- steps: [...existingOutput.steps, ...finalOutput.steps],
2892
- publicAssets: [
2893
- ...existingOutput.publicAssets,
2894
- ...finalOutput.publicAssets
2895
- ]
2896
- },
2897
- manifest: newManifest,
2898
- warnings: manifestWarnings
2899
- };
2900
- }
2901
-
2902
- // src/core/utils/building/internal-build.ts
2903
- import { relative as relative6 } from "node:path";
2904
-
2905
- // src/core/utils/validation.ts
2906
- function validateEntrypoints(entrypoints) {
2907
- const errors = entrypoints.flatMap((entrypoint) => {
2908
- switch (entrypoint.type) {
2909
- case "content-script":
2910
- return validateContentScriptEntrypoint(entrypoint);
2911
- default:
2912
- return validateBaseEntrypoint(entrypoint);
2913
- }
2914
- });
2915
- let errorCount = 0;
2916
- let warningCount = 0;
2917
- for (const err of errors) {
2918
- if (err.type === "warning") warningCount++;
2919
- else errorCount++;
2920
- }
2921
- return {
2922
- errors,
2923
- errorCount,
2924
- warningCount
2925
- };
2926
- }
2927
- function validateContentScriptEntrypoint(definition) {
2928
- const errors = validateBaseEntrypoint(definition);
2929
- if (definition.options.matches == null) {
2930
- errors.push({
2931
- type: "error",
2932
- message: "`matches` is required",
2933
- value: definition.options.matches,
2934
- entrypoint: definition
2935
- });
2936
- }
2937
- return errors;
2938
- }
2939
- function validateBaseEntrypoint(definition) {
2940
- const errors = [];
2941
- if (definition.options.exclude != null && !Array.isArray(definition.options.exclude)) {
2942
- errors.push({
2943
- type: "error",
2944
- message: "`exclude` must be an array of browser names",
2945
- value: definition.options.exclude,
2946
- entrypoint: definition
2947
- });
2948
- }
2949
- if (definition.options.include != null && !Array.isArray(definition.options.include)) {
2950
- errors.push({
2951
- type: "error",
2952
- message: "`include` must be an array of browser names",
2953
- value: definition.options.include,
2954
- entrypoint: definition
2955
- });
2956
- }
2957
- return errors;
2958
- }
2959
- var ValidationError = class extends Error {
2960
- };
2961
-
2962
- // src/core/utils/building/internal-build.ts
2963
- import { mergeJsonOutputs } from "@aklinker1/rollup-plugin-visualizer";
2964
- import { isCI } from "ci-info";
2965
- async function internalBuild() {
2966
- await wxt.hooks.callHook("build:before", wxt);
2967
- const verb = wxt.config.command === "serve" ? "Pre-rendering" : "Building";
2968
- const target = `${wxt.config.browser}-mv${wxt.config.manifestVersion}`;
2969
- wxt.logger.info(
2970
- `${verb} ${pc5.cyan(target)} for ${pc5.cyan(wxt.config.mode)} with ${pc5.green(
2971
- `${wxt.builder.name} ${wxt.builder.version}`
2972
- )}`
2973
- );
2974
- const startTime = Date.now();
2975
- await fs13.rm(wxt.config.outDir, { recursive: true, force: true });
2976
- await fs13.ensureDir(wxt.config.outDir);
2977
- const entrypoints = await findEntrypoints();
2978
- wxt.logger.debug("Detected entrypoints:", entrypoints);
2979
- const validationResults = validateEntrypoints(entrypoints);
2980
- if (validationResults.errorCount + validationResults.warningCount > 0) {
2981
- printValidationResults(validationResults);
2982
- }
2983
- if (validationResults.errorCount > 0) {
2984
- throw new ValidationError(`Entrypoint validation failed`, {
2985
- cause: validationResults
2986
- });
2987
- }
2988
- const groups = groupEntrypoints(entrypoints);
2989
- await wxt.hooks.callHook("entrypoints:grouped", wxt, groups);
2990
- const { output, warnings } = await rebuild(entrypoints, groups, void 0);
2991
- await wxt.hooks.callHook("build:done", wxt, output);
2992
- await printBuildSummary(
2993
- wxt.logger.success,
2994
- `Built extension in ${formatDuration(Date.now() - startTime)}`,
2995
- output
2996
- );
2997
- for (const warning of warnings) {
2998
- wxt.logger.warn(...warning);
2999
- }
3000
- if (wxt.config.analysis.enabled) {
3001
- await combineAnalysisStats();
3002
- const statsPath = relative6(wxt.config.root, wxt.config.analysis.outputFile);
3003
- wxt.logger.info(
3004
- `Analysis complete:
3005
- ${pc5.gray("\u2514\u2500")} ${pc5.yellow(statsPath)}`
3006
- );
3007
- if (wxt.config.analysis.open) {
3008
- if (isCI) {
3009
- wxt.logger.debug(`Skipped opening ${pc5.yellow(statsPath)} in CI`);
3010
- } else {
3011
- wxt.logger.info(`Opening ${pc5.yellow(statsPath)} in browser...`);
3012
- const { default: open } = await import("open");
3013
- open(wxt.config.analysis.outputFile);
3014
- }
3015
- }
3016
- }
3017
- return output;
3018
- }
3019
- async function combineAnalysisStats() {
3020
- const unixFiles = await glob4(`${wxt.config.analysis.outputName}-*.json`, {
3021
- cwd: wxt.config.analysis.outputDir,
3022
- absolute: true
3023
- });
3024
- const absolutePaths = unixFiles.map(unnormalizePath);
3025
- await mergeJsonOutputs({
3026
- inputs: absolutePaths,
3027
- template: wxt.config.analysis.template,
3028
- filename: wxt.config.analysis.outputFile
3029
- });
3030
- if (!wxt.config.analysis.keepArtifacts) {
3031
- await Promise.all(absolutePaths.map((statsFile) => fs13.remove(statsFile)));
3032
- }
3033
- }
3034
- function printValidationResults({
3035
- errorCount,
3036
- errors,
3037
- warningCount
3038
- }) {
3039
- (errorCount > 0 ? wxt.logger.error : wxt.logger.warn)(
3040
- `Entrypoint validation failed: ${errorCount} error${errorCount === 1 ? "" : "s"}, ${warningCount} warning${warningCount === 1 ? "" : "s"}`
3041
- );
3042
- const cwd = process.cwd();
3043
- const entrypointErrors = errors.reduce((map, error) => {
3044
- const entryErrors = map.get(error.entrypoint) ?? [];
3045
- entryErrors.push(error);
3046
- map.set(error.entrypoint, entryErrors);
3047
- return map;
3048
- }, /* @__PURE__ */ new Map());
3049
- Array.from(entrypointErrors.entries()).forEach(([entrypoint, errors2]) => {
3050
- wxt.logger.log(relative6(cwd, entrypoint.inputPath));
3051
- console.log();
3052
- errors2.forEach((err) => {
3053
- const type = err.type === "error" ? pc5.red("ERROR") : pc5.yellow("WARN");
3054
- const recieved = pc5.dim(`(recieved: ${JSON.stringify(err.value)})`);
3055
- wxt.logger.log(` - ${type} ${err.message} ${recieved}`);
3056
- });
3057
- console.log();
3058
- });
3059
- }
3060
-
3061
- // src/core/wxt.ts
3062
- import { createHooks } from "hookable";
3063
-
3064
- // src/core/package-managers/index.ts
3065
- import {
3066
- detectPackageManager,
3067
- addDependency,
3068
- addDevDependency,
3069
- ensureDependencyInstalled,
3070
- installDependencies,
3071
- removeDependency
3072
- } from "nypm";
3073
-
3074
- // src/core/package-managers/npm.ts
3075
- import path7 from "node:path";
3076
- import { ensureDir as ensureDir3 } from "fs-extra";
3077
- var npm = {
3078
- overridesKey: "overrides",
3079
- async downloadDependency(id, downloadDir) {
3080
- await ensureDir3(downloadDir);
3081
- const { execa } = await import("./execa-4UBDUBJZ.js");
3082
- const res = await execa("npm", ["pack", id, "--json"], {
3083
- cwd: downloadDir
3084
- });
3085
- const packed = JSON.parse(res.stdout);
3086
- return path7.resolve(downloadDir, packed[0].filename);
3087
- },
3088
- async listDependencies(options) {
3089
- const args = ["ls", "--json"];
3090
- if (options?.all) {
3091
- args.push("--depth", "Infinity");
3092
- }
3093
- const { execa } = await import("./execa-4UBDUBJZ.js");
3094
- const res = await execa("npm", args, { cwd: options?.cwd });
3095
- const project = JSON.parse(res.stdout);
3096
- return flattenNpmListOutput([project]);
3097
- }
3098
- };
3099
- function flattenNpmListOutput(projects) {
3100
- const queue = projects.flatMap(
3101
- (project) => {
3102
- const acc = [];
3103
- if (project.dependencies) acc.push(project.dependencies);
3104
- if (project.devDependencies) acc.push(project.devDependencies);
3105
- return acc;
3106
- }
3107
- );
3108
- const dependencies = [];
3109
- while (queue.length > 0) {
3110
- Object.entries(queue.pop()).forEach(([name, meta]) => {
3111
- dependencies.push({
3112
- name,
3113
- version: meta.version
3114
- });
3115
- if (meta.dependencies) queue.push(meta.dependencies);
3116
- if (meta.devDependencies) queue.push(meta.devDependencies);
3117
- });
3118
- }
3119
- return dedupeDependencies(dependencies);
3120
- }
3121
- function dedupeDependencies(dependencies) {
3122
- const hashes = /* @__PURE__ */ new Set();
3123
- return dependencies.filter((dep) => {
3124
- const hash = `${dep.name}@${dep.version}`;
3125
- if (hashes.has(hash)) {
3126
- return false;
3127
- } else {
3128
- hashes.add(hash);
3129
- return true;
3130
- }
3131
- });
3132
- }
3133
-
3134
- // src/core/package-managers/bun.ts
3135
- var bun = {
3136
- overridesKey: "overrides",
3137
- // But also supports "resolutions"
3138
- downloadDependency(...args) {
3139
- return npm.downloadDependency(...args);
3140
- },
3141
- async listDependencies(options) {
3142
- const args = ["pm", "ls"];
3143
- if (options?.all) {
3144
- args.push("--all");
3145
- }
3146
- const { execa } = await import("./execa-4UBDUBJZ.js");
3147
- const res = await execa("bun", args, { cwd: options?.cwd });
3148
- return dedupeDependencies(
3149
- res.stdout.split("\n").slice(1).map((line) => line.trim()).map((line) => /.* (@?\S+)@(\S+)$/.exec(line)).filter((match) => !!match).map(([_, name, version2]) => ({ name, version: version2 }))
3150
- );
3151
- }
3152
- };
3153
-
3154
- // src/core/package-managers/yarn.ts
3155
- var yarn = {
3156
- overridesKey: "resolutions",
3157
- downloadDependency(...args) {
3158
- return npm.downloadDependency(...args);
3159
- },
3160
- async listDependencies(options) {
3161
- const args = ["list", "--json"];
3162
- if (options?.all) {
3163
- args.push("--depth", "Infinity");
3164
- }
3165
- const { execa } = await import("./execa-4UBDUBJZ.js");
3166
- const res = await execa("yarn", args, { cwd: options?.cwd });
3167
- const tree = res.stdout.split("\n").map((line) => JSON.parse(line)).find((line) => line.type === "tree")?.data;
3168
- if (tree == null) throw Error("'yarn list --json' did not output a tree");
3169
- const queue = [...tree.trees];
3170
- const dependencies = [];
3171
- while (queue.length > 0) {
3172
- const { name: treeName, children } = queue.pop();
3173
- const match = /(@?\S+)@(\S+)$/.exec(treeName);
3174
- if (match) {
3175
- const [_, name, version2] = match;
3176
- dependencies.push({ name, version: version2 });
3177
- }
3178
- if (children != null) {
3179
- queue.push(...children);
3180
- }
3181
- }
3182
- return dedupeDependencies(dependencies);
3183
- }
3184
- };
3185
-
3186
- // src/core/package-managers/pnpm.ts
3187
- var pnpm = {
3188
- overridesKey: "resolutions",
3189
- // "pnpm.overrides" has a higher priority, but I don't want to deal with nesting
3190
- downloadDependency(...args) {
3191
- return npm.downloadDependency(...args);
3192
- },
3193
- async listDependencies(options) {
3194
- const args = ["ls", "-r", "--json"];
3195
- if (options?.all) {
3196
- args.push("--depth", "Infinity");
3197
- }
3198
- if (typeof process !== "undefined" && process.env.WXT_PNPM_IGNORE_WORKSPACE === "true") {
3199
- args.push("--ignore-workspace");
3200
- }
3201
- const { execa } = await import("./execa-4UBDUBJZ.js");
3202
- const res = await execa("pnpm", args, { cwd: options?.cwd });
3203
- const projects = JSON.parse(res.stdout);
3204
- return flattenNpmListOutput(projects);
3205
- }
3206
- };
3207
-
3208
- // src/core/package-managers/index.ts
3209
- async function createWxtPackageManager(root) {
3210
- const pm = await detectPackageManager(root, {
3211
- includeParentDirs: true
3212
- });
3213
- const requirePm = (cb) => {
3214
- if (pm == null) throw Error("Could not detect package manager");
3215
- return cb(pm);
3216
- };
3217
- return {
3218
- get name() {
3219
- return requirePm((pm2) => pm2.name);
3220
- },
3221
- get command() {
3222
- return requirePm((pm2) => pm2.command);
3223
- },
3224
- get version() {
3225
- return requirePm((pm2) => pm2.version);
3226
- },
3227
- get majorVersion() {
3228
- return requirePm((pm2) => pm2.majorVersion);
3229
- },
3230
- get lockFile() {
3231
- return requirePm((pm2) => pm2.lockFile);
3232
- },
3233
- get files() {
3234
- return requirePm((pm2) => pm2.files);
3235
- },
3236
- addDependency,
3237
- addDevDependency,
3238
- ensureDependencyInstalled,
3239
- installDependencies,
3240
- removeDependency,
3241
- get overridesKey() {
3242
- return requirePm((pm2) => packageManagers[pm2.name].overridesKey);
3243
- },
3244
- downloadDependency(...args) {
3245
- return requirePm(
3246
- (pm2) => packageManagers[pm2.name].downloadDependency(...args)
3247
- );
3248
- },
3249
- listDependencies(...args) {
3250
- return requirePm(
3251
- (pm2) => packageManagers[pm2.name].listDependencies(...args)
3252
- );
3253
- }
3254
- };
3255
- }
3256
- var packageManagers = {
3257
- npm,
3258
- pnpm,
3259
- bun,
3260
- yarn
3261
- };
3262
-
3263
- // src/core/builders/vite/index.ts
3264
- import { ViteNodeServer } from "vite-node/server";
3265
- import { ViteNodeRunner } from "vite-node/client";
3266
- import { installSourcemapsSupport } from "vite-node/source-map";
3267
- async function createViteBuilder(wxtConfig, hooks, server) {
3268
- const vite = await import("vite");
3269
- const getBaseConfig = async () => {
3270
- const config = await wxtConfig.vite(wxtConfig.env);
3271
- config.root = wxtConfig.root;
3272
- config.configFile = false;
3273
- config.logLevel = "warn";
3274
- config.mode = wxtConfig.mode;
3275
- config.build ??= {};
3276
- config.publicDir = wxtConfig.publicDir;
3277
- config.build.copyPublicDir = false;
3278
- config.build.outDir = wxtConfig.outDir;
3279
- config.build.emptyOutDir = false;
3280
- if (config.build.minify == null && wxtConfig.command === "serve") {
3281
- config.build.minify = false;
3282
- }
3283
- if (config.build.sourcemap == null && wxtConfig.command === "serve") {
3284
- config.build.sourcemap = "inline";
3285
- }
3286
- config.plugins ??= [];
3287
- config.plugins.push(
3288
- download(wxtConfig),
3289
- devHtmlPrerender(wxtConfig, server),
3290
- resolveVirtualModules(wxtConfig),
3291
- devServerGlobals(wxtConfig, server),
3292
- tsconfigPaths(wxtConfig),
3293
- noopBackground(),
3294
- globals(wxtConfig),
3295
- excludeBrowserPolyfill(wxtConfig),
3296
- defineImportMeta(),
3297
- wxtPluginLoader(wxtConfig),
3298
- resolveAppConfig(wxtConfig)
3299
- );
3300
- if (wxtConfig.analysis.enabled) {
3301
- config.plugins.push(bundleAnalysis(wxtConfig));
3302
- }
3303
- return config;
3304
- };
3305
- const getLibModeConfig = (entrypoint) => {
3306
- const entry = getRollupEntry(entrypoint);
3307
- const plugins = [
3308
- entrypointGroupGlobals(entrypoint)
3309
- ];
3310
- if (entrypoint.type === "content-script-style" || entrypoint.type === "unlisted-style") {
3311
- plugins.push(cssEntrypoints(entrypoint, wxtConfig));
3312
- }
3313
- const iifeReturnValueName = safeVarName(entrypoint.name);
3314
- const libMode = {
3315
- mode: wxtConfig.mode,
3316
- plugins,
3317
- esbuild: {
3318
- // Add a footer with the returned value so it can return values to `scripting.executeScript`
3319
- // Footer is added apart of esbuild to make sure it's not minified. It
3320
- // get's removed if added to `build.rollupOptions.output.footer`
3321
- // See https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/scripting/executeScript#return_value
3322
- footer: iifeReturnValueName + ";"
3323
- },
3324
- build: {
3325
- lib: {
3326
- entry,
3327
- formats: ["iife"],
3328
- name: iifeReturnValueName,
3329
- fileName: entrypoint.name
3330
- },
3331
- rollupOptions: {
3332
- output: {
3333
- // There's only a single output for this build, so we use the desired bundle path for the
3334
- // entry output (like "content-scripts/overlay.js")
3335
- entryFileNames: getEntrypointBundlePath(
3336
- entrypoint,
3337
- wxtConfig.outDir,
3338
- ".js"
3339
- ),
3340
- // Output content script CSS to `content-scripts/`, but all other scripts are written to
3341
- // `assets/`.
3342
- assetFileNames: ({ name }) => {
3343
- if (entrypoint.type === "content-script" && name?.endsWith("css")) {
3344
- return `content-scripts/${entrypoint.name}.[ext]`;
3345
- } else {
3346
- return `assets/${entrypoint.name}.[ext]`;
3347
- }
3348
- }
3349
- }
3350
- }
3351
- },
3352
- define: {
3353
- // See https://github.com/aklinker1/vite-plugin-web-extension/issues/96
3354
- "process.env.NODE_ENV": JSON.stringify(wxtConfig.mode)
3355
- }
3356
- };
3357
- return libMode;
3358
- };
3359
- const getMultiPageConfig = (entrypoints) => {
3360
- const htmlEntrypoints = new Set(
3361
- entrypoints.filter(isHtmlEntrypoint).map((e) => e.name)
3362
- );
3363
- return {
3364
- mode: wxtConfig.mode,
3365
- plugins: [
3366
- multipageMove(entrypoints, wxtConfig),
3367
- entrypointGroupGlobals(entrypoints)
3368
- ],
3369
- build: {
3370
- rollupOptions: {
3371
- input: entrypoints.reduce((input, entry) => {
3372
- input[entry.name] = getRollupEntry(entry);
3373
- return input;
3374
- }, {}),
3375
- output: {
3376
- // Include a hash to prevent conflicts
3377
- chunkFileNames: "chunks/[name]-[hash].js",
3378
- entryFileNames: ({ name }) => {
3379
- if (htmlEntrypoints.has(name)) return "chunks/[name]-[hash].js";
3380
- return "[name].js";
3381
- },
3382
- // We can't control the "name", so we need a hash to prevent conflicts
3383
- assetFileNames: "assets/[name]-[hash].[ext]"
3384
- }
3385
- }
3386
- }
3387
- };
3388
- };
3389
- const getCssConfig = (entrypoint) => {
3390
- return {
3391
- mode: wxtConfig.mode,
3392
- plugins: [entrypointGroupGlobals(entrypoint)],
3393
- build: {
3394
- rollupOptions: {
3395
- input: {
3396
- [entrypoint.name]: entrypoint.inputPath
3397
- },
3398
- output: {
3399
- assetFileNames: () => {
3400
- if (entrypoint.type === "content-script-style") {
3401
- return `content-scripts/${entrypoint.name}.[ext]`;
3402
- } else {
3403
- return `assets/${entrypoint.name}.[ext]`;
3404
- }
3405
- }
3406
- }
3407
- }
3408
- }
3409
- };
3410
- };
3411
- return {
3412
- name: "Vite",
3413
- version: vite.version,
3414
- async importEntrypoint(path8) {
3415
- switch (wxtConfig.experimental.entrypointImporter) {
3416
- default:
3417
- case "jiti": {
3418
- return await importEntrypointFile(path8);
3419
- }
3420
- case "vite-runtime": {
3421
- const baseConfig = await getBaseConfig();
3422
- const envConfig = {
3423
- plugins: [
3424
- webextensionPolyfillMock(wxtConfig),
3425
- removeEntrypointMainFunction(wxtConfig, path8)
3426
- ]
3427
- };
3428
- const config = vite.mergeConfig(baseConfig, envConfig);
3429
- const server2 = await vite.createServer(config);
3430
- await server2.listen();
3431
- const runtime = await vite.createViteRuntime(server2, { hmr: false });
3432
- const module = await runtime.executeUrl(path8);
3433
- await server2.close();
3434
- return module.default;
3435
- }
3436
- case "vite-node": {
3437
- const baseConfig = await getBaseConfig();
3438
- baseConfig.optimizeDeps ??= {};
3439
- baseConfig.optimizeDeps.noDiscovery = true;
3440
- baseConfig.optimizeDeps.include = [];
3441
- const envConfig = {
3442
- plugins: [
3443
- webextensionPolyfillMock(wxtConfig),
3444
- removeEntrypointMainFunction(wxtConfig, path8)
3445
- ]
3446
- };
3447
- const config = vite.mergeConfig(baseConfig, envConfig);
3448
- const server2 = await vite.createServer(config);
3449
- await server2.pluginContainer.buildStart({});
3450
- const node = new ViteNodeServer(
3451
- // @ts-ignore: Some weird type error...
3452
- server2
3453
- );
3454
- installSourcemapsSupport({
3455
- getSourceMap: (source) => node.getSourceMap(source)
3456
- });
3457
- const runner = new ViteNodeRunner({
3458
- root: server2.config.root,
3459
- base: server2.config.base,
3460
- // when having the server and runner in a different context,
3461
- // you will need to handle the communication between them
3462
- // and pass to this function
3463
- fetchModule(id) {
3464
- return node.fetchModule(id);
3465
- },
3466
- resolveId(id, importer) {
3467
- return node.resolveId(id, importer);
3468
- }
3469
- });
3470
- const res = await runner.executeFile(path8);
3471
- await server2.close();
3472
- return res.default;
3473
- }
3474
- }
3475
- },
3476
- async build(group) {
3477
- let entryConfig;
3478
- if (Array.isArray(group)) entryConfig = getMultiPageConfig(group);
3479
- else if (group.inputPath.endsWith(".css"))
3480
- entryConfig = getCssConfig(group);
3481
- else entryConfig = getLibModeConfig(group);
3482
- const buildConfig = vite.mergeConfig(await getBaseConfig(), entryConfig);
3483
- await hooks.callHook(
3484
- "vite:build:extendConfig",
3485
- toArray(group),
3486
- buildConfig
3487
- );
3488
- const result = await vite.build(buildConfig);
3489
- return {
3490
- entrypoints: group,
3491
- chunks: getBuildOutputChunks(result)
3492
- };
3493
- },
3494
- async createServer(info) {
3495
- const serverConfig = {
3496
- server: {
3497
- port: info.port,
3498
- strictPort: true,
3499
- host: info.hostname,
3500
- origin: info.origin
3501
- }
3502
- };
3503
- const baseConfig = await getBaseConfig();
3504
- const finalConfig = vite.mergeConfig(baseConfig, serverConfig);
3505
- await hooks.callHook("vite:devServer:extendConfig", finalConfig);
3506
- const viteServer = await vite.createServer(finalConfig);
3507
- const server2 = {
3508
- async listen() {
3509
- await viteServer.listen(info.port);
3510
- },
3511
- async close() {
3512
- await viteServer.close();
3513
- },
3514
- transformHtml(...args) {
3515
- return viteServer.transformIndexHtml(...args);
3516
- },
3517
- ws: {
3518
- send(message, payload) {
3519
- return viteServer.ws.send(message, payload);
3520
- },
3521
- on(message, cb) {
3522
- viteServer.ws.on(message, cb);
3523
- }
3524
- },
3525
- watcher: viteServer.watcher
3526
- };
3527
- return server2;
3528
- }
3529
- };
3530
- }
3531
- function getBuildOutputChunks(result) {
3532
- if ("on" in result) throw Error("wxt does not support vite watch mode.");
3533
- if (Array.isArray(result)) return result.flatMap(({ output }) => output);
3534
- return result.output;
3535
- }
3536
- function getRollupEntry(entrypoint) {
3537
- let virtualEntrypointType;
3538
- switch (entrypoint.type) {
3539
- case "background":
3540
- case "unlisted-script":
3541
- virtualEntrypointType = entrypoint.type;
3542
- break;
3543
- case "content-script":
3544
- virtualEntrypointType = entrypoint.options.world === "MAIN" ? "content-script-main-world" : "content-script-isolated-world";
3545
- break;
3546
- }
3547
- if (virtualEntrypointType) {
3548
- const moduleId = `virtual:wxt-${virtualEntrypointType}-entrypoint`;
3549
- return `${moduleId}?${entrypoint.inputPath}`;
3550
- }
3551
- return entrypoint.inputPath;
3552
- }
3553
-
3554
- // src/core/wxt.ts
3555
- var wxt;
3556
- async function registerWxt(command, inlineConfig = {}, getServer) {
3557
- const hooks = createHooks();
3558
- const config = await resolveConfig(inlineConfig, command);
3559
- const server = await getServer?.(config);
3560
- const builder = await createViteBuilder(config, hooks, server);
3561
- const pm = await createWxtPackageManager(config.root);
3562
- wxt = {
3563
- config,
3564
- hooks,
3565
- get logger() {
3566
- return config.logger;
3567
- },
3568
- async reloadConfig() {
3569
- wxt.config = await resolveConfig(inlineConfig, command);
3570
- },
3571
- pm,
3572
- builder,
3573
- server
3574
- };
3575
- const initModule = async (module) => {
3576
- if (module.hooks) wxt.hooks.addHooks(module.hooks);
3577
- await module.setup?.(
3578
- wxt,
3579
- // @ts-expect-error: Untyped configKey field
3580
- module.configKey ? config[module.configKey] : void 0
3581
- );
3582
- };
3583
- for (const builtinModule of builtinModules) await initModule(builtinModule);
3584
- for (const userModule of config.userModules) await initModule(userModule);
3585
- wxt.hooks.addHooks(config.hooks);
3586
- await wxt.hooks.callHook("ready", wxt);
3587
- }
3588
-
3589
- export {
3590
- normalizePath,
3591
- unnormalizePath,
3592
- getEntrypointBundlePath,
3593
- isHtmlEntrypoint,
3594
- formatDuration,
3595
- download,
3596
- tsconfigPaths,
3597
- globals,
3598
- webextensionPolyfillMock,
3599
- resolveAppConfig,
3600
- kebabCaseAlphanumeric,
3601
- vitePlugin,
3602
- wxt,
3603
- registerWxt,
3604
- detectDevChanges,
3605
- findEntrypoints,
3606
- generateTypesDir,
3607
- resolveConfig,
3608
- printFileList,
3609
- version,
3610
- mapWxtOptionsToRegisteredContentScript,
3611
- getContentScriptJs,
3612
- getPackageJson,
3613
- getContentScriptCssFiles,
3614
- getContentScriptsCssMap,
3615
- rebuild,
3616
- internalBuild
3617
- };