mirror of
https://forgejo.ellis.link/continuwuation/continuwuity.git
synced 2026-05-26 20:49:55 +00:00
Move terser off of the main thread
This commit is contained in:
@@ -19,6 +19,7 @@
|
|||||||
"@sveltejs/kit": "^2.5.7",
|
"@sveltejs/kit": "^2.5.7",
|
||||||
"@sveltejs/vite-plugin-svelte": "^3.1.0",
|
"@sveltejs/vite-plugin-svelte": "^3.1.0",
|
||||||
"@types/node": "^20.12.7",
|
"@types/node": "^20.12.7",
|
||||||
|
"@types/sharedworker": "^0.0.115",
|
||||||
"glob": "^10.3.12",
|
"glob": "^10.3.12",
|
||||||
"mdsvex": "^0.11.0",
|
"mdsvex": "^0.11.0",
|
||||||
"rehype-slug": "^6.0.0",
|
"rehype-slug": "^6.0.0",
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
import type { MinifyOptions, MinifyOutput } from "terser";
|
||||||
|
import { recieveMessageData, sendMessageData } from "./util";
|
||||||
|
|
||||||
|
export function init() {
|
||||||
|
|
||||||
|
let worker: SharedWorker;
|
||||||
|
let currentId = 0;
|
||||||
|
let terserModule: typeof import("terser");
|
||||||
|
let promises: { [id: number]: [(value: MinifyOutput | PromiseLike<MinifyOutput>) => void, (reason?: any) => void] } = {};
|
||||||
|
return {
|
||||||
|
minify: async function minify(files: string | string[] | {
|
||||||
|
[file: string]: string;
|
||||||
|
}, options?: MinifyOptions): Promise<MinifyOutput> {
|
||||||
|
|
||||||
|
if (!!window.SharedWorker) {
|
||||||
|
if (!worker) {
|
||||||
|
worker = new SharedWorker(new URL('./terserWorker.ts', import.meta.url), { type: "module" })
|
||||||
|
worker.port.onmessage = (e: MessageEvent<any>) => {
|
||||||
|
// invoke the promise's resolve() or reject() depending on whether there was an error.
|
||||||
|
promises[e.data[recieveMessageData.MessageId]][e.data[recieveMessageData.MessageType]](e.data[recieveMessageData.Return]);
|
||||||
|
|
||||||
|
// ... then delete the promise controller
|
||||||
|
delete promises[e.data[recieveMessageData.MessageId]];
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
worker.port.start()
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
promises[++currentId] = [resolve, reject];
|
||||||
|
|
||||||
|
let data = {
|
||||||
|
[sendMessageData.MessageId]: currentId,
|
||||||
|
[sendMessageData.Parameters]: [files, options
|
||||||
|
]
|
||||||
|
}
|
||||||
|
worker.port.postMessage(data)
|
||||||
|
});
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (!terserModule) {
|
||||||
|
terserModule = await import("terser")
|
||||||
|
}
|
||||||
|
return await terserModule.minify(files, options)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import { minify, type MinifyOptions } from "terser";
|
||||||
|
import { recieveMessageTypes, sendMessageData } from "./util";
|
||||||
|
|
||||||
|
/// <reference lib="sharedworker " />
|
||||||
|
declare var self: SharedWorkerGlobalScope;
|
||||||
|
|
||||||
|
self.onconnect = function (event) {
|
||||||
|
const port = event.ports[0];
|
||||||
|
port.onmessage = function (e: MessageEvent<{
|
||||||
|
[sendMessageData.MessageId]: number,
|
||||||
|
[sendMessageData.Parameters]: [string | string[] | {
|
||||||
|
[file: string]: string;
|
||||||
|
}, MinifyOptions?
|
||||||
|
]
|
||||||
|
}>) {
|
||||||
|
minify(...e.data[sendMessageData.Parameters]).then(
|
||||||
|
// success handler - callback(id, SUCCESS(0), result)
|
||||||
|
// if `d` is transferable transfer zero-copy
|
||||||
|
d => {
|
||||||
|
|
||||||
|
port.postMessage([e.data[0], recieveMessageTypes.RESOLVE, d],
|
||||||
|
// @ts-ignore
|
||||||
|
[d].filter(x => (
|
||||||
|
(x instanceof ArrayBuffer) ||
|
||||||
|
(x instanceof MessagePort)
|
||||||
|
// || (self.ImageBitmap && x instanceof ImageBitmap)
|
||||||
|
)));
|
||||||
|
},
|
||||||
|
// error handler - callback(id, ERROR(1), error)
|
||||||
|
er => { postMessage([e.data[0], recieveMessageTypes.REJECT, '' + er]); }
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
export type FunctionMap = { [x: string]: Function }
|
||||||
|
|
||||||
|
export enum sendMessageData {
|
||||||
|
MessageId,
|
||||||
|
Function,
|
||||||
|
Parameters
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface sendMessageMap <T> {
|
||||||
|
[sendMessageData.MessageId]: number,
|
||||||
|
[sendMessageData.Function]: number,
|
||||||
|
[sendMessageData.Parameters]: T[],
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum recieveMessageTypes {
|
||||||
|
RESOLVE, // OK
|
||||||
|
REJECT // ERROR
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export enum recieveMessageData {
|
||||||
|
MessageId,
|
||||||
|
MessageType,
|
||||||
|
Return
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface recieveMessageMap <T> {
|
||||||
|
[recieveMessageData.MessageId]: number,
|
||||||
|
[recieveMessageData.MessageType]: recieveMessageTypes,
|
||||||
|
[recieveMessageData.Return]: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// // worker
|
||||||
|
// import { recieveMessageTypes, type FunctionMap } from "./util";
|
||||||
|
|
||||||
|
// function makeMessageHandler(functions: FunctionMap) {
|
||||||
|
|
||||||
|
// return (e) => {
|
||||||
|
// // Invoking within then() captures exceptions in the supplied async function as rejections
|
||||||
|
// Promise.resolve(e.data[1]).then(
|
||||||
|
// v => $$.apply($$, v)
|
||||||
|
// ).then(
|
||||||
|
// // success handler - callback(id, SUCCESS(0), result)
|
||||||
|
// // if `d` is transferable transfer zero-copy
|
||||||
|
// d => {
|
||||||
|
// postMessage([e.data[0], recieveMessageTypes.SUCCESS, d], [d].filter(x => (
|
||||||
|
// (x instanceof ArrayBuffer) ||
|
||||||
|
// (x instanceof MessagePort) ||
|
||||||
|
// (self.ImageBitmap && x instanceof ImageBitmap)
|
||||||
|
// )));
|
||||||
|
// },
|
||||||
|
// // error handler - callback(id, ERROR(1), error)
|
||||||
|
// er => { postMessage([e.data[0], recieveMessageTypes.ERROR, '' + er]); }
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // host
|
||||||
|
// import { recieveMessageData, recieveMessageTypes, sendMessageData, type recieveMessageMap, type sendMessageMap } from "./util";
|
||||||
|
|
||||||
|
// function makeHostHandler(worker: Worker) {
|
||||||
|
|
||||||
|
// let currentId = 0;
|
||||||
|
|
||||||
|
// // Outward-facing promises store their "controllers" (`[request, reject]`) here:
|
||||||
|
// const promises: { [id: number]: { [t: number]: IArguments } } = {}
|
||||||
|
// ;
|
||||||
|
// /** Handle RPC results/errors coming back out of the worker.
|
||||||
|
// * Messages coming from the worker take the form `[id, status, result]`:
|
||||||
|
// * id - counter-based unique ID for the RPC call
|
||||||
|
// * status - 0 for success, 1 for failure
|
||||||
|
// * result - the result or error, depending on `status`
|
||||||
|
// */
|
||||||
|
// worker.onmessage = (e: MessageEvent<recieveMessageMap>) => {
|
||||||
|
// // invoke the promise's resolve() or reject() depending on whether there was an error.
|
||||||
|
// promises[e.data[0]][e.data[1]](e.data[2]);
|
||||||
|
|
||||||
|
// // ... then delete the promise controller
|
||||||
|
// promises[e.data[0]] = null;
|
||||||
|
// };
|
||||||
|
|
||||||
|
// // Return a proxy function that forwards calls to the worker & returns a promise for the result.
|
||||||
|
// return function () {
|
||||||
|
// let args = [].slice.call(arguments);
|
||||||
|
// return new Promise(function () {
|
||||||
|
// // Add the promise controller to the registry
|
||||||
|
// promises[++currentId] = arguments;
|
||||||
|
|
||||||
|
// // Send an RPC call to the worker - call(id, params)
|
||||||
|
// // The filter is to provide a list of transferables to send zero-copy
|
||||||
|
// let data: sendMessageMap<any> = {
|
||||||
|
// [sendMessageData.MessageId]: currentId,
|
||||||
|
// [sendMessageData.Function]: 1,
|
||||||
|
// [sendMessageData.Parameters]: args
|
||||||
|
// }
|
||||||
|
// worker.postMessage(data, args.filter(x => (
|
||||||
|
// (x instanceof ArrayBuffer) ||
|
||||||
|
// (x instanceof MessagePort) ||
|
||||||
|
// (self.ImageBitmap && x instanceof ImageBitmap)
|
||||||
|
// )));
|
||||||
|
// });
|
||||||
|
// };
|
||||||
|
|
||||||
|
// }
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
import SvelteSeo from "svelte-seo";
|
import SvelteSeo from "svelte-seo";
|
||||||
import { bookmarkify, parseMeta } from "./bookmarklets";
|
import { bookmarkify, parseMeta } from "./bookmarklets";
|
||||||
import type { Config } from "./config";
|
import type { Config } from "./config";
|
||||||
|
import { init } from "$lib/workers/terser";
|
||||||
import { SITE_URL } from '$lib/metadata';
|
import { SITE_URL } from '$lib/metadata';
|
||||||
|
|
||||||
/** @type {import('./$types').Snapshot<string>} */
|
/** @type {import('./$types').Snapshot<string>} */
|
||||||
@@ -12,12 +12,14 @@
|
|||||||
restore: (v: string) => (value = v),
|
restore: (v: string) => (value = v),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let minify = init().minify
|
||||||
|
|
||||||
let value = "";
|
let value = "";
|
||||||
let output = "";
|
let output = "";
|
||||||
let options: Config = {};
|
let options: Config = {};
|
||||||
async function process(str: string) {
|
async function process(str: string) {
|
||||||
options = await parseMeta(str);
|
options = await parseMeta(str);
|
||||||
let res = await bookmarkify(str, options);
|
let res = await bookmarkify(str, options, minify);
|
||||||
if (typeof res == "string") {
|
if (typeof res == "string") {
|
||||||
output = res;
|
output = res;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,14 +2,17 @@
|
|||||||
|
|
||||||
import MagicString from "magic-string";
|
import MagicString from "magic-string";
|
||||||
import { Parser } from "acorn";
|
import { Parser } from "acorn";
|
||||||
import { minify } from "terser";
|
import { type MinifyOptions, type MinifyOutput } from "terser";
|
||||||
|
|
||||||
let sourceMap = false;
|
let sourceMap = false;
|
||||||
|
|
||||||
import { configSchema } from "./config.schema";
|
import { configSchema } from "./config.schema";
|
||||||
import type { Config } from "./config";
|
import type { Config } from "./config";
|
||||||
// console.log(configSchema)
|
// console.log(configSchema)
|
||||||
export async function bookmarkify(code: string, options: Config) {
|
export async function bookmarkify(code: string, options: Config, minify: (files: string | string[] | {
|
||||||
|
[file: string]: string;
|
||||||
|
}, options?: MinifyOptions | undefined) => Promise<MinifyOutput>
|
||||||
|
) {
|
||||||
|
|
||||||
// try {
|
// try {
|
||||||
if (options.script) {
|
if (options.script) {
|
||||||
|
|||||||
Generated
+8
@@ -101,6 +101,9 @@ importers:
|
|||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^20.12.7
|
specifier: ^20.12.7
|
||||||
version: 20.12.7
|
version: 20.12.7
|
||||||
|
'@types/sharedworker':
|
||||||
|
specifier: ^0.0.115
|
||||||
|
version: 0.0.115
|
||||||
glob:
|
glob:
|
||||||
specifier: ^10.3.12
|
specifier: ^10.3.12
|
||||||
version: 10.3.12
|
version: 10.3.12
|
||||||
@@ -872,6 +875,9 @@ packages:
|
|||||||
'@types/resolve@1.20.2':
|
'@types/resolve@1.20.2':
|
||||||
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
|
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
|
||||||
|
|
||||||
|
'@types/sharedworker@0.0.115':
|
||||||
|
resolution: {integrity: sha512-istxrCv9mbZQt7kXMVMsc4U+dbxG5y+ae5N+9f6pM9VOJmclF7FBWtTog9SMT16s1pZUTjga7ewaMVgqhDpTOg==}
|
||||||
|
|
||||||
'@types/unist@2.0.10':
|
'@types/unist@2.0.10':
|
||||||
resolution: {integrity: sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==}
|
resolution: {integrity: sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==}
|
||||||
|
|
||||||
@@ -2841,6 +2847,8 @@ snapshots:
|
|||||||
|
|
||||||
'@types/resolve@1.20.2': {}
|
'@types/resolve@1.20.2': {}
|
||||||
|
|
||||||
|
'@types/sharedworker@0.0.115': {}
|
||||||
|
|
||||||
'@types/unist@2.0.10': {}
|
'@types/unist@2.0.10': {}
|
||||||
|
|
||||||
'@types/unist@3.0.2': {}
|
'@types/unist@3.0.2': {}
|
||||||
|
|||||||
Reference in New Issue
Block a user