Skip to content

Commit 500e1d7

Browse files
committed
feat: annotation preprocess compilation
1 parent 25b5ef8 commit 500e1d7

File tree

8 files changed

+129
-45
lines changed

8 files changed

+129
-45
lines changed

packages/force-copy/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "force-copy",
3-
"version": "1.0.4",
3+
"version": "1.0.5",
44
"author": "Czy",
55
"license": "MIT",
66
"sideEffects": false,

packages/force-copy/rspack.config.js

+11
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,17 @@ module.exports = {
8080
],
8181
type: "css",
8282
},
83+
{
84+
test: /\.(jsx?|tsx?)$/,
85+
use: [
86+
{
87+
loader: "./script/define",
88+
options: {
89+
// debug: true,
90+
},
91+
},
92+
],
93+
},
8394
],
8495
},
8596
output: {

packages/force-copy/script/define.js

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
const path = require("path");
2+
const fs = require("fs");
3+
4+
// 条件编译: `process.env.PLATFORM`的深层次嵌套
5+
// #IFDEF #ENDIF: `C/C++`预处理指令 平台层面扩展性
6+
7+
const src = path.resolve("src");
8+
/**
9+
* @type {import('@rspack/core').LoaderContext}
10+
* @param {string} source
11+
* @returns {string}
12+
*/
13+
function DefineLoader(source) {
14+
const debug = this.query.debug;
15+
const resourcePath = this.resourcePath;
16+
const platform = (process.env.PLATFORM || "").toLowerCase();
17+
if (!platform || !resourcePath.startsWith(src)) return source;
18+
// 迭代时控制该行是否命中预处理条件
19+
let terser = false;
20+
let terserIndex = -1;
21+
/** @type {number[]} */
22+
const stack = [];
23+
const lines = source.split("\n");
24+
const target = lines.map((line, index) => {
25+
// 去掉首尾的空白 去掉行首注释符号与空白符(可选)
26+
const code = line.trim().replace(/^\/\/\s*/, "");
27+
// 检查预处理指令起始 `#IFDEF`只会置`true`
28+
if (/^#IFDEF/.test(code)) {
29+
stack.push(index);
30+
// 如果是`true`继续即可
31+
if (terser) return "";
32+
const match = code.replace("#IFDEF", "").trim();
33+
const group = match.split("|").map(item => item.trim().toLowerCase());
34+
if (group.indexOf(platform) === -1) {
35+
terser = true;
36+
terserIndex = index;
37+
}
38+
return "";
39+
}
40+
// 检查预处理指令结束 `#IFDEF`只会置`false`
41+
if (/^#ENDIF$/.test(code)) {
42+
const index = stack.pop();
43+
// 额外的`#ENDIF`忽略
44+
if (index === undefined) return "";
45+
if (index === terserIndex) {
46+
terser = false;
47+
terserIndex = -1;
48+
}
49+
return "";
50+
}
51+
// 如果命中预处理条件则擦除
52+
if (terser) return "";
53+
return line;
54+
});
55+
if (debug) {
56+
// rm -rf ./**/*.log
57+
fs.writeFile(resourcePath + ".log", target.join("\n"), () => null);
58+
}
59+
return target.join("\n");
60+
}
61+
62+
module.exports = DefineLoader;

packages/force-copy/src/content/runtime/implant-script.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export const implantScript = () => {
22
const fn = window[process.env.INJECT_FILE as unknown as number] as unknown as () => void;
3-
if (process.env.PLATFORM !== "chromium" && fn) {
3+
// #IFDEF GECKO
4+
if (fn) {
45
const script = document.createElementNS("http://www.w3.org/1999/xhtml", "script");
56
script.setAttribute("type", "text/javascript");
67
script.innerText = `;(${fn.toString()})();`;
@@ -10,4 +11,5 @@ export const implantScript = () => {
1011
// @ts-ignore
1112
delete window[process.env.INJECT_FILE];
1213
}
14+
// #ENDIF
1315
};

packages/force-copy/src/popup/utils/badge.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ export const cipherBadgeNumber = (checked: boolean) => {
1010
})
1111
.then(tabId => {
1212
if (tabId) {
13-
const action = process.env.PLATFORM === "chromium" ? cross.action : cross.browserAction;
13+
let action: typeof cross.action | typeof cross.browserAction = cross.action;
14+
// #IFDEF GECKO
15+
action = cross.browserAction;
16+
// #ENDIF
1417
action.getBadgeText({ tabId }).then(text => {
1518
const badge = Number(text) || 0;
1619
const next = badge + (checked ? 1 : -1);
+3-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
let env = chrome;
22

3-
if (process.env.PLATFORM === "gecko" && typeof browser !== "undefined") {
3+
// #IFDEF GECKO
4+
if (typeof browser !== "undefined") {
45
env = browser;
56
}
7+
// #ENDIF
68

79
export const cross = env;

packages/force-copy/src/worker/runtime/content-message.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@ export const onContentMessage = (data: CWRequestType, sender: chrome.runtime.Mes
1414
const { payload } = data;
1515
if (payload && sender.tab && sender.tab.id) {
1616
const tabId = sender.tab.id;
17-
const action = process.env.PLATFORM === "chromium" ? cross.action : cross.browserAction;
17+
let action: typeof cross.action | typeof cross.browserAction = cross.action;
18+
// #IFDEF GECKO
19+
action = cross.browserAction;
20+
// #ENDIF
1821
action.setBadgeText({ text: payload.toString(), tabId });
1922
action.setBadgeBackgroundColor({ color: "#4e5969", tabId });
2023
}

packages/force-copy/src/worker/runtime/implant-script.ts

+41-40
Original file line numberDiff line numberDiff line change
@@ -4,47 +4,48 @@ import { logger } from "@/utils/logger";
44

55
export const implantScript = () => {
66
/** RUN INJECT SCRIPT IN DOCUMENT START **/
7-
if (process.env.PLATFORM === "chromium") {
8-
// https://bugs.chromium.org/p/chromium/issues/detail?id=634381
9-
// https://stackoverflow.com/questions/75495191/chrome-extension-manifest-v3-how-to-use-window-addeventlistener
10-
if (cross.scripting && cross.scripting.registerContentScripts) {
11-
logger.info("Register Inject Scripts By Scripting API");
12-
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/scripting/registerContentScripts
13-
cross.scripting
14-
.registerContentScripts([
15-
{
16-
matches: [...URL_MATCH],
17-
runAt: "document_start",
18-
world: "MAIN",
19-
allFrames: true,
20-
js: [process.env.INJECT_FILE + ".js"],
21-
id: process.env.INJECT_FILE,
22-
},
23-
])
24-
.catch(err => {
25-
logger.warning("Register Inject Scripts Failed", err);
26-
});
27-
} else {
28-
logger.info("Register Inject Scripts By Tabs API");
29-
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/onUpdated
30-
cross.tabs.onUpdated.addListener((_, changeInfo, tab) => {
31-
if (changeInfo.status == "loading") {
32-
const tabId = tab && tab.id;
33-
const tabURL = tab && tab.url;
34-
if (tabURL && !URL_MATCH.some(match => new RegExp(match).test(tabURL))) {
35-
return void 0;
36-
}
37-
if (tabId && cross.scripting) {
38-
cross.scripting.executeScript({
39-
target: { tabId: tabId, allFrames: true },
40-
files: [process.env.INJECT_FILE + ".js"],
41-
injectImmediately: true,
42-
});
43-
}
44-
}
7+
// #IFDEF CHROMIUM
8+
// https://bugs.chromium.org/p/chromium/issues/detail?id=634381
9+
// https://stackoverflow.com/questions/75495191/chrome-extension-manifest-v3-how-to-use-window-addeventlistener
10+
if (cross.scripting && cross.scripting.registerContentScripts) {
11+
logger.info("Register Inject Scripts By Scripting API");
12+
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/scripting/registerContentScripts
13+
cross.scripting
14+
.registerContentScripts([
15+
{
16+
matches: [...URL_MATCH],
17+
runAt: "document_start",
18+
world: "MAIN",
19+
allFrames: true,
20+
js: [process.env.INJECT_FILE + ".js"],
21+
id: process.env.INJECT_FILE,
22+
},
23+
])
24+
.catch(err => {
25+
logger.warning("Register Inject Scripts Failed", err);
4526
});
46-
}
4727
} else {
48-
logger.info("Register Inject Scripts By Inline Code");
28+
logger.info("Register Inject Scripts By Tabs API");
29+
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/onUpdated
30+
cross.tabs.onUpdated.addListener((_, changeInfo, tab) => {
31+
if (changeInfo.status == "loading") {
32+
const tabId = tab && tab.id;
33+
const tabURL = tab && tab.url;
34+
if (tabURL && !URL_MATCH.some(match => new RegExp(match).test(tabURL))) {
35+
return void 0;
36+
}
37+
if (tabId && cross.scripting) {
38+
cross.scripting.executeScript({
39+
target: { tabId: tabId, allFrames: true },
40+
files: [process.env.INJECT_FILE + ".js"],
41+
injectImmediately: true,
42+
});
43+
}
44+
}
45+
});
4946
}
47+
// #ENDIF
48+
// #IFDEF GECKO
49+
logger.info("Register Inject Scripts By Content Script Inline Code");
50+
// #ENDIF
5051
};

0 commit comments

Comments
 (0)