Patch zeroperl-ts so worker WASM load honors custom fetch.
Postinstall updates @6over3/zeroperl-ts and wires the worker to load zeroperl.wasm via Vite ?url.
This commit is contained in:
@@ -7,7 +7,7 @@
|
|||||||
"dev": "vite --host 0.0.0.0",
|
"dev": "vite --host 0.0.0.0",
|
||||||
"build": "vue-tsc -b && vite build",
|
"build": "vue-tsc -b && vite build",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"postinstall": "node patches/patch-exiftool-stderr.mjs"
|
"postinstall": "node patches/patch-exiftool-stderr.mjs && node patches/patch-zeroperl-worker-fetch.mjs"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tailwindcss/vite": "^4.3.3",
|
"@tailwindcss/vite": "^4.3.3",
|
||||||
|
|||||||
@@ -14,3 +14,16 @@ Instead, `patches/patch-exiftool-stderr.mjs` runs on `postinstall` and removes t
|
|||||||
See the script for exact literals and upstream context.
|
See the script for exact literals and upstream context.
|
||||||
|
|
||||||
When upgrading `@uswriting/exiftool`, run `npm install` and confirm the script still finds both guards (or update the script for the new bundle).
|
When upgrading `@uswriting/exiftool`, run `npm install` and confirm the script still finds both guards (or update the script for the new bundle).
|
||||||
|
|
||||||
|
## `@6over3/zeroperl-ts@1.0.10` — WASM load in module workers
|
||||||
|
|
||||||
|
`patches/patch-zeroperl-worker-fetch.mjs` changes the WASM loader so a custom `fetch` (from `@uswriting/exiftool` options) is honored even when `document` is missing (Web Workers).
|
||||||
|
|
||||||
|
| Snippet | Role |
|
||||||
|
| ----- | ---- |
|
||||||
|
| `if(Ee())a=await...` → `if(Ee()\|\|e)a=await...` (ESM) | Use fetch path when `options.fetch` is set |
|
||||||
|
| `if(pe())a=await...` → `if(pe()\|\|e)a=await...` (CJS) | Same for CJS bundle |
|
||||||
|
|
||||||
|
Workers still pass Vite’s WASM URL via `zeroperl.wasm?url` and `exiftoolParseOptions.fetch` in app code.
|
||||||
|
|
||||||
|
When upgrading `@6over3/zeroperl-ts`, re-run `npm install` and confirm the script still matches (or update literals).
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
/**
|
||||||
|
* Patch @6over3/zeroperl-ts@1.0.10 after install.
|
||||||
|
*
|
||||||
|
* Problem: WASM loader treats only `window` + `document` as browser. Module workers have
|
||||||
|
* neither, so it dynamic-imports `node:fs/promises` and fails under Vite.
|
||||||
|
* Custom `fetch` from @uswriting/exiftool is ignored on that branch.
|
||||||
|
*
|
||||||
|
* Fix: use the fetch path when a custom fetch is provided (`Ee() || e`).
|
||||||
|
*
|
||||||
|
* Upstream: https://github.com/6over3/zeroperl-ts
|
||||||
|
*
|
||||||
|
* Re-verify when bumping @6over3/zeroperl-ts: search dist for the ORIGINAL snippets below.
|
||||||
|
*/
|
||||||
|
import fs from 'node:fs';
|
||||||
|
import path from 'node:path';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
|
|
||||||
|
const patches = [
|
||||||
|
{
|
||||||
|
relativePath: 'esm/index.js',
|
||||||
|
original: 'if(Ee())a=await(await(e??fetch)(q)).arrayBuffer();',
|
||||||
|
patched: 'if(Ee()||e)a=await(await(e??fetch)(q)).arrayBuffer();'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
relativePath: 'cjs/index.cjs',
|
||||||
|
original: 'if(pe())a=await(await(e??fetch)(w)).arrayBuffer();',
|
||||||
|
patched: 'if(pe()||e)a=await(await(e??fetch)(w)).arrayBuffer();'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const packageRoot = path.resolve(
|
||||||
|
path.dirname(fileURLToPath(import.meta.url)),
|
||||||
|
'../node_modules/@6over3/zeroperl-ts/dist'
|
||||||
|
);
|
||||||
|
|
||||||
|
const patchFile = ({ relativePath, original, patched }) => {
|
||||||
|
const filePath = path.join(packageRoot, relativePath);
|
||||||
|
|
||||||
|
if (!fs.existsSync(filePath)) {
|
||||||
|
throw new Error(`patch-zeroperl-worker-fetch: missing ${filePath} (is @6over3/zeroperl-ts installed?)`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const content = fs.readFileSync(filePath, 'utf8');
|
||||||
|
|
||||||
|
if (content.includes(patched)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!content.includes(original)) {
|
||||||
|
throw new Error(
|
||||||
|
`patch-zeroperl-worker-fetch: ${relativePath} does not match @6over3/zeroperl-ts@1.0.10; update or remove this script`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.writeFileSync(filePath, content.replaceAll(original, patched));
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const entry of patches) {
|
||||||
|
patchFile(entry);
|
||||||
|
}
|
||||||
@@ -1,8 +1,12 @@
|
|||||||
|
import zeroperlWasmUrl from '@6over3/zeroperl-ts/zeroperl.wasm?url';
|
||||||
import { parseMetadata } from '@uswriting/exiftool';
|
import { parseMetadata } from '@uswriting/exiftool';
|
||||||
import { EXIFTOOL_WORKER_INIT_JPEG } from '@/consts/exiftoolWorkerInitJpeg';
|
import { EXIFTOOL_WORKER_INIT_JPEG } from '@/consts/exiftoolWorkerInitJpeg';
|
||||||
import type { ExiftoolWorkerInMessage } from '@/types/workers/exiftoolWorkerInMessage';
|
import type { ExiftoolWorkerInMessage } from '@/types/workers/exiftoolWorkerInMessage';
|
||||||
import { resolveErrorMessage } from '@/utils/resolveErrorMessage';
|
import { resolveErrorMessage } from '@/utils/resolveErrorMessage';
|
||||||
|
|
||||||
|
/** Custom fetch function for `@uswriting/exiftool` to load `zeroperl.wasm` from the worker. */
|
||||||
|
const exiftoolParseOptions = { fetch: () => fetch(zeroperlWasmUrl) };
|
||||||
|
|
||||||
let initialized = false;
|
let initialized = false;
|
||||||
let initializeWorkerPromise: Promise<void> | null = null;
|
let initializeWorkerPromise: Promise<void> | null = null;
|
||||||
|
|
||||||
@@ -19,7 +23,7 @@ let initializeWorkerPromise: Promise<void> | null = null;
|
|||||||
* Concurrent callers (init message, read-metadata, future write) share one in-flight warmup.
|
* Concurrent callers (init message, read-metadata, future write) share one in-flight warmup.
|
||||||
*
|
*
|
||||||
* @throws When warmup `parseMetadata` fails (network, WASM, or ExifTool error).
|
* @throws When warmup `parseMetadata` fails (network, WASM, or ExifTool error).
|
||||||
* @see Main thread `initialize()` posts `{ type: 'init' }` when idle.
|
* @see Main thread `initializeExiftool()` posts `{ type: 'init' }` when idle.
|
||||||
*/
|
*/
|
||||||
const initializeWorker = async (): Promise<void> => {
|
const initializeWorker = async (): Promise<void> => {
|
||||||
if (initialized) {
|
if (initialized) {
|
||||||
@@ -29,7 +33,10 @@ const initializeWorker = async (): Promise<void> => {
|
|||||||
if (!initializeWorkerPromise) {
|
if (!initializeWorkerPromise) {
|
||||||
initializeWorkerPromise = (async () => {
|
initializeWorkerPromise = (async () => {
|
||||||
try {
|
try {
|
||||||
const result = await parseMetadata({ name: 'init.jpg', data: EXIFTOOL_WORKER_INIT_JPEG });
|
const result = await parseMetadata(
|
||||||
|
{ name: 'init.jpg', data: EXIFTOOL_WORKER_INIT_JPEG },
|
||||||
|
exiftoolParseOptions
|
||||||
|
);
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
throw new Error(result.error);
|
throw new Error(result.error);
|
||||||
@@ -69,7 +76,7 @@ self.addEventListener('message', async (event: MessageEvent<ExiftoolWorkerInMess
|
|||||||
try {
|
try {
|
||||||
await initializeWorker();
|
await initializeWorker();
|
||||||
|
|
||||||
const result = await parseMetadata(message.file);
|
const result = await parseMetadata(message.file, exiftoolParseOptions);
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
self.postMessage({ type: 'read-metadata-error', id: message.id, message: result.error });
|
self.postMessage({ type: 'read-metadata-error', id: message.id, message: result.error });
|
||||||
|
|||||||
Reference in New Issue
Block a user