wxt 0.0.2 → 0.1.1-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.
@@ -45,7 +45,7 @@ function setupWebSocket(onMessage) {
45
45
  }
46
46
 
47
47
  // src/client/virtual-modules/background-entrypoint.ts
48
- import browser2 from "webextension-polyfill";
48
+ import browser3 from "webextension-polyfill";
49
49
 
50
50
  // src/client/utils/keepServiceWorkerAlive.ts
51
51
  import browser from "webextension-polyfill";
@@ -55,14 +55,62 @@ function keepServiceWorkerAlive() {
55
55
  }, 5e3);
56
56
  }
57
57
 
58
+ // src/client/utils/reloadContentScript.ts
59
+ import browser2 from "webextension-polyfill";
60
+ import { MatchPattern } from "@webext-core/match-patterns";
61
+ function reloadContentScript(contentScript) {
62
+ const manifest = browser2.runtime.getManifest();
63
+ if (manifest.manifest_version == 2) {
64
+ void reloadContentScriptMv2(contentScript);
65
+ } else {
66
+ void reloadContentScriptMv3(contentScript);
67
+ }
68
+ }
69
+ async function reloadContentScriptMv3(contentScript) {
70
+ const id = `wxt:${contentScript.js[0]}`;
71
+ logger.log("Reloading content script:", contentScript);
72
+ const registered = await browser2.scripting.getRegisteredContentScripts();
73
+ logger.debug("Existing scripts:", registered);
74
+ const existing = registered.find((cs) => cs.id === id);
75
+ if (existing) {
76
+ logger.debug("Updating content script", existing);
77
+ await browser2.scripting.updateContentScripts([{ ...contentScript, id }]);
78
+ } else {
79
+ logger.debug("Registering new content script...");
80
+ await browser2.scripting.registerContentScripts([{ ...contentScript, id }]);
81
+ }
82
+ const allTabs = await browser2.tabs.query({});
83
+ const matchPatterns = contentScript.matches.map(
84
+ (match) => new MatchPattern(match)
85
+ );
86
+ const matchingTabs = allTabs.filter((tab) => {
87
+ const url = tab.url;
88
+ if (!url)
89
+ return false;
90
+ return !!matchPatterns.find((pattern) => pattern.includes(url));
91
+ });
92
+ await Promise.all(matchingTabs.map((tab) => browser2.tabs.reload(tab.id)));
93
+ }
94
+ async function reloadContentScriptMv2(contentScript) {
95
+ throw Error("TODO: reloadContentScriptMv2");
96
+ }
97
+
58
98
  // src/client/virtual-modules/background-entrypoint.ts
