taglib-wasm
Version:
TagLib-Wasm is the universal tagging library for TypeScript/JavaScript platforms: Browsers, Node.js, Deno, Bun, Cloudflare Workers, and Electron apps
111 lines (110 loc) • 3.75 kB
JavaScript
import {
EnvironmentError,
errorMessage,
TagLibInitializationError
} from "../errors/classes.js";
import { isDenoCompiled } from "./deno-detect.js";
import { checkNodeVersion } from "./detector.js";
async function loadTagLibModule(options) {
const g = globalThis;
const nodeVersion = g.process?.versions?.node;
const versionError = checkNodeVersion(nodeVersion);
if (versionError) {
throw new EnvironmentError("Node.js", versionError, "WASI support");
}
if (options?.forceWasmType === "wasi" && options?.wasmBinary) {
throw new TagLibInitializationError(
"wasmBinary is not supported by the WASI backend: it loads from a filesystem path or URL. Use wasmUrl, or omit forceWasmType to use the Emscripten backend",
{ forceWasmType: "wasi" }
);
}
if (!options?.wasmBinary && !options?.wasmUrl && !options?.forceWasmType && isDenoCompiled()) {
const wasmBinary = await tryLoadEmbeddedWasm();
if (!wasmBinary) {
console.warn(
"[TagLib] Deno compile detected but embedded Wasm not found. Include taglib-web.wasm with: deno compile --include taglib-web.wasm"
);
}
return loadBufferModeTagLibModule({
...options,
forceWasmType: "emscripten",
...wasmBinary ? { wasmBinary } : {}
});
}
if (options?.forceWasmType === "emscripten") {
return loadBufferModeTagLibModule(options);
}
try {
const { loadUnifiedTagLibModule } = await import("./unified-loader/index.js");
return await loadUnifiedTagLibModule({
wasmBinary: options?.wasmBinary,
wasmUrl: options?.wasmUrl,
forceWasmType: options?.forceWasmType,
debug: false
});
} catch (error) {
if (options?.forceWasmType === "wasi") {
throw new TagLibInitializationError(
`WASI backend failed to load: ${errorMessage(error)}. forceWasmType is "wasi", so the Emscripten fallback was not attempted`,
{ cause: error, forceWasmType: "wasi" }
);
}
console.warn(
`[TagLib] Unified loader failed, falling back to buffer mode: ${errorMessage(error)}`
);
return loadBufferModeTagLibModule(options || {});
}
}
async function loadBufferModeTagLibModule(options) {
let createTagLibModule;
try {
const module2 = await import("../../taglib-wrapper.js");
createTagLibModule = module2.default;
} catch {
try {
const module2 = await import("../../taglib-wrapper.js");
createTagLibModule = module2.default;
} catch {
throw new TagLibInitializationError(
"Could not load taglib-wrapper.js from either ./build or ./dist"
);
}
}
const moduleConfig = {};
if (options?.wasmBinary) {
moduleConfig.wasmBinary = options.wasmBinary;
}
if (options?.wasmUrl) {
moduleConfig.locateFile = (path) => {
if (path.endsWith(".wasm")) {
return options.wasmUrl;
}
return path;
};
} else if (!options?.wasmBinary) {
const wasmUrl = new URL("../../taglib-web.wasm", import.meta.url);
moduleConfig.locateFile = (path) => path.endsWith(".wasm") ? wasmUrl.href : path;
}
const module = await createTagLibModule(moduleConfig);
return module;
}
async function tryLoadEmbeddedWasm() {
const strategies = [
// Relative to user's entry point (where --include embeds files)
() => Deno.readFile(new URL("./taglib-web.wasm", Deno.mainModule)),
// Relative to this library module
() => Deno.readFile(new URL("./taglib-web.wasm", import.meta.url)),
// CWD fallback (last resort — depends on where the binary is invoked)
() => Deno.readFile("taglib-web.wasm")
];
for (const strategy of strategies) {
try {
return await strategy();
} catch {
}
}
return null;
}
export {
loadTagLibModule
};