@siglum/engine 0.1.1 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -15,7 +15,8 @@ The full bundle is ~195MB to deploy, but clients only download what their docume
15
15
 
16
16
  **Guides:**
17
17
  - [Examples & Playground Tutorial](examples/README.md) — Build a LaTeX editor UI
18
- - [CTAN Proxy Guide](docs/CTAN_PROXY.md) — Self-host the package proxy for production
18
+ - [CTAN Proxy Guide](docs/ctan-proxy.md) — Self-host the package proxy for production
19
+ - [Building from Source](docs/building.md) — Build WASM engine and bundles
19
20
 
20
21
  ## Quick Start (Local Demo)
21
22
 
@@ -95,6 +96,8 @@ const compiler = new SiglumCompiler({
95
96
 
96
97
  ## Usage
97
98
 
99
+ > **Note:** If using a bundler (Vite, Webpack, etc.), see [Usage with Bundlers](#usage-with-bundlers-vite-webpack-etc) for required setup.
100
+
98
101
  ```javascript
99
102
  import { SiglumCompiler } from '@siglum/engine';
100
103
 
@@ -129,7 +132,7 @@ const compiler = new SiglumCompiler({
129
132
  wasmUrl: '/wasm/busytex.wasm', // URL to WASM binary
130
133
  jsUrl: null, // URL to busytex.js (derived from wasmUrl if null)
131
134
  ctanProxyUrl: null, // CTAN proxy URL (enables CTAN fetching when set)
132
- workerUrl: null, // Custom worker URL (uses embedded worker if null)
135
+ workerUrl: null, // Custom worker URL (required for bundlers)
133
136
 
134
137
  // Feature flags
135
138
  enableCtan: false, // Auto-enabled when ctanProxyUrl is set
@@ -260,6 +263,29 @@ compiler.init(); // Fire and forget — bundles download in background
260
263
  await compiler.compile(source); // Already warmed up
261
264
  ```
262
265
 
266
+ ## Usage with Bundlers (Vite, Webpack, etc.)
267
+
268
+ Bundlers pre-bundle dependencies, which breaks the automatic worker loading. You need to copy the worker file and pass an explicit URL:
269
+
270
+ ```json
271
+ // package.json
272
+ {
273
+ "scripts": {
274
+ "postinstall": "cp node_modules/@siglum/engine/src/worker.js public/worker.js"
275
+ }
276
+ }
277
+ ```
278
+
279
+ ```javascript
280
+ const compiler = new SiglumCompiler({
281
+ bundlesUrl: '/bundles',
282
+ wasmUrl: '/busytex.wasm',
283
+ workerUrl: '/worker.js', // Explicit path to copied worker
284
+ });
285
+ ```
286
+
287
+ The `postinstall` script runs automatically on `npm install`, keeping the worker in sync with the package version.
288
+
263
289
  ## Engines
264
290
 
265
291
  | Engine | Status |
@@ -312,7 +338,7 @@ bun packages/ctan-proxy.ts
312
338
 
313
339
  Packages are cached permanently. The proxy tries TexLive 2025 archives first, then falls back to CTAN mirrors.
314
340
 
315
- For configuration and deployment options, see **[docs/CTAN_PROXY.md](docs/CTAN_PROXY.md)**.
341
+ For configuration and deployment options, see **[docs/ctan-proxy.md](docs/ctan-proxy.md)**.
316
342
 
317
343
  ## Browser Requirements
318
344
 
package/package.json CHANGED
@@ -1,16 +1,31 @@
1
1
  {
2
2
  "name": "@siglum/engine",
3
- "version": "0.1.1",
3
+ "version": "0.1.4",
4
4
  "description": "A browser-based LaTeX compiler. TeX Live 2025 running in WebAssembly, with lazy bundle loading and on-demand package fetching.",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
7
7
  "types": "types/index.d.ts",
8
8
  "exports": {
9
- ".": "./src/index.js",
10
- "./compiler": "./src/compiler.js",
11
- "./bundles": "./src/bundles.js",
12
- "./ctan": "./src/ctan.js",
13
- "./storage": "./src/storage.js"
9
+ ".": {
10
+ "types": "./types/index.d.ts",
11
+ "default": "./src/index.js"
12
+ },
13
+ "./compiler": {
14
+ "types": "./types/compiler.d.ts",
15
+ "default": "./src/compiler.js"
16
+ },
17
+ "./bundles": {
18
+ "types": "./types/bundles.d.ts",
19
+ "default": "./src/bundles.js"
20
+ },
21
+ "./ctan": {
22
+ "types": "./types/ctan.d.ts",
23
+ "default": "./src/ctan.js"
24
+ },
25
+ "./storage": {
26
+ "types": "./types/storage.d.ts",
27
+ "default": "./src/storage.js"
28
+ }
14
29
  },
15
30
  "files": [
16
31
  "src/",
@@ -18,7 +33,6 @@
18
33
  ],
19
34
  "scripts": {
20
35
  "dev": "bun serve-local.ts",
21
- "build:worker": "cp src/worker.js ../webtex/siglum-ui/app/public/worker.js && echo 'Copied worker.js to siglum-ui'",
22
36
  "proxy": "cd packages && bun run ctan-proxy.ts",
23
37
  "build:types": "tsc",
24
38
  "prepublishOnly": "tsc"
package/src/compiler.js CHANGED
@@ -10,7 +10,7 @@ import { BundleManager, detectEngine, extractPreamble, hashPreamble } from './bu
10
10
  * @property {string} [bundlesUrl] - URL to bundles directory
11
11
  * @property {string} [wasmUrl] - URL to busytex.wasm
12
12
  * @property {string} [jsUrl] - URL to busytex.js (derived from wasmUrl if not provided)
13
- * @property {string|null} [workerUrl] - URL to worker.js or null for embedded worker
13
+ * @property {string|null} [workerUrl] - URL to worker.js (required for bundlers like Vite/Webpack)
14
14
  * @property {string} [ctanProxyUrl] - CTAN proxy URL
15
15
  * @property {string} [xzwasmUrl] - XZ decompression WASM URL
16
16
  * @property {(msg: string) => void} [onLog] - Logging callback
@@ -320,7 +320,7 @@ export class SiglumCompiler {
320
320
  _globalActiveWorker = null;
321
321
  }
322
322
 
323
- // Get worker code - use external URL or read from src/worker.js
323
+ // Get worker code - use external URL or fetch from package
324
324
  let workerUrl = this.workerUrl;
325
325
  if (!workerUrl) {
326
326
  // Fetch worker.js and create blob URL
package/src/ctan.js CHANGED
@@ -135,6 +135,7 @@ export class CTANFetcher {
135
135
  this.bundlesUrl = options.bundlesUrl || this.proxyUrl + '/bundles';
136
136
  this.mountedFiles = new Set();
137
137
  this.fileCache = new Map(); // Memory cache for file contents
138
+ this.loadedPackages = new Set(); // Track packages already loaded into memory
138
139
  this.fetchCount = 0;
139
140
  this.onLog = options.onLog || (() => {});
140
141
 
@@ -268,7 +269,7 @@ export class CTANFetcher {
268
269
 
269
270
  // Skip cache for version-specific requests - we want a different version
270
271
  if (!tlYear) {
271
- // Check cache first
272
+ // Check persistent cache
272
273
  const cached = await this.loadPackageFromCache(packageName);
273
274
  if (cached) {
274
275
  if (cached.notFound) {
@@ -288,6 +289,7 @@ export class CTANFetcher {
288
289
  return null;
289
290
  }
290
291
  this.onLog(`[FETCH] ${packageName}: loaded from cache`);
292
+ this.loadedPackages.add(packageName);
291
293
  return cached;
292
294
  }
293
295
  } else {
@@ -334,7 +336,7 @@ export class CTANFetcher {
334
336
  return this.fetchCtanPackage(packageName, tlYear);
335
337
  }
336
338
 
337
- // Check cache first (same cache as CTAN)
339
+ // Check persistent cache (same cache as CTAN)
338
340
  const cached = await this.loadPackageFromCache(packageName);
339
341
  if (cached) {
340
342
  if (cached.notFound) {
@@ -342,6 +344,7 @@ export class CTANFetcher {
342
344
  return null;
343
345
  }
344
346
  this.onLog(`Package ${packageName} loaded from cache (TexLive)`);
347
+ this.loadedPackages.add(packageName);
345
348
  return cached;
346
349
  }
347
350
 
@@ -526,6 +529,10 @@ export class CTANFetcher {
526
529
  }
527
530
 
528
531
  this.fetchCount++;
532
+ this.loadedPackages.add(packageName);
533
+ if (texlivePkg !== packageName) {
534
+ this.loadedPackages.add(texlivePkg);
535
+ }
529
536
  return { files, dependencies: [] };
530
537
  } catch (e) {
531
538
  this.onLog(`[TEXLIVE] EXTRACTION ERROR for ${packageName}: ${e.message}`);
@@ -638,6 +645,10 @@ export class CTANFetcher {
638
645
  }
639
646
 
640
647
  this.fetchCount++;
648
+ this.loadedPackages.add(packageName);
649
+ if (ctanPkg !== packageName) {
650
+ this.loadedPackages.add(ctanPkg);
651
+ }
641
652
  return {
642
653
  files,
643
654
  dependencies: data.dependencies || [],
@@ -695,14 +706,21 @@ export class CTANFetcher {
695
706
  const uniquePackages = [...new Set(packageNames)];
696
707
  const toFetch = [];
697
708
 
698
- // Check cache first
709
+ // Check cache first - use memory cache to avoid filesystem reads on every recompile
699
710
  for (const pkgName of uniquePackages) {
711
+ // Skip filesystem check if package already loaded into memory this session
712
+ if (this.loadedPackages.has(pkgName)) {
713
+ skipped.push(pkgName);
714
+ continue;
715
+ }
716
+
700
717
  const cached = await this.loadPackageFromCache(pkgName);
701
718
  if (cached && cached.files && !cached.notFound) {
702
719
  // Already cached and has files - populate memory cache
703
720
  for (const [path, content] of cached.files) {
704
721
  this.fileCache.set(path, content);
705
722
  }
723
+ this.loadedPackages.add(pkgName);
706
724
  skipped.push(pkgName);
707
725
  } else {
708
726
  toFetch.push(pkgName);
@@ -728,6 +746,7 @@ export class CTANFetcher {
728
746
  for (const res of results) {
729
747
  if (res.status === 'fulfilled' && res.value.result) {
730
748
  fetched.push(res.value.pkgName);
749
+ this.loadedPackages.add(res.value.pkgName);
731
750
  } else {
732
751
  const pkgName = res.status === 'fulfilled'
733
752
  ? res.value.pkgName
@@ -761,10 +780,12 @@ export class CTANFetcher {
761
780
  }
762
781
 
763
782
  /**
764
- * Clear the mounted files set.
783
+ * Clear the mounted files set and memory caches.
765
784
  */
766
785
  clearMountedFiles() {
767
786
  this.mountedFiles.clear();
787
+ this.fileCache.clear();
788
+ this.loadedPackages.clear();
768
789
  }
769
790
  }
770
791
 
@@ -184,7 +184,7 @@ export type SiglumCompilerOptions = {
184
184
  */
185
185
  jsUrl?: string;
186
186
  /**
187
- * - URL to worker.js or null for embedded worker
187
+ * - URL to worker.js (required for bundlers like Vite/Webpack)
188
188
  */
189
189
  workerUrl?: string | null;
190
190
  /**
package/types/ctan.d.ts CHANGED
@@ -42,6 +42,7 @@ export class CTANFetcher {
42
42
  bundlesUrl: string;
43
43
  mountedFiles: Set<any>;
44
44
  fileCache: Map<any, any>;
45
+ loadedPackages: Set<any>;
45
46
  fetchCount: number;
46
47
  onLog: (msg: string) => void;
47
48
  /**
@@ -118,7 +119,7 @@ export class CTANFetcher {
118
119
  mountedFiles: number;
119
120
  };
120
121
  /**
121
- * Clear the mounted files set.
122
+ * Clear the mounted files set and memory caches.
122
123
  */
123
124
  clearMountedFiles(): void;
124
125
  }