Skip to content

Commit

Permalink
feat(webextension): support multiple workers
Browse files Browse the repository at this point in the history
  • Loading branch information
azu committed Aug 2, 2020
1 parent de26db2 commit 79f8a0a
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 25 deletions.
52 changes: 43 additions & 9 deletions packages/webextension/app/scripts/background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { createBackgroundEndpoint, isMessagePort } from "comlink-extension";
import * as Comlink from "comlink";
import { createTextlintWorker } from "./background/textlint";
import { openDatabase } from "./background/openDatabase";
import { LintEngineAPI } from "textchecker-element";
import { TextlintFixResult, TextlintMessage, TextlintResult } from "@textlint/types";

browser.runtime.onInstalled.addListener((details) => {
console.log("previousVersion", details.previousVersion);
Expand Down Expand Up @@ -63,10 +65,8 @@ type ThenArg<T> = T extends PromiseLike<infer U> ? U : T;

type DataBase = ReturnType<typeof openDatabase>;
export type backgroundExposedObject = {
lintText: ReturnType<typeof createTextlintWorker>["lintText"];
fixText: ReturnType<typeof createTextlintWorker>["fixText"];
addScript: ThenArg<DataBase>["addScript"];
};
} & LintEngineAPI;
browser.runtime.onConnect.addListener(async (port) => {
if (isMessagePort(port)) {
return;
Expand All @@ -78,22 +78,56 @@ browser.runtime.onConnect.addListener(async (port) => {
const blob = new Blob([script.code], { type: "application/javascript" });
return createTextlintWorker(URL.createObjectURL(blob));
});
// TODO multiple worker?
const lintText:ReturnType<typeof createTextlintWorker>["lintText"] = ()
console.log("[Background] workers", workers);
// Support multiple workers
const ext = ".md";
const lintEngine: LintEngineAPI = {
async lintText({ text }: { text: string }): Promise<TextlintResult[]> {
console.log("[Background] text", text);
const allLintResults = await Promise.all(
workers.map((worker) => {
return worker.createLintEngine({ ext }).lintText({ text });
})
);
return allLintResults.flat();
},
async fixText({ text, message }): Promise<{ output: string }> {
if (!message.fix || !message.fix.range) {
return { output: text };
}
// replace fix.range[0, 1] with fix.text
return {
output: text.slice(0, message.fix.range[0]) + message.fix.text + text.slice(message.fix.range[1])
};
},
async fixAll({ text }: { text: string }): Promise<TextlintFixResult> {
return workers.slice(1).reduce((promise, worker) => {
return promise.then(() => {
return worker.createLintEngine({ ext }).fixAll({ text });
});
}, workers[0].createLintEngine({ ext }).fixAll({ text }));
},
fixRule({ text, message }: { text: string; message: TextlintMessage }): Promise<TextlintFixResult> {
return workers.slice(1).reduce((promise, worker) => {
return promise.then(() => {
return worker.createLintEngine({ ext }).fixRule({ text, message });
});
}, workers[0].createLintEngine({ ext }).fixRule({ text, message }));
}
};
const backgroundExposedObject: backgroundExposedObject = {
lintText: textlint.lintText,
fixText: textlint.fixText,
...lintEngine,
addScript: (script) => {
return db.addScript(script);
}
};
port.onDisconnect.addListener(() => {
console.log("dispose worker");
console.log("[Background] dispose worker");
workers.forEach((worker) => {
worker.dispose();
});
});
console.log(port.sender);
console.log("[Background] content port", port);
await Promise.all(workers.map((worker) => worker.ready()));
Comlink.expose(backgroundExposedObject, createBackgroundEndpoint(port));
});
35 changes: 28 additions & 7 deletions packages/webextension/app/scripts/background/textlint.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { browser } from "webextension-polyfill-ts";
import { TextlintFixResult, TextlintMessage, TextlintResult } from "@textlint/types";
import type { TextlintFixResult, TextlintMessage, TextlintResult } from "@textlint/types";
import type { LintEngineAPI } from "textchecker-element";
import { TextlintWorkerCommandFix, TextlintWorkerCommandLint, TextlintWorkerCommandResponse } from "@textlint/compiler";

browser.runtime.onInstalled.addListener((details) => {
Expand Down Expand Up @@ -49,14 +50,14 @@ const createWorkerRef = (worker: Worker) => {
export const createTextlintWorker = (defaultWorkerUrl: string | URL = "download/textlint.js") => {
const defaultWorker = new Worker(defaultWorkerUrl);
const workerRef = createWorkerRef(defaultWorker);
const lintText = async ({ text, ext }: { text: string; ext: string }): Promise<TextlintResult> => {
const lintText = async ({ text, ext }: { text: string; ext: string }): Promise<TextlintResult[]> => {
return new Promise((resolve, _reject) => {
workerRef.current.addEventListener(
"message",
function (event) {
const data: TextlintWorkerCommandResponse = event.data;
if (data.command === "lint:result") {
resolve(data.result);
resolve([data.result]);
}
},
{
Expand All @@ -77,7 +78,7 @@ export const createTextlintWorker = (defaultWorkerUrl: string | URL = "download/
}: {
text: string;
ext: string;
message: TextlintMessage;
message?: TextlintMessage;
}): Promise<TextlintFixResult> => {
return new Promise((resolve, _reject) => {
workerRef.current.addEventListener(
Expand All @@ -95,14 +96,34 @@ export const createTextlintWorker = (defaultWorkerUrl: string | URL = "download/
return workerRef.current.postMessage({
command: "fix",
text,
ruleId: message.ruleId,
ruleId: message?.ruleId,
ext: ext
} as TextlintWorkerCommandFix);
});
};
return {
lintText,
fixText,
createLintEngine({ ext }: { ext: string }) {
const lintEngine: LintEngineAPI = {
lintText: ({ text }) => lintText({ text, ext }),
fixText: async ({ text, message }): Promise<{ output: string }> => {
if (!message.fix || !message.fix.range) {
return { output: text };
}
// replace fix.range[0, 1] with fix.text
return {
output:
text.slice(0, message.fix.range[0]) + message.fix.text + text.slice(message.fix.range[1])
};
},
fixAll({ text }: { text: string }): Promise<TextlintFixResult> {
return fixText({ text, ext });
},
fixRule({ text, message }: { text: string; message: TextlintMessage }): Promise<TextlintFixResult> {
return fixText({ text, message, ext });
}
};
return lintEngine;
},
ready() {
return workerRef.ready();
},
Expand Down
29 changes: 21 additions & 8 deletions packages/webextension/app/scripts/contentScript.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,32 @@
// @ts-ignore - replace webcomponent to shim
import "@webcomponents/custom-elements";
import { browser } from "webextension-polyfill-ts";
import { attachToTextArea } from "textchecker-element";
import { attachToTextArea, LintEngineAPI } from "textchecker-element";
import { createEndpoint } from "comlink-extension";
import * as Comlink from "comlink";
import type { backgroundExposedObject } from "./background";

const port = Comlink.wrap<backgroundExposedObject>(createEndpoint(browser.runtime.connect()));
const targetElement = document.querySelectorAll("textarea");
targetElement.forEach((element) => {
const extOfTextarea = ".md";
return attachToTextArea({
textAreaElement: element,
lintText: (args) => port.lintText({ ...args, ext: extOfTextarea }),
fixText: (args) => port.fixText({ ...args, ext: extOfTextarea }),
lintingDebounceMs: 200

async function contentScriptMain() {
const lintEngine: LintEngineAPI = {
lintText: port.lintText,
fixText: port.fixText,
fixAll: port.fixAll,
fixRule: port.fixRule
};
console.log("[ContentScript]", lintEngine);
targetElement.forEach((element) => {
return attachToTextArea({
textAreaElement: element,
lintingDebounceMs: 200,
lintEngine: lintEngine
});
});
}

console.log("[ContentScript]", "main");
contentScriptMain().catch((error) => {
console.error("[texlint editor ContentScriptError]", error);
});
2 changes: 1 addition & 1 deletion packages/webextension/app/scripts/install-dialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ async function installHandler() {
console.log(content);
// Save to DB
await port.addScript({
name: "default",
name: location.href,
code: content,
pattern: "**/*"
});
Expand Down

0 comments on commit 79f8a0a

Please sign in to comment.