Skip to content

Commit

Permalink
fix(webextension): cache worker x script
Browse files Browse the repository at this point in the history
improve worker cache
  • Loading branch information
azu committed Apr 17, 2021
1 parent a3e86dc commit 8ea8ea5
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 48 deletions.
58 changes: 27 additions & 31 deletions packages/webextension/app/scripts/background.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import { browser } from "webextension-polyfill-ts";
import { createBackgroundEndpoint, isMessagePort } from "comlink-extension";
import * as Comlink from "comlink";
import { createTextlintWorker, TextlintWorker } from "./background/textlint";
import { createTextlintWorker } from "./background/textlint";
import { openDatabase } from "./background/database";
import { LintEngineAPI } from "textchecker-element";
import { TextlintResult } from "@textlint/types";
import { scriptWorkerSet } from "./background/scriptWorkerSet";

browser.runtime.onInstalled.addListener((details) => {
console.log("previousVersion", details.previousVersion);
});

browser.tabs.onUpdated.addListener(async (tabId) => {
browser.pageAction.show(tabId);
});
// browser.runtime.onInstalled.addListener((details) => {
// // console.log("previousVersion", details.previousVersion);
// });
//
// browser.tabs.onUpdated.addListener(async (tabId) => {
// // await browser?.pageAction?.show(tabId);
// });

const gContentTypeRe = (() => {
const userScriptTypes = [
Expand Down Expand Up @@ -73,23 +74,7 @@ export type backgroundPopupObject = {
updateScript: DataBase["updateScript"];
openEditor: (options: { name: string; namespace: string }) => void;
};
const workerMap = new Map<TextlintWorker, Set<string>>();
const addWorker = (url: string, worker: TextlintWorker) => {
const set = workerMap.get(worker) ?? new Set<string>();
set.add(url);
workerMap.set(worker, set);
};
const removeWorker = (url: string) => {
for (const [worker, urlSet] of workerMap.entries()) {
if (urlSet.has(url)) {
urlSet.delete(url);
}
if (urlSet.size === 0) {
worker.dispose();
workerMap.delete(worker);
}
}
};

browser.runtime.onConnect.addListener(async (port) => {
if (isMessagePort(port)) {
return;
Expand Down Expand Up @@ -118,11 +103,18 @@ browser.runtime.onConnect.addListener(async (port) => {
return Comlink.expose(exports, createBackgroundEndpoint(port));
}
const scripts = await db.findScriptsWithPatten(originUrl);
console.log("scripts", scripts);
const scriptWorkers = scripts.map((script) => {
const blob = new Blob([script.code], { type: "application/javascript" });
const runningWorker = scriptWorkerSet.get(script);
if (runningWorker) {
return {
worker: runningWorker,
ext: script.ext
};
}
// TODO: comment support for textlintrc
const textlintWorker = createTextlintWorker(URL.createObjectURL(blob), JSON.parse(script.textlintrc));
addWorker(originUrl, textlintWorker);
const textlintWorker = createTextlintWorker(script);
scriptWorkerSet.add({ script, worker: textlintWorker, url: originUrl });
return {
worker: textlintWorker,
ext: script.ext
Expand All @@ -138,7 +130,7 @@ browser.runtime.onConnect.addListener(async (port) => {
return worker.createLintEngine({ ext }).lintText({ text });
})
);
console.log("[Background]", allLintResults);
console.log("[Background] lintText", allLintResults);
return allLintResults.flat();
},
async fixText({ text }): Promise<{ output: string }> {
Expand Down Expand Up @@ -166,11 +158,15 @@ browser.runtime.onConnect.addListener(async (port) => {
return db.addScript(script);
}
};
port.onDisconnect.addListener(() => {
port.onDisconnect.addListener(async () => {
console.log("[Background] dispose worker");
removeWorker(originUrl);
const scripts = await db.findScriptsWithPatten(originUrl);
scripts.forEach((script) => {
scriptWorkerSet.delete({ script: script, url: originUrl });
});
});
console.log("[Background] content port", port);
scriptWorkerSet.dump();
Comlink.expose(backgroundExposedObject, createBackgroundEndpoint(port));
await Promise.all(scriptWorkers.map(({ worker }) => worker.ready()));
port.postMessage("textlint-editor-boot");
Expand Down
5 changes: 4 additions & 1 deletion packages/webextension/app/scripts/background/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@ export type Script = {
export type TextlintDBSchema = {
scripts: Script[];
};
export const keyOfScript = (script: { name: string; namespace: string }): string => {
return `${script.namespace}@${script.name}`;
};
const equalScript = (a: { name: string; namespace: string }, b: { name: string; namespace: string }): boolean => {
return a.name === b.name && a.namespace === b.namespace;
return keyOfScript(a) === keyOfScript(b);
};

export async function openDatabase() {
Expand Down
36 changes: 36 additions & 0 deletions packages/webextension/app/scripts/background/scriptWorkerSet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { TextlintWorker } from "./textlint";
import { keyOfScript, Script } from "./database";

// worker: Set<url>
const _workerRunningUrlMap = new Map<TextlintWorker, Set<string>>();
const _scriptRunningWorkerMap = new Map<string, TextlintWorker>();
export const scriptWorkerSet = {
get(script: Script) {
return _scriptRunningWorkerMap.get(keyOfScript(script));
},
has(script: Script) {
return _scriptRunningWorkerMap.has(keyOfScript(script));
},
add({ script, worker, url }: { script: Script; worker: TextlintWorker; url: string }) {
const set = _workerRunningUrlMap.get(worker) ?? new Set<string>();
set.add(url);
_workerRunningUrlMap.set(worker, set);
return _scriptRunningWorkerMap.set(keyOfScript(script), worker);
},
delete({ script, url }: { script: Script; url: string }) {
for (const [worker, urlSet] of _workerRunningUrlMap.entries()) {
if (urlSet.has(url)) {
urlSet.delete(url);
}
if (urlSet.size === 0) {
worker.dispose();
_workerRunningUrlMap.delete(worker);
}
}
return _scriptRunningWorkerMap.delete(keyOfScript(script));
},
dump() {
console.log("Running Scripts: ", _scriptRunningWorkerMap.keys());
console.log("Running Workers x URLs: ", _workerRunningUrlMap.entries());
}
};
20 changes: 9 additions & 11 deletions packages/webextension/app/scripts/background/textlint.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { browser } from "webextension-polyfill-ts";
import type { TextlintFixResult, TextlintMessage, TextlintResult } from "@textlint/types";
import type { LintEngineAPI } from "textchecker-element";
import {
Expand All @@ -8,14 +7,7 @@ import {
TextlintWorkerCommandResponse
} from "@textlint/script-compiler";
import type { TextlintRcConfig } from "@textlint/config-loader";

browser.runtime.onInstalled.addListener((details) => {
console.log("previousVersion", details.previousVersion);
});

browser.tabs.onUpdated.addListener(async (tabId) => {
browser.pageAction.show(tabId);
});
import { Script } from "./database";
const waiterForInit = (worker: Worker) => {
let initialized = false;
let _resolve: null | ((init: boolean) => void) = null;
Expand Down Expand Up @@ -54,8 +46,11 @@ const createWorkerRef = (worker: Worker) => {
};
};
export type TextlintWorker = ReturnType<typeof createTextlintWorker>;
export const createTextlintWorker = (defaultWorkerUrl: string | URL, textlintrc?: TextlintRcConfig) => {
const defaultWorker = new Worker(defaultWorkerUrl);
export const createTextlintWorker = (script: Script) => {
const blob = new Blob([script.code], { type: "application/javascript" });
const workerUrl = URL.createObjectURL(blob);
const textlintrc = JSON.parse(script.textlintrc) as TextlintRcConfig;
const defaultWorker = new Worker(workerUrl);
const workerRef = createWorkerRef(defaultWorker);
const lintText = async ({ text, ext }: { text: string; ext: string }): Promise<TextlintResult[]> => {
return new Promise((resolve, _reject) => {
Expand All @@ -78,6 +73,9 @@ export const createTextlintWorker = (defaultWorkerUrl: string | URL, textlintrc?
} as TextlintWorkerCommandLint);
});
};
// Note: currently does not use background implementation.
// Just use @textlint/source-code-fixer
// See pageScript.ts
const fixText = async ({
text,
ext,
Expand Down
2 changes: 2 additions & 0 deletions packages/webextension/app/scripts/pageScript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ const lintEngine: LintEngineAPI = {
};
});
},
// Note: currently does not use background implementation.
// Just use @textlint/source-code-fixer
async fixText({ text, messages }): Promise<{ output: string }> {
const fixableMessages = messages.filter((message) => !isIgnored({ text, message }));
return {
Expand Down
2 changes: 1 addition & 1 deletion packages/webextension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,6 @@
"react-codemirror2": "^7.2.1",
"react-dom": "^17.0.1",
"textchecker-element": "^0.8.1",
"webextension-polyfill-ts": "^0.22.0"
"webextension-polyfill-ts": "^0.25.0"
}
}
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -13453,10 +13453,10 @@ webextension-polyfill-ts@^0.19.0:
dependencies:
webextension-polyfill "^0.6.0"

webextension-polyfill-ts@^0.22.0:
version "0.22.0"
resolved "https://registry.yarnpkg.com/webextension-polyfill-ts/-/webextension-polyfill-ts-0.22.0.tgz#86cfd7bab4d9d779d98c8340983f4b691b2343f3"
integrity sha512-3P33ClMwZ/qiAT7UH1ROrkRC1KM78umlnPpRhdC/292UyoTTW9NcjJEqDsv83HbibcTB6qCtpVeuB2q2/oniHQ==
webextension-polyfill-ts@^0.25.0:
version "0.25.0"
resolved "https://registry.yarnpkg.com/webextension-polyfill-ts/-/webextension-polyfill-ts-0.25.0.tgz#fff041626365dbd0e29c40b197e989a55ec221ca"
integrity sha512-ikQhwwHYkpBu00pFaUzIKY26I6L87DeRI+Q6jBT1daZUNuu8dSrg5U9l/ZbqdaQ1M/TTSPKeAa3kolP5liuedw==
dependencies:
webextension-polyfill "^0.7.0"

Expand Down

0 comments on commit 8ea8ea5

Please sign in to comment.