Pandoc 3.8.3 compilé en WebAssembly pour la conversion de documents dans des environnements WASI.
Ce projet est expérimental et constitue avant tout un travail de recherche.
- Les patches appliqués aux dépendances Haskell peuvent ne pas être parfaits et n'ont pas été audités de manière exhaustive
- Ce projet peut ne pas convenir à tous les cas d'usage
- Les fichiers de travail de Ralph (agent IA) ont été volontairement conservés dans le dossier
.ralph/pour montrer la méthodologie et le processus de développement - Le binaire résultant (166 MB) est optimisé pour la compatibilité WASI, pas pour la taille
Utilisez ce projet en connaissance de cause et à vos propres risques.
Ce projet permet de compiler Pandoc, le convertisseur de documents universel, en WebAssembly (WASM) pour l'exécuter dans des environnements compatibles WASI (WebAssembly System Interface).
- Binaire :
pandoc.wasm(~166 MB) - Runtime : wasmtime ou tout runtime WASI compatible
- Fonctionnalités : Conversion Markdown vers HTML, PPTX, DOCX, et autres formats supportés par Pandoc
- Limitations : Pas de réseau, pas de Lua, pas de serveur HTTP (voir Limitations)
Pour utiliser pandoc.wasm comme dépendance dans vos projets Node.js :
npm install @nathanhimpens/pandoc-wasmLe fichier pandoc.wasm sera automatiquement téléchargé depuis les GitHub Releases lors de l'installation.
const pandocWasmPath = require('@nathanhimpens/pandoc-wasm');
const { execSync } = require('child_process');
// Utilisation avec wasmtime
execSync(`wasmtime run --dir . ${pandocWasmPath} -o output.pptx input.md`);Le package nécessite que pandoc.wasm soit disponible dans une release GitHub. Si aucune release n'existe encore, vous devrez :
- Compiler le binaire vous-même (voir section HOW TO : Compiler soi-même)
- Créer une release GitHub avec
pandoc.wasmen pièce jointe - Ou copier manuellement le fichier dans
node_modules/@nathanhimpens/pandoc-wasm/
Pour utiliser pandoc.wasm comme dépendance dans vos projets Ruby/Rails :
gem install pandoc_wasmOu ajoutez-le à votre Gemfile :
gem 'pandoc_wasm', '~> 1.0'require 'pandoc_wasm'
# (Optionnel) Configurer le chemin du binaire et le runtime
PandocWasm.binary_path = "/path/to/pandoc.wasm"
PandocWasm.runtime = "wasmtime" # par défaut
# Télécharger le binaire depuis GitHub Releases
PandocWasm.download_to_binary_path!
# Convertir un document (Markdown → PowerPoint)
PandocWasm.run("-o", "output.pptx", "input.md", wasm_dir: ".")
# Avec des arguments pandoc supplémentaires
PandocWasm.run("-o", "output.pptx", "--slide-level=2", "input.md", wasm_dir: ".")
# Vérifier si pandoc.wasm est disponible
PandocWasm.available? # => true / falseLa gem nécessite que pandoc.wasm soit disponible. Vous pouvez :
- Appeler
PandocWasm.download_to_binary_path!pour le télécharger depuis une GitHub Release - Compiler le binaire vous-même (voir section HOW TO : Compiler soi-même)
- Ou copier manuellement le fichier et configurer le chemin avec
PandocWasm.binary_path =
flowchart LR
A[Source Haskell] --> B[GHC WASM 9.12]
B --> C[pandoc.wasm]
C --> D[wasmtime]
D --> E[Conversion de documents]
subgraph patches [Packages Patchés]
P1[basement]
P2[memory]
P3[network]
P4[crypton]
P5[cborg]
P6[xml-conduit]
P7[pandoc-cli]
end
patches --> B
Le compilateur GHC WASM cross-compile le code Haskell vers WebAssembly. Plusieurs packages ont dû être patchés pour supporter la plateforme 32-bit WASM et l'environnement WASI limité.
| Outil | Version | Description |
|---|---|---|
| ghc-wasm-meta | 9.12 | Compilateur GHC pour WASM |
| wasmtime | >= 41.0 | Runtime WASI pour exécuter le binaire |
| cabal | >= 3.10 | Gestionnaire de packages Haskell (inclus dans ghc-wasm-meta) |
# Installation du compilateur GHC WASM
cd ~
curl -sSL https://gitlab.haskell.org/haskell-wasm/ghc-wasm-meta/-/raw/master/bootstrap.sh | FLAVOUR=9.12 sh
# Charger l'environnement (à ajouter dans ~/.zshrc ou ~/.bashrc)
source ~/.ghc-wasm/env
# Vérifier l'installation
wasm32-wasi-ghc --version
# Devrait afficher: The Glorious Glasgow Haskell Compilation System, version 9.12.xgit clone https://github.com/NathanHimpens/pandoc-wasm.git
cd pandoc-wasmsource ~/.ghc-wasm/env
wasm32-wasi-cabal update# Compilation (peut prendre 30-60 minutes selon votre machine)
# L'option -j1 évite les race conditions de compilation
wasm32-wasi-cabal build pandoc-cli -j1
# Le binaire se trouve dans :
# dist-newstyle/build/wasm32-wasi/ghc-9.12.x/pandoc-cli-3.8.3/x/pandoc/build/pandoc/pandoc.wasmcp dist-newstyle/build/wasm32-wasi/ghc-*/pandoc-cli-3.8.3/x/pandoc/build/pandoc/pandoc.wasm .
ls -lh pandoc.wasm
# Devrait afficher ~166M# Test simple : Markdown vers HTML
echo "# Hello World" | wasmtime run --dir . pandoc.wasm
# Test : Markdown vers PowerPoint
wasmtime run --dir . pandoc.wasm -o output.pptx tests/small.md
ls -la output.pptx
# Tests de validation complets
wasmtime run --dir . pandoc.wasm -o small.pptx tests/small.md
wasmtime run --dir . pandoc.wasm -o medium.pptx tests/medium.md
wasmtime run --dir . pandoc.wasm -o large.pptx tests/large.md
echo "Tests réussis si les 3 fichiers .pptx sont créés"wasmtime run --dir . pandoc.wasm [OPTIONS] [FICHIER_ENTREE]Important : L'option
--dir .est obligatoire pour donner accès au système de fichiers via WASI.
# Markdown vers HTML (sortie standard)
wasmtime run --dir . pandoc.wasm document.md
# Markdown vers PowerPoint
wasmtime run --dir . pandoc.wasm -o presentation.pptx document.md
# Markdown vers DOCX
wasmtime run --dir . pandoc.wasm -o document.docx input.md
# Spécifier les formats explicitement
wasmtime run --dir . pandoc.wasm -f markdown -t html document.md
# Depuis stdin
echo "# Titre" | wasmtime run --dir . pandoc.wasm -t htmlLes formats de Pandoc sont supportés, à l'exception de ceux nécessitant :
- Des appels réseau (HTTP)
- Le moteur Lua
- Des processus externes (LaTeX pour PDF)
Ce projet a été réalisé avec l'aide de Ralph, un agent IA autonome spécialisé dans les tâches de développement complexes. Ralph a travaillé sur ce projet en 4 sessions, documentées dans le dossier .ralph/.
| Fichier | Description |
|---|---|
.ralph/progress.md |
Journal de progression détaillé |
.ralph/signs.md |
Leçons apprises et pièges à éviter |
.ralph/activity.log |
Log des commandes exécutées |
.ralph/tasks.yaml |
État des tâches |
RALPH_TASK.md |
Définition initiale de la tâche |
Ces fichiers montrent :
- La méthodologie : Comment aborder la compilation WASM de projets Haskell complexes
- Les obstacles rencontrés : Problèmes de compatibilité 32-bit, APIs manquantes, etc.
- Les solutions appliquées : Patches spécifiques pour chaque package
- La transparence : Le processus complet de développement est visible
Sept packages ont nécessité des modifications pour compiler en WASM. Voir SECURITY.md pour les détails techniques et implications de sécurité.
| Package | Version | Raison du patch |
|---|---|---|
basement |
0.0.16 | Compatibilité 32-bit, suppression GHC.IntWord64 |
memory |
0.18.0 | Désactivation mmap, corrections FFI |
network |
3.2.8.0 | Stubs pour fonctions socket non supportées par WASI |
cborg |
0.2.10.0 | Corrections primitives 32-bit |
crypton |
1.0.5 | Désactivation pthread (ARGON2_NO_THREADS) |
xml-conduit |
1.10.1.0 | Build-type Custom → Simple |
pandoc-cli |
3.8.3 | Suppression flag -threaded |
| Fonctionnalité | Raison | Alternative |
|---|---|---|
| Lua scripting | Complexité d'intégration WASM | Utiliser des filtres JSON |
| Serveur HTTP | Pas de réseau en WASI | N/A |
| Requêtes réseau | WASI ne supporte pas les sockets | Télécharger les ressources localement |
| PDF via LaTeX | Nécessite processus externe | Utiliser HTML ou DOCX |
- Mono-thread : Le runtime WASM n'a pas de threading
- Pas de mmap : Memory-mapping désactivé
- Fonctions réseau stubées : Retournent
ENOSYS - Taille du binaire : ~166 MB (données embarquées)
Extraits de .ralph/signs.md - les pièges à éviter lors de la compilation WASM :
Les primitives
Int64#/Word64#sont maintenant dansGHC.Prim, pasGHC.IntWord64.
Les packages avec
build-type: Customéchouent car le Setup.hs est compilé pour le HOST, pas la TARGET WASM. Solution : patcher versbuild-type: Simple.
GHC WASM n'a pas de runtime threadé. Retirer
-threadeddes ghc-options.
WASI P1 fournit certaines fonctions socket (accept, send, recv) mais pas d'autres (socket, bind, listen, connect). Ne stubber que les fonctions manquantes.
pandoc-wasm/
├── README.md # Ce fichier
├── CHANGELOG.md # Journal des modifications
├── SECURITY.md # Détails des patches de sécurité
├── LICENSE.txt # Licence GPL-2.0-or-later
├── RALPH_TASK.md # Définition de la tâche pour Ralph
├── pandoc_wasm.gemspec # Spécification de la gem Ruby
├── Gemfile # Dépendances de développement
├── Rakefile # Tâches rake (test, build, release)
├── cabal.project # Configuration de build Cabal
├── .gitignore
├── lib/ # Code source de la gem
│ ├── pandoc_wasm.rb # Point d'entrée — module + API publique
│ └── pandoc_wasm/
│ ├── version.rb # Constante VERSION
│ ├── downloader.rb # Téléchargement du .wasm depuis GitHub
│ └── runner.rb # Exécution via le runtime WASI
├── test/ # Tests unitaires et d'intégration (Minitest)
│ ├── test_helper.rb
│ ├── pandoc_wasm_test.rb
│ ├── runner_test.rb
│ ├── downloader_test.rb
│ └── integration_test.rb
├── tests/ # Fichiers de test Markdown
│ ├── small.md
│ ├── medium.md
│ ├── large.md
│ └── test.md
├── patches/ # Packages Haskell patchés
│ ├── basement-0.0.16/
│ ├── memory-0.18.0/
│ ├── network-3.2.8.0/
│ ├── cborg-0.2.10.0/
│ ├── crypton-1.0.5/
│ ├── xml-conduit-1.10.1.0/
│ └── pandoc-cli-3.8.3/
└── .ralph/ # Fichiers de travail Ralph
├── progress.md
├── signs.md
├── activity.log
└── tasks.yaml
Ce projet utilise Pandoc qui est sous licence GPL-2.0-or-later. Les patches sont fournis sous la même licence que les packages originaux.
Ce projet s'inspire du travail de haskell-wasm/pandoc-wasm, qui a démontré la faisabilité de compiler Pandoc en WebAssembly.