@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 +29 -3
- package/package.json +21 -7
- package/src/compiler.js +2 -2
- package/src/ctan.js +25 -4
- package/types/compiler.d.ts +1 -1
- package/types/ctan.d.ts +2 -1
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/
|
|
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 (
|
|
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/
|
|
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.
|
|
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
|
-
".":
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
"./
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
package/types/compiler.d.ts
CHANGED
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
|
}
|