feat: frontend support.
This commit is contained in:
0
js/.gitignore
vendored
Normal file
0
js/.gitignore
vendored
Normal file
@@ -4,12 +4,19 @@
|
||||
"workspaces": {
|
||||
"": {
|
||||
"name": "anisette-js",
|
||||
"dependencies": {
|
||||
"@types/node": "^25.3.2",
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.4.0",
|
||||
},
|
||||
},
|
||||
},
|
||||
"packages": {
|
||||
"@types/node": ["@types/node@25.3.2", "", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-RpV6r/ij22zRRdyBPcxDeKAzH43phWVKEjL2iksqo1Vz3CuBUrgmPpPhALKiRfU7OMCmeeO9vECBMsV0hMTG8Q=="],
|
||||
|
||||
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
||||
|
||||
"undici-types": ["undici-types@7.18.2", "", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,16 +7,24 @@
|
||||
"types": "./dist/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts"
|
||||
"types": "./dist/index.d.ts",
|
||||
"default": "./src/browser.ts",
|
||||
"node": "./src/index.ts"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"./src/anisette_rs.js",
|
||||
"./src/anisette_rs.node.js"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "bun build src/index.ts --outfile ../dist/anisette.js --target node --format esm --minify-syntax --minify-whitespace",
|
||||
"build:cjs": "bun build src/index.ts --outfile dist/anisette.cjs --target node --format cjs --minify",
|
||||
"build": "tsc && cp src/anisette_rs.js dist/ && cp src/anisette_rs.node.js dist/",
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.4.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/node": "^25.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
25
js/src/browser.ts
Normal file
25
js/src/browser.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
//@ts-expect-error no types for the Emscripten module factory
|
||||
import ModuleFactory from "./anisette_rs.js";
|
||||
export * from './index';
|
||||
export type EmscriptenModule = any;
|
||||
export interface ModuleOverrides {
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
const wasmUrl = new URL("./anisette_rs.wasm", import.meta.url).href;
|
||||
|
||||
export async function loadWasmModule(
|
||||
moduleOverrides: ModuleOverrides = {}
|
||||
): Promise<EmscriptenModule> {
|
||||
return ModuleFactory({
|
||||
...moduleOverrides,
|
||||
locateFile: (filename: string) => {
|
||||
if (filename.endsWith(".wasm")) return wasmUrl;
|
||||
return filename;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export const loadWasm = loadWasmModule;
|
||||
export const isNodeEnvironment = () => false;
|
||||
export const getWasmBinaryPath = () => wasmUrl;
|
||||
@@ -1,7 +1,6 @@
|
||||
// Public entry point — re-exports everything users need
|
||||
|
||||
export { Anisette } from "./anisette.js";
|
||||
export { loadWasm } from "./wasm-loader.js";
|
||||
export { WasmBridge } from "./wasm-bridge.js";
|
||||
export { Device } from "./device.js";
|
||||
export { LibraryStore } from "./library.js";
|
||||
@@ -15,3 +14,12 @@ export type {
|
||||
DeviceJson,
|
||||
} from "./types.js";
|
||||
export type { AnisetteOptions } from "./anisette.js";
|
||||
|
||||
export {
|
||||
loadWasmModule,
|
||||
loadWasmModule as loadWasm,
|
||||
isNodeEnvironment,
|
||||
getWasmBinaryPath,
|
||||
type EmscriptenModule,
|
||||
type ModuleOverrides,
|
||||
} from "./wasm-loader.js";
|
||||
|
||||
@@ -1,7 +1,94 @@
|
||||
// @ts-expect-error — glue file is generated, no types available
|
||||
import ModuleFactory from "../../dist/anisette_rs.node.js";
|
||||
// Unified WASM loader with automatic environment detection
|
||||
// Uses import.meta.url + protocol detection to support both Node.js and Browser
|
||||
//
|
||||
// Browser (Vite/Webpack/etc): https://... or http://... -> anisette_rs.js + .wasm
|
||||
// Node.js: file://... -> anisette_rs.node.js + .wasm
|
||||
|
||||
// Get the base URL from import.meta.url
|
||||
const MODULE_URL = new URL(import.meta.url);
|
||||
const IS_NODE = MODULE_URL.protocol === "file:";
|
||||
|
||||
// Determine which WASM build to use based on environment
|
||||
const WASM_JS_PATH = IS_NODE
|
||||
? new URL("../dist/anisette_rs.node.js", MODULE_URL)
|
||||
: new URL("../dist/anisette_rs.js", MODULE_URL);
|
||||
|
||||
const WASM_BINARY_PATH = IS_NODE
|
||||
? new URL("../dist/anisette_rs.node.wasm", MODULE_URL)
|
||||
: new URL("../dist/anisette_rs.wasm", MODULE_URL);
|
||||
|
||||
// Module overrides type (Emscripten module configuration)
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export async function loadWasm(moduleOverrides?: Record<string, any>): Promise<any> {
|
||||
return ModuleFactory({ ...moduleOverrides });
|
||||
export type EmscriptenModule = any;
|
||||
|
||||
export interface ModuleOverrides {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the Emscripten WASM module with automatic environment detection.
|
||||
*
|
||||
* This function automatically:
|
||||
* - Detects Node.js vs Browser environment via import.meta.url protocol
|
||||
* - Loads the appropriate WASM build (node or web)
|
||||
* - Configures locateFile to find the .wasm binary
|
||||
* - Initializes the module with optional overrides
|
||||
*
|
||||
* @param moduleOverrides - Optional Emscripten module configuration overrides
|
||||
* @returns Initialized Emscripten module with all exports (_malloc, _free, _anisette_* etc.)
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // Browser (Vue/React/Next.js) and Node.js - same code!
|
||||
* const module = await loadWasmModule();
|
||||
*
|
||||
* // With custom overrides
|
||||
* const module = await loadWasmModule({
|
||||
* print: (text: string) => console.log("WASM:", text),
|
||||
* printErr: (text: string) => console.error("WASM Error:", text),
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
export async function loadWasmModule(
|
||||
moduleOverrides: ModuleOverrides = {}
|
||||
): Promise<EmscriptenModule> {
|
||||
// Dynamic import of the appropriate Emscripten glue file
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const { default: ModuleFactory } = await import(/* @vite-ignore */ WASM_JS_PATH.href) as { default: (config: ModuleOverrides) => Promise<EmscriptenModule> };
|
||||
|
||||
// In browser: let Emscripten use default fetch behavior
|
||||
// In Node.js: provide locateFile to resolve the .wasm path
|
||||
const config: ModuleOverrides = IS_NODE
|
||||
? {
|
||||
...moduleOverrides,
|
||||
locateFile: (filename: string) => {
|
||||
if (filename.endsWith(".wasm")) {
|
||||
// In Node.js, return the absolute file path
|
||||
return WASM_BINARY_PATH.pathname;
|
||||
}
|
||||
return filename;
|
||||
},
|
||||
}
|
||||
: moduleOverrides;
|
||||
|
||||
return ModuleFactory(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function to check if running in Node.js environment.
|
||||
* Uses the same protocol detection as the loader.
|
||||
*/
|
||||
export function isNodeEnvironment(): boolean {
|
||||
return IS_NODE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the resolved WASM binary path (useful for debugging).
|
||||
*/
|
||||
export function getWasmBinaryPath(): string {
|
||||
return IS_NODE ? WASM_BINARY_PATH.pathname : WASM_BINARY_PATH.href;
|
||||
}
|
||||
|
||||
// Re-export for backward compatibility
|
||||
export { loadWasmModule as loadWasm };
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"target": "ES2022",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"lib": ["ES2020", "DOM"],
|
||||
"lib": ["ES2022", "DOM"],
|
||||
"outDir": "./dist",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
|
||||
Reference in New Issue
Block a user