From 063aca6b94dd3b74cd3b12a0937a207b0c710c0c Mon Sep 17 00:00:00 2001 From: johnathan <952508490@qq.com> Date: Wed, 23 Apr 2025 18:06:57 +0800 Subject: [PATCH] Adjust Config & Update wanderDetailPage --- .vscode/launch.json | 2 +- scripts/prepare.ts | 7 ++---- shim.d.ts | 1 - src/contentScripts/index.ts | 16 +++++------- src/logic/common-setup.ts | 4 +++ src/logic/execute-script.ts | 38 ++++++++++++++++++++++++---- src/logic/index.ts | 1 - src/logic/page-worker/index.ts | 25 ++++++++++++++++--- src/logic/page-worker/types.d.ts | 10 +++++++- src/manifest.ts | 5 ---- src/options/Options.vue | 39 ----------------------------- src/options/index.html | 12 --------- src/options/main.ts | 8 ------ src/popup/Popup.vue | 43 -------------------------------- src/popup/index.html | 12 --------- src/popup/main.ts | 7 ------ src/sidepanel/Sidepanel.vue | 2 +- vite.config.mts | 2 -- 18 files changed, 77 insertions(+), 157 deletions(-) delete mode 100644 src/logic/index.ts delete mode 100644 src/options/Options.vue delete mode 100644 src/options/index.html delete mode 100644 src/options/main.ts delete mode 100644 src/popup/Popup.vue delete mode 100644 src/popup/index.html delete mode 100644 src/popup/main.ts diff --git a/.vscode/launch.json b/.vscode/launch.json index 9e22072..3cb6354 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -10,7 +10,7 @@ "name": "Attach to side panel", "webRoot": "${workspaceFolder}/src/", "port": 9222, - "urlFilter": "chrome-extension://*" + "urlFilter": "chrome-extension://fmalpbpehdilmjhnanhpjmnkgbahopfj/*" } ] } diff --git a/scripts/prepare.ts b/scripts/prepare.ts index 5e74961..c547d04 100644 --- a/scripts/prepare.ts +++ b/scripts/prepare.ts @@ -8,17 +8,14 @@ import { isDev, log, port, r } from './utils'; * Stub index.html to use Vite in development */ async function stubIndexHtml() { - const views = ['options', 'popup', 'sidepanel']; + const views = ['sidepanel']; for (const view of views) { await fs.ensureDir(r(`extension/dist/${view}`)); let data = await fs.readFile(r(`src/${view}/index.html`), 'utf-8'); data = data .replace('"./main.ts"', `"http://localhost:${port}/${view}/main.ts"`) - .replace( - '
', - '
Vite server did not start
', - ); + .replace('
', '
Vite server did not start
'); await fs.writeFile(r(`extension/dist/${view}/index.html`), data, 'utf-8'); log('PRE', `stub ${view}`); } diff --git a/shim.d.ts b/shim.d.ts index c7dabe1..5019d15 100644 --- a/shim.d.ts +++ b/shim.d.ts @@ -4,6 +4,5 @@ declare module 'webext-bridge' { export interface ProtocolMap { // define message protocol types // see https://github.com/antfu/webext-bridge#type-safe-protocols - 'tab-update': { tabId: number }; } } diff --git a/src/contentScripts/index.ts b/src/contentScripts/index.ts index 4637622..d7a5ebd 100644 --- a/src/contentScripts/index.ts +++ b/src/contentScripts/index.ts @@ -2,23 +2,20 @@ import App from './views/App.vue'; import { setupApp } from '~/logic/common-setup'; -// 是否挂在ContentScript Vue APP +// 是否在ContentScript挂载Vue APP const MOUNT_COMPONENT = false; +/** + * mount component to context window + */ const mountComponent = () => { - // mount component to context window const container = document.createElement('div'); container.id = __NAME__; const root = document.createElement('div'); const styleEl = document.createElement('link'); - const shadowDOM = - container.attachShadow?.({ mode: __DEV__ ? 'open' : 'closed' }) || - container; + const shadowDOM = container.attachShadow?.({ mode: __DEV__ ? 'open' : 'closed' }) || container; styleEl.setAttribute('rel', 'stylesheet'); - styleEl.setAttribute( - 'href', - browser.runtime.getURL('dist/contentScripts/index.css'), - ); + styleEl.setAttribute('href', browser.runtime.getURL('dist/contentScripts/index.css')); shadowDOM.appendChild(styleEl); shadowDOM.appendChild(root); document.body.appendChild(container); @@ -33,4 +30,3 @@ const mountComponent = () => { mountComponent(); } })(); - diff --git a/src/logic/common-setup.ts b/src/logic/common-setup.ts index 7d98d66..cbe4b58 100644 --- a/src/logic/common-setup.ts +++ b/src/logic/common-setup.ts @@ -1,5 +1,9 @@ import type { App } from 'vue'; +/** + * Setup Vue app + * @param app Vue app + */ export function setupApp(app: App) { // Inject a globally available `$app` object in template app.config.globalProperties.$app = { diff --git a/src/logic/execute-script.ts b/src/logic/execute-script.ts index 91f6197..8ce7299 100644 --- a/src/logic/execute-script.ts +++ b/src/logic/execute-script.ts @@ -1,13 +1,41 @@ /** - * Execute Script on Document - * @param tabId - * @param func - * @returns + * Executes a provided asynchronous function in the context of a specific browser tab. + * @param tabId - The ID of the browser tab where the script will be executed. + * @param func - The asynchronous function to execute in the tab's context. This function + * should be serializable and must not rely on external closures. + * @param payload - An optional payload object to pass as an argument to the executed function. + * + * @returns A promise that resolves to the result of the executed function, or `null` if an error occurs. + * + * @throws This function does not throw directly but logs an error to the console if the script injection fails. + * + * @example + * ```typescript + * const result = await exec( + * tabId, + * async (payload) => { + * return payload?.value ?? 0; + * }, + * { value: 42 } + * ); + * console.log(result); // Outputs: 42 + * ``` */ -export async function exec(tabId: number, func: () => Promise): Promise { +export async function exec(tabId: number, func: () => Promise): Promise; +export async function exec>( + tabId: number, + func: (payload: P) => Promise, + payload: P, +): Promise; +export async function exec>( + tabId: number, + func: (payload?: P) => Promise, + payload?: P, +): Promise { const injectResults = await browser.scripting.executeScript({ target: { tabId }, func, + args: payload ? [payload] : undefined, }); const ret = injectResults.pop(); if (ret?.error) { diff --git a/src/logic/index.ts b/src/logic/index.ts deleted file mode 100644 index 8b13789..0000000 --- a/src/logic/index.ts +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/logic/page-worker/index.ts b/src/logic/page-worker/index.ts index 1f2cfed..374bb27 100644 --- a/src/logic/page-worker/index.ts +++ b/src/logic/page-worker/index.ts @@ -1,6 +1,6 @@ import Emittery from 'emittery'; import type { AmazonGoodsLinkItem, AmazonPageWorker, AmazonPageWorkerEvents } from './types'; -import Browser from 'webextension-polyfill'; +import type { Tabs } from 'webextension-polyfill'; import { exec } from '../execute-script'; /** @@ -19,7 +19,7 @@ class AmazonPageWorkerImpl implements AmazonPageWorker { readonly channel = new Emittery(); - private async getCurrentTab(): Promise { + private async getCurrentTab(): Promise { const tab = await browser.tabs .query({ active: true, currentWindow: true }) .then((tabs) => tabs[0]); @@ -41,7 +41,7 @@ class AmazonPageWorkerImpl implements AmazonPageWorker { return url.toString(); } - private async wanderSearchSinglePage(tab: Browser.Tabs.Tab) { + private async wanderSearchSinglePage(tab: Tabs.Tab) { const tabId = tab.id!; // #region Wait for the Next button to appear, indicating that the product items have finished loading await exec(tabId, async () => { @@ -134,7 +134,7 @@ class AmazonPageWorkerImpl implements AmazonPageWorker { return { data, hasNextPage }; } - public async wanderSearchList(): Promise { + public async wanderSearchPage(): Promise { const tab = await this.getCurrentTab(); let stopSignal = false; const stop = async (_: unknown): Promise => { @@ -240,6 +240,23 @@ class AmazonPageWorkerImpl implements AmazonPageWorker { }); } //#endregion + //#region Fetch Goods' Images + const imageUrls = await exec(tab.id!, async () => { + const node = document.evaluate( + `//div[@id='imgTagWrapperId']/img`, + document, + null, + XPathResult.FIRST_ORDERED_NODE_TYPE, + null, + ).singleNodeValue as HTMLImageElement | null; + return node ? [node.getAttribute('src')!] : null; + }); + imageUrls && + this.channel.emit('item-images-collected', { + asin, + urls: imageUrls, + }); + //#endregion } } diff --git a/src/logic/page-worker/types.d.ts b/src/logic/page-worker/types.d.ts index 010fc9b..c6ceef3 100644 --- a/src/logic/page-worker/types.d.ts +++ b/src/logic/page-worker/types.d.ts @@ -26,6 +26,14 @@ interface AmazonPageWorkerEvents { category2?: { name: string; rank: number }; }; + /** + * The event is fired when images collected + */ + ['item-images-collected']: { + asin: string; + urls: string[]; + }; + /** * Error event that occurs when there is an issue with the Amazon page worker. */ @@ -49,7 +57,7 @@ interface AmazonPageWorker { /** * Browsing goods search page and collect links to those goods. */ - wanderSearchList(): Promise; + wanderSearchPage(): Promise; /** * Browsing goods detail page and collect target information. diff --git a/src/manifest.ts b/src/manifest.ts index e626f87..6bb2184 100644 --- a/src/manifest.ts +++ b/src/manifest.ts @@ -15,11 +15,6 @@ export async function getManifest() { description: pkg.description, action: { default_icon: './assets/icon-512.png', - default_popup: './dist/popup/index.html', - }, - options_ui: { - page: './dist/options/index.html', - open_in_tab: true, }, background: isFirefox ? { diff --git a/src/options/Options.vue b/src/options/Options.vue deleted file mode 100644 index 29b5196..0000000 --- a/src/options/Options.vue +++ /dev/null @@ -1,39 +0,0 @@ - - - - - diff --git a/src/options/index.html b/src/options/index.html deleted file mode 100644 index 72ab198..0000000 --- a/src/options/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - Options - - -
- - - diff --git a/src/options/main.ts b/src/options/main.ts deleted file mode 100644 index a1aa667..0000000 --- a/src/options/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { createApp } from 'vue'; -import App from './Options.vue'; -import { setupApp } from '~/logic/common-setup'; -import '../styles'; - -const app = createApp(App); -setupApp(app); -app.mount('#app'); diff --git a/src/popup/Popup.vue b/src/popup/Popup.vue deleted file mode 100644 index 1614abf..0000000 --- a/src/popup/Popup.vue +++ /dev/null @@ -1,43 +0,0 @@ - - - - - diff --git a/src/popup/index.html b/src/popup/index.html deleted file mode 100644 index 28ab624..0000000 --- a/src/popup/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - Popup - - -
- - - diff --git a/src/popup/main.ts b/src/popup/main.ts deleted file mode 100644 index a9d6ea0..0000000 --- a/src/popup/main.ts +++ /dev/null @@ -1,7 +0,0 @@ -import App from './Popup.vue'; -import { setupApp } from '~/logic/common-setup'; -import '../styles'; - -const app = createApp(App); -setupApp(app); -app.mount('#app'); diff --git a/src/sidepanel/Sidepanel.vue b/src/sidepanel/Sidepanel.vue index f04cc57..845baa0 100644 --- a/src/sidepanel/Sidepanel.vue +++ b/src/sidepanel/Sidepanel.vue @@ -72,7 +72,7 @@ const onCollect = async () => { message.error(msg); }); await worker.doSearch(keywords.value); - await worker.wanderSearchList(); + await worker.wanderSearchPage(); message.info('完成'); }; diff --git a/vite.config.mts b/vite.config.mts index b270fb0..14bfd29 100644 --- a/vite.config.mts +++ b/vite.config.mts @@ -94,8 +94,6 @@ export default defineConfig(({ command }) => ({ }, rollupOptions: { input: { - options: r('src/options/index.html'), - popup: r('src/popup/index.html'), sidepanel: r('src/sidepanel/index.html'), }, },