Refactor source structure and update build process
Moved source files into a structured src/ directory for better organization. Updated build.py to copy and flatten files from src/ during the build process for Chrome and Firefox, introducing a new flatten_for_browser function. Improved .gitignore to exclude additional build artifacts. Also reformatted and improved error handling in webext-compat.js.
This commit is contained in:
1 parent
00ee7e6592
commit
7dee5da5ed
10 files changed
+181
-81
No files matched your search
@@ -7,7 +7,9 @@ yarn-error.log*
|
|||||||
# Build outputs
|
# Build outputs
|
||||||
dist/
|
dist/
|
||||||
build/
|
build/
|
||||||
|
packages/
|
||||||
*.zip
|
*.zip
|
||||||
|
*.xpi
|
||||||
extension.zip
|
extension.zip
|
||||||
|
|
||||||
# OS generated files
|
# OS generated files
|
||||||
|
|||||||
@@ -43,20 +43,22 @@ def copy_common_files(build_dir):
|
|||||||
Args:
|
Args:
|
||||||
build_dir (Path): 目标构建目录
|
build_dir (Path): 目标构建目录
|
||||||
"""
|
"""
|
||||||
common_files = [
|
# 创建 src 目录结构
|
||||||
"webext-compat.js",
|
src_dir = build_dir / "src"
|
||||||
"background.js",
|
|
||||||
"content.js",
|
# 复制源代码目录
|
||||||
"popup.js",
|
if os.path.exists("src"):
|
||||||
"popup.html",
|
shutil.copytree("src", src_dir, dirs_exist_ok=True)
|
||||||
"platforms.js",
|
|
||||||
|
# 复制根目录的文档文件
|
||||||
|
doc_files = [
|
||||||
"LICENSE",
|
"LICENSE",
|
||||||
"README.md",
|
"README.md",
|
||||||
"PRIVACY_POLICY.md",
|
"PRIVACY_POLICY.md",
|
||||||
"SECURITY.md",
|
"SECURITY.md",
|
||||||
]
|
]
|
||||||
|
|
||||||
for file in common_files:
|
for file in doc_files:
|
||||||
if os.path.exists(file):
|
if os.path.exists(file):
|
||||||
shutil.copy2(file, build_dir)
|
shutil.copy2(file, build_dir)
|
||||||
|
|
||||||
@@ -81,8 +83,8 @@ def build_chrome():
|
|||||||
# 复制 Chrome manifest
|
# 复制 Chrome manifest
|
||||||
shutil.copy2("manifest.json", build_dir / "manifest.json")
|
shutil.copy2("manifest.json", build_dir / "manifest.json")
|
||||||
|
|
||||||
# 修改 background.js 为 Chrome 优化
|
# 为 Chrome 创建扁平化的文件结构
|
||||||
optimize_for_chrome(build_dir)
|
flatten_for_browser(build_dir, "chrome")
|
||||||
|
|
||||||
print(f"Chrome 版本构建完成: {build_dir}")
|
print(f"Chrome 版本构建完成: {build_dir}")
|
||||||
return build_dir
|
return build_dir
|
||||||
@@ -104,13 +106,79 @@ def build_firefox():
|
|||||||
# 复制 Firefox manifest
|
# 复制 Firefox manifest
|
||||||
shutil.copy2("manifest-firefox.json", build_dir / "manifest.json")
|
shutil.copy2("manifest-firefox.json", build_dir / "manifest.json")
|
||||||
|
|
||||||
# 优化文件以适配 Firefox
|
# 为 Firefox 创建扁平化的文件结构
|
||||||
optimize_for_firefox(build_dir)
|
flatten_for_browser(build_dir, "firefox")
|
||||||
|
|
||||||
print(f"Firefox 版本构建完成: {build_dir}")
|
print(f"Firefox 版本构建完成: {build_dir}")
|
||||||
return build_dir
|
return build_dir
|
||||||
|
|
||||||
|
|
||||||
|
def flatten_for_browser(build_dir, platform):
|
||||||
|
"""
|
||||||
|
将 src 目录中的文件扁平化到构建目录根
|
||||||
|
|
||||||
|
Args:
|
||||||
|
build_dir (Path): 构建目录路径
|
||||||
|
platform (str): 目标平台 (chrome/firefox)
|
||||||
|
"""
|
||||||
|
src_dir = build_dir / "src"
|
||||||
|
|
||||||
|
if not src_dir.exists():
|
||||||
|
print(f"警告: {src_dir} 不存在")
|
||||||
|
return
|
||||||
|
|
||||||
|
# 将文件从 src 子目录移动到根目录
|
||||||
|
# background/index.js -> background.js
|
||||||
|
bg_file = src_dir / "background" / "index.js"
|
||||||
|
if bg_file.exists():
|
||||||
|
shutil.copy2(bg_file, build_dir / "background.js")
|
||||||
|
|
||||||
|
# content/index.js -> content.js
|
||||||
|
content_file = src_dir / "content" / "index.js"
|
||||||
|
if content_file.exists():
|
||||||
|
shutil.copy2(content_file, build_dir / "content.js")
|
||||||
|
|
||||||
|
# popup/index.html -> popup.html
|
||||||
|
popup_html = src_dir / "popup" / "index.html"
|
||||||
|
if popup_html.exists():
|
||||||
|
shutil.copy2(popup_html, build_dir / "popup.html")
|
||||||
|
|
||||||
|
# popup/popup.js -> popup.js
|
||||||
|
popup_js = src_dir / "popup" / "popup.js"
|
||||||
|
if popup_js.exists():
|
||||||
|
shutil.copy2(popup_js, build_dir / "popup.js")
|
||||||
|
|
||||||
|
# shared/platforms.js -> platforms.js
|
||||||
|
platforms_file = src_dir / "shared" / "platforms.js"
|
||||||
|
if platforms_file.exists():
|
||||||
|
shutil.copy2(platforms_file, build_dir / "platforms.js")
|
||||||
|
|
||||||
|
# shared/platform-detector.js -> platform-detector.js
|
||||||
|
detector_file = src_dir / "shared" / "platform-detector.js"
|
||||||
|
if detector_file.exists():
|
||||||
|
shutil.copy2(detector_file, build_dir / "platform-detector.js")
|
||||||
|
|
||||||
|
# shared/compat/webext-compat.js -> webext-compat.js
|
||||||
|
webext_compat = src_dir / "shared" / "compat" / "webext-compat.js"
|
||||||
|
if webext_compat.exists():
|
||||||
|
shutil.copy2(webext_compat, build_dir / "webext-compat.js")
|
||||||
|
|
||||||
|
# shared/compat/firefox-compat.js -> firefox-compat.js
|
||||||
|
firefox_compat = src_dir / "shared" / "compat" / "firefox-compat.js"
|
||||||
|
if firefox_compat.exists():
|
||||||
|
shutil.copy2(firefox_compat, build_dir / "firefox-compat.js")
|
||||||
|
|
||||||
|
# 删除 src 目录
|
||||||
|
if src_dir.exists():
|
||||||
|
shutil.rmtree(src_dir)
|
||||||
|
|
||||||
|
# 平台特定优化
|
||||||
|
if platform == "chrome":
|
||||||
|
optimize_for_chrome(build_dir)
|
||||||
|
elif platform == "firefox":
|
||||||
|
optimize_for_firefox(build_dir)
|
||||||
|
|
||||||
|
|
||||||
def optimize_for_chrome(build_dir):
|
def optimize_for_chrome(build_dir):
|
||||||
"""
|
"""
|
||||||
为 Chrome 优化文件
|
为 Chrome 优化文件
|
||||||
|
|||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -23,7 +23,7 @@
|
|||||||
const detectBrowser = () => {
|
const detectBrowser = () => {
|
||||||
const ua = navigator.userAgent;
|
const ua = navigator.userAgent;
|
||||||
let manifest;
|
let manifest;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
manifest = chrome.runtime.getManifest();
|
manifest = chrome.runtime.getManifest();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -101,7 +101,7 @@ const webext = (() => {
|
|||||||
runtime: { getManifest: () => ({ version: "0.0.0" }) },
|
runtime: { getManifest: () => ({ version: "0.0.0" }) },
|
||||||
storage: { local: {}, sync: {} },
|
storage: { local: {}, sync: {} },
|
||||||
tabs: {},
|
tabs: {},
|
||||||
downloads: {}
|
downloads: {},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,7 +162,10 @@ const webext = (() => {
|
|||||||
// sendMessage(message)
|
// sendMessage(message)
|
||||||
runtimeAPI.sendMessage(args[0], (response) => {
|
runtimeAPI.sendMessage(args[0], (response) => {
|
||||||
if (api.runtime.lastError) {
|
if (api.runtime.lastError) {
|
||||||
console.warn("SendMessage failed:", api.runtime.lastError.message);
|
console.warn(
|
||||||
|
"SendMessage failed:",
|
||||||
|
api.runtime.lastError.message
|
||||||
|
);
|
||||||
resolve(null);
|
resolve(null);
|
||||||
} else {
|
} else {
|
||||||
resolve(response);
|
resolve(response);
|
||||||
@@ -170,15 +173,18 @@ const webext = (() => {
|
|||||||
});
|
});
|
||||||
} else if (args.length === 2) {
|
} else if (args.length === 2) {
|
||||||
// 检查第二个参数是否是函数(回调)
|
// 检查第二个参数是否是函数(回调)
|
||||||
if (typeof args[1] === 'function') {
|
if (typeof args[1] === "function") {
|
||||||
// sendMessage(message, callback) - 直接调用回调,不使用 Promise
|
// sendMessage(message, callback) - 直接调用回调,不使用 Promise
|
||||||
runtimeAPI.sendMessage(args[0], args[1]);
|
runtimeAPI.sendMessage(args[0], args[1]);
|
||||||
resolve(undefined); // 立即解析 Promise
|
resolve(undefined); // 立即解析 Promise
|
||||||
} else if (typeof args[0] === 'string' && args[0].length > 10) {
|
} else if (typeof args[0] === "string" && args[0].length > 10) {
|
||||||
// sendMessage(extensionId, message)
|
// sendMessage(extensionId, message)
|
||||||
runtimeAPI.sendMessage(args[0], args[1], (response) => {
|
runtimeAPI.sendMessage(args[0], args[1], (response) => {
|
||||||
if (api.runtime.lastError) {
|
if (api.runtime.lastError) {
|
||||||
console.warn("SendMessage failed:", api.runtime.lastError.message);
|
console.warn(
|
||||||
|
"SendMessage failed:",
|
||||||
|
api.runtime.lastError.message
|
||||||
|
);
|
||||||
resolve(null);
|
resolve(null);
|
||||||
} else {
|
} else {
|
||||||
resolve(response);
|
resolve(response);
|
||||||
@@ -188,7 +194,10 @@ const webext = (() => {
|
|||||||
// sendMessage(message, options)
|
// sendMessage(message, options)
|
||||||
runtimeAPI.sendMessage(args[0], args[1], (response) => {
|
runtimeAPI.sendMessage(args[0], args[1], (response) => {
|
||||||
if (api.runtime.lastError) {
|
if (api.runtime.lastError) {
|
||||||
console.warn("SendMessage failed:", api.runtime.lastError.message);
|
console.warn(
|
||||||
|
"SendMessage failed:",
|
||||||
|
api.runtime.lastError.message
|
||||||
|
);
|
||||||
resolve(null);
|
resolve(null);
|
||||||
} else {
|
} else {
|
||||||
resolve(response);
|
resolve(response);
|
||||||
@@ -197,7 +206,7 @@ const webext = (() => {
|
|||||||
}
|
}
|
||||||
} else if (args.length === 3) {
|
} else if (args.length === 3) {
|
||||||
// 检查第三个参数是否是函数(回调)
|
// 检查第三个参数是否是函数(回调)
|
||||||
if (typeof args[2] === 'function') {
|
if (typeof args[2] === "function") {
|
||||||
// sendMessage(extensionId, message, callback) 或 sendMessage(message, options, callback)
|
// sendMessage(extensionId, message, callback) 或 sendMessage(message, options, callback)
|
||||||
runtimeAPI.sendMessage(args[0], args[1], args[2]);
|
runtimeAPI.sendMessage(args[0], args[1], args[2]);
|
||||||
resolve(undefined); // 立即解析 Promise
|
resolve(undefined); // 立即解析 Promise
|
||||||
@@ -205,14 +214,17 @@ const webext = (() => {
|
|||||||
// sendMessage(extensionId, message, options)
|
// sendMessage(extensionId, message, options)
|
||||||
runtimeAPI.sendMessage(args[0], args[1], args[2], (response) => {
|
runtimeAPI.sendMessage(args[0], args[1], args[2], (response) => {
|
||||||
if (api.runtime.lastError) {
|
if (api.runtime.lastError) {
|
||||||
console.warn("SendMessage failed:", api.runtime.lastError.message);
|
console.warn(
|
||||||
|
"SendMessage failed:",
|
||||||
|
api.runtime.lastError.message
|
||||||
|
);
|
||||||
resolve(null);
|
resolve(null);
|
||||||
} else {
|
} else {
|
||||||
resolve(response);
|
resolve(response);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (args.length === 4 && typeof args[3] === 'function') {
|
} else if (args.length === 4 && typeof args[3] === "function") {
|
||||||
// sendMessage(extensionId, message, options, callback)
|
// sendMessage(extensionId, message, options, callback)
|
||||||
runtimeAPI.sendMessage(args[0], args[1], args[2], args[3]);
|
runtimeAPI.sendMessage(args[0], args[1], args[2], args[3]);
|
||||||
resolve(undefined); // 立即解析 Promise
|
resolve(undefined); // 立即解析 Promise
|
||||||
@@ -244,7 +256,10 @@ const webext = (() => {
|
|||||||
// sendMessage(tabId, message)
|
// sendMessage(tabId, message)
|
||||||
tabsAPI.sendMessage(tabId, message, (response) => {
|
tabsAPI.sendMessage(tabId, message, (response) => {
|
||||||
if (api.runtime.lastError) {
|
if (api.runtime.lastError) {
|
||||||
console.warn("Tabs sendMessage failed:", api.runtime.lastError.message);
|
console.warn(
|
||||||
|
"Tabs sendMessage failed:",
|
||||||
|
api.runtime.lastError.message
|
||||||
|
);
|
||||||
resolve(null);
|
resolve(null);
|
||||||
} else {
|
} else {
|
||||||
resolve(response);
|
resolve(response);
|
||||||
@@ -254,7 +269,10 @@ const webext = (() => {
|
|||||||
// sendMessage(tabId, message, options)
|
// sendMessage(tabId, message, options)
|
||||||
tabsAPI.sendMessage(tabId, message, options, (response) => {
|
tabsAPI.sendMessage(tabId, message, options, (response) => {
|
||||||
if (api.runtime.lastError) {
|
if (api.runtime.lastError) {
|
||||||
console.warn("Tabs sendMessage failed:", api.runtime.lastError.message);
|
console.warn(
|
||||||
|
"Tabs sendMessage failed:",
|
||||||
|
api.runtime.lastError.message
|
||||||
|
);
|
||||||
resolve(null);
|
resolve(null);
|
||||||
} else {
|
} else {
|
||||||
resolve(response);
|
resolve(response);
|
||||||
@@ -285,33 +303,35 @@ const webext = (() => {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// Tabs API
|
// Tabs API
|
||||||
tabs: api.tabs ? {
|
tabs: api.tabs
|
||||||
query: promisifyNoFail(api.tabs, "query", []),
|
? {
|
||||||
get: promisifyNoFail(api.tabs, "get"),
|
query: promisifyNoFail(api.tabs, "query", []),
|
||||||
create: promisifyNoFail(api.tabs, "create"),
|
get: promisifyNoFail(api.tabs, "get"),
|
||||||
update: promisifyNoFail(api.tabs, "update"),
|
create: promisifyNoFail(api.tabs, "create"),
|
||||||
remove: promisifyNoFail(api.tabs, "remove"),
|
update: promisifyNoFail(api.tabs, "update"),
|
||||||
sendMessage: createTabsSendMessage(api.tabs),
|
remove: promisifyNoFail(api.tabs, "remove"),
|
||||||
executeScript: promisifyNoFail(api.tabs, "executeScript"),
|
sendMessage: createTabsSendMessage(api.tabs),
|
||||||
insertCSS: promisifyNoFail(api.tabs, "insertCSS"),
|
executeScript: promisifyNoFail(api.tabs, "executeScript"),
|
||||||
removeCSS: promisifyNoFail(api.tabs, "removeCSS"),
|
insertCSS: promisifyNoFail(api.tabs, "insertCSS"),
|
||||||
onUpdated: api.tabs.onUpdated,
|
removeCSS: promisifyNoFail(api.tabs, "removeCSS"),
|
||||||
onActivated: api.tabs.onActivated,
|
onUpdated: api.tabs.onUpdated,
|
||||||
onRemoved: api.tabs.onRemoved,
|
onActivated: api.tabs.onActivated,
|
||||||
} : {
|
onRemoved: api.tabs.onRemoved,
|
||||||
query: async () => [],
|
}
|
||||||
get: async () => null,
|
: {
|
||||||
create: async () => null,
|
query: async () => [],
|
||||||
update: async () => null,
|
get: async () => null,
|
||||||
remove: async () => null,
|
create: async () => null,
|
||||||
sendMessage: async () => null,
|
update: async () => null,
|
||||||
executeScript: async () => null,
|
remove: async () => null,
|
||||||
insertCSS: async () => null,
|
sendMessage: async () => null,
|
||||||
removeCSS: async () => null,
|
executeScript: async () => null,
|
||||||
onUpdated: { addListener: () => {}, removeListener: () => {} },
|
insertCSS: async () => null,
|
||||||
onActivated: { addListener: () => {}, removeListener: () => {} },
|
removeCSS: async () => null,
|
||||||
onRemoved: { addListener: () => {}, removeListener: () => {} },
|
onUpdated: { addListener: () => {}, removeListener: () => {} },
|
||||||
},
|
onActivated: { addListener: () => {}, removeListener: () => {} },
|
||||||
|
onRemoved: { addListener: () => {}, removeListener: () => {} },
|
||||||
|
},
|
||||||
|
|
||||||
// Storage API
|
// Storage API
|
||||||
storage: {
|
storage: {
|
||||||
@@ -338,35 +358,43 @@ const webext = (() => {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// Downloads API
|
// Downloads API
|
||||||
downloads: api.downloads ? {
|
downloads: api.downloads
|
||||||
download: promisifyNoFail(api.downloads, "download"),
|
? {
|
||||||
search: promisifyNoFail(api.downloads, "search", []),
|
download: promisifyNoFail(api.downloads, "download"),
|
||||||
cancel: promisifyNoFail(api.downloads, "cancel"),
|
search: promisifyNoFail(api.downloads, "search", []),
|
||||||
pause: promisifyNoFail(api.downloads, "pause"),
|
cancel: promisifyNoFail(api.downloads, "cancel"),
|
||||||
resume: promisifyNoFail(api.downloads, "resume"),
|
pause: promisifyNoFail(api.downloads, "pause"),
|
||||||
erase: promisifyNoFail(api.downloads, "erase"),
|
resume: promisifyNoFail(api.downloads, "resume"),
|
||||||
removeFile: promisifyNoFail(api.downloads, "removeFile"),
|
erase: promisifyNoFail(api.downloads, "erase"),
|
||||||
show: promisifyNoFail(api.downloads, "show"),
|
removeFile: promisifyNoFail(api.downloads, "removeFile"),
|
||||||
showDefaultFolder: promisifyNoFail(api.downloads, "showDefaultFolder"),
|
show: promisifyNoFail(api.downloads, "show"),
|
||||||
onCreated: api.downloads.onCreated,
|
showDefaultFolder: promisifyNoFail(
|
||||||
onChanged: api.downloads.onChanged,
|
api.downloads,
|
||||||
onErased: api.downloads.onErased,
|
"showDefaultFolder"
|
||||||
onDeterminingFilename: api.downloads.onDeterminingFilename,
|
),
|
||||||
} : {
|
onCreated: api.downloads.onCreated,
|
||||||
download: async () => null,
|
onChanged: api.downloads.onChanged,
|
||||||
search: async () => [],
|
onErased: api.downloads.onErased,
|
||||||
cancel: async () => null,
|
onDeterminingFilename: api.downloads.onDeterminingFilename,
|
||||||
pause: async () => null,
|
}
|
||||||
resume: async () => null,
|
: {
|
||||||
erase: async () => null,
|
download: async () => null,
|
||||||
removeFile: async () => null,
|
search: async () => [],
|
||||||
show: async () => null,
|
cancel: async () => null,
|
||||||
showDefaultFolder: async () => null,
|
pause: async () => null,
|
||||||
onCreated: { addListener: () => {}, removeListener: () => {} },
|
resume: async () => null,
|
||||||
onChanged: { addListener: () => {}, removeListener: () => {} },
|
erase: async () => null,
|
||||||
onErased: { addListener: () => {}, removeListener: () => {} },
|
removeFile: async () => null,
|
||||||
onDeterminingFilename: { addListener: () => {}, removeListener: () => {} },
|
show: async () => null,
|
||||||
},
|
showDefaultFolder: async () => null,
|
||||||
|
onCreated: { addListener: () => {}, removeListener: () => {} },
|
||||||
|
onChanged: { addListener: () => {}, removeListener: () => {} },
|
||||||
|
onErased: { addListener: () => {}, removeListener: () => {} },
|
||||||
|
onDeterminingFilename: {
|
||||||
|
addListener: () => {},
|
||||||
|
removeListener: () => {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
// Browser Action / Action API (兼容不同版本)
|
// Browser Action / Action API (兼容不同版本)
|
||||||
action: (() => {
|
action: (() => {
|
||||||
@@ -435,7 +463,9 @@ if (typeof module !== "undefined" && module.exports) {
|
|||||||
// 服务工作器环境
|
// 服务工作器环境
|
||||||
self.webext = webext;
|
self.webext = webext;
|
||||||
self.webextFlavor = webextFlavor;
|
self.webextFlavor = webextFlavor;
|
||||||
console.log("WebExt compatibility layer loaded in service worker environment");
|
console.log(
|
||||||
|
"WebExt compatibility layer loaded in service worker environment"
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
// 全局环境
|
// 全局环境
|
||||||
this.webext = webext;
|
this.webext = webext;
|
||||||
File renamed without changes.
File renamed without changes.
Reference in new issue
Block a user