59
99
  if (__COMMAND__ === "serve") {
60
100
  try {
61
- setupWebSocket((message) => {
101
+ const ws = setupWebSocket((message) => {
62
102
  if (message.event === "wxt:reload-extension")
63
- browser2.runtime.reload();
103
+ browser3.runtime.reload();
104
+ if (message.event === "wxt:reload-content-script" && message.data != null)
105
+ reloadContentScript(message.data);
64
106
  });
65
- keepServiceWorkerAlive();
107
+ if (__MANIFEST_VERSION__ === 3) {
108
+ ws.addEventListener("open", () => {
109
+ const msg = { type: "custom", event: "wxt:background-initialized" };
110
+ ws.send(JSON.stringify(msg));
111
+ });
112
+ keepServiceWorkerAlive();
113
+ }
66
114
  } catch (err) {
67
115
  logger.error("Failed to setup web socket connection with dev server", err);
68
116
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/client/virtual-modules/background-entrypoint.ts","../../src/client/utils/logger.ts","../../src/client/utils/setupWebSocket.ts","../../src/client/utils/keepServiceWorkerAlive.ts"],"sourcesContent":["import definition from 'virtual:user-background';\nimport { setupWebSocket } from '../utils/setupWebSocket';\nimport { logger } from '../utils/logger';\nimport browser from 'webextension-polyfill';\nimport { keepServiceWorkerAlive } from '../utils/keepServiceWorkerAlive';\n\nif (__COMMAND__ === 'serve') {\n try {\n setupWebSocket((message) => {\n if (message.event === 'wxt:reload-extension') browser.runtime.reload();\n });\n\n // Web Socket will disconnect if the service worker is killed\n keepServiceWorkerAlive();\n } catch (err) {\n logger.error('Failed to setup web socket connection with dev server', err);\n }\n}\n\ntry {\n const res = definition.main();\n // @ts-expect-error: res shouldn't be a promise, but we're checking it anyways\n if (res instanceof Promise) {\n console.warn(\n \"The background's main() function return a promise, but it must be synchonous\",\n );\n }\n} catch (err) {\n logger.error('The background script crashed on startup!');\n throw err;\n}\n","function print(method: (...args: any[]) => void, ...args: any[]) {\n if (typeof args[0] === 'string') {\n const message = args.shift();\n method(`[wxt] ${message}`, ...args);\n } else {\n method('[wxt]', ...args);\n }\n}\n\n/**\n * Wrapper around `console` with a \"[wxt]\" prefix\n */\nexport const logger = {\n debug: (...args: any[]) => print(console.debug, ...args),\n log: (...args: any[]) => print(console.log, ...args),\n warn: (...args: any[]) => print(console.warn, ...args),\n error: (...args: any[]) => print(console.error, ...args),\n};\n","import { logger } from './logger';\n\ninterface WebSocketMessage {\n type: string;\n event: string;\n data?: any;\n}\n\n/**\n * Connect to the websocket and listen for messages.\n *\n * @param onMessage Optional callback that is called when a message is recieved and we've verified\n * it's structure is what we expect.\n */\nexport function setupWebSocket(\n onMessage?: (message: WebSocketMessage) => void,\n) {\n const serverUrl = `${__DEV_SERVER_PROTOCOL__}//${__DEV_SERVER_HOSTNAME__}:${__DEV_SERVER_PORT__}`;\n logger.debug('Connecting to dev server @', serverUrl);\n const ws = new WebSocket(serverUrl, 'vite-hmr');\n\n ws.addEventListener('open', () => {\n logger.debug('Connected to dev server');\n });\n ws.addEventListener('close', () => {\n logger.debug('Disconnected from dev server');\n });\n ws.addEventListener('error', (event) => {\n logger.error('Failed to connect to dev server', event);\n });\n\n ws.addEventListener('message', (e) => {\n try {\n const message = JSON.parse(e.data) as WebSocketMessage;\n if (message.type === 'custom' && message.event?.startsWith?.('wxt:')) {\n onMessage?.(message);\n }\n } catch (err) {\n logger.error('Failed to handle message', err);\n }\n });\n\n return ws;\n}\n","import browser from 'webextension-polyfill';\n\n/**\n * https://developer.chrome.com/blog/longer-esw-lifetimes/\n */\nexport function keepServiceWorkerAlive() {\n setInterval(async () => {\n // Calling an async browser API resets the service worker's timeout\n await browser.runtime.getPlatformInfo();\n }, 5e3);\n}\n"],"mappings":";AAAA,OAAO,gBAAgB;;;ACAvB,SAAS,MAAM,WAAqC,MAAa;AAC/D,MAAI,OAAO,KAAK,CAAC,MAAM,UAAU;AAC/B,UAAM,UAAU,KAAK,MAAM;AAC3B,WAAO,SAAS,WAAW,GAAG,IAAI;AAAA,EACpC,OAAO;AACL,WAAO,SAAS,GAAG,IAAI;AAAA,EACzB;AACF;AAKO,IAAM,SAAS;AAAA,EACpB,OAAO,IAAI,SAAgB,MAAM,QAAQ,OAAO,GAAG,IAAI;AAAA,EACvD,KAAK,IAAI,SAAgB,MAAM,QAAQ,KAAK,GAAG,IAAI;AAAA,EACnD,MAAM,IAAI,SAAgB,MAAM,QAAQ,MAAM,GAAG,IAAI;AAAA,EACrD,OAAO,IAAI,SAAgB,MAAM,QAAQ,OAAO,GAAG,IAAI;AACzD;;;ACHO,SAAS,eACd,WACA;AACA,QAAM,YAAY,GAAG,4BAA4B,2BAA2B;AAC5E,SAAO,MAAM,8BAA8B,SAAS;AACpD,QAAM,KAAK,IAAI,UAAU,WAAW,UAAU;AAE9C,KAAG,iBAAiB,QAAQ,MAAM;AAChC,WAAO,MAAM,yBAAyB;AAAA,EACxC,CAAC;AACD,KAAG,iBAAiB,SAAS,MAAM;AACjC,WAAO,MAAM,8BAA8B;AAAA,EAC7C,CAAC;AACD,KAAG,iBAAiB,SAAS,CAAC,UAAU;AACtC,WAAO,MAAM,mCAAmC,KAAK;AAAA,EACvD,CAAC;AAED,KAAG,iBAAiB,WAAW,CAAC,MAAM;AACpC,QAAI;AACF,YAAM,UAAU,KAAK,MAAM,EAAE,IAAI;AACjC,UAAI,QAAQ,SAAS,YAAY,QAAQ,OAAO,aAAa,MAAM,GAAG;AACpE,oBAAY,OAAO;AAAA,MACrB;AAAA,IACF,SAAS,KAAP;AACA,aAAO,MAAM,4BAA4B,GAAG;AAAA,IAC9C;AAAA,EACF,CAAC;AAED,SAAO;AACT;;;AFxCA,OAAOA,cAAa;;;AGHpB,OAAO,aAAa;AAKb,SAAS,yBAAyB;AACvC,cAAY,YAAY;AAEtB,UAAM,QAAQ,QAAQ,gBAAgB;AAAA,EACxC,GAAG,GAAG;AACR;;;AHJA,IAAI,gBAAgB,SAAS;AAC3B,MAAI;AACF,mBAAe,CAAC,YAAY;AAC1B,UAAI,QAAQ,UAAU;AAAwB,QAAAC,SAAQ,QAAQ,OAAO;AAAA,IACvE,CAAC;AAGD,2BAAuB;AAAA,EACzB,SAAS,KAAP;AACA,WAAO,MAAM,yDAAyD,GAAG;AAAA,EAC3E;AACF;AAEA,IAAI;AACF,QAAM,MAAM,WAAW,KAAK;AAE5B,MAAI,eAAe,SAAS;AAC1B,YAAQ;AAAA,MACN;AAAA,IACF;AAAA,EACF;AACF,SAAS,KAAP;AACA,SAAO,MAAM,2CAA2C;AACxD,QAAM;AACR;","names":["browser","browser"]}
1
+ {"version":3,"sources":["../../src/client/virtual-modules/background-entrypoint.ts","../../src/client/utils/logger.ts","../../src/client/utils/setupWebSocket.ts","../../src/client/utils/keepServiceWorkerAlive.ts","../../src/client/utils/reloadContentScript.ts"],"sourcesContent":["import definition from 'virtual:user-background';\nimport { setupWebSocket } from '../utils/setupWebSocket';\nimport { logger } from '../utils/logger';\nimport browser from 'webextension-polyfill';\nimport { keepServiceWorkerAlive } from '../utils/keepServiceWorkerAlive';\nimport { reloadContentScript } from '../utils/reloadContentScript';\n\nif (__COMMAND__ === 'serve') {\n try {\n const ws = setupWebSocket((message) => {\n if (message.event === 'wxt:reload-extension') browser.runtime.reload();\n if (message.event === 'wxt:reload-content-script' && message.data != null)\n reloadContentScript(message.data);\n });\n\n if (__MANIFEST_VERSION__ === 3) {\n // Tell the server the background script is loaded and ready to go\n ws.addEventListener('open', () => {\n const msg = { type: 'custom', event: 'wxt:background-initialized' };\n ws.send(JSON.stringify(msg));\n });\n\n // Web Socket will disconnect if the service worker is killed\n keepServiceWorkerAlive();\n }\n } catch (err) {\n logger.error('Failed to setup web socket connection with dev server', err);\n }\n}\n\ntry {\n const res = definition.main();\n // @ts-expect-error: res shouldn't be a promise, but we're checking it anyways\n if (res instanceof Promise) {\n console.warn(\n \"The background's main() function return a promise, but it must be synchonous\",\n );\n }\n} catch (err) {\n logger.error('The background script crashed on startup!');\n throw err;\n}\n","function print(method: (...args: any[]) => void, ...args: any[]) {\n if (typeof args[0] === 'string') {\n const message = args.shift();\n method(`[wxt] ${message}`, ...args);\n } else {\n method('[wxt]', ...args);\n }\n}\n\n/**\n * Wrapper around `console` with a \"[wxt]\" prefix\n */\nexport const logger = {\n debug: (...args: any[]) => print(console.debug, ...args),\n log: (...args: any[]) => print(console.log, ...args),\n warn: (...args: any[]) => print(console.warn, ...args),\n error: (...args: any[]) => print(console.error, ...args),\n};\n","import { logger } from './logger';\n\ninterface WebSocketMessage {\n type: string;\n event: string;\n data?: any;\n}\n\n/**\n * Connect to the websocket and listen for messages.\n *\n * @param onMessage Optional callback that is called when a message is recieved and we've verified\n * it's structure is what we expect.\n */\nexport function setupWebSocket(\n onMessage?: (message: WebSocketMessage) => void,\n) {\n const serverUrl = `${__DEV_SERVER_PROTOCOL__}//${__DEV_SERVER_HOSTNAME__}:${__DEV_SERVER_PORT__}`;\n logger.debug('Connecting to dev server @', serverUrl);\n const ws = new WebSocket(serverUrl, 'vite-hmr');\n\n ws.addEventListener('open', () => {\n logger.debug('Connected to dev server');\n });\n ws.addEventListener('close', () => {\n logger.debug('Disconnected from dev server');\n });\n ws.addEventListener('error', (event) => {\n logger.error('Failed to connect to dev server', event);\n });\n\n ws.addEventListener('message', (e) => {\n try {\n const message = JSON.parse(e.data) as WebSocketMessage;\n if (message.type === 'custom' && message.event?.startsWith?.('wxt:')) {\n onMessage?.(message);\n }\n } catch (err) {\n logger.error('Failed to handle message', err);\n }\n });\n\n return ws;\n}\n","import browser from 'webextension-polyfill';\n\n/**\n * https://developer.chrome.com/blog/longer-esw-lifetimes/\n */\nexport function keepServiceWorkerAlive() {\n setInterval(async () => {\n // Calling an async browser API resets the service worker's timeout\n await browser.runtime.getPlatformInfo();\n }, 5e3);\n}\n","import browser, { Manifest } from 'webextension-polyfill';\nimport { logger } from './logger';\nimport { MatchPattern } from '@webext-core/match-patterns';\n\nexport function reloadContentScript(contentScript: Manifest.ContentScript) {\n const manifest = browser.runtime.getManifest();\n if (manifest.manifest_version == 2) {\n void reloadContentScriptMv2(contentScript);\n } else {\n void reloadContentScriptMv3(contentScript);\n }\n}\n\nexport async function reloadContentScriptMv3(\n contentScript: Manifest.ContentScript,\n) {\n const id = `wxt:${contentScript.js![0]}`;\n logger.log('Reloading content script:', contentScript);\n const registered = await browser.scripting.getRegisteredContentScripts();\n logger.debug('Existing scripts:', registered);\n\n const existing = registered.find((cs) => cs.id === id);\n\n if (existing) {\n logger.debug('Updating content script', existing);\n await browser.scripting.updateContentScripts([{ ...contentScript, id }]);\n } else {\n logger.debug('Registering new content script...');\n await browser.scripting.registerContentScripts([{ ...contentScript, id }]);\n }\n\n const allTabs = await browser.tabs.query({});\n const matchPatterns = contentScript.matches.map(\n (match) => new MatchPattern(match),\n );\n const matchingTabs = allTabs.filter((tab) => {\n const url = tab.url;\n if (!url) return false;\n return !!matchPatterns.find((pattern) => pattern.includes(url));\n });\n await Promise.all(matchingTabs.map((tab) => browser.tabs.reload(tab.id)));\n}\n\nexport async function reloadContentScriptMv2(\n contentScript: Manifest.ContentScript,\n) {\n throw Error('TODO: reloadContentScriptMv2');\n}\n"],"mappings":"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","names":["browser","browser","browser","browser"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "wxt",
3
3
  "type": "module",
4
- "version": "0.0.2",
4
+ "version": "0.1.1-alpha1",
5
5
  "description": "Next gen framework for developing web extensions",
6
6
  "repository": {
7
7
  "type": "git",
@@ -41,6 +41,7 @@
41
41
  }
42
42
  },
43
43
  "dependencies": {
44
+ "@webext-core/match-patterns": "^1.0.1",
44
45
  "async-mutex": "^0.4.0",
45
46
  "c12": "^1.4.2",
46
47
  "cac": "^6.7.14",
@@ -75,7 +76,7 @@
75
76
  "tsup": "^7.0.0",
76
77
  "tsx": "^3.12.7",
77
78
  "typescript": "^5.1.3",
78
- "vitest": "^0.32.2",
79
+ "vitest": "^0.32.4",
79
80
  "webextension-polyfill": "^0.10.0"
80
81
  },
81
82
  "peerDependencies": {