From 105bfadfa3e34305d6e97d05678262e9cc2caadf Mon Sep 17 00:00:00 2001 From: johnathan <952508490@qq.com> Date: Wed, 25 Jun 2025 14:15:25 +0800 Subject: [PATCH] Adjust firefox config --- .gitignore | 3 +- extension-firefox/assets/icon-512.png | Bin 0 -> 2338 bytes extension-firefox/assets/icon.svg | 3 + package.json | 17 ++--- pnpm-lock.yaml | 10 +-- scripts/manifest.ts | 99 +++++++++++++++++++++++++- scripts/prepare.ts | 8 +-- scripts/utils.ts | 1 + src/background/main.ts | 21 +++--- src/env.ts | 1 + src/global.d.ts | 19 +++++ src/logic/execute-script.ts | 11 +++ src/manifest.ts | 79 -------------------- vite.config.background.mts | 8 +-- vite.config.content.mts | 8 +-- vite.config.mts | 6 +- 16 files changed, 172 insertions(+), 122 deletions(-) create mode 100644 extension-firefox/assets/icon-512.png create mode 100644 extension-firefox/assets/icon.svg delete mode 100644 src/manifest.ts diff --git a/.gitignore b/.gitignore index cedc91d..e1e6686 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ dist dist-ssr extension/manifest.json +extension-firefox/manifest.json node_modules src/auto-imports.d.ts src/components.d.ts @@ -18,4 +19,4 @@ src/components.d.ts **/test_data.ts **/TestPanel.vue -**/test_notebook.ipynb \ No newline at end of file +**/test_notebook.ipynb diff --git a/extension-firefox/assets/icon-512.png b/extension-firefox/assets/icon-512.png new file mode 100644 index 0000000000000000000000000000000000000000..ed3fc20ceef99c72e965c716e078ad0d3847b87f GIT binary patch literal 2338 zcmeAS@N?(olHy`uVBq!ia0y~yU;;9k7&zE~)R&4Yzkn2Hfk$L90|U1(2s1Lwnj--e zWGoJHcVbv~PUa<$!;&U>cv7h@-A}a#}$97K_$B+ufw>K~5KK2k`xcJPmF-PsS zkKb%oQO2pQqFpj4t%T>zVeT~!e9y@Im+R7m*cme!f##418vb84Vo=GwT{gG)$DX@+ z=N|@4XH>|Hoc7(a{dl%*yYpXT28TWdh6V+o*^WSeHL(Dl$_aFz5CemN3Il_J2Lpq{ zgi!@#gu^t&w{`p9Gpnq9oyFE-$v8y9c){s{9l5vf#mVn~CL_lTOdCJsuBS%+n=2e~ zy;PE+D28z~InXFu=rOBr$h}<(%$tq!dH28DZ@>N4@WbIDlyDf@Z+-up964?O;fZy7 zuic(=;Pw9hdvk9WtT=!B?Kc@dRfY!@{iU(;hZEzNzy6Y1lV8jifB&nM%*&5az+!3L zP$_F(7}c~N-}nB!W#jL^|LmTB$bKNRZ{Gj@haU3}KV&&zz5`guT6PMvGR!%2{X_j; zW;tg2Iod;|Jl(~U`FfXLG1KjBvC~s4<$pZf_wD81y6xfpUn};m{>Rf^1gs&3MlCU& zk#DQc>G!#}+no2F^?dXD-^W|b_3eji{w@Q?5`)b9Us4R$7rxrK?sf8m_F`atJVboe sSX}Y$_rLT9&#U=JYzR<8c|pT}2K&Wv#^&2^Yy_F->FVdQ&MBb@0C&rF^8f$< literal 0 HcmV?d00001 diff --git a/extension-firefox/assets/icon.svg b/extension-firefox/assets/icon.svg new file mode 100644 index 0000000..31c2b75 --- /dev/null +++ b/extension-firefox/assets/icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/package.json b/package.json index 1b92d4d..2410fe8 100644 --- a/package.json +++ b/package.json @@ -5,14 +5,14 @@ "private": true, "description": "Starter modify by honestfox101", "scripts": { - "dev": "npm run clear && cross-env NODE_ENV=development run-p dev:*", - "dev-firefox": "npm run clear && cross-env NODE_ENV=development EXTENSION=firefox run-p dev:*", + "dev": "npm run clear && cross-env NODE_ENV=development run-p dev:prepare dev:web dev:background dev:js", + "dev-firefox": "npm run clear-firefox && cross-env NODE_ENV=development EXTENSION=firefox run-p dev:prepare dev:web dev:background dev:js", "dev:prepare": "esno scripts/prepare.ts", - "dev:background": "npm run build:background -- --mode development", "dev:web": "vite", + "dev:background": "npm run build:background -- --mode development", "dev:js": "npm run build:js -- --mode development", "build": "cross-env NODE_ENV=production run-s clear build:web build:prepare build:background build:js", - "build:firefox": "cross-env NODE_ENV=production EXTENSION=firefox run-s clear build:web build:prepare build:background build:js", + "build-firefox": "cross-env NODE_ENV=production EXTENSION=firefox run-s clear-firefox build:web build:prepare build:background build:js", "build:prepare": "esno scripts/prepare.ts", "build:background": "vite build --config vite.config.background.mts", "build:web": "vite build", @@ -23,7 +23,8 @@ "pack:xpi": "cross-env WEB_EXT_ARTIFACTS_DIR=./ web-ext build --source-dir ./extension --filename extension.xpi --overwrite-dest", "start:chromium": "web-ext run --source-dir ./extension --target=chromium", "start:firefox": "web-ext run --source-dir ./extension --target=firefox-desktop", - "clear": "rimraf --glob extension/dist extension/manifest.json extension.*", + "clear": "rimraf --glob extension/dist extension/manifest.json extension.* ", + "clear-firefox": "rimraf --glob extension-firefox/dist extension-firefox/manifest.json extension.*", "test": "vitest test", "typecheck": "tsc --noEmit", "prepare": "husky" @@ -33,7 +34,7 @@ "@iconify/json": "^2.2.293", "@types/fs-extra": "^11.0.4", "@types/node": "^22.10.5", - "@types/webextension-polyfill": "^0.12.1", + "@types/webextension-polyfill": "^0.12.3", "@vitejs/plugin-vue": "^5.2.1", "@vitejs/plugin-vue-jsx": "^4.2.0", "@vue/test-utils": "^2.4.6", @@ -66,8 +67,8 @@ "vue-demi": "^0.14.10", "vue-router": "^4.5.1", "web-ext": "^8.5.0", - "webextension-polyfill": "^0.12.0", - "webext-bridge": "link:webext-bridge" + "webext-bridge": "link:webext-bridge", + "webextension-polyfill": "^0.12.0" }, "lint-staged": { "**/*": "prettier --write --ignore-unknown" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ee07671..4b560ff 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,8 +20,8 @@ importers: specifier: ^22.10.5 version: 22.10.5 '@types/webextension-polyfill': - specifier: ^0.12.1 - version: 0.12.1 + specifier: ^0.12.3 + version: 0.12.3 '@vitejs/plugin-vue': specifier: ^5.2.1 version: 5.2.1(vite@6.2.4(@types/node@22.10.5)(sass-embedded@1.86.2)(tsx@4.19.2)(yaml@2.7.1))(vue@3.5.13(typescript@5.8.2)) @@ -1370,10 +1370,10 @@ packages: integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==, } - '@types/webextension-polyfill@0.12.1': + '@types/webextension-polyfill@0.12.3': resolution: { - integrity: sha512-xPTFWwQ8BxPevPF2IKsf4hpZNss4LxaOLZXypQH4E63BDLmcwX/RMGdI4tB4VO4Nb6xDBH3F/p4gz4wvof1o9w==, + integrity: sha512-F58aDVSeN/MjUGazXo/cPsmR76EvqQhQ1v4x23hFjUX0cfAJYE+JBWwiOGW36/VJGGxoH74sVlRIF3z7SJCKyg==, } '@types/yauzl@2.10.3': @@ -7484,7 +7484,7 @@ snapshots: '@types/web-bluetooth@0.0.20': {} - '@types/webextension-polyfill@0.12.1': {} + '@types/webextension-polyfill@0.12.3': {} '@types/yauzl@2.10.3': dependencies: diff --git a/scripts/manifest.ts b/scripts/manifest.ts index 16b3ee3..047d8b6 100644 --- a/scripts/manifest.ts +++ b/scripts/manifest.ts @@ -1,9 +1,102 @@ import fs from 'fs-extra'; -import { getManifest } from '../src/manifest'; -import { log, r } from './utils'; +import { isDev, isFirefox, log, outputDir, port, r } from './utils'; +import { type Manifest } from 'webextension-polyfill'; +import type PkgType from '../package.json'; + +async function getManifest() { + const pkg = (await fs.readJSON(r('package.json'))) as typeof PkgType; + + // update this file to update this manifest.json + // can also be conditional based on your need + const manifest: Manifest.WebExtensionManifest = { + manifest_version: isFirefox ? 2 : 3, + name: pkg.displayName || pkg.name, + version: pkg.version, + description: pkg.description, + options_ui: { + page: './dist/options/index.html', + open_in_tab: true, + }, + background: isFirefox + ? { + scripts: ['dist/background/index.mjs'], + type: 'module', + } + : { + service_worker: './dist/background/index.mjs', + }, + icons: { + 16: './assets/icon-512.png', + 48: './assets/icon-512.png', + 128: './assets/icon-512.png', + }, + permissions: ['tabs', 'storage', 'activeTab', 'scripting', 'unlimitedStorage', 'contextMenus'], + content_security_policy: { + extension_pages: isDev + ? `script-src \'self\' http://localhost:${port}; object-src \'self\';` + : "script-src 'self'; object-src 'self'", + }, + }; + + // add extension action icon + if (!isFirefox) { + manifest.action = { + default_icon: './assets/icon-512.png', + }; + } + + // add host permissions + if (isFirefox) { + manifest.permissions?.push('*://*/*'); + } else { + manifest.host_permissions = ['*://*/*']; + } + + // add content security policy + if (isFirefox) { + manifest.content_security_policy = `script-src 'self' http://localhost:${port}; object-src 'self';`; + } else { + manifest.content_security_policy = { + extension_pages: isDev + ? `script-src 'self' http://localhost:${port}; object-src 'self';` + : "script-src 'self'; object-src 'self'", + }; + } + + // add content scripts + manifest.content_scripts = [ + { + matches: [''], + js: ['dist/contentScripts/index.global.js'], + }, + ]; + manifest.web_accessible_resources = isFirefox + ? ['dist/contentScripts/index.css'] + : [ + { + resources: ['dist/contentScripts/index.css'], + matches: [''], + }, + ]; + + // add sidepanel + if (isFirefox) { + manifest.sidebar_action = { + default_panel: 'dist/sidepanel/index.html', + }; + } else { + // the sidebar_action does not work for chromium based + (manifest as any).side_panel = { + default_path: 'dist/sidepanel/index.html', + }; + manifest.permissions?.push('sidePanel'); + } + + return manifest; +} export async function writeManifest() { - await fs.writeJSON(r('extension/manifest.json'), await getManifest(), { + await fs.writeJSON(r(`${outputDir}/manifest.json`), await getManifest(), { spaces: 2, }); log('PRE', 'write manifest.json'); diff --git a/scripts/prepare.ts b/scripts/prepare.ts index 3bc062b..ee1995e 100644 --- a/scripts/prepare.ts +++ b/scripts/prepare.ts @@ -2,7 +2,7 @@ import { execSync } from 'node:child_process'; import fs from 'fs-extra'; import chokidar from 'chokidar'; -import { isDev, log, port, r } from './utils'; +import { isDev, log, outputDir, port, r } from './utils'; /** * Stub index.html to use Vite in development @@ -11,12 +11,12 @@ async function stubIndexHtml() { const views = ['sidepanel', 'options']; for (const view of views) { - await fs.ensureDir(r(`extension/dist/${view}`)); + await fs.ensureDir(r(`${outputDir}/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
'); - await fs.writeFile(r(`extension/dist/${view}/index.html`), data, 'utf-8'); + await fs.writeFile(r(`${outputDir}/dist/${view}/index.html`), data, 'utf-8'); log('PRE', `stub ${view}`); } } @@ -32,7 +32,7 @@ if (isDev) { chokidar.watch(r('src/**/*.html')).on('change', () => { stubIndexHtml(); }); - chokidar.watch([r('src/manifest.ts'), r('package.json')]).on('change', () => { + chokidar.watch([r('scripts/manifest.ts'), r('package.json')]).on('change', () => { writeManifest(); }); } diff --git a/scripts/utils.ts b/scripts/utils.ts index 679a09c..e6f0f11 100644 --- a/scripts/utils.ts +++ b/scripts/utils.ts @@ -6,6 +6,7 @@ export const port = Number(process.env.PORT || '') || 3303; export const r = (...args: string[]) => resolve(__dirname, '..', ...args); export const isDev = process.env.NODE_ENV !== 'production'; export const isFirefox = process.env.EXTENSION === 'firefox'; +export const outputDir = isFirefox ? 'extension-firefox' : 'extension'; export function log(name: string, message: string) { console.log(black(bgCyan(` ${name} `)), message); diff --git a/src/background/main.ts b/src/background/main.ts index 271f8ed..dbe4f85 100644 --- a/src/background/main.ts +++ b/src/background/main.ts @@ -1,3 +1,5 @@ +import { isFirefox } from '~/env'; + // https://github.com/serversideup/webext-bridge/issues/67#issuecomment-2676094094 import('webext-bridge/background'); @@ -13,22 +15,21 @@ if (import.meta.hot) { const USE_SIDE_PANEL = true; // to toggle the sidepanel with the action button in chromium: -if (USE_SIDE_PANEL) { - // @ts-expect-error missing types - browser.sidePanel - .setPanelBehavior({ openPanelOnActionClick: true }) - .catch((error: unknown) => console.error(error)); +if (USE_SIDE_PANEL && !isFirefox) { + (browser as unknown as Chrome).sidePanel?.setPanelBehavior({ openPanelOnActionClick: true }); } browser.runtime.onInstalled.addListener(() => { // eslint-disable-next-line no-console console.log('Azon Seeker installed'); - browser.contextMenus.create({ - id: 'show-result', - title: '结果页', - contexts: ['action'], - }); + if (USE_SIDE_PANEL && !isFirefox) { + browser.contextMenus.create({ + id: 'show-result', + title: '结果页', + contexts: ['action'], + }); + } }); browser.contextMenus.onClicked.addListener((info) => { diff --git a/src/env.ts b/src/env.ts index 22128e7..ea86683 100644 --- a/src/env.ts +++ b/src/env.ts @@ -4,6 +4,7 @@ const forbiddenProtocols = [ 'chrome://', 'devtools://', 'edge://', + 'moz-extension://', 'https://chrome.google.com/webstore', ]; diff --git a/src/global.d.ts b/src/global.d.ts index a5ea335..2ae7115 100644 --- a/src/global.d.ts +++ b/src/global.d.ts @@ -9,6 +9,25 @@ declare module '*.vue' { export default component; } +declare interface Chrome { + sidePanel?: { + setPanelBehavior: (options: { openPanelOnActionClick: boolean }) => void; + setOptions: (options: { path?: string }) => void; + onShown: { + addListener: (callback: () => void) => void; + removeListener: (callback: () => void) => void; + hasListener: (callback: () => void) => boolean; + }; + onHidden: { + addListener: (callback: () => void) => void; + removeListener: (callback: () => void) => void; + hasListener: (callback: () => void) => boolean; + }; + // V3 还支持指定页面的侧边栏配置 + getOptions: (options: { tabId?: number }) => Promise<{ path?: string }>; + }; +} + declare type AmazonSearchItem = { keywords: string; page: number; diff --git a/src/logic/execute-script.ts b/src/logic/execute-script.ts index 0710cc6..c03411c 100644 --- a/src/logic/execute-script.ts +++ b/src/logic/execute-script.ts @@ -1,3 +1,5 @@ +import { isFirefox } from '~/env'; + /** * 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. @@ -45,6 +47,15 @@ export async function exec>( ): Promise { const { timeout = 30000 } = options; return new Promise(async (resolve, reject) => { + if (isFirefox) { + while (true) { + const tab = await browser.tabs.get(tabId); + if (tab.status === 'complete') { + break; + } + await new Promise((r) => setTimeout(r, 100)); + } + } setTimeout(() => reject('脚本运行超时'), timeout); try { const injectResults = await browser.scripting.executeScript({ diff --git a/src/manifest.ts b/src/manifest.ts deleted file mode 100644 index f97a72a..0000000 --- a/src/manifest.ts +++ /dev/null @@ -1,79 +0,0 @@ -import fs from 'fs-extra'; -import { type Manifest } from 'webextension-polyfill'; -import type PkgType from '../package.json'; -import { isDev, isFirefox, port, r } from '../scripts/utils'; - -export async function getManifest() { - const pkg = (await fs.readJSON(r('package.json'))) as typeof PkgType; - - // update this file to update this manifest.json - // can also be conditional based on your need - const manifest: Manifest.WebExtensionManifest = { - manifest_version: 3, - name: pkg.displayName || pkg.name, - version: pkg.version, - description: pkg.description, - action: { - default_icon: './assets/icon-512.png', - }, - options_ui: { - page: './dist/options/index.html', - open_in_tab: true, - }, - background: isFirefox - ? { - scripts: ['dist/background/index.mjs'], - type: 'module', - } - : { - service_worker: './dist/background/index.mjs', - }, - icons: { - 16: './assets/icon-512.png', - 48: './assets/icon-512.png', - 128: './assets/icon-512.png', - }, - permissions: [ - 'tabs', - 'storage', - 'activeTab', - 'sidePanel', - 'scripting', - 'unlimitedStorage', - 'contextMenus', - ], - host_permissions: ['*://*/*'], - content_scripts: [ - { - matches: [''], - js: ['dist/contentScripts/index.global.js'], - }, - ], - web_accessible_resources: [ - { - resources: ['dist/contentScripts/index.css'], - matches: [''], - }, - ], - content_security_policy: { - extension_pages: isDev - ? // this is required on dev for Vite script to load - `script-src \'self\' http://localhost:${port}; object-src \'self\'` - : "script-src 'self'; object-src 'self'", - }, - }; - - // add sidepanel - if (isFirefox) { - manifest.sidebar_action = { - default_panel: 'dist/sidepanel/index.html', - }; - } else { - // the sidebar_action does not work for chromium based - (manifest as any).side_panel = { - default_path: 'dist/sidepanel/index.html', - }; - } - - return manifest; -} diff --git a/vite.config.background.mts b/vite.config.background.mts index 502f1df..575e0de 100644 --- a/vite.config.background.mts +++ b/vite.config.background.mts @@ -1,6 +1,6 @@ import { defineConfig } from 'vite'; import { sharedConfig } from './vite.config.mjs'; -import { isDev, r } from './scripts/utils'; +import { isDev, outputDir, r } from './scripts/utils'; import packageJson from './package.json'; // bundling the content script using Vite @@ -11,13 +11,11 @@ export default defineConfig({ __NAME__: JSON.stringify(packageJson.name), // https://github.com/vitejs/vite/issues/9320 // https://github.com/vitejs/vite/issues/9186 - 'process.env.NODE_ENV': JSON.stringify( - isDev ? 'development' : 'production', - ), + 'process.env.NODE_ENV': JSON.stringify(isDev ? 'development' : 'production'), }, build: { watch: isDev ? {} : undefined, - outDir: r('extension/dist/background'), + outDir: r(`${outputDir}/dist/background`), cssCodeSplit: false, emptyOutDir: false, sourcemap: isDev ? 'inline' : false, diff --git a/vite.config.content.mts b/vite.config.content.mts index 19f3aac..3f3b9ed 100644 --- a/vite.config.content.mts +++ b/vite.config.content.mts @@ -1,6 +1,6 @@ import { defineConfig } from 'vite'; import { sharedConfig } from './vite.config.mjs'; -import { isDev, r } from './scripts/utils'; +import { isDev, outputDir, r } from './scripts/utils'; import packageJson from './package.json'; // bundling the content script using Vite @@ -11,13 +11,11 @@ export default defineConfig({ __NAME__: JSON.stringify(packageJson.name), // https://github.com/vitejs/vite/issues/9320 // https://github.com/vitejs/vite/issues/9186 - 'process.env.NODE_ENV': JSON.stringify( - isDev ? 'development' : 'production', - ), + 'process.env.NODE_ENV': JSON.stringify(isDev ? 'development' : 'production'), }, build: { watch: isDev ? {} : undefined, - outDir: r('extension/dist/contentScripts'), + outDir: r(`${outputDir}/dist/contentScripts`), cssCodeSplit: false, emptyOutDir: false, sourcemap: isDev ? 'inline' : false, diff --git a/vite.config.mts b/vite.config.mts index 1ee9722..143d825 100644 --- a/vite.config.mts +++ b/vite.config.mts @@ -11,7 +11,7 @@ import Components from 'unplugin-vue-components/vite'; import AutoImport from 'unplugin-auto-import/vite'; import { NaiveUiResolver } from 'unplugin-vue-components/resolvers'; -import { isDev, port, r } from './scripts/utils'; +import { isDev, outputDir, port, r } from './scripts/utils'; import packageJson from './package.json'; export const sharedConfig: UserConfig = { @@ -87,16 +87,18 @@ export default defineConfig(({ command }) => ({ host: 'localhost', }, origin: `http://localhost:${port}`, + cors: { origin: [/moz-extension:\/\/.+/] }, }, build: { watch: isDev ? {} : undefined, - outDir: r('extension/dist'), + outDir: r(`${outputDir}/dist`), emptyOutDir: false, sourcemap: isDev ? 'inline' : false, // https://developer.chrome.com/docs/webstore/program_policies/#:~:text=Code%20Readability%20Requirements terserOptions: { mangle: false, }, + chunkSizeWarningLimit: 1024, // 1MB rollupOptions: { input: { sidepanel: r('src/sidepanel/index.html'),