Adjust firefox config

This commit is contained in:
johnathan 2025-06-25 14:15:25 +08:00
parent 2ef935fd9a
commit 105bfadfa3
16 changed files with 172 additions and 122 deletions

1
.gitignore vendored
View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -0,0 +1,3 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M26.6667 1.66667H24V7H8V9.66667H5.33333V20.3333H8V23H10.6667V28.3333H21.3333V25.6667H26.6667V23H21.3333V20.3333H26.6667V17.6667H21.3333V15H10.6667V20.3333H8V9.66667H24V7H26.6667V1.66667ZM18.6667 25.6667H13.3333V17.6667H18.6667V25.6667Z" fill="#888888"/>
</svg>

After

Width:  |  Height:  |  Size: 366 B

View File

@ -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"

10
pnpm-lock.yaml generated
View File

@ -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:

View File

@ -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: ['<all_urls>'],
js: ['dist/contentScripts/index.global.js'],
},
];
manifest.web_accessible_resources = isFirefox
? ['dist/contentScripts/index.css']
: [
{
resources: ['dist/contentScripts/index.css'],
matches: ['<all_urls>'],
},
];
// 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');

View File

@ -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('<div id="app"></div>', '<div id="app">Vite server did not start</div>');
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();
});
}

View File

@ -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);

View File

@ -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');
if (USE_SIDE_PANEL && !isFirefox) {
browser.contextMenus.create({
id: 'show-result',
title: '结果页',
contexts: ['action'],
});
}
});
browser.contextMenus.onClicked.addListener((info) => {

View File

@ -4,6 +4,7 @@ const forbiddenProtocols = [
'chrome://',
'devtools://',
'edge://',
'moz-extension://',
'https://chrome.google.com/webstore',
];

19
src/global.d.ts vendored
View File

@ -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;

View File

@ -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<T, P extends Record<string, unknown>>(
): Promise<T> {
const { timeout = 30000 } = options;
return new Promise<T>(async (resolve, reject) => {
if (isFirefox) {
while (true) {
const tab = await browser.tabs.get(tabId);
if (tab.status === 'complete') {
break;
}
await new Promise<void>((r) => setTimeout(r, 100));
}
}
setTimeout(() => reject('脚本运行超时'), timeout);
try {
const injectResults = await browser.scripting.executeScript({

View File

@ -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: ['<all_urls>'],
js: ['dist/contentScripts/index.global.js'],
},
],
web_accessible_resources: [
{
resources: ['dist/contentScripts/index.css'],
matches: ['<all_urls>'],
},
],
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;
}

View File

@ -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,

View File

@ -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,

View File

@ -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'),