wxt 0.18.14 → 0.19.0-alpha1

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