# Installing and using third party packs in WASM swipl

**URL:** <https://swi-prolog.discourse.group/t/installing-and-using-third-party-packs-in-wasm-swipl/9107>\
**Category:** General\
**Created:** [July 19, 2025, 8:44am UTC](https://swi-prolog.discourse.group/t/installing-and-using-third-party-packs-in-wasm-swipl/9107 "2025-07-19T08:44:14Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![meditans](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/meditans/32/1768_2.png) [@meditans](https://swi-prolog.discourse.group/u/meditans)\
**Post date:** [July 19, 2025, 8:44am UTC](https://swi-prolog.discourse.group/t/installing-and-using-third-party-packs-in-wasm-swipl/9107/1 "2025-07-19T08:44:14Z")

</div>

As the title says, I didn’t find a way to install and use a third party pack while using WASM swipl. Can this be done?

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [July 20, 2025, 7:27am UTC](https://swi-prolog.discourse.group/t/installing-and-using-third-party-packs-in-wasm-swipl/9107/2 "2025-07-20T07:27:40Z")

</div>

You mean a Prolog pack? pack\_install/1,2 won’t work. Typically I’d clone the pack as a git submodule of your application and use attach\_packs/1,2 to make them available.

---

<div class="post-metadata">

**Author:** ![meditans](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/meditans/32/1768_2.png) [@meditans](https://swi-prolog.discourse.group/u/meditans)\
**Post date:** [July 21, 2025, 3:54pm UTC](https://swi-prolog.discourse.group/t/installing-and-using-third-party-packs-in-wasm-swipl/9107/3 "2025-07-21T15:54:37Z")

</div>

Thank you @jan. I’m not sure how to use the `attach_packs/1,2` family of predicates. I put the pack in `static/prolog/packs` in my webapp, and am trying to include them with:

```prolog
:- attach_packs('static/prolog/packs').
:- use_module(library(mavis)).

```

but this doesn’t work, and `pack_attach/1` doesn’t really take a string as an argument, and I’m unsure what the right way of setting this up is.

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [July 21, 2025, 5:32pm UTC](https://swi-prolog.discourse.group/t/installing-and-using-third-party-packs-in-wasm-swipl/9107/4 "2025-07-21T17:32:19Z")

</div>

attach\_packs/1 takes a directory name as argument. Is the directory really there in the WASM version? And is mavis below that dir with a file `pack.pl` and a directory `prolog` holding `mavis.pl`?

---

<div class="post-metadata">

**Author:** ![meditans](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/meditans/32/1768_2.png) [@meditans](https://swi-prolog.discourse.group/u/meditans)\
**Post date:** [July 21, 2025, 6:24pm UTC](https://swi-prolog.discourse.group/t/installing-and-using-third-party-packs-in-wasm-swipl/9107/5 "2025-07-21T18:24:47Z")

</div>

I’m not sure, here’s how my directory structure looks like:

```prolog
...
├── src
│ ├── app.css
│ ├── app.html
│ ├── lib
│ │ ├── components
│ │ ├── ... js specific components ...
│ │ └── index.js
│ └── routes
│ ├── +layout.svelte
│ └── +page.svelte
├── static
│ ├── favicon.png
│ ├── prolog
│ │ ├── ... application specific prolog code ...
│ └── prolog_packs
│ └── mavis-0.2.3
│ ├── pack.pl
│ ├── prolog
│ │ └── mavis.pl
│ ├── README.md
│ └── t
│ ├── intersection.pl
│ ├── predicates.pl
│ └── subtypes.pl
...

```

I am passing the `prolog_packs` directory, in different variations, and the command doesn’t error out, but then the command:

```prolog
:- attach_packs('/prolog_packs').
:- use_module(library(mavis)).

```

Fails because `source_sink library(mavis) does not exist`. I suppose the `static` directory could not be the right place, because that’s for `js` to find stuff, not prolog, but I installed swipl wasm version from `npm`, so I’m not sure where else to put the files.

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [July 22, 2025, 7:18am UTC](https://swi-prolog.discourse.group/t/installing-and-using-third-party-packs-in-wasm-swipl/9107/6 "2025-07-22T07:18:55Z")

</div>

I’m afraid I know very little about web packaging. What matters is what ends up in the WASM file system. Or, do you plan to server the Prolog files from the server?

A good way to package many applications for the wasm version is to use

```
 swipl qlf compile --include <mainfile.pl>

```

That should give a stand-alone .qlf file that you can then load from the WASM app. Does require swipl to be the same version as the WASM version you target.

There may be other ways. The docs may help. @jeswr, how do you package?

---

<div class="post-metadata">

**Author:** ![vognir](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/vognir/32/8052_2.png) [@vognir](https://swi-prolog.discourse.group/u/vognir)\
**Post date:** [August 24, 2026, 5:51pm UTC](https://swi-prolog.discourse.group/t/installing-and-using-third-party-packs-in-wasm-swipl/9107/7 "2026-08-24T17:51:59Z")

</div>

Sorry to resurrect this thread after more than a year but I am also struggling with this issue.

My setup involves serving the following files to access as a web app in the browser:

```prolog
pkg/
  web.pl % the Prolog entry point for my web app
  ... % other Prolog source code files
  swipl-bundle.js % the bundled WASM build of swipl
  index.html % HTML entry point
  style.css % web page styling
  packs/ % directory with packs such as reif
    reif/
      pack.pl
      prolog/
        reif.pl

```

My `index.html` contains a small Javascript `<script>` which loads the WASM module and uses `Prolog.forEach()` to query the `main.` goal defined in `web.pl`. This seems to work very well and loads all the other Prolog source files in the served directory.

However, this breaks down when I introduce packs (stored in the served subdirectory `packs`). No permutation of `attach_packs/1` seems to work, it only silently fails and then I will get `source_sink` errors when I try to `use_module(library(reif))`.

After doing a bit of tracing I’m wondering if the issue is that, for example when I try `attach_packs(packs)` it is attempting to add `./packs` from the Emcripten _virtual file system_, rather than the URL location `https://.../packs`? I can see that `library(wasm)` defines a `user:prolog_load_file/2` specifically for handling files over the internet, but perhaps `file_search_path/2` is only using the Emscripten file system?

Am I missing an obvious way to use packs that are served as part of the web app? If I wanted to add my `packs` directory to the Emscripten file system I assume I would need to compile swipl from scratch (NB: I am currently using the very helpful pre-made builds from [GitHub - SWI-Prolog/npm-swipl-wasm: SWI-Prolog WebAssembly build as a NPM package · GitHub](https://github.com/SWI-Prolog/npm-swipl-wasm)).

(_I’m not sure how to make the `qlf` pre-compilation approach work since I use `library(wasm)` which appears to only be available when running in WASM? Is there a way to “cross-compile” for a different target?_)

---

<div class="post-metadata">

**Author:** ![rla](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/rla/32/6863_2.png) [@rla](https://swi-prolog.discourse.group/u/rla)\
**Post date:** [August 24, 2026, 8:17pm UTC](https://swi-prolog.discourse.group/t/installing-and-using-third-party-packs-in-wasm-swipl/9107/8 "2026-08-24T20:17:26Z")

</div>

If you want to do it manual way through the Emscripten file system, then this old example should show how to put files into the filesystem before loading them with use\_module (check source): [SWI-Prolog Virtual DOM demo](http://demos.rlaanemets.com/prolog-vdom/examples/wasm/index.html)

You might need to write a script that generates either JS code to load all files of a pack or emits some configuration file with the location of files. Then you can iterate them and load them into the filesystem.

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [August 25, 2026, 9:53am UTC](https://swi-prolog.discourse.group/t/installing-and-using-third-party-packs-in-wasm-swipl/9107/9 "2026-08-25T09:53:39Z")

</div>

The problem is that the pack infrastructure heavily relies on file search and this works rather poorly if you have to deal with a large number of candidate HTTP locations ☹ . You should be able to load the required files directly from the pack’s content. As @rla says, adding to the virtual file system is another option. You can also download them to the filesystem using JavaScript and than add the directory using attach\_packs/1.

Suggestions to fix this otherwise are welcome … Some kind of overall pack index we could download, so we do not need searching?

> [@vognir](#):
>
> (_I’m not sure how to make the `qlf` pre-compilation approach work since I use `library(wasm)` which appears to only be available when running in WASM? Is there a way to “cross-compile” for a different target?_)

You should be able to do so using the WASM version under node. Not sure how to get that running though. If you build from source you get `src/swipl.js` that runs the CLI version under `node`.

---

<div class="post-metadata">

**Author:** ![vognir](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/vognir/32/8052_2.png) [@vognir](https://swi-prolog.discourse.group/u/vognir)\
**Post date:** [August 25, 2026, 10:40am UTC](https://swi-prolog.discourse.group/t/installing-and-using-third-party-packs-in-wasm-swipl/9107/10 "2026-08-25T10:40:34Z")

</div>

> [@rla](#):
>
> You might need to write a script that generates either JS code to load all files of a pack or emits some configuration file with the location of files. Then you can iterate them and load them into the filesystem.

Ah I made the incorrect assumption that the virtual filesystem would be immutable once the WASM module is compiled, I wasn’t aware of the [Emscripten Filesystem API](https://emscripten.org/docs/api_reference/Filesystem-API.html) and the ability to dynamically update it from Javascript. This might be the easiest solution as then I can keep my existing (non-virtual) file structure for other (non-WASM) contexts and write a bit of JS glue to make swipl happy. Thanks @rla for sharing the example!

> [@jan](#):
>
> The problem is that the pack infrastructure heavily relies on file search and this works rather poorly if you have to deal with a large number of candidate HTTP locations ☹ .

Yes this is tricky! I’m not familiar with the underlying implementation but my (probably overly simplistic) first thought was to wonder whether `file_search_path/2` could be used with URLs like:

```prolog
file_search_path(library, 'http://.../library/')

```

such that `library(reif)` would be expanded to `'http://.../library/reif.pl'` and the file fetched rather than read from the virtual file system. However that is probably not straightforward to implement!

> [@jan](#):
>
> You should be able to do so using the WASM version under node.

Ah yes of course, my second incorrect assumption of the day. Thanks @jan I should have thought to use node for this.

---

<div class="post-metadata">

**Author:** ![vognir](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/vognir/32/8052_2.png) [@vognir](https://swi-prolog.discourse.group/u/vognir)\
**Post date:** [August 25, 2026, 11:13am UTC](https://swi-prolog.discourse.group/t/installing-and-using-third-party-packs-in-wasm-swipl/9107/11 "2026-08-25T11:13:00Z")

</div>

For anyone else searching on this topic, I ended up using something along the following lines (inspired by @rla’s approach):

```javascript
// Fetch packs and write to Emscripten virtual file system
function loadPacks(module) {
  const dirs = ["packs/reif/prolog"];
  const files = [
    "packs/reif/pack.pl",
    "packs/reif/prolog/reif.pl"
  ];
  dirs.map((d) => module.FS.mkdirTree(d));
  return Promise.all(files.map((f) => {
    fetch(f).then((response) => response.arrayBuffer())
            .then((content) => module.FS.writeFile(f, content))
  }));
}

```

This means that `attach_packs(packs)` now works as expected.
