{"id":20225460,"url":"https://github.com/purescript/spago-legacy","last_synced_at":"2026-01-07T21:10:16.491Z","repository":{"id":194985648,"uuid":"692005729","full_name":"purescript/spago-legacy","owner":"purescript","description":"[DEPRECATED] 🍝 PureScript package manager and build tool powered by Dhall and package-sets","archived":false,"fork":false,"pushed_at":"2024-07-28T14:20:12.000Z","size":2470,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":9,"default_branch":"master","last_synced_at":"2024-10-29T21:05:43.701Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/purescript.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-09-15T10:58:59.000Z","updated_at":"2024-07-28T14:20:15.000Z","dependencies_parsed_at":null,"dependency_job_id":"aaa1fb0c-9f0a-4519-8979-d153a6cc31a0","html_url":"https://github.com/purescript/spago-legacy","commit_stats":{"total_commits":674,"total_committers":92,"mean_commits":7.326086956521739,"dds":"0.41246290801186947","last_synced_commit":"886b3d0951fcc04fa788c5964142e46cd3098950"},"previous_names":["purescript/spago-legacy"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/purescript%2Fspago-legacy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/purescript%2Fspago-legacy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/purescript%2Fspago-legacy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/purescript%2Fspago-legacy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/purescript","download_url":"https://codeload.github.com/purescript/spago-legacy/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245480221,"owners_count":20622271,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-14T07:12:58.796Z","updated_at":"2026-01-07T21:10:16.455Z","avatar_url":"https://github.com/purescript.png","language":"Haskell","readme":"# [DEPRECATED] spago-legacy\n\n[![npm](https://img.shields.io/npm/v/spago.svg)][spago-npm]\n[![Latest release](https://img.shields.io/github/v/release/purescript/spago-legacy.svg)](https://github.com/purescript/spago-legacy/releases)\n[![build](https://github.com/purescript/spago-legacy/actions/workflows/build.yml/badge.svg)](https://github.com/purescript/spago-legacy/actions/workflows/build.yml)\n[![Cabal build](https://github.com/purescript/spago-legacy/actions/workflows/cabal.yml/badge.svg)](https://github.com/purescript/spago-legacy/actions/workflows/cabal.yml)\n[![Maintainer: f-f](https://img.shields.io/badge/maintainer-f%2d-f-teal.svg)](http://github.com/f-f)\n\n*(IPA: /ˈspaɡo/)*\n\nPureScript package manager and build tool powered by [Dhall][dhall] and\n[package-sets][package-sets].\n\n\u003e [!WARNING]\\\n\u003e This codebase has been deprecated and is in a frozen state - only critical security vulnerabilities will be merged.\\\n\u003e Please head to the [new Spago codebase](https://github.com/purescript/spago), and keep in mind that all the following docs refer to the legacy releases of Spago, that end with the `0.21.x` line.\n\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"./logo.png\" height=\"500px\" alt=\"Spago logo - a 3d box containing a blob of spaghetti\"\u003e\n\u003c/p\u003e\n\n## Installation\n\nThe recommended installation method for Windows, Linux and macOS is `npm` (see the latest releases on npm\n  [here][spago-npm]):\n\n```\nnpm install -g spago@0.21.0\n```\n\nOther installation methods available:\n- Download the binary from the [latest GitHub release][spago-latest-release]\n- Compile from source by cloning this repo and running `make install`\n- With Nix, using [easy-purescript-nix][spago-nix]\n- On FreeBSD, install with `pkg install hs-spago`\n- On macOS, install with `brew install spago`\n\n**General notes:**\n- The assumption is that you already installed the [PureScript compiler][purescript].\n  If not, get it with `npm install -g purescript`, or the recommended method for your OS.\n- You might have issues with `npm` and Docker (e.g. getting the message \"Downloading the spago binary failed..\" etc)\n  You have two options:\n  - either **do not run npm as root**, because it doesn't work well with binaries. Use it as a nonprivileged user.\n  - or use `--unsafe-perm`: `npm install -g --unsafe-perm spago`\n\n\n## Super quick tutorial\n\nLet's set up a new project!\n\n```console\n$ mkdir purescript-unicorns\n$ cd purescript-unicorns\n$ spago init\n```\n\nThis last command will create a bunch of files:\n\n```\n.\n├── packages.dhall\n├── spago.dhall\n├── src\n│   └── Main.purs\n└── test\n    └── Main.purs\n```\n\nLet's take a look at the two [Dhall][dhall] configuration files that `spago` requires:\n- `packages.dhall`: this file is meant to contain the *totality* of the packages\n  available to your project (that is, any package you might want to import).\n\n  In practice it pulls in the [official package-set][package-sets] as a base,\n  and you are then able to add any package that might not be in the package set,\n  or override existing ones.\n- `spago.dhall`: this is your project configuration. It includes the above package set,\n  the list of your dependencies, the source paths that will be used to build, and any\n  other project-wide setting that `spago` will use.\n\nTo build your project, run:\n\n```console\n$ spago build\n```\n\nThis will download the necessary dependencies and compile the sample project in the `output/`\ndirectory. You can take a look at the content of `output/Main/index.js` to see what kind\nof JavaScript has been generated from your new `Main.purs` file.\n\nYou can already see your project running, by doing\n\n```console\n$ spago run\n```\n\n..which is basically equivalent to the following command:\n\n```console\n$ node -e \"import('./output/Main/index').then(m =\u003e m.main())\"\n```\n\n..which imports the JS file you just looked at, and runs the `main` with Node.\n\nYou can also bundle the project in a single file with an entry point, so it can be run directly (useful for CLI apps):\n\n```console\n$ spago bundle-app\n$ node .\n```\n\n\n\u003c!-- START doctoc generated TOC please keep comment here to allow auto update --\u003e\n\u003c!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --\u003e\n\n- [Design goals and reasons](#design-goals-and-reasons)\n  - [Brief survey of other package managers and build tools available](#brief-survey-of-other-package-managers-and-build-tools-available)\n- [Developing and contributing](#developing-and-contributing)\n- [How do I...](#how-do-i)\n  - [Switch from `psc-package`](#switch-from-psc-package)\n  - [Switch from `bower`](#switch-from-bower)\n  - [See what commands and flags are supported](#see-what-commands-and-flags-are-supported)\n  - [Setup a new project using a specific package set](#setup-a-new-project-using-a-specific-package-set)\n  - [Install a direct dependency](#install-a-direct-dependency)\n  - [Download my dependencies locally](#download-my-dependencies-locally)\n  - [Build and run my project](#build-and-run-my-project)\n  - [Test my project](#test-my-project)\n  - [Run a repl](#run-a-repl)\n  - [Run a standalone PureScript file as a script](#run-a-standalone-purescript-file-as-a-script)\n  - [List available packages](#list-available-packages)\n  - [Install all the packages in the set](#install-all-the-packages-in-the-set)\n  - [Override a package in the package set with a local one](#override-a-package-in-the-package-set-with-a-local-one)\n  - [Override a package in the package set with a remote one](#override-a-package-in-the-package-set-with-a-remote-one)\n  - [Add a package to the package set](#add-a-package-to-the-package-set)\n  - [`bower link`](#bower-link)\n  - [Verify that an addition/override doesn't break the package set](#verify-that-an-additionoverride-doesnt-break-the-package-set)\n  - [Upgrade the package set...](#upgrade-the-package-set)\n    - [...to the latest release automatically](#to-the-latest-release-automatically)\n    - [...to a specific release automatically](#to-a-specific-release-automatically)\n    - [...to a specific tag manually](#to-a-specific-tag-manually)\n  - [Monorepo](#monorepo)\n  - [`devDependencies`, `testDependencies`, or in general a situation with many configurations](#devdependencies-testdependencies-or-in-general-a-situation-with-many-configurations)\n  - [Bundle a project into a single JS file](#bundle-a-project-into-a-single-js-file)\n    - [1. `spago bundle-app`](#1-spago-bundle-app)\n    - [2. `spago bundle-module`](#2-spago-bundle-module)\n    - [Skip the \"build\" step](#skip-the-build-step)\n  - [Make a project with PureScript + JavaScript](#make-a-project-with-purescript--javascript)\n    - [Get started from scratch with Parcel (frontend projects)](#get-started-from-scratch-with-parcel-frontend-projects)\n    - [Get started from scratch with Webpack (frontend projects)](#get-started-from-scratch-with-webpack-frontend-projects)\n    - [Get started from scratch with Nodemon (backend and/or CLI projects)](#get-started-from-scratch-with-nodemon-backend-andor-cli-projects)\n  - [Generate documentation for my project](#generate-documentation-for-my-project)\n  - [Get source maps for my project](#get-source-maps-for-my-project)\n  - [Use alternate backends to compile to Go, C++, Kotlin, etc](#use-alternate-backends-to-compile-to-go-c-kotlin-etc)\n  - [Publish my library](#publish-my-library)\n  - [Get all the licenses of my dependencies](#get-all-the-licenses-of-my-dependencies)\n  - [Know which `purs` commands are run under the hood](#know-which-purs-commands-are-run-under-the-hood)\n  - [Install autocompletions for `bash`](#install-autocompletions-for-bash)\n  - [Install autocompletions for `zsh`](#install-autocompletions-for-zsh)\n  - [Ignore or update the global cache](#ignore-or-update-the-global-cache)\n  - [Know the output path for my compiled code](#know-the-output-path-for-my-compiled-code)\n- [Explanations](#explanations)\n  - [Visual Overview: What happens when you do 'spago build'?](#visual-overview-what-happens-when-you-do-spago-build)\n  - [Configuration file format](#configuration-file-format)\n  - [Why can't `spago` also install my npm dependencies?](#why-cant-spago-also-install-my-npm-dependencies)\n  - [Why we don't resolve JS dependencies when bundling, and how to do it](#why-we-dont-resolve-js-dependencies-when-bundling-and-how-to-do-it)\n  - [How does the \"global cache\" work?](#how-does-the-global-cache-work)\n- [Troubleshooting](#troubleshooting)\n    - [Spago is failing with some errors about \"too many open files\"](#spago-is-failing-with-some-errors-about-too-many-open-files)\n    - [Package set caching problems](#package-set-caching-problems)\n    - [I added a new package to the `packages.dhall`, but `spago` is not installing it. Why?](#i-added-a-new-package-to-the-packagesdhall-but-spago-is-not-installing-it-why)\n\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\n\n\n## Design goals and reasons\n\nOur main design goals are:\n- **Great UX**: you're not supposed to spend your life configuring the build for your project.\n  A good build system just does what's most expected and gets out of the way so you can focus\n  on actually writing the software.\n- **Minimal dependencies**: users should not be expected to install a myriad of tools on their\n  system to support various workflows. We depend only on `git` and `purs` being installed.\n- **Reproducible builds**: thanks to [package sets][package-sets] and [Dhall][dhall], if your\n  project builds today it will also build tomorrow and every day after that.\n\nSome tools that inspired `spago` are: [Rust's Cargo][cargo], [Haskell's Stack][stack],\n[`psc-package`][psc-package], [`pulp`][pulp] and [`purp`][purp].\n\n\n### Brief survey of other package managers and build tools available\n\n`pulp` is excellent, but it is only a build tool. This means that you'll have to use it with\neither `bower` or `psc-package`:\n- If you go for `bower`, you're missing out on package-sets (that is: packages versions\n  that are known to be working together, saving you the headache of fitting package\n  versions together all the time).\n- If you use `psc-package`, you have the problem of not having the ability of overriding\n  packages versions when needed, leading everyone to make their own package-set, which\n  then goes unmaintained, etc.\n\n  Of course you can use the package-set-local-setup to solve this issue, but this is\n  exactly what we're doing here: integrating all the workflow in a single tool, `spago`,\n  instead of having to install and use `pulp`, `psc-package`, `purp`, etc.\n\n\n## Developing and contributing\n\nWe'd love your help, and welcome PRs and contributions!\n\nSome ideas for getting started:\n- [Build and run `spago`](CONTRIBUTING.md#developing-spago)\n- [Help us fix bugs and build features](https://github.com/purescript/spago/issues?utf8=%E2%9C%93\u0026q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22+label%3A%22defect%22)\n- Help us improve our documentation\n- Help us [log bugs and open issues][new-issue]\n\nFor more details see the [`CONTRIBUTING.md`][contributing]\n\n\n## How do I...\n\nThis section contains a collection of workflows you might want to use to get things done with `spago`\n\n### Switch from `psc-package`\n\nDo you have an existing `psc-package` project and want to switch to `spago`?\n\nNo problem! If you run `spago init`, we'll port your existing `psc-package.json`\nconfiguration into a new `spago.dhall` 😎\n\nNote: `spago` won't otherwise touch your `psc-package.json` file, so you'll have to\nremove it yourself.\n\nYou'll note that most of the `psc-package` commands are the same in `spago`, so porting\nyour existing build is just a matter of search-and-replace most of the times.\n\n\n### Switch from `bower`\n\nSwitching from `bower` is about the same workflow: just run `spago init` and\nwe'll try to match the package versions in your `bower.json` with the ones in\nthe package set, porting the packages to your `spago.dhall`\n\nNote: `spago` won't otherwise touch your `bower.json` file, so you'll have to\nremove it yourself.\n\nSome packages might not be found or have the wrong version, in which case\nyou'll have to carefully:\n- try to run `spago install some-package` for packages in the set\n- [add the missing packages](#add-a-package-to-the-package-set) if not in the set\n\n### See what commands and flags are supported\n\nFor an overview of the available commands, run:\n\n```console\n$ spago --help\n```\n\nYou will see several subcommands (e.g. `build`, `test`); you can ask for help\nabout them by invoking the command with `--help`, e.g.:\n\n```console\n$ spago build --help\n```\n\nThis will give a detailed view of the command, and list any command-specific\n(vs global) flags.\n\n### Setup a new project using a specific package set\n\nSince `spago init` does not necessarily use the latest package set. Fortunately, you can specify which package set to use via the `--tag` argument. See the [`purescript/package-sets` repo's releases](https://github.com/purescript/package-sets/releases) for tags you can use:\n\n```console\n$ spago init --tag \"psc-0.13.8-20200822\"\n```\n\n\n### Install a direct dependency\n\nYou can add dependencies that are available in your package set by running:\n\n```console\n# E.g. installing Halogen\n$ spago install halogen\n\n# This also supports multiple packages\n$ spago install foreign simple-json\n```\n\n\n### Download my dependencies locally\n\n```console\n$ spago install\n```\n\nThis will download all the transitive dependencies of your project (i.e. the direct dependencies,\ni.e. the ones listed in the `dependencies` key of `spago.dhall`, plus all their dependencies,\nrecursively) to the local `.spago` folder (and the global cache, if possible).\n\nHowever, running this directly is usually **not necessary**, as all commands that need the dependencies\nto be installed will run this for you.\n\n### Build and run my project\n\nWe can build the project and its dependencies by running:\n\n```console\n$ spago build\n```\n\nThis is mostly just a thin layer above the PureScript compiler command `purs compile`.\n\n*Note*: by default the `build` command will try to install any dependencies that haven't been\nfetched yet - if you wish to disable this behaviour, you can pass the `--no-install` flag.\n\nThe build will produce very many JavaScript files in the `output/` folder. These\nare CommonJS modules, and you can just `require()` them e.g. on Node.\n\nIt's also possible to include custom source paths when building (the ones declared in your\n`sources` config are always included):\n\n```console\n$ spago build --path 'another_source/**/*.purs'\n\n```\n\n**Note**: the wrapper on the compiler is so thin that you can pass options to `purs`.\nE.g. if you wish to output your files in some other place than `output/`, you can run\n\n```console\n$ spago build --purs-args \"-o myOutput/\"\n```\n\nIf you wish to automatically have your project rebuilt when making changes to source files\nyou can use the `--watch` flag:\n\n```console\n$ spago build --watch\n\n# or, to clear the screen on rebuild:\n$ spago build --watch --clear-screen\n\n# files ignored through git (i.e. via .gitignore) don't trigger\n# rebuild by default. If you wish to override this behavior:\n$ spago build --watch --allow-ignored\n```\n\nTo run a command before a build you can use the `--before` flag, eg to post a notification that a build has started:\n\n```console\n$ spago build --watch --before \"notify-send 'Building'\"\n```\n\nTo run a command after the build, use `--then` for successful builds, or `--else` for unsuccessful builds:\n\n```console\n$ spago build --watch --then \"notify-send 'Built successfully'\" --else \"notify-send 'Build failed'\"\n```\n\nMultiple commands are possible - they will be run in the order specified:\n\n```console\n$ spago build --watch --before clear --before \"notify-send 'Building'\"\n```\n\n\nIf you want to run the program (akin to `pulp run`), just use `run`:\n```console\n# The main module defaults to \"Main\"\n$ spago run\n\n# Or define your own module path to Main\n$ spago run --main ModulePath.To.Main\n\n# And pass arguments through to `purs compile`\n$ spago run --main ModulePath.To.Main --purs-args \"--verbose-errors\"\n\n# Or pass arguments to the backend, in this case node\n$ spago run --exec-args \"arg1 arg2\"\n\n# For versions 18 and below, use `node-args` instead:\n$ spago run --node-args \"arg1 arg2\"\n\n```\n\n\n### Test my project\n\nYou can also test your project with `spago`:\n\n```console\n# Test.Main is the default here, but you can override it as usual\n$ spago test --main Test.Main\nBuild succeeded.\nYou should add some tests.\nTests succeeded.\n```\n\n\n### Run a repl\n\nYou can start a repl with the following command:\n\n```console\n$ spago repl\n```\n\n\n### Run a standalone PureScript file as a script\n\nYou can run a standalone PureScript file as a script via `spago script`.\nNote: The module name must be `Main`, and it must export a function `main :: Effect Unit`.\n\nBy default, the following dependencies are installed: `effect`, `console`, `prelude`.\n\nYou can run a script via the following, optionally specifying a package set to use, and additional dependencies to pull from there:\n\n```console\n$ spago script --tag psc-13.8 -d node-fs path/to/script.purs\n```\n\n\n### List available packages\n\nIt is sometimes useful to know which packages are contained in our package set\n(e.g. to see which version we're using, or to search for packages).\n\nYou can get a complete list of the packages your `packages.dhall` imports (together\nwith their versions and URLs) by running:\n\n```console\n$ spago ls packages\n```\n\nBy using the `ls deps` command instead you can restrict the list to direct or transitive dependencies:\n\n```console\n# Direct dependencies, i.e. only the ones listed in spago.dhall\n$ spago ls deps\n\n# Transitive dependencies, i.e. all the dependencies of your dependencies\n$ spago ls deps --transitive\n```\n\n\n### Install all the packages in the set\n\nThere might be cases where you'd like your project to depend on all the packages\nthat are contained in the package set (this is sometimes called\n[\"acme build\"](https://hackage.haskell.org/package/acme-everything)).\n\nYou can accomplish this in pure Dhall in your `spago.dhall`\n\nIt might look something like this (example from [here](https://github.com/purescript/spago/issues/607#issuecomment-612512906)):\n\n```dhall\nlet packages = ./packages.dhall\nlet Package = { dependencies : List Text, repo : Text, version : Text }\nlet PackageAssoc = { mapKey : Text, mapValue : Package }\nlet getPackageName = \\(v : PackageAssoc) -\u003e v.mapKey\nlet List/map = https://prelude.dhall-lang.org/List/map\nin\n  { name = \"acme\"\n  , dependencies =\n        List/map PackageAssoc Text getPackageName (toMap packages)\n  , packages = packages\n  , sources = [ \"src/**/*.purs\" ]\n  }\n```\n\n\n### Override a package in the package set with a local one\n\nLet's say I'm a user of the `simple-json` package. Now, let's say I stumble upon a bug\nin there, but thankfully I figure how to fix it. So I clone it locally and add my fix.\n\nNow if I want to test this version in my current project, how can I tell `spago` to do it?\n\nWe have a `overrides` record in `packages.dhall` just for that!\n\nIn this case we override the package with its local copy, which must have a `spago.dhall`.\n(it should be enough to do `spago init` to have the Bower configuration imported)\n\nIt might look like this:\n\n```haskell\nlet upstream = -- \u003cpackage set URL here\u003e\nin  upstream\n  with simple-json = ../purescript-simple-json/spago.dhall as Location\n```\n\nNote that if we do `spago ls packages`, we'll see that it is now included as a local package:\n\n```console\n$ spago ls packages\n...\nsignal                v10.1.0   Remote \"https://github.com/bodil/purescript-signal.git\"\nsijidou               v0.1.0    Remote \"https://github.com/justinwoo/purescript-sijidou.git\"\nsimple-json           local     Local \"./../purescript-simple-json\"\nsimple-json-generics  v0.1.0    Remote \"https://github.com/justinwoo/purescript-simple-json-generics.git\"\nsmolder               v11.0.1   Remote \"https://github.com/bodil/purescript-smolder.git\"\n...\n```\n\nAnd since local packages are just included in the build, if we add it to the `dependencies`\nin `spago.dhall` and then do `spago install`, it will not be downloaded.\n\n\n### Override a package in the package set with a remote one\n\nLet's now say that we test that our fix from above works, and we are ready to Pull Request the fix.\n\nSo we push our fork and open the PR, but while we wait for the fix to land on the next\n`package sets` release, we still want to use the fix in our production build.\n\nIn this case, we can just change the override to point to some commit of our fork, like this:\n\n\n```haskell\nlet upstream = -- \u003cpackage set URL here\u003e\nin  upstream\n  with simple-json.repo = \"https://github.com/my-user/purescript-simple-json.git\"\n  with simple-json.version = \"701f3e44aafb1a6459281714858fadf2c4c2a977\"\n```\n\n**Note**: you can use a \"branch\", a \"tag\" or a \"commit hash\" as a `version`.\nGenerally it's recommended that you avoid using branches, because if you push new\ncommits to a branch, `spago` won't pick them up unless you delete the `.spago` folder.\n\n\n### Add a package to the package set\n\nIf a package is not in the upstream package set, you can add it in a similar way,\nby changing the `additions` record in the `packages.dhall` file.\n\nE.g. if we want to add the `facebook` package:\n\n```haskell\nlet upstream = -- \u003cpackage set URL here\u003e\nin  upstream\n  with facebook =\n    { dependencies =\n        [ \"console\"\n        , \"aff\"\n        , \"prelude\"\n        , \"foreign\"\n        , \"foreign-generic\"\n        , \"errors\"\n        , \"effect\"\n        ]\n    , repo =\n        \"https://github.com/Unisay/purescript-facebook.git\"\n    , version =\n        \"v0.3.0\"  -- branch, tag, or commit hash\n    }\n```\n\nAs you might expect, this works also in the case of adding local packages:\n\nExample:\n\n```haskell\nlet upstream = -- \u003cpackage set URL here\u003e\nin  upstream\n  with foobar = ../foobar/spago.dhall as Location\n```\n\n\n### `bower link`\n\nSee how to [add local packages](#add-a-package-to-the-package-set) or [override existing ones](#override-a-package-in-the-package-set-with-a-local-one)\n\n\n### Verify that an addition/override doesn't break the package set\n\n\"But wait\", you might say, \"how do I know that my override doesn't break the package set?\"\n\nThis is a fair question, and you can verify that your fix didn't break the rest of the\npackage-set by running the `verify` command.\n\nE.g. if you patched the `foreign` package, and added it as a local package to your package-set,\nyou can check that you didn't break its dependents (also called \"reverse dependencies\")\nby running:\n\n```console\n$ spago verify foreign\n```\n\nOnce you check that the packages you added verify correctly, we would of course very much love\nif you could pull request it to the [Upstream package-set][package-sets] ❤️\n\nIf you decide so, you can read up on how to do it [here][package-sets-contributing].\n\n\n### Upgrade the package set...\n\nThe version of the package-set you depend on is fixed in the `packages.dhall` file\n(look for the `upstream` var).\n\nYou can upgrade to the latest version of the package-set with the `upgrade-set`\ncommand. It will download the package set and write\nthe new url and hashes in the `packages.dhall` file for you.\n\nSpago can update the package set to the latest release or to a specific release automagically. If you wish to use a specific commit, you will have to manually edit one part of your `packages.dhall` file. Each is covered below.\n\n#### ...to the latest release automatically\n\nRunning it would look something like this:\n\n```console\n$ spago upgrade-set\n[info] Updating package-set tag to \"psc-0.13.8-20200822\"\nFetching the new one and generating hashes.. (this might take some time)\n[info] Generating new hashes for the package set file so it will be cached.. (this might take some time)\n```\n\n#### ...to a specific release automatically\n\nIf the package set exists, running `upgrade-set` would look something like this:\n\n```console\n$ spago upgrade-set --tag \"psc-0.13.8-20200822\"\n[info] Updating package-set tag to \"psc-0.13.8-20200822\"\nFetching the new one and generating hashes.. (this might take some time)\n[info] Generating new hashes for the package set file so it will be cached.. (this might take some time)\n```\n\nIf the package set does not exist, your `packages.dhall` file will not be touched and you will see a warning:\n\n```console\nspago upgrade-set --tag \"whoops-i-made-a-big-typo\"\n[info] Updating package-set tag to \"whoops-i-made-a-big-typo\"\nFetching the new one and generating hashes.. (this might take some time)\n[warn] Package-set tag \"whoops-i-made-a-big-typo\" in the repo \"purescript/package-sets\" does not exist.\nWill ignore user-specified tag and continue using current tag: \"psc-0.13.4-20191025\"\n```\n\n#### ...to a specific tag manually\n\nIf you wish to detach from tags for your package-set, you can of course point it to a\nspecific commit. Just set your `upstream` to look something like this:\n\n```haskell\nlet upstream =\n      https://raw.githubusercontent.com/purescript/package-sets/bd72269fec59950404a380a46e293bde34b4618f/src/packages.dhall\n```\n\n### Monorepo\n\nSpago aims to support [\"monorepos\"][luu-monorepo], allowing you to split a blob of code\ninto different \"compilation units\" that might have different dependencies, deliverables, etc.\n\nA typical monorepo setup in spago consists of:\n- some \"libraries\" (i.e. packages that other packages will depend on), each having their own `spago.dhall`\n- some \"apps\" (i.e. packages that no one depends on), each having their own `spago.dhall`\n- a single `packages.dhall` , that includes all the \"libraries\" as local packages, and that\n  all `spago.dhall` files refer to - this is so that all packages share the same package set.\n\nSo for example if you have `lib1`, `lib2` and `app1`, you might have the following file tree:\n\n```\n.\n├── app1\n│   ├── spago.dhall\n│   ├── src\n│   │   └── Main.purs\n│   └── test\n│       └── Main.purs\n├── lib1\n│   ├── spago.dhall\n│   └── src\n│       └── Main.purs\n├── lib2\n│   ├── spago.dhall\n│   └── src\n│       └── Main.purs\n└── packages.dhall\n```\n\nThen:\n- the top level `packages.dhall` might look like this:\n\n```dhall\nlet upstream = https://github.com/purescript/package-sets/releases/download/psc-0.13.4-20191025/packages.dhall sha256:f9eb600e5c2a439c3ac9543b1f36590696342baedab2d54ae0aa03c9447ce7d4\nin upstream\n  with lib1 = ./lib1/spago.dhall as Location\n  with lib2 = ./lib2/spago.dhall as Location\n```\n\n- `lib1/spago.dhall` might look something like this:\n\n```dhall\n{ name =\n    \"lib1\"\n, dependencies =\n    [ \"effect\"\n    , \"console\"\n    , \"prelude\"\n    ]\n, sources =\n    [ \"src/**/*.purs\" ]\n, packages =\n    ../packages.dhall   -- Note: this refers to the top-level packages file\n}\n```\n\n- assuming `lib2` depends on `lib1`, `lib2/spago.dhall` might look something like this:\n\n```dhall\n{ name =\n    \"lib2\"\n, dependencies =\n    [ \"effect\"\n    , \"console\"\n    , \"prelude\"\n    , \"lib1\"            -- Note the dependency here\n    ]\n, sources =\n    [ \"src/**/*.purs\" ]\n, packages =\n    ../packages.dhall\n}\n```\n\n- and then `app1/spago.dhall` might look something like this:\n\n```hs\n{ name =\n    \"app1\"\n, dependencies =\n    -- Note: the app does not include all the dependencies that the lib included\n    [ \"prelude\"\n    , \"simple-json\" -- Note: this dep was not used by the library, only the app uses it\n    , \"lib2\"        -- Note: we add `lib2` as dependency\n    ]\n, packages =\n    -- We also refer to the top-level packages file here, so deps stay in sync for all packages\n    ../packages.dhall\n}\n```\n\n\n### `devDependencies`, `testDependencies`, or in general a situation with many configurations\n\nYou might have a simpler situation than a monorepo, where e.g. you just want to \"split\" dependencies.\n\nA common case is when you don't want to include your test dependencies in your app's dependencies.\n\nE.g. if you want to add `purescript-spec` to your test dependencies you can have a `test.dhall` that looks like this:\n```dhall\nlet conf = ./spago.dhall\n\nin conf // {\n  sources = conf.sources # [ \"test/**/*.purs\" ],\n  dependencies = conf.dependencies # [ \"spec\" ]\n}\n```\n\nAnd then you can run tests like this:\n```console\n$ spago -x test.dhall test\n```\n\n### Bundle a project into a single JS file\n\nFor the cases when you wish to produce a single JS file from your PureScript project,\nthere are basically two ways to do that:\n\n#### 1. `spago bundle-app`\n\nThis will produce a single, executable, dead-code-eliminated file:\n\n**\u003e= v0.15.0**\n\nSince v0.15.0 spago uses `esbuild` as the underlying default bundler. See the [`esbuild` getting started](https://esbuild.github.io/getting-started/#install-esbuild) for installation instructions.\n```console\n# You can specify the main module and the target file, or these defaults will be used. This will bundle for the browser by default.\n$ spago bundle-app --main Main --to index.js\nBundle succeeded and output file to index.js\n\n# If you want to minify the build, use \n$ spago bundle-app --main Main --to index.js --minify\n\n# Or if you want to bundle for node\n$ spago bundle-app --main Main --to index.js --platform node\nBundle succeeded and output file to index.js\n\n\n# We can then run it with node:\n$ node .\n```\n`spago bundle-app` uses the [esbuild bundle format](https://esbuild.github.io/api/#format) [IIFE](https://esbuild.github.io/api/#format-iife).\n\n**\u003c= v0.14.0**\n```console\n# You can specify the main module and the target file, or these defaults will be used\n$ spago bundle-app --main Main --to index.js\nBundle succeeded and output file to index.js\n\n# We can then run it with node:\n$ node .\n```\n\n#### 2. `spago bundle-module`\n\nIf you wish to produce a single, dead-code-eliminated JS module that you can `import` from\nJavaScript:\n\n**\u003e= v0.15.0**\n\n```console\n# You can specify the main module and the target file, or these defaults will be used\n$ spago bundle-module --main Main --to index.js\nBundling first...\nBundle succeeded and output file to index.js\nMake module succeeded and output file to index.js\n\n$ node -e \"import('./index.js').then(m =\u003e console.log(m.main))\"                              \n[Function]\n```\n\n**\u003c= v0.14.0**\n```console\n# You can specify the main module and the target file, or these defaults will be used\n$ spago bundle-module --main Main --to index.js\nBundling first...\nBundle succeeded and output file to index.js\nMake module succeeded and output file to index.js\n\n$ node -e \"console.log(require('./index').main)\"\n[Function]\n```\n\n#### Skip the \"build\" step\n\nWhen running `spago bundle-app` and `spago bundle-module`, Spago will first try to `build`\nyour project, since bundling requires the project to be compiled first.\n\nIf you already compiled your project and want to skip this step you can pass the `--no-build` flag.\n\n\n### Make a project with PureScript + JavaScript\n\nTake a look at [TodoMVC with react-basic + spago + parcel][todomvc] for a working example,\nor follow one of the next \"get started\" sections:\n\n#### Get started from scratch with Parcel (frontend projects)\n\nTo start a project using Spago and Parcel together, here's the commands and file setup you'll need:\n\n1. Follow [Spago's \"Super quick tutorial\"](#super-quick-tutorial)\n2. Initialise a JavaScript/npm project with `npm init`\n3. Install Parcel as a development-time dependency `npm i parcel --save-dev`\n4. Add a JavaScript file which imports and calls the `main` function from the output of `src/Main.purs`.\n  This can be placed in the root directory for your project. Traditionally this file is named `index.js`.\n  The `main` function from `Main.purs` can accept arguments, this is useful since Parcel will replace\n  environment variables inside of JavaScript.\n  It is recommended to read any environment variables in the JavaScript file and pass them as\n  arguments to `main`. Here is an example JavaScript file:\n\n  **\u003e= v0.15.0**\n  ```js\n  import * as Main from './output/Main/index';\n\n  function main () {\n      /*\n      Here we could add variables such as\n\n      var baseUrl = process.env.BASE_URL;\n\n      Parcel will replace `process.env.BASE_URL`\n      with the string contents of the BASE_URL environment\n      variable at bundle/build time.\n      A .env file can also be used to override shell variables\n      for more information, see https://en.parceljs.org/env.html\n\n      These variables can be supplied to the Main.main function.\n      However, you will need to change the type to accept variables, by default it is an Effect.\n      You will probably want to make it a function from String -\u003e Effect ()\n    */\n\n    Main.main();\n  }\n\n  // HMR setup. For more info see: https://parceljs.org/hmr.html\n  if (module.hot) {\n    module.hot.accept(function () {\n      console.log('Reloaded, running main again');\n      main();\n    });\n  }\n\n  console.log('Starting app');\n\n  main();\n  ```\n\n  **\u003c= v0.14.0**\n  ```js\n  var Main = require('./output/Main');\n\n  function main () {\n      /*\n      Here we could add variables such as\n\n      var baseUrl = process.env.BASE_URL;\n\n      Parcel will replace `process.env.BASE_URL`\n      with the string contents of the BASE_URL environment\n      variable at bundle/build time.\n      A .env file can also be used to override shell variables\n      for more information, see https://en.parceljs.org/env.html\n\n      These variables can be supplied to the Main.main function.\n      However, you will need to change the type to accept variables, by default it is an Effect.\n      You will probably want to make it a function from String -\u003e Effect ()\n    */\n\n    Main.main();\n  }\n\n  // HMR setup. For more info see: https://parceljs.org/hmr.html\n  if (module.hot) {\n    module.hot.accept(function () {\n      console.log('Reloaded, running main again');\n      main();\n    });\n  }\n\n  console.log('Starting app');\n\n  main();\n  ```\n\n5. Add an HTML file which sources your JavaScript file. This can be named `index.html`\n  and placed in the root directory of your project. Here is an example HTML file:\n\n  ```html\n  \u003c!doctype html\u003e\n  \u003chtml lang=\"en\" data-framework=\"purescript\"\u003e\n  \u003chead\u003e\n    \u003cmeta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"\u003e\n  \u003c/head\u003e\n\n  \u003cbody\u003e\n    \u003cdiv id=\"app\"\u003e\u003c/div\u003e\n    \u003cscript src=\"./index.js\" type=\"module\"\u003e\u003c/script\u003e\n  \u003c/body\u003e\n  \u003c/html\u003e\n  ```\n\n6. Add a development script to `package.json` which will hot-reload the JavaScript generated\n  by the compiler using Parcel. Here, we'll call this script `dev`:\n\n  ```js\n  ...\n    \"scripts\": {\n      \"dev\": \"parcel index.html\",\n    },\n  ...\n  ```\n\n  But in order for this script to pick up the changes we make to our PureScript files,\n  we should have something that hot-recompiles our code.\n\n  If you're using an editor integration then `purs ide` will take care of this\n  recompilation transparently as you save the files.\n  If not, you can run `spago build --watch` in another terminal to achieve the\n  same result.\n\n  NPM scripts allow project dependencies to be treated as if they are on your `$PATH`.\n  When you run it with `npm run dev`, Parcel will tell you which port your application\n  is being served on, by default this will be `localhost:1234`.\n\n  If you've followed this guide you can navigate there in a browser and open the JavaScript console,\n  you will see the output of both `index.js` and the compiled `Main.purs` file.\n  When you modify any purescript file in `./src`, you should see Spago and Parcel rebuild your application,\n  and the browser should execute the new code.\n  For some applications you may adjust the JavaScript function that handles hot modules to\n  fully reload the page with `window.location.reload();`.\n\n7. At this point we should be able to test our program by running `npm run dev`.\n  When you navigate a browser to `localhost:1234`, you should see '🍝' as output in the JavaScript console\n  if this was performed successfully!\n\n8. When you are ready to build and deploy your application as static html/js/css,\n  you may add a `build` script to `package.json` in order to produce a final bundle.\n  This script is usually something like `spago build \u0026\u0026 parcel build index.html`.\n\n\n#### Get started from scratch with Webpack (frontend projects)\n\n1. Follow [Spago's \"Super quick tutorial\"](#super-quick-tutorial)\n2. Initialise a JavaScript/npm project with `npm init`\n3. Add Webpack and purescript-psa as development-time dependencies: `npm install --save-dev webpack webpack-cli webpack-dev-server purescript-psa`\n4. **\u003e= v0.15.0** \n\n  Install the HTML plugin for WebPack `npm install --save-dev html-webpack-plugin`.\n\n  **\u003c= v0.14.0** \n  \n  Install the PureScript loader and HTML plugin for WebPack `npm install --save-dev purs-loader html-webpack-plugin`.\n  Note that you may require additional loaders for css/scss, image files, etc. Please refer to the [Webpack documentation](https://webpack.js.org/) for more information.\n  \n5. Create an HTML file that will serve as the entry point for your application.\n  Typically this is `index.html`. In your HTML file, be sure to pull in the `bundle.js` file, which will be Webpack's output. Here is an example HTML file:\n\n  ```html\n  \u003c!doctype html\u003e\n  \u003chtml lang=\"en\" data-framework=\"purescript\"\u003e\n  \u003chead\u003e\n    \u003cmeta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"\u003e\n  \u003c/head\u003e\n\n  \u003cbody\u003e\n    \u003cdiv id=\"app\"\u003e\u003c/div\u003e\n    \u003cscript src=\"./bundle.js\"\u003e\u003c/script\u003e\n  \u003c/body\u003e\n  \u003c/html\u003e\n  ```\n\n6. Create a `webpack.config.js` file in the root of your project. Here is an example webpack configuration:\n\n  **\u003e= v0.15.0** \n  ```js\n  import path from 'path'\n  import HtmlWebpackPlugin from 'html-webpack-plugin'\n  import webpack from 'webpack'\n  import { dirname } from 'path';\n  import { fileURLToPath } from 'url';\n\n  const __dirname = dirname(fileURLToPath(import.meta.url));\n  const isWebpackDevServer = process.argv.some(a =\u003e path.basename(a) === 'webpack-dev-server')\n  const isWatch = process.argv.some(a =\u003e a === '--watch')\n\n  const plugins =\n    isWebpackDevServer || !isWatch ? [] : [\n      function () {\n        this.plugin('done', function (stats) {\n          process.stderr.write(stats.toString('errors-only'))\n        })\n      }\n    ]\n\n\n  export default {\n    devtool: 'eval-source-map',\n    mode: 'development',\n    devServer: {\n      port: 4008,\n      static: {\n        directory: path.resolve(__dirname,'dist'),\n      },\n    },\n\n    entry: './index.js',\n\n    output: {\n      path: path.resolve(__dirname,'dist'),\n      filename: 'bundle.js'\n    },\n\n    module: {\n      rules: [\n        {\n          test: /\\.(png|jpg|gif)$/i,\n          use: [\n            {\n              loader: 'url-loader',\n              options: {\n                limit: 8192,\n              },\n            },\n          ],\n        },\n      ]\n    },\n\n    resolve: {\n      modules: ['node_modules'],\n      extensions: ['.js']\n    },\n\n    plugins: [\n      new webpack.LoaderOptionsPlugin({\n        debug: true\n      }),\n      new HtmlWebpackPlugin({\n        title: 'purescript-webpack-example',\n        template: 'index.html',\n        inject: false  // See stackoverflow.com/a/38292765/3067181\n      })\n    ].concat(plugins)\n  }\n  ```\n\n  **\u003c= v0.14.0**\n  ```js\n\n  'use strict';\n\n  const path = require('path');\n  const HtmlWebpackPlugin = require('html-webpack-plugin');\n  const webpack = require('webpack');\n  const isWebpackDevServer = process.argv.some(a =\u003e path.basename(a) === 'webpack-dev-server');\n  const isWatch = process.argv.some(a =\u003e a === '--watch');\n\n  const plugins =\n    isWebpackDevServer || !isWatch ? [] : [\n      function(){\n        this.plugin('done', function(stats){\n          process.stderr.write(stats.toString('errors-only'));\n        });\n      }\n    ]\n  ;\n\n  module.exports = {\n    devtool: 'eval-source-map',\n\n    devServer: {\n      contentBase: path.resolve(__dirname, 'dist'),\n      port: 4008,\n      stats: 'errors-only'\n    },\n\n    entry: './src/index.js',\n\n    output: {\n      path: path.resolve(__dirname, 'dist'),\n      filename: 'bundle.js'\n    },\n\n    module: {\n      rules: [\n        {\n          test: /\\.purs$/,\n          use: [\n            {\n              loader: 'purs-loader',\n              options: {\n                src: [\n                  'src/**/*.purs'\n                ],\n                spago: true,\n                watch: isWebpackDevServer || isWatch,\n                pscIde: true\n              }\n            }\n          ]\n        },\n        {\n          test: /\\.(png|jpg|gif)$/i,\n          use: [\n            {\n              loader: 'url-loader',\n              options: {\n                limit: 8192,\n              },\n            },\n          ],\n        },\n      ]\n    },\n\n    resolve: {\n      modules: [ 'node_modules' ],\n      extensions: [ '.purs', '.js']\n    },\n\n    plugins: [\n      new webpack.LoaderOptionsPlugin({\n        debug: true\n      }),\n      new HtmlWebpackPlugin({\n        title: 'purescript-webpack-example',\n        template: 'index.html',\n        inject: false  // See stackoverflow.com/a/38292765/3067181\n      })\n    ].concat(plugins)\n  };\n  ```\n\n7. Add a `src/index.js`: this file will import and execute the PureScript `Main` module,\n  and serves as the entry point for the Webpack bundler.\n\n  You can also use this file to refer to environment variables which can then be passed to PureScript code.\n  Please refer to the Webpack documentation on environment variable replacement during bundling.\n  Here is an example `index.js` file:\n\n  **\u003e= v0.15.0**\n  ```js\n  import { main } from '../output/Main/index'\n\n  main()\n  console.log('app starting');\n  ```\n\n  **\u003c= v0.14.0**\n  ```js\n\n  'use strict';\n\n  require('./Main.purs').main();\n\n  if (module.hot) {\n    module.hot.accept();\n  }\n\n  console.log('app starting');\n  ```\n\n  Also, make sure you are calling `main` properly if you are passing arguments (due to\n  PureScript specifics of [modelling effectful computations](https://stackoverflow.com/a/55750945/3067181)):\n\n  **\u003e= v0.15.0**\n\n  ```js\n\n  var arg1 = 'arg1';\n  main(arg1)();\n\n  ```\n\n  **\u003c= v0.14.0**\n  ```js\n\n  var arg1 = 'arg1';\n  require('./Main.purs').main(arg1)();\n\n  ```\n\n8. Add the following development script to `package.json`:\n\n  **\u003e= v0.15.0**\n  ```js\n  ...\n    \"scripts\": {\n      ...,\n      \"webpack:server\": \"spago build -w \u0026 webpack-dev-server --progress --hot\"\n    },\n  ...\n  ```\n\n  **\u003c= v0.14.0**\n  ```js\n  ...\n    \"scripts\": {\n      ...,\n      \"webpack:server\": \"webpack-dev-server --progress --hot\"\n    },\n  ...\n  ```\n\n9. At this point we should be able to run our program by calling `npm run webpack:server`.\n  If you point your browser to `localhost:4008` you should see `🍝` in the JavaScript\n  development console. This means everything went alright!\n\n10. For production builds, it is recommended to have separate scripts to build and serve.\n  Please refer to the [Webpack documentation](https://webpack.js.org/) for more information.\n\n\n#### Get started from scratch with Nodemon (backend and/or CLI projects)\n\n1. Follow [Spago's \"Super quick tutorial\"](#super-quick-tutorial)\n2. Initialise a JavaScript/npm project with `npm init`\n3. Add Nodemon as a development-time dependency: `npm install --save-dev nodemon`\n4. Add a JavaScript file which imports and calls the `main` function from the output of `src/Main.purs`.\n\n  This can be placed in the root directory of your project, and traditionally this file is named `index.js`.\n\n  The `main` function from `Main.purs` can accept arguments, and this is useful since the Node\n  runtime will replace environment variables inside of JavaScript.\n  It is recommended to read any environment variables in the JavaScript file and pass them as arguments to `main`.\n\n  Here is an example JavaScript file:\n  \n  **\u003e= v0.15.0**\n  ```js\n  import * as Main from './output/Main';\n\n  function main () {\n      /*\n      Here we could add variables such as\n\n      var baseUrl = process.env.BASE_URL;\n\n      Node will replace `process.env.BASE_URL`\n      with the string contents of the BASE_URL environment\n      variable at bundle/build time.\n\n      These variables can be supplied to the Main.main function,\n      however, you will need to change the type to accept variables, by default it is an Effect.\n      You will probably want to make it a function from String -\u003e Effect ()\n    */\n\n    Main.main();\n  }\n  ```\n\n  **\u003c= v0.14.0**\n  ```js\n  'use strict'\n\n  var Main = require('./output/Main');\n\n  function main () {\n      /*\n      Here we could add variables such as\n\n      var baseUrl = process.env.BASE_URL;\n\n      Node will replace `process.env.BASE_URL`\n      with the string contents of the BASE_URL environment\n      variable at bundle/build time.\n\n      These variables can be supplied to the Main.main function,\n      however, you will need to change the type to accept variables, by default it is an Effect.\n      You will probably want to make it a function from String -\u003e Effect ()\n    */\n\n    Main.main();\n  }\n  ```\n\n5. At this point we should be able to run our program by calling `spago build` followed by `node index.js`.\n  If you see `🍝` as output then this was successful!\n6. Now we want to enable Nodemon, which will watch for file changes in the dependency tree and\n  reload our Node program every time there is a new change.\n  We'll also tell Spago to watch our PureScript source files so that they are compiled,\n  which in turn will trigger a Nodemon reload.\n\n  To configure this, add the following script to your `package.json` file:\n\n  ```js\n  ..\n    \"scripts\": {\n      \"dev\": \"spago build --watch \u0026 nodemon \\\"node index.js\\\"\",\n    },\n  ...\n  ```\n\n7. You can now run your development environment by calling `npm run dev`\n\n8. For a production build, add the following scripts to your `package.json`:\n\n  ```js\n  ...\n    \"scripts\": {\n      \"build\": \"spago build \u0026\u0026 node index.js\"\n    },\n  ...\n  ```\n\n9. To run a production build, you can now run `npm run build`!\n\nFor publishing CLI programs or NPM modules, please refer to the [relevant npm documentation](https://docs.npmjs.com/cli/publish).\n\nPlease note that if you are publishing a Node module for consumption by JavaScript users,\nit is recommended that you pre-compile your PureScript project before distributing it.\n\n\n### Generate documentation for my project\n\nTo build documentation for your project and its dependencies (i.e. a \"project-local\n[Pursuit][pursuit]\"), you can use the `docs` command:\n```console\n$ spago docs\n```\n\nThis will generate all the documentation in the `./generated-docs` folder of your project.\nYou might then want to open the `index.html` file in there.\n\nIf you wish for the documentation to be opened in browser when generated, you can pass an `open` flag:\n```console\n$ spago docs --open\n```\n\nTo build the documentation as Markdown instead of HTML, or to generate tags for your project,\nyou can pass a `format` flag:\n```console\n$ spago docs --format ctags\n```\n\n### Get source maps for my project\n\nQuoting from [this tweet](https://twitter.com/jusrin00/status/1092071407356387328):\n\n1. build with `--purs-args \"-g sourcemaps\"`\n2. source output (like `var someModule = require('./output/Whatever/index.js');`) and use\n   something like `parcel`, to avoid mangling/destroying the sourcemaps\n3. now you can see your breakpoints in action\n\n**Note**: In \u003e= v0.15.0 this needs to be `import * as someModule from './output/Whatever/index.js'`\n\n### Use alternate backends to compile to Go, C++, Kotlin, etc\n\nSpago supports compiling with alternate purescript backends like [psgo] or [pskt].\nTo use an alternate backend, add the `backend` option to your `spago.dhall` file:\n\n```dhall\n{ name = \"aaa\"\n, backend = \"psgo\"\n...\n```\n\nThe value of the `backend` entry should be the name of the backend executable.\n\n### Publish my library\n\n\nIf you wish to develop a library with `spago` you can definitely do so, and use it to\nmanage and build your project, until you need to \"publish\" your library, where you'll need\nto use `pulp`.\n\nBefore you start you need to have instaled pulp and bower, both of these can be installed using npm\n\nYou also need to add some keys to your `spago.dhall` file:\n  * The first one is `license` it need to be a valid [SPDX license](https://spdx.org/licenses/). \n  * You also need to add a `repository` key that references the location of the project repository\nhere is a example\n``` dhall\n{ name = \"my-first-package\"\n, dependencies =\n  [ \"console\", \"prelude\", \"psci-support\" ]\n, packages = ./packages.dhall\n, sources = [ \"src/**/*.purs\", \"test/**/*.purs\" ]\n, license = \"MIT\"\n, repository = \"https://github.com/me/purescript-my-first-project\"\n}\n```\n\nThis will generate a correct `bower.json` file which will be used by `pulp` later.\n\n\nWhen you decide you want to publish your library for others to use, you should:\n- run `spago bump-version --no-dry-run \u003cBUMP\u003e`. This will generate a `bower.json` in a new  commit in Git that is tagged with the version.\n- run `pulp login`. This will ensure that you are logged in befor you try to publish a package\n- run `pulp publish`. This will ensure the package is registered in Bower, push the version tag to Git and upload documentation to Pursuit.\n- create a PR to add your package to https://github.com/purescript/registry/blob/master/new-packages.json\n\nThe PureScript ecosystem uses the Bower registry as a \"unique names registry\".\nSo in order to \"publish\" a package one needs to add it there, and eventually to [`package-sets`][package-sets].\nConsequentially, package-sets requires (full instructions [here][package-sets-contributing])\nthat packages in it:\n- are in the Bower registry\n- use `spago bump-version` or `pulp version` (because this gives versions with `vX.Y.Z`)\n- use `pulp publish` (so it's available on the Bower registry and on [Pursuit][pursuit])\n\nAll of this will be automated in future versions, removing the need for Pulp.\n\nA library published in this way is [purescript-rave](https://github.com/reactormonk/purescript-rave).\n\n\n### Get all the licenses of my dependencies\n\nFor compliance reasons, you might need to fetch all the `LICENSE` files of your dependencies.\n\nTo do this you can exploit the `ls deps` command.\n\nE.g. if you want to print out all the `LICENSE` files of your direct dependencies:\n\n```bash\n#!/usr/bin/env bash\n\n# Note: the `awk` part is to cut out only the package name\nfor dep in $(spago ls deps | awk '{print $1}')\ndo\n  cat $(find \".spago/${dep}\" -iname 'LICENSE')\ndone\n```\n\n### Know which `purs` commands are run under the hood\n\nThe `-v` flag will print out all the `purs` commands that `spago` invokes during its operations,\nplus a lot of diagnostic info, so you might want to use it to troubleshoot weird behaviours\nand/or crashes.\n\n\n### Install autocompletions for `bash`\n\nYou can just add this to your `.bashrc`:\n\n```bash\nsource \u003c(spago --bash-completion-script `which spago`)\n```\n\nor alternatively if you don't want to edit your `~/.bashrc`:\n\n```bash\nspago --bash-completion-script $(which spago) \u003e\u003e ~/.bash_completion\n```\n\n### Install autocompletions for `zsh`\n\nAutocompletions for `zsh` need to be somewhere in the `fpath` - you can see the folders\nincluded in your by running `echo $fpath`.\n\nYou can also make a new folder - e.g. `~/.my-completions` - and add it to the `fpath`\nby just adding this to your `~/.zshrc`:\n\n```bash\nfpath=(~/.my-completions $fpath)\n```\n\nThen you can obtain the completion definition for zsh and put it in a file called\n`_spago` [(yes it needs to be called like that)](https://github.com/zsh-users/zsh-completions/blob/master/zsh-completions-howto.org#telling-zsh-which-function-to-use-for-completing-a-command):\n\n```bash\nspago --zsh-completion-script $(which spago) \u003e ~/.my-completions/_spago\n```\n\nThen, reload completions with:\n\n```bash\ncompinit\n```\n\n*Note*: you might need to call this multiple times for it to work.\n\n\n### Ignore or update the global cache\n\nThere is a global cache that `spago` uses to avoid re-downloading things - its\nlocation will be printed if you call e.g. `spago install -v`.\n\nIt's possible to change the behaviour of the global cache with the `--global-cache` flag\nthat is accepted by many commands. You can either:\n- skip the cache with `--global-cache=skip`: in this case the global cache will be ignored\n  and the local project will re-download everything\n- update the cache to the latest version with `--global-cache=update`: this might be useful\n  if you want to globally cache a tag or commit that is newer than 24h - the time `spago` will\n  wait before updating its metadata file about \"which things are globally cacheable\".\n\n### Know the output path for my compiled code\n\nAs there are now various factors that can affect the output path of compiled code, run\n`spago path output` along with any flags you would pass to `spago build` (like\n`--purs-args`) to return the output path Spago is using.\nThis can be useful for sharing an output folder with `webpack`, for instance.\n\n## Explanations\n\n### Visual Overview: What happens when you do 'spago build'?\n\n![spago-flowchart.svg](./diagrams/spago-flowchart.svg)\n\n### Configuration file format\n\nIt's indeed useful to know what's the format (or more precisely, the [Dhall][dhall]\ntype) of the files that `spago` expects. Let's define them in Dhall:\n\n```haskell\n-- The basic building block is a Package:\nlet Package =\n  { dependencies : List Text  -- the list of dependencies of the Package\n  , repo = Text               -- the address of the git repo the Package is at\n  , version = Text            -- git tag, branch, or commit hash\n  }\n\n-- The type of `packages.dhall` is a Record from a PackageName to a Package\n-- We're kind of stretching Dhall syntax here when defining this, but let's\n-- say that its type is something like this:\nlet PackageSet =\n  { console : Package\n  , effect : Package\n  ...                  -- and so on, for all the packages in the package-set\n  }\n\n-- The type of the `spago.dhall` configuration is then the following:\nlet Config =\n  { name : Text                   -- the name of our project\n  , dependencies : List Text      -- the list of dependencies of our app\n  , backend : Maybe Text          -- Nothing by default, meaning use purs. If specified, spago will use the executable as the backend\n  , sources : List Text           -- the list of globs for the paths to always include in the build\n  , packages : PackageSet         -- this is the type we just defined above\n  }\n```\n\n### Why can't `spago` also install my npm dependencies?\n\nA common scenario is that you'd like to use things like `react-basic`, or want to depend\non JS libraries like ThreeJS.\nIn any case, you end up depending on some NPM package.\n\nAnd it would be really nice if `spago` would take care of installing all of these\ndependencies, so we don't have to worry about running npm besides it, right?\n\nWhile these scenarios are common, they are also really hard to support.\nIn fact, it might be that a certain NPM package in your transitive dependencies\nwould only support the browser, or only node. Should `spago` warn about that?\nAnd if yes, where should we get all of this info?\n\nAnother big problem is that the JS backend is not the only backend around. For example,\nPureScript has a [C backend][purec] and an [Erlang backend][purerl] among the others.\n\nThese backends are going to use different package managers for their native dependencies,\nand while it's feasible for `spago` to support the backends themselves, also supporting\nall the possible native package managers (and doing things like building package-sets for their\ndependencies' versions) is not a scalable approach (though we might do this in the future if\nthere's enough demand).\n\nSo this is the reason why if you or one of your dependencies need to depend on some \"native\"\npackages, you should run the appropriate package-manager for that (e.g. npm).\n\nFor examples on how to do it, see next section.\n\n\n### Why we don't resolve JS dependencies when bundling, and how to do it\n\n`spago` only takes care of PureScript land. In particular, `bundle-module` will do the\nmost we can do on the PureScript side of things (dead code elimination), but will\nleave the `require`s still in.\n\nTo fill them in you should use the proper js tool of the day, at the time of\nwriting [ParcelJS][parcel] looks like a good option.\n\nIf you wish to see an example of a project building with `spago` + `parcel`, a simple\nstarting point is the [TodoMVC app with `react-basic`][todomvc].\nYou can see in its `package.json` that a \"production build\" is just\n`spago build \u0026\u0026 parcel build index.html`.\n\nIf you open its `index.js` you'll see that it does a `require('./output/Todo.App')`:\nthe files in `output` are generated by `spago build`, and then the `parcel` build resolves\nall the `require`s and bundles all these js files in.\n\nThough this is not the only way to include the built js - for a slimmer build or for importing\nsome PureScript component in another js build we might want to use the output of `bundle-module`.\n\nFor an example of this in a \"production setting\" you can take a look at [affresco][affresco].\nIt is a PureScript monorepo of React-based components and apps.\n\nThe gist of it is that the PureScript apps in the repo are built with `spago build`\n(look in the `package.json` for it), but all the React components can be imported from\nJS apps as well, given that proper modules are built out of the PS sources.\n\nThis is where `spago bundle-module` is used: the `build-purs.rb` builds a bundle out of every\nsingle React component in each component's folder - e.g. let's say we `bundle-module` from\nthe `ksf-login` component and output it in the `index.js` of the component's folder; we can\nthen `yarn install` the single component (note it contains a `package.json`), and require it\nas a separate npm package with `require('@affresco/ksf-login')`.\n\n### How does the \"global cache\" work?\n\nEvery time `spago` will need to \"install dependencies\" it will:\n- check if the package is local to the filesystem: if it is then it will skip it as we can just\n  point to the files\n- check if the ref is already in the global cache. If it is, it will just copy it\n  to the project-local cache\n- download [a metadata file from the `package-sets-metadata`][package-sets-metadata-file] repo\n  if missing from the global cache or older than 24 hours.\n\n  This file contains the list of *tags* and *commits* for every package currently in the package\n  set, updated hourly.\n- check if the tag or commit of the package we need to download is in this cached index,\n  and if it is then this means we can \"globally cache\" that version - this is because commit\n  hashes are immutable, and tags are \"immutable enough\"\n- if a version is deemed to be \"globally cacheable\" then a tarball of that ref is downloaded\n  from GitHub and copied to both the global and the local cache\n- otherwise, the repo is just cloned to the local cache\n\nNote: a question that might come up while reading the above might be \"why not just hit GitHub\nto check commits and tags for every repo while installing?\"\n\nThe problem is that GitHub limits token-less API requests to 50 per hour, so any\ndecently-sized installation will fail to get all the \"cacheable\" items, making the\nglobal cache kind of useless. So we are just caching all of that info for everyone here.\n\n\n## Troubleshooting\n\n#### Spago is failing with some errors about \"too many open files\"\n\nThis might happen because the limit of \"open files per process\" is too low in your OS - as\n`spago` will try to fetch all dependencies in parallel, and this requires lots of file operations.\n\nYou can limit the number of concurrent operations with the `-j` flag, e.g.:\n\n```\n$ spago -j 10 install\n```\n\nTo get a ballpark value for the `j` flag you can take the result of the `ulimit -n` command\n(which gives you the current limit), and divide it by four.\n\n\n#### Package set caching problems\n\nIf you encounter any issues with the hashes for the package-set (e.g. the hash is not deemed\ncorrect by `spago`), then you can have the hashes recomputed by running the `freeze` command:\n\n```console\n$ spago freeze\n```\n\nHowever, this is a pretty rare situation and in principle it should not happen, and when\nit happens it might not be secure to run the above command.\n\nTo understand all the implications of this I'd invite you to read about\n[the safety guarantees][dhall-hash-safety] that Dhall offers.\n\n\n#### I added a new package to the `packages.dhall`, but `spago` is not installing it. Why?\n\nAdding a package to the package-set just includes it in the set of possible packages you\ncan depend on. However, if you wish `spago` to install it you should then add it to\nthe `dependencies` list in your `spago.dhall`.\n\n\n[psgo]: https://github.com/andyarvanitis/purescript-native\n[pskt]: https://github.com/csicar/pskt\n[pulp]: https://github.com/purescript-contrib/pulp\n[purp]: https://github.com/justinwoo/purp\n[dhall]: https://github.com/dhall-lang/dhall-lang\n[cargo]: https://github.com/rust-lang/cargo\n[stack]: https://github.com/commercialhaskell/stack\n[purec]: https://github.com/pure-c/purec\n[parcel]: https://parceljs.org\n[purerl]: https://github.com/purerl/purescript\n[pursuit]: https://pursuit.purescript.org/\n[todomvc]: https://github.com/f-f/purescript-react-basic-todomvc\n[affresco]: https://github.com/KSF-Media/affresco/tree/4b430b48059701a544dfb65b2ade07ef9f36328a\n[spago-npm]: https://www.npmjs.com/package/spago\n[new-issue]: https://github.com/purescript/spago/issues/new\n[spago-nix]: https://github.com/justinwoo/easy-purescript-nix/blob/master/spago.nix\n[purescript]: https://github.com/purescript/purescript\n[psc-package]: https://github.com/purescript/psc-package\n[contributing]: CONTRIBUTING.md\n[luu-monorepo]: https://danluu.com/monorepo/\n[package-sets]: https://github.com/purescript/package-sets\n[travis-spago]: https://travis-ci.com/purescript/spago\n[spago-issues]: https://github.com/purescript/spago/issues\n[spacchettibotti]: https://github.com/spacchettibotti\n[dhall-hash-safety]: https://github.com/dhall-lang/dhall-lang/wiki/Safety-guarantees#code-injection\n[windows-issue-yarn]: https://github.com/purescript/spago/issues/187\n[spago-latest-release]: https://github.com/purescript/spago/releases/tag/0.21.0\n[ubuntu-issue-netbase]: https://github.com/purescript/spago/issues/196\n[ubuntu-issue-libtinfo]: https://github.com/purescript/spago/issues/104#issue-408423391\n[package-sets-metadata]: https://github.com/spacchetti/package-sets-metadata\n[package-sets-contributing]: https://github.com/purescript/package-sets/blob/master/CONTRIBUTING.md\n[package-sets-metadata-file]: https://github.com/spacchetti/package-sets-metadata/blob/master/metadataV1.json\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpurescript%2Fspago-legacy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpurescript%2Fspago-legacy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpurescript%2Fspago-legacy/lists"}