Détail du package

spago

purescript9.3kMIT0.21.0

🍝 PureScript package manager and build tool powered by Dhall and package-sets

purescript, psc-package, spago, spacchetti

readme

spago

npm Latest release build Build status Maintainer: f-f

(IPA: /ˈspaɡo/)

PureScript package manager and build tool powered by Dhall and package-sets.

spacchetti logo

Installation

The recommended installation method for Windows, Linux and macOS is npm (see the latest releases on npm here):

npm install -g spago

Other installation methods available:

  • Download the binary from the latest GitHub release
  • Compile from source by cloning this repo and running make install
  • With Nix, using easy-purescript-nix
  • On FreeBSD, install with pkg install hs-spago
  • On macOS, install with brew install spago

General notes:

  • The assumption is that you already installed the PureScript compiler. If not, get it with npm install -g purescript, or the recommended method for your OS.
  • You might have issues with npm and Docker (e.g. getting the message "Downloading the spago binary failed.." etc) You have two options:
    • either do not run npm as root, because it doesn't work well with binaries. Use it as a nonprivileged user.
    • or use --unsafe-perm: npm install -g --unsafe-perm spago

Super quick tutorial

Let's set up a new project!

$ mkdir purescript-unicorns
$ cd purescript-unicorns
$ spago init

This last command will create a bunch of files:

.
├── packages.dhall
├── spago.dhall
├── src
│   └── Main.purs
└── test
    └── Main.purs

Let's take a look at the two Dhall configuration files that spago requires:

  • packages.dhall: this file is meant to contain the totality of the packages available to your project (that is, any package you might want to import).

    In practice it pulls in the official package-set as a base, and you are then able to add any package that might not be in the package set, or override existing ones.

  • spago.dhall: this is your project configuration. It includes the above package set, the list of your dependencies, the source paths that will be used to build, and any other project-wide setting that spago will use.

To build your project, run:

$ spago build

This will download the necessary dependencies and compile the sample project in the output/ directory. You can take a look at the content of output/Main/index.js to see what kind of JavaScript has been generated from your new Main.purs file.

You can already see your project running, by doing

$ spago run

..which is basically equivalent to the following command:

$ node -e "import('./output/Main/index').then(m => m.main())"

..which imports the JS file you just looked at, and runs the main with Node.

You can also bundle the project in a single file with an entry point, so it can be run directly (useful for CLI apps):

$ spago bundle-app
$ node .

Design goals and reasons

Our main design goals are:

  • Great UX: you're not supposed to spend your life configuring the build for your project. A good build system just does what's most expected and gets out of the way so you can focus on actually writing the software.
  • Minimal dependencies: users should not be expected to install a myriad of tools on their system to support various workflows. We depend only on git and purs being installed.
  • Reproducible builds: thanks to package sets and Dhall, if your project builds today it will also build tomorrow and every day after that.

Some tools that inspired spago are: Rust's Cargo, Haskell's Stack, psc-package, pulp and purp.

Brief survey of other package managers and build tools available

pulp is excellent, but it is only a build tool. This means that you'll have to use it with either bower or psc-package:

  • If you go for bower, you're missing out on package-sets (that is: packages versions that are known to be working together, saving you the headache of fitting package versions together all the time).
  • If you use psc-package, you have the problem of not having the ability of overriding packages versions when needed, leading everyone to make their own package-set, which then goes unmaintained, etc.

    Of course you can use the package-set-local-setup to solve this issue, but this is exactly what we're doing here: integrating all the workflow in a single tool, spago, instead of having to install and use pulp, psc-package, purp, etc.

Developing and contributing

We'd love your help, and welcome PRs and contributions!

Some ideas for getting started:

For more details see the CONTRIBUTING.md

How do I...

This section contains a collection of workflows you might want to use to get things done with spago

Switch from psc-package

Do you have an existing psc-package project and want to switch to spago?

No problem! If you run spago init, we'll port your existing psc-package.json configuration into a new spago.dhall 😎

Note: spago won't otherwise touch your psc-package.json file, so you'll have to remove it yourself.

You'll note that most of the psc-package commands are the same in spago, so porting your existing build is just a matter of search-and-replace most of the times.

Switch from bower

Switching from bower is about the same workflow: just run spago init and we'll try to match the package versions in your bower.json with the ones in the package set, porting the packages to your spago.dhall

Note: spago won't otherwise touch your bower.json file, so you'll have to remove it yourself.

Some packages might not be found or have the wrong version, in which case you'll have to carefully:

See what commands and flags are supported

For an overview of the available commands, run:

$ spago --help

You will see several subcommands (e.g. build, test); you can ask for help about them by invoking the command with --help, e.g.:

$ spago build --help

This will give a detailed view of the command, and list any command-specific (vs global) flags.

Setup a new project using a specific package set

Since 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 for tags you can use:

$ spago init --tag "psc-0.13.8-20200822"

Install a direct dependency

You can add dependencies that are available in your package set by running:

# E.g. installing Halogen
$ spago install halogen

# This also supports multiple packages
$ spago install foreign simple-json

Download my dependencies locally

$ spago install

This will download all the transitive dependencies of your project (i.e. the direct dependencies, i.e. the ones listed in the dependencies key of spago.dhall, plus all their dependencies, recursively) to the local .spago folder (and the global cache, if possible).

However, running this directly is usually not necessary, as all commands that need the dependencies to be installed will run this for you.

Build and run my project

We can build the project and its dependencies by running:

$ spago build

This is mostly just a thin layer above the PureScript compiler command purs compile.

Note: by default the build command will try to install any dependencies that haven't been fetched yet - if you wish to disable this behaviour, you can pass the --no-install flag.

The build will produce very many JavaScript files in the output/ folder. These are CommonJS modules, and you can just require() them e.g. on Node.

It's also possible to include custom source paths when building (the ones declared in your sources config are always included):

$ spago build --path 'another_source/**/*.purs'

Note: the wrapper on the compiler is so thin that you can pass options to purs. E.g. if you wish to output your files in some other place than output/, you can run

$ spago build --purs-args "-o myOutput/"

If you wish to automatically have your project rebuilt when making changes to source files you can use the --watch flag:

$ spago build --watch

# or, to clear the screen on rebuild:
$ spago build --watch --clear-screen

# files ignored through git (i.e. via .gitignore) don't trigger
# rebuild by default. If you wish to override this behavior:
$ spago build --watch --allow-ignored

To run a command before a build you can use the --before flag, eg to post a notification that a build has started:

$ spago build --watch --before "notify-send 'Building'"

To run a command after the build, use --then for successful builds, or --else for unsuccessful builds:

$ spago build --watch --then "notify-send 'Built successfully'" --else "notify-send 'Build failed'"

Multiple commands are possible - they will be run in the order specified:

$ spago build --watch --before clear --before "notify-send 'Building'"

If you want to run the program (akin to pulp run), just use run:

# The main module defaults to "Main"
$ spago run

# Or define your own module path to Main
$ spago run --main ModulePath.To.Main

# And pass arguments through to `purs compile`
$ spago run --main ModulePath.To.Main --purs-args "--verbose-errors"

# Or pass arguments to the backend, in this case node
$ spago run --exec-args "arg1 arg2"

# For versions 18 and below, use `node-args` instead:
$ spago run --node-args "arg1 arg2"

Test my project

You can also test your project with spago:

# Test.Main is the default here, but you can override it as usual
$ spago test --main Test.Main
Build succeeded.
You should add some tests.
Tests succeeded.

Run a repl

You can start a repl with the following command:

$ spago repl

Run a standalone PureScript file as a script

You can run a standalone PureScript file as a script via spago script. Note: The module name must be Main, and it must export a function main :: Effect Unit.

By default, the following dependencies are installed: effect, console, prelude.

You can run a script via the following, optionally specifying a package set to use, and additional dependencies to pull from there:

$ spago script --tag psc-13.8 -d node-fs path/to/script.purs

List available packages

It is sometimes useful to know which packages are contained in our package set (e.g. to see which version we're using, or to search for packages).

You can get a complete list of the packages your packages.dhall imports (together with their versions and URLs) by running:

$ spago ls packages

By using the ls deps command instead you can restrict the list to direct or transitive dependencies:

# Direct dependencies, i.e. only the ones listed in spago.dhall
$ spago ls deps

# Transitive dependencies, i.e. all the dependencies of your dependencies
$ spago ls deps --transitive

Install all the packages in the set

There might be cases where you'd like your project to depend on all the packages that are contained in the package set (this is sometimes called "acme build").

You can accomplish this in pure Dhall in your spago.dhall

It might look something like this (example from here):

let packages = ./packages.dhall
let Package = { dependencies : List Text, repo : Text, version : Text }
let PackageAssoc = { mapKey : Text, mapValue : Package }
let getPackageName = \(v : PackageAssoc) -> v.mapKey
let List/map = https://prelude.dhall-lang.org/List/map
in
  { name = "acme"
  , dependencies =
        List/map PackageAssoc Text getPackageName (toMap packages)
  , packages = packages
  , sources = [ "src/**/*.purs" ]
  }

Override a package in the package set with a local one

Let's say I'm a user of the simple-json package. Now, let's say I stumble upon a bug in there, but thankfully I figure how to fix it. So I clone it locally and add my fix.

Now if I want to test this version in my current project, how can I tell spago to do it?

We have a overrides record in packages.dhall just for that!

In this case we override the package with its local copy, which must have a spago.dhall. (it should be enough to do spago init to have the Bower configuration imported)

It might look like this:

let upstream = -- <package set URL here>
in  upstream
  with simple-json = ../purescript-simple-json/spago.dhall as Location

Note that if we do spago ls packages, we'll see that it is now included as a local package:

$ spago ls packages
...
signal                v10.1.0   Remote "https://github.com/bodil/purescript-signal.git"
sijidou               v0.1.0    Remote "https://github.com/justinwoo/purescript-sijidou.git"
simple-json           local     Local "./../purescript-simple-json"
simple-json-generics  v0.1.0    Remote "https://github.com/justinwoo/purescript-simple-json-generics.git"
smolder               v11.0.1   Remote "https://github.com/bodil/purescript-smolder.git"
...

And since local packages are just included in the build, if we add it to the dependencies in spago.dhall and then do spago install, it will not be downloaded.

Override a package in the package set with a remote one

Let's now say that we test that our fix from above works, and we are ready to Pull Request the fix.

So we push our fork and open the PR, but while we wait for the fix to land on the next package sets release, we still want to use the fix in our production build.

In this case, we can just change the override to point to some commit of our fork, like this:

let upstream = -- <package set URL here>
in  upstream
  with simple-json.repo = "https://github.com/my-user/purescript-simple-json.git"
  with simple-json.version = "701f3e44aafb1a6459281714858fadf2c4c2a977"

Note: you can use a "branch", a "tag" or a "commit hash" as a version. Generally it's recommended that you avoid using branches, because if you push new commits to a branch, spago won't pick them up unless you delete the .spago folder.

Add a package to the package set

If a package is not in the upstream package set, you can add it in a similar way, by changing the additions record in the packages.dhall file.

E.g. if we want to add the facebook package:

let upstream = -- <package set URL here>
in  upstream
  with facebook =
    { dependencies =
        [ "console"
        , "aff"
        , "prelude"
        , "foreign"
        , "foreign-generic"
        , "errors"
        , "effect"
        ]
    , repo =
        "https://github.com/Unisay/purescript-facebook.git"
    , version =
        "v0.3.0"  -- branch, tag, or commit hash
    }

As you might expect, this works also in the case of adding local packages:

Example:

let upstream = -- <package set URL here>
in  upstream
  with foobar = ../foobar/spago.dhall as Location

bower link

See how to add local packages or override existing ones

Verify that an addition/override doesn't break the package set

"But wait", you might say, "how do I know that my override doesn't break the package set?"

This is a fair question, and you can verify that your fix didn't break the rest of the package-set by running the verify command.

E.g. if you patched the foreign package, and added it as a local package to your package-set, you can check that you didn't break its dependents (also called "reverse dependencies") by running:

$ spago verify foreign

Once you check that the packages you added verify correctly, we would of course very much love if you could pull request it to the Upstream package-set ❤️

If you decide so, you can read up on how to do it here.

Upgrade the package set...

The version of the package-set you depend on is fixed in the packages.dhall file (look for the upstream var).

You can upgrade to the latest version of the package-set with the upgrade-set command. It will download the package set and write the new url and hashes in the packages.dhall file for you.

Spago 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.

...to the latest release automatically

Running it would look something like this:

$ spago upgrade-set
[info] Updating package-set tag to "psc-0.13.8-20200822"
Fetching the new one and generating hashes.. (this might take some time)
[info] Generating new hashes for the package set file so it will be cached.. (this might take some time)

...to a specific release automatically

If the package set exists, running upgrade-set would look something like this:

$ spago upgrade-set --tag "psc-0.13.8-20200822"
[info] Updating package-set tag to "psc-0.13.8-20200822"
Fetching the new one and generating hashes.. (this might take some time)
[info] Generating new hashes for the package set file so it will be cached.. (this might take some time)

If the package set does not exist, your packages.dhall file will not be touched and you will see a warning:

spago upgrade-set --tag "whoops-i-made-a-big-typo"
[info] Updating package-set tag to "whoops-i-made-a-big-typo"
Fetching the new one and generating hashes.. (this might take some time)
[warn] Package-set tag "whoops-i-made-a-big-typo" in the repo "purescript/package-sets" does not exist.
Will ignore user-specified tag and continue using current tag: "psc-0.13.4-20191025"

...to a specific tag manually

If you wish to detach from tags for your package-set, you can of course point it to a specific commit. Just set your upstream to look something like this:

let upstream =
      https://raw.githubusercontent.com/purescript/package-sets/bd72269fec59950404a380a46e293bde34b4618f/src/packages.dhall

Monorepo

Spago aims to support "monorepos", allowing you to split a blob of code into different "compilation units" that might have different dependencies, deliverables, etc.

A typical monorepo setup in spago consists of:

  • some "libraries" (i.e. packages that other packages will depend on), each having their own spago.dhall
  • some "apps" (i.e. packages that no one depends on), each having their own spago.dhall
  • a single packages.dhall , that includes all the "libraries" as local packages, and that all spago.dhall files refer to - this is so that all packages share the same package set.

So for example if you have lib1, lib2 and app1, you might have the following file tree:

.
├── app1
│   ├── spago.dhall
│   ├── src
│   │   └── Main.purs
│   └── test
│       └── Main.purs
├── lib1
│   ├── spago.dhall
│   └── src
│       └── Main.purs
├── lib2
│   ├── spago.dhall
│   └── src
│       └── Main.purs
└── packages.dhall

Then:

  • the top level packages.dhall might look like this:
let upstream = https://github.com/purescript/package-sets/releases/download/psc-0.13.4-20191025/packages.dhall sha256:f9eb600e5c2a439c3ac9543b1f36590696342baedab2d54ae0aa03c9447ce7d4
in upstream
  with lib1 = ./lib1/spago.dhall as Location
  with lib2 = ./lib2/spago.dhall as Location
  • lib1/spago.dhall might look something like this:
{ name =
    "lib1"
, dependencies =
    [ "effect"
    , "console"
    , "prelude"
    ]
, sources =
    [ "src/**/*.purs" ]
, packages =
    ../packages.dhall   -- Note: this refers to the top-level packages file
}
  • assuming lib2 depends on lib1, lib2/spago.dhall might look something like this:
{ name =
    "lib2"
, dependencies =
    [ "effect"
    , "console"
    , "prelude"
    , "lib1"            -- Note the dependency here
    ]
, sources =
    [ "src/**/*.purs" ]
, packages =
    ../packages.dhall
}
  • and then app1/spago.dhall might look something like this:
{ name =
    "app1"
, dependencies =
    -- Note: the app does not include all the dependencies that the lib included
    [ "prelude"
    , "simple-json" -- Note: this dep was not used by the library, only the app uses it
    , "lib2"        -- Note: we add `lib2` as dependency
    ]
, packages =
    -- We also refer to the top-level packages file here, so deps stay in sync for all packages
    ../packages.dhall
}

devDependencies, testDependencies, or in general a situation with many configurations

You might have a simpler situation than a monorepo, where e.g. you just want to "split" dependencies.

A common case is when you don't want to include your test dependencies in your app's dependencies.

E.g. if you want to add purescript-spec to your test dependencies you can have a test.dhall that looks like this:

let conf = ./spago.dhall

in conf // {
  sources = conf.sources # [ "test/**/*.purs" ],
  dependencies = conf.dependencies # [ "spec" ]
}

And then you can run tests like this:

$ spago -x test.dhall test

Bundle a project into a single JS file

For the cases when you wish to produce a single JS file from your PureScript project, there are basically two ways to do that:

1. spago bundle-app

This will produce a single, executable, dead-code-eliminated file:

>= v0.15.0

Since v0.15.0 spago uses esbuild as the underlying default bundler. See the esbuild getting started for installation instructions.

# You can specify the main module and the target file, or these defaults will be used. This will bundle for the browser by default.
$ spago bundle-app --main Main --to index.js
Bundle succeeded and output file to index.js

# If you want to minify the build, use 
$ spago bundle-app --main Main --to index.js --minify

# Or if you want to bundle for node
$ spago bundle-app --main Main --to index.js --platform node
Bundle succeeded and output file to index.js


# We can then run it with node:
$ node .

spago bundle-app uses the esbuild bundle format IIFE.

<= v0.14.0

# You can specify the main module and the target file, or these defaults will be used
$ spago bundle-app --main Main --to index.js
Bundle succeeded and output file to index.js

# We can then run it with node:
$ node .

2. spago bundle-module

If you wish to produce a single, dead-code-eliminated JS module that you can import from JavaScript:

>= v0.15.0

# You can specify the main module and the target file, or these defaults will be used
$ spago bundle-module --main Main --to index.js
Bundling first...
Bundle succeeded and output file to index.js
Make module succeeded and output file to index.js

$ node -e "import('./index.js').then(m => console.log(m.main))"                              
[Function]

<= v0.14.0

# You can specify the main module and the target file, or these defaults will be used
$ spago bundle-module --main Main --to index.js
Bundling first...
Bundle succeeded and output file to index.js
Make module succeeded and output file to index.js

$ node -e "console.log(require('./index').main)"
[Function]

Skip the "build" step

When running spago bundle-app and spago bundle-module, Spago will first try to build your project, since bundling requires the project to be compiled first.

If you already compiled your project and want to skip this step you can pass the --no-build flag.

Make a project with PureScript + JavaScript

Take a look at TodoMVC with react-basic + spago + parcel for a working example, or follow one of the next "get started" sections:

Get started from scratch with Parcel (frontend projects)

To start a project using Spago and Parcel together, here's the commands and file setup you'll need:

  1. Follow Spago's "Super quick tutorial"
  2. Initialise a JavaScript/npm project with npm init
  3. Install Parcel as a development-time dependency npm i parcel --save-dev
  4. Add a JavaScript file which imports and calls the main function from the output of src/Main.purs. This can be placed in the root directory for your project. Traditionally this file is named index.js. The main function from Main.purs can accept arguments, this is useful since Parcel will replace environment variables inside of JavaScript. It is recommended to read any environment variables in the JavaScript file and pass them as arguments to main. Here is an example JavaScript file:

    >= v0.15.0

    import * as Main from './output/Main/index';
    
    function main () {
       /*
       Here we could add variables such as
    
       var baseUrl = process.env.BASE_URL;
    
       Parcel will replace `process.env.BASE_URL`
       with the string contents of the BASE_URL environment
       variable at bundle/build time.
       A .env file can also be used to override shell variables
       for more information, see https://en.parceljs.org/env.html
    
       These variables can be supplied to the Main.main function.
       However, you will need to change the type to accept variables, by default it is an Effect.
       You will probably want to make it a function from String -> Effect ()
     */
    
     Main.main();
    }
    
    // HMR setup. For more info see: https://parceljs.org/hmr.html
    if (module.hot) {
     module.hot.accept(function () {
       console.log('Reloaded, running main again');
       main();
     });
    }
    
    console.log('Starting app');
    
    main();
    

    <= v0.14.0

    var Main = require('./output/Main');
    
    function main () {
       /*
       Here we could add variables such as
    
       var baseUrl = process.env.BASE_URL;
    
       Parcel will replace `process.env.BASE_URL`
       with the string contents of the BASE_URL environment
       variable at bundle/build time.
       A .env file can also be used to override shell variables
       for more information, see https://en.parceljs.org/env.html
    
       These variables can be supplied to the Main.main function.
       However, you will need to change the type to accept variables, by default it is an Effect.
       You will probably want to make it a function from String -> Effect ()
     */
    
     Main.main();
    }
    
    // HMR setup. For more info see: https://parceljs.org/hmr.html
    if (module.hot) {
     module.hot.accept(function () {
       console.log('Reloaded, running main again');
       main();
     });
    }
    
    console.log('Starting app');
    
    main();
    
  5. Add an HTML file which sources your JavaScript file. This can be named index.html and placed in the root directory of your project. Here is an example HTML file:

    <!doctype html>
    <html lang="en" data-framework="purescript">
    <head>
     <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    </head>
    
    <body>
     <div id="app"></div>
     <script src="./index.js" type="module"></script>
    </body>
    </html>
    
  6. Add a development script to package.json which will hot-reload the JavaScript generated by the compiler using Parcel. Here, we'll call this script dev:

    ...
     "scripts": {
       "dev": "parcel index.html",
     },
    ...
    

    But in order for this script to pick up the changes we make to our PureScript files, we should have something that hot-recompiles our code.

    If you're using an editor integration then purs ide will take care of this recompilation transparently as you save the files. If not, you can run spago build --watch in another terminal to achieve the same result.

    NPM scripts allow project dependencies to be treated as if they are on your $PATH. When you run it with npm run dev, Parcel will tell you which port your application is being served on, by default this will be localhost:1234.

    If you've followed this guide you can navigate there in a browser and open the JavaScript console, you will see the output of both index.js and the compiled Main.purs file. When you modify any purescript file in ./src, you should see Spago and Parcel rebuild your application, and the browser should execute the new code. For some applications you may adjust the JavaScript function that handles hot modules to fully reload the page with window.location.reload();.

  7. At this point we should be able to test our program by running npm run dev. When you navigate a browser to localhost:1234, you should see '🍝' as output in the JavaScript console if this was performed successfully!

  8. When you are ready to build and deploy your application as static html/js/css, you may add a build script to package.json in order to produce a final bundle. This script is usually something like spago build && parcel build index.html.

Get started from scratch with Webpack (frontend projects)

  1. Follow Spago's "Super quick tutorial"
  2. Initialise a JavaScript/npm project with npm init
  3. Add Webpack and purescript-psa as development-time dependencies: npm install --save-dev webpack webpack-cli webpack-dev-server purescript-psa
  4. >= v0.15.0

    Install the HTML plugin for WebPack npm install --save-dev html-webpack-plugin.

    <= v0.14.0

    Install the PureScript loader and HTML plugin for WebPack npm install --save-dev purs-loader html-webpack-plugin. Note that you may require additional loaders for css/scss, image files, etc. Please refer to the Webpack documentation for more information.

  5. Create an HTML file that will serve as the entry point for your application. 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:

    <!doctype html>
    <html lang="en" data-framework="purescript">
    <head>
     <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    </head>
    
    <body>
     <div id="app"></div>
     <script src="./bundle.js"></script>
    </body>
    </html>
    
  6. Create a webpack.config.js file in the root of your project. Here is an example webpack configuration:

    >= v0.15.0 ```js import path from 'path' import HtmlWebpackPlugin from 'html-webpack-plugin' import webpack from 'webpack' import { dirname } from 'path'; import { fileURLToPath } from 'url';

    const __dirname = dirname(fileURLToPath(import.meta.url)); const isWebpackDevServer = process.argv.some(a => path.basename(a) === 'webpack-dev-server') const isWatch = process.argv.some(a => a === '--watch')

    const plugins = isWebpackDevServer || !isWatch ? [] : [ function () {

     this.plugin('done', function (stats) {
       process.stderr.write(stats.toString('errors-only'))
     })
    

    } ]

export default { devtool: 'eval-source-map', mode: 'development', devServer: { port: 4008, static: { directory: path.resolve(__dirname,'dist'), }, },

entry: './index.js',

output: {
  path: path.resolve(__dirname,'dist'),
  filename: 'bundle.js'
},

module: {
  rules: [
    {
      test: /\.(png|jpg|gif)$/i,
      use: [
        {
          loader: 'url-loader',
          options: {
            limit: 8192,
          },
        },
      ],
    },
  ]
},

resolve: {
  modules: ['node_modules'],
  extensions: ['.js']
},

plugins: [
  new webpack.LoaderOptionsPlugin({
    debug: true
  }),
  new HtmlWebpackPlugin({
    title: 'purescript-webpack-example',
    template: 'index.html',
    inject: false  // See stackoverflow.com/a/38292765/3067181
  })
].concat(plugins)

}


  **<= v0.14.0**
  ```js

  'use strict';

  const path = require('path');
  const HtmlWebpackPlugin = require('html-webpack-plugin');
  const webpack = require('webpack');
  const isWebpackDevServer = process.argv.some(a => path.basename(a) === 'webpack-dev-server');
  const isWatch = process.argv.some(a => a === '--watch');

  const plugins =
    isWebpackDevServer || !isWatch ? [] : [
      function(){
        this.plugin('done', function(stats){
          process.stderr.write(stats.toString('errors-only'));
        });
      }
    ]
  ;

  module.exports = {
    devtool: 'eval-source-map',

    devServer: {
      contentBase: path.resolve(__dirname, 'dist'),
      port: 4008,
      stats: 'errors-only'
    },

    entry: './src/index.js',

    output: {
      path: path.resolve(__dirname, 'dist'),
      filename: 'bundle.js'
    },

    module: {
      rules: [
        {
          test: /\.purs$/,
          use: [
            {
              loader: 'purs-loader',
              options: {
                src: [
                  'src/**/*.purs'
                ],
                spago: true,
                watch: isWebpackDevServer || isWatch,
                pscIde: true
              }
            }
          ]
        },
        {
          test: /\.(png|jpg|gif)$/i,
          use: [
            {
              loader: 'url-loader',
              options: {
                limit: 8192,
              },
            },
          ],
        },
      ]
    },

    resolve: {
      modules: [ 'node_modules' ],
      extensions: [ '.purs', '.js']
    },

    plugins: [
      new webpack.LoaderOptionsPlugin({
        debug: true
      }),
      new HtmlWebpackPlugin({
        title: 'purescript-webpack-example',
        template: 'index.html',
        inject: false  // See stackoverflow.com/a/38292765/3067181
      })
    ].concat(plugins)
  };
  1. Add a src/index.js: this file will import and execute the PureScript Main module, and serves as the entry point for the Webpack bundler.

    You can also use this file to refer to environment variables which can then be passed to PureScript code. Please refer to the Webpack documentation on environment variable replacement during bundling. Here is an example index.js file:

    >= v0.15.0

    import { main } from '../output/Main/index'
    
    main()
    console.log('app starting');
    

    <= v0.14.0

    
    'use strict';
    
    require('./Main.purs').main();
    
    if (module.hot) {
     module.hot.accept();
    }
    
    console.log('app starting');
    

    Also, make sure you are calling main properly if you are passing arguments (due to PureScript specifics of modelling effectful computations):

    >= v0.15.0

    
    var arg1 = 'arg1';
    main(arg1)();
    

    <= v0.14.0

    
    var arg1 = 'arg1';
    require('./Main.purs').main(arg1)();
    
  2. Add the following development script to package.json:

    >= v0.15.0

    ...
     "scripts": {
       ...,
       "webpack:server": "spago build -w & webpack-dev-server --progress --hot"
     },
    ...
    

    <= v0.14.0

    ...
     "scripts": {
       ...,
       "webpack:server": "webpack-dev-server --progress --hot"
     },
    ...
    
  3. At this point we should be able to run our program by calling npm run webpack:server. If you point your browser to localhost:4008 you should see 🍝 in the JavaScript development console. This means everything went alright!

  4. For production builds, it is recommended to have separate scripts to build and serve. Please refer to the Webpack documentation for more information.

Get started from scratch with Nodemon (backend and/or CLI projects)

  1. Follow Spago's "Super quick tutorial"
  2. Initialise a JavaScript/npm project with npm init
  3. Add Nodemon as a development-time dependency: npm install --save-dev nodemon
  4. Add a JavaScript file which imports and calls the main function from the output of src/Main.purs.

    This can be placed in the root directory of your project, and traditionally this file is named index.js.

    The main function from Main.purs can accept arguments, and this is useful since the Node runtime will replace environment variables inside of JavaScript. It is recommended to read any environment variables in the JavaScript file and pass them as arguments to main.

    Here is an example JavaScript file:

    >= v0.15.0

    import * as Main from './output/Main';
    
    function main () {
       /*
       Here we could add variables such as
    
       var baseUrl = process.env.BASE_URL;
    
       Node will replace `process.env.BASE_URL`
       with the string contents of the BASE_URL environment
       variable at bundle/build time.
    
       These variables can be supplied to the Main.main function,
       however, you will need to change the type to accept variables, by default it is an Effect.
       You will probably want to make it a function from String -> Effect ()
     */
    
     Main.main();
    }
    

    <= v0.14.0

    'use strict'
    
    var Main = require('./output/Main');
    
    function main () {
       /*
       Here we could add variables such as
    
       var baseUrl = process.env.BASE_URL;
    
       Node will replace `process.env.BASE_URL`
       with the string contents of the BASE_URL environment
       variable at bundle/build time.
    
       These variables can be supplied to the Main.main function,
       however, you will need to change the type to accept variables, by default it is an Effect.
       You will probably want to make it a function from String -> Effect ()
     */
    
     Main.main();
    }
    
  5. At this point we should be able to run our program by calling spago build followed by node index.js. If you see 🍝 as output then this was successful!

  6. Now we want to enable Nodemon, which will watch for file changes in the dependency tree and reload our Node program every time there is a new change. We'll also tell Spago to watch our PureScript source files so that they are compiled, which in turn will trigger a Nodemon reload.

    To configure this, add the following script to your package.json file:

    ..
     "scripts": {
       "dev": "spago build --watch & nodemon \"node index.js\"",
     },
    ...
    
  7. You can now run your development environment by calling npm run dev

  8. For a production build, add the following scripts to your package.json:

    ...
     "scripts": {
       "build": "spago build && node index.js"
     },
    ...
    
  9. To run a production build, you can now run npm run build!

For publishing CLI programs or NPM modules, please refer to the relevant npm documentation.

Please note that if you are publishing a Node module for consumption by JavaScript users, it is recommended that you pre-compile your PureScript project before distributing it.

Generate documentation for my project

To build documentation for your project and its dependencies (i.e. a "project-local Pursuit"), you can use the docs command:

$ spago docs

This will generate all the documentation in the ./generated-docs folder of your project. You might then want to open the index.html file in there.

If you wish for the documentation to be opened in browser when generated, you can pass an open flag:

$ spago docs --open

To build the documentation as Markdown instead of HTML, or to generate tags for your project, you can pass a format flag:

$ spago docs --format ctags

Get source maps for my project

Quoting from this tweet:

  1. build with --purs-args "-g sourcemaps"
  2. source output (like var someModule = require('./output/Whatever/index.js');) and use something like parcel, to avoid mangling/destroying the sourcemaps
  3. now you can see your breakpoints in action

Note: In >= v0.15.0 this needs to be import * as someModule from './output/Whatever/index.js'

Use alternate backends to compile to Go, C++, Kotlin, etc

Spago supports compiling with alternate purescript backends like psgo or pskt. To use an alternate backend, add the backend option to your spago.dhall file:

{ name = "aaa"
, backend = "psgo"
...

The value of the backend entry should be the name of the backend executable.

Publish my library

If you wish to develop a library with spago you can definitely do so, and use it to manage and build your project, until you need to "publish" your library, where you'll need to use pulp.

Before you start you need to have instaled pulp and bower, both of these can be installed using npm

You also need to add some keys to your spago.dhall file:

  • The first one is license it need to be a valid SPDX license.
  • You also need to add a repository key that references the location of the project repository here is a example
    { name = "my-first-package"
    , dependencies =
    [ "console", "prelude", "psci-support" ]
    , packages = ./packages.dhall
    , sources = [ "src/**/*.purs", "test/**/*.purs" ]
    , license = "MIT"
    , repository = "https://github.com/me/purescript-my-first-project"
    }
    

This will generate a correct bower.json file which will be used by pulp later.

When you decide you want to publish your library for others to use, you should:

  • run spago bump-version --no-dry-run <BUMP>. This will generate a bower.json in a new commit in Git that is tagged with the version.
  • run pulp login. This will ensure that you are logged in befor you try to publish a package
  • run pulp publish. This will ensure the package is registered in Bower, push the version tag to Git and upload documentation to Pursuit.
  • create a PR to add your package to https://github.com/purescript/registry/blob/master/new-packages.json

The PureScript ecosystem uses the Bower registry as a "unique names registry". So in order to "publish" a package one needs to add it there, and eventually to package-sets. Consequentially, package-sets requires (full instructions here) that packages in it:

  • are in the Bower registry
  • use spago bump-version or pulp version (because this gives versions with vX.Y.Z)
  • use pulp publish (so it's available on the Bower registry and on Pursuit)

All of this will be automated in future versions, removing the need for Pulp.

A library published in this way is purescript-rave.

Get all the licenses of my dependencies

For compliance reasons, you might need to fetch all the LICENSE files of your dependencies.

To do this you can exploit the ls deps command.

E.g. if you want to print out all the LICENSE files of your direct dependencies:

#!/usr/bin/env bash

# Note: the `awk` part is to cut out only the package name
for dep in $(spago ls deps | awk '{print $1}')
do
  cat $(find ".spago/${dep}" -iname 'LICENSE')
done

Know which purs commands are run under the hood

The -v flag will print out all the purs commands that spago invokes during its operations, plus a lot of diagnostic info, so you might want to use it to troubleshoot weird behaviours and/or crashes.

Install autocompletions for bash

You can just add this to your .bashrc:

source <(spago --bash-completion-script `which spago`)

or alternatively if you don't want to edit your ~/.bashrc:

spago --bash-completion-script $(which spago) >> ~/.bash_completion

Install autocompletions for zsh

Autocompletions for zsh need to be somewhere in the fpath - you can see the folders included in your by running echo $fpath.

You can also make a new folder - e.g. ~/.my-completions - and add it to the fpath by just adding this to your ~/.zshrc:

fpath=(~/.my-completions $fpath)

Then you can obtain the completion definition for zsh and put it in a file called _spago (yes it needs to be called like that):

spago --zsh-completion-script $(which spago) > ~/.my-completions/_spago

Then, reload completions with:

compinit

Note: you might need to call this multiple times for it to work.

Ignore or update the global cache

There is a global cache that spago uses to avoid re-downloading things - its location will be printed if you call e.g. spago install -v.

It's possible to change the behaviour of the global cache with the --global-cache flag that is accepted by many commands. You can either:

  • skip the cache with --global-cache=skip: in this case the global cache will be ignored and the local project will re-download everything
  • update the cache to the latest version with --global-cache=update: this might be useful if you want to globally cache a tag or commit that is newer than 24h - the time spago will wait before updating its metadata file about "which things are globally cacheable".

Know the output path for my compiled code

As there are now various factors that can affect the output path of compiled code, run spago path output along with any flags you would pass to spago build (like --purs-args) to return the output path Spago is using. This can be useful for sharing an output folder with webpack, for instance.

Explanations

Visual Overview: What happens when you do 'spago build'?

spago-flowchart.svg

Configuration file format

It's indeed useful to know what's the format (or more precisely, the Dhall type) of the files that spago expects. Let's define them in Dhall:

-- The basic building block is a Package:
let Package =
  { dependencies : List Text  -- the list of dependencies of the Package
  , repo = Text               -- the address of the git repo the Package is at
  , version = Text            -- git tag, branch, or commit hash
  }

-- The type of `packages.dhall` is a Record from a PackageName to a Package
-- We're kind of stretching Dhall syntax here when defining this, but let's
-- say that its type is something like this:
let PackageSet =
  { console : Package
  , effect : Package
  ...                  -- and so on, for all the packages in the package-set
  }

-- The type of the `spago.dhall` configuration is then the following:
let Config =
  { name : Text                   -- the name of our project
  , dependencies : List Text      -- the list of dependencies of our app
  , backend : Maybe Text          -- Nothing by default, meaning use purs. If specified, spago will use the executable as the backend
  , sources : List Text           -- the list of globs for the paths to always include in the build
  , packages : PackageSet         -- this is the type we just defined above
  }

Why can't spago also install my npm dependencies?

A common scenario is that you'd like to use things like react-basic, or want to depend on JS libraries like ThreeJS. In any case, you end up depending on some NPM package.

And it would be really nice if spago would take care of installing all of these dependencies, so we don't have to worry about running npm besides it, right?

While these scenarios are common, they are also really hard to support. In fact, it might be that a certain NPM package in your transitive dependencies would only support the browser, or only node. Should spago warn about that? And if yes, where should we get all of this info?

Another big problem is that the JS backend is not the only backend around. For example, PureScript has a C backend and an Erlang backend among the others.

These backends are going to use different package managers for their native dependencies, and while it's feasible for spago to support the backends themselves, also supporting all the possible native package managers (and doing things like building package-sets for their dependencies' versions) is not a scalable approach (though we might do this in the future if there's enough demand).

So this is the reason why if you or one of your dependencies need to depend on some "native" packages, you should run the appropriate package-manager for that (e.g. npm).

For examples on how to do it, see next section.

Why we don't resolve JS dependencies when bundling, and how to do it

spago only takes care of PureScript land. In particular, bundle-module will do the most we can do on the PureScript side of things (dead code elimination), but will leave the requires still in.

To fill them in you should use the proper js tool of the day, at the time of writing ParcelJS looks like a good option.

If you wish to see an example of a project building with spago + parcel, a simple starting point is the TodoMVC app with react-basic. You can see in its package.json that a "production build" is just spago build && parcel build index.html.

If you open its index.js you'll see that it does a require('./output/Todo.App'): the files in output are generated by spago build, and then the parcel build resolves all the requires and bundles all these js files in.

Though this is not the only way to include the built js - for a slimmer build or for importing some PureScript component in another js build we might want to use the output of bundle-module.

For an example of this in a "production setting" you can take a look at affresco. It is a PureScript monorepo of React-based components and apps.

The gist of it is that the PureScript apps in the repo are built with spago build (look in the package.json for it), but all the React components can be imported from JS apps as well, given that proper modules are built out of the PS sources.

This is where spago bundle-module is used: the build-purs.rb builds a bundle out of every single React component in each component's folder - e.g. let's say we bundle-module from the ksf-login component and output it in the index.js of the component's folder; we can then yarn install the single component (note it contains a package.json), and require it as a separate npm package with require('@affresco/ksf-login').

How does the "global cache" work?

Every time spago will need to "install dependencies" it will:

  • check if the package is local to the filesystem: if it is then it will skip it as we can just point to the files
  • check if the ref is already in the global cache. If it is, it will just copy it to the project-local cache
  • download a metadata file from the package-sets-metadata repo if missing from the global cache or older than 24 hours.

    This file contains the list of tags and commits for every package currently in the package set, updated hourly.

  • check if the tag or commit of the package we need to download is in this cached index, and if it is then this means we can "globally cache" that version - this is because commit hashes are immutable, and tags are "immutable enough"
  • if a version is deemed to be "globally cacheable" then a tarball of that ref is downloaded from GitHub and copied to both the global and the local cache
  • otherwise, the repo is just cloned to the local cache

Note: a question that might come up while reading the above might be "why not just hit GitHub to check commits and tags for every repo while installing?"

The problem is that GitHub limits token-less API requests to 50 per hour, so any decently-sized installation will fail to get all the "cacheable" items, making the global cache kind of useless. So we are just caching all of that info for everyone here.

Troubleshooting

Spago is failing with some errors about "too many open files"

This might happen because the limit of "open files per process" is too low in your OS - as spago will try to fetch all dependencies in parallel, and this requires lots of file operations.

You can limit the number of concurrent operations with the -j flag, e.g.:

$ spago -j 10 install

To get a ballpark value for the j flag you can take the result of the ulimit -n command (which gives you the current limit), and divide it by four.

Package set caching problems

If you encounter any issues with the hashes for the package-set (e.g. the hash is not deemed correct by spago), then you can have the hashes recomputed by running the freeze command:

$ spago freeze

However, this is a pretty rare situation and in principle it should not happen, and when it happens it might not be secure to run the above command.

To understand all the implications of this I'd invite you to read about the safety guarantees that Dhall offers.

I added a new package to the packages.dhall, but spago is not installing it. Why?

Adding a package to the package-set just includes it in the set of possible packages you can depend on. However, if you wish spago to install it you should then add it to the dependencies list in your spago.dhall.

changelog

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

[Unreleased]

[0.21.0] - 2023-05-04

Features:

  • Add spago migrate command to port a spago.dhall configuration to the new-style spago.yaml (#901)

Bugfixes:

  • Windows: forward the proper exit code when running spago via NPM (#883, #884)

Other improvements:

  • CI: cleanup CI for 0.15.0 PureScript updates (#879)

[0.20.9] - 2022-05-03

Bugfixes:

  • Use iife format when bundling browser apps (#880)

[0.20.8] - 2022-04-27

Features:

  • Make spago bundle-app and spago bundle-module use esbuild and es modules for projects >= v0.15 (#862)
  • Make spago run use es modules for projects >= v0.15 (#858)

Bugfixes:

  • Fix spago run and spago test to accept command line arguments correctly, by writing a JS file to run (#865, #866)
  • Remove support for node versions older than 12.0.0 as they do not work with es modules (#866)
  • Retry git clone up to two times (#834, #873)

Other improvements:

  • Docs: update README with documentation for PureScript v0.15 (#867)
  • Linux: support Glibc versions >= 2.24

[0.20.7] - 2022-02-12

Bugfixes:

  • Make spago run work when node-args includes flag-like value (#856)

[0.20.6] - 2022-02-09

Bugfixes:

  • Oh no, not libtinfo again (#853, #854)

[0.20.5] - 2022-02-08

Features:

  • Drop need for psci-support to be defined in dependencies field (#817)

Other improvements:

  • Upgrade to latest Dhall version (#848, #851)

[0.20.4] - 2022-01-31

Bugfixes:

  • Don't warn on unused deps when building with --deps-only (#794)
  • Add line buffering for console output when doing parallel work (#800, #729)
  • Avoid writing a JS file when executing spago run (#845, #846, #822)

Other improvements:

  • CI: Add sha256 checksum generation on the release workflow (#816)
  • CI: Update the Ubuntu runner to a non-deprecated version (#826)
  • Install: replace deprecated request by make-fetch-happen for NPM installation (#840)
  • Error messages: output additional info when failing to access cache directory (#799)
  • Deps: add compatibility with versions-5.0.0 (#798)
  • Internals: convert deps and source paths from List to Set (#818)
  • Docs: various improvements (#802, #803, #806, #809, #823, #824)

[0.20.3] - 2021-05-12

Bugfixes:

  • Fix docs command error due to bad templates (#792)

[0.20.2] - 2021-05-06

Bugfixes:

  • Remove npm install from release CI to prevent overwriting the install script with the Linux binary (#783, #786)
  • Use spago.cabal instead of package.yaml to get version number (#787, #788)
  • Assume compatibility with newer minor versions of purs (#782, #777)
  • Fix test command not working on purs older than v0.14.0 (#790, #789)

Other improvements:

  • Docs: add more useful comments in spago.dhall (#778, 708)
  • Dev: remove package.yaml, use only cabal file (#780)
  • Dev: use make to orchestrate builds (#781)
  • Deps: upgrade to GHC8.10 and lts-17 (#743)

[0.20.1] - 2021-04-20

Bugfixes:

  • Color output now works correctly or is disabled on Windows (#768, #749)
  • Fix spago docs for PureScript 0.14, by updating docs-search to 0.0.11 (#775, #752)

Other improvements:

  • Color output is now automatically disabled when output is redirected to a file. Also respects a NO_COLOR environment variable (#768)
  • Fixes tests failing if the test platform has psa installed (#772)
  • Print spago install command to fix missing transitive dependencies (#770, #769, #776)
  • Refactor the graph support to remove the custom module name parser (#773)

[0.20.0] - 2021-04-07

Breaking changes (😱!!!):

  • spago build fails when source files directly import transitive dependencies (#730, #598)

Bugfixes:

  • Properly call psa to avoid warnings (#730)

Other improvements:

  • spago build now detects and warns about unused dependencies (#730, #598)

[0.19.2] - 2021-03-31

New features:

  • Allow verify and verify-set to work with alternate backends, when run in the context of a spago.dhall with backend set (#754)

Bugfixes:

  • Don't fail bump-version if the packages don't exist in the Bower registry (#682)

Other improvements:

  • CI: bump purescript version to 0.14.0 (#759)
  • Docs: add FreeBSD installation instructions (#760)
  • Docs: clarify description for --path flag (#762, #761)

[0.19.1] - 2021-02-22

Bugfixes:

  • Fix psa not being found on Windows (#740, #693)
  • Use the correct path when erroring out about alternate configurations missing (#746, #747)

Other improvements:

  • Bump dhall dependency from 1.37.1 to 1.38.0 (#739)
  • Fix caching on Windows CI (#728, #741)

[0.19.0] - 2021-01-06

Breaking changes (😱!!!):

  • Deprecate -d flag for deps-only (#712) - instead only support the --deps-only long form
  • Switch from -D to -d as shorthand for specifying dependencies within spago repl (#712)

New features:

  • Add spago script command. It can be used to run standalone PureScript files as scripts (#712, #724, #683)

Other improvements:

  • spago repl will no longer create a (mostly unused) full project skeleton in a temporary directory when a config is not found (#712)
  • spago init and spago upgrade-set will now pick the latest set for the available compiler, rathen than just the latest (#721, #687, #657, #666)

[0.18.1] - 2020-12-22

Breaking changes (😱!!!):

  • Remove login command (#705)

    It was introduced in preparation for a publish command that would require a GitHub token to be provided, but it is obsolete now, as the new Registry workflow will not require it. While it's technically a breaking change, it should be of very low impact since no one should be using this anyways.

  • Upgrade to Dhall 20.0.0 and GHC 8.6.5 (#695, #685)

    The upgrade fixes several bugs related to the upstream dhall-haskell implementation, but introduces a breaking change in the parser, as reserved words are not accepted anymore in certain positions. While the upstream package sets have been patched to be compatible with the change, this is a breaking change for all the existing configurations that make use of Dhall reserved words (such as assert, let, etc).

New features:

  • Add exec-args as alias to node-args, to clarify that the args are forwarded to whichever backend is being targeted (go, js, etc), not exclusively NodeJS (#710, #709)

Bugfixes:

  • Don't create the global cache folder at all if the user specifies --global-cache=skip (#705, 704)
  • Don't require a spago.dhall anymore when the --no-build flag is passed (#705, 634)

Other improvements:

  • CI: switch from Travis to GitHub Actions (#695)

[0.17.0] - 2020-10-29

Breaking changes (😱!!!):

  • Specify the package set version via --tag (#680)

    Example usage: spago init --tag psc-0.13.2-20190725 and spago upgrade-set --tag psc-0.13.2-20190725. This is a breaking change because we are removing support for the old spacchetti/spacchetti-style location (i.e. in the src/packages.dhall) for the upgrade-set command.

Bugfixes:

  • Remove dependency on libtinfo, removing the biggest cause of friction for using the precompiled binary on various Linux distros (#684)
  • Correctly parse flags to be passed to the compiler (#688)

[0.16.0] - 2020-08-14

Breaking changes (😱!!!):

  • Remove shorthands for color, before, then, and else flags (#670, #664)

    Both then and target had the shorthand t, so the shorthand for then was removed. Since then, before, and else are all shared between several commands, it seemed natural to remove the shorthands for the other shared commands too, so as to not cause future shorthand name conflicts. A similar collision problem happened with the color flag, so its shorthand was removed.

  • Pass main function argument to --run for alternate backends (#668)

    This is a braking change because now alternate backends are expected to accept an argument to their run flag. This change was coordinated among various backends so the migration should be relatively smooth, but you should check if your backend it able to support this.

New features:

  • Upgrade to docs-search@v0.0.10, that introduces grouping by package in local docs (#679)
  • Ignore .gitignored files in --watch by default - you can disable this with --allow-ignored (#665)
  • Support upgrade-set for alternative package-set repositories (#671)

Bugfixes:

  • Make the output of spago --version the same with spago version (#675)
  • Ensure the existence of the global cache directory (#672, #667)

Other improvements:

  • Docs: updated package addition/overriding syntax to use with syntax (#661, #663)
  • Docs: fix Webpack template (#653)
  • Docs: document how to pass arguments to main (#655)
  • Error messages: do not print "Installation complete" if nothing was installed (#676)

[0.15.3] - 2020-06-15

New features:

  • Add --version flag to print the version (in addition to the version command) (#628)

Bugfixes:

  • Actually run else commands when spago run fails (#632)
  • Don't use absolute paths for executables in Windows (#639)

Other improvements:

  • Docs: note that build also runs install (#624)
  • Docs: document how to install all the packages in the set (#625)
  • Docs: stop suggesting using Parcel and Spago at the same time (#626)
  • Docs: document how to install bash and zsh autocompletions (#627)
  • Docs: fix explanation in monorepo example (#631)
  • Docs: add note about using single quotes for purs-args (#637)
  • Docs: add quotes for all OSes with purs-args (#638)
  • Docs: fix typos in spago bundle-app help message (#641)
  • Deps: upgrade rio to 0.1.13.0 (#616)
  • CI: upgrade to purs v.13.8 (#642)
  • CI: stop upgrading broken static binary on release (#620)

[0.15.2] - 2020-04-15

Breaking changes (😱!!!):

  • Remove the deprecated --no-share-output flag (#610)

    It has been disabled since some time now, so you can just remove it from your build commands.

New features:

  • Add the spago path global-cache subcommand to output the location of the global cache (#613, #591)

Bugfixes:

  • Fix encoding issues causing crashes when running in various locales (#595, #533, #507, #576)
  • Respect TERM=dumb by disabling colors when set (#581, #579)
  • Run package set commands without a project config being present (#393, #610)
  • Fail as soon as possible when not finding a necessary executable (#578, #610)
  • Don't exclude the metadata package from the set (#609, #610)
  • Ensure psci-support is installed when starting the repl (#612, #550)
  • Ensure dependencies are installed before starting the repl (#611, #610)

Other improvements:

  • Errors: make the "dropping the 'purescript-' prefix" warning milder (#571, #570)
  • Docs: update README example to include source files (#574)
  • Docs: add info about SPDX license for publishing (#606)
  • CI: update Travis deployment to dpl-v2 (#569, #617)
  • Deps: upgrade dhall to 1.31.1 (#600)
  • Curator: move to its own repo (#586)

[0.14.0] - 2020-02-09

Breaking changes (😱!!!):

  • Replace list-packages command with ls packages and ls deps (#563)

    This is happening for future extensibility, i.e. so that we can add any spago ls $whatever subcommand in a non-breaking way whenever we'll want to list more things.

    How things got renamed:

    • spago list-packagesspago ls packages
    • spago list-packages -f directspago ls deps
    • spago list-packages -f transitivespago ls deps -t

    Note: the list-packages command is still there to provide a semi-gracious transition path for folks, and will be removed in a future release.

New features:

  • Allow verify-set to work with either a spago.dhall or a packages.dhall (#515)
  • Create .purs-repl file when running spago init (#555, #558)
  • Add --source-maps flag to build commands (#545, #562)
  • Add --quiet and --no-color global flags to better control logging (#548)

Bugfixes:

  • Fix a few watch-mode buffering and concurrency issues (#549)
  • Fix watching relative paths in sources config (e.g. ../src/**/*.purs) (#556)
  • Make the ensureConfig function safe (#561, #531)
  • Retry downloading packages on network errors (#557, #565)

Other improvements:

  • Docs: fix misc typos in README (#566)
  • Docs: fix typo in packages.dhall template (#539)
  • Docs: remove mention of shared output folder in README (#559, #552)
  • Docs: update links: spacchetti/spago → purescript/spago
  • CI: update to purs-0.13.6 (#542)
  • CI: update CI to the new location of the repo (#560)
  • Deps: update to purescript-docs-search-0.0.8 (#543)
  • Deps: update to dhall-1.29 and github-0.24 (#553)

[0.13.1] - 2020-01-10

New features:

  • Add --before, --then and --else flags to specify commands to run before and after a build (#532, #410)

Other improvements:

  • Docs: fix npm command line argument in README (#597)

[0.13.0] - 2019-12-19

Breaking changes (😱!!!):

  • Disable output folder sharing (#526)

    This reverts an (accidentally) breaking changes introduced in 0.11.0, for which Spago would take decisions on where the output folder should be in order to share some compilation results. This turned out to break some other things, so we'll stop trying to be smart about it here.

New features:

  • Enable HTTP(S) proxies on the NPM installation (#460, #522)

Other improvements:

  • Log backend build command when building (#521)
  • Deps: update purescript-docs-search version to 0.0.6 (#525)
  • CI: update purs version to 0.13.5 (#513)
  • CI: fix Haddocks and start testing them in CI (#511, #516)
  • Curator: automate updating purs version (#514)
  • Curator: automate updating the purescript-docs-search version (#519)

[0.12.1] - 2019-11-17

Bugfixes:

  • Fix macOS release artifact (#503, #504)
  • Complete parser implementation for module declarations, for spago test (#499)

Other improvements:

  • Docs: fix typo in README (#498)
  • Errors: use logWarn for all warnings (#501)

[0.12.0] - 2019-11-15

Breaking changes (😱!!!):

  • Revert back to dynamically linked binary on Linux (#502, #500, #497)

    The static binary was still dynamically linking to glibc, causing it to be broken on some distros. So for now we're back on a dynamically-linked executable.

[0.11.1] - 2019-11-12

This is identical to 0.11.0, but published under a new version number due to mishaps in the publishing CI process.

[0.11.0] - 2019-11-12

Breaking changes (😱!!!):

  • Remove psc-package-related commands (#423, #425)

    Since we are approaching a stable release and spago feature set is a superset of psc-package ones, from this release we do not support the commands to interop with psc-package: psc-package-local-setup, psc-package-insdhall and psc-package-clean commands.

  • Start sharing the output folder in monorepos, to reduce build duplication (#377, #422)

    This is a breaking change because your build might stop working if you were relying on the output folder being in a certain place, and if you were passing --output as an option to purs. However, you can pass the --no-share-output flag to disable this behavior

  • Build static binaries for Linux (#437, 427)

    This should fix the dynamic-library-compatibility problems on some distributions. It should work as well as the old dynamic binary, but it's theoretically a breaking change since some behaviours might be different.

  • Move all logging to stderr (#256, #475, #476, #486)

    All "business output" (e.g. spago sources) will stay on stdout, so in practice everything should be fine, but this is theoretically a breaking change since someone might be depending on the output we had so far.

New features:

  • add support for spago build and spago run with alternate backends (#355, #426, #452, #435)

    E.g: add the key backend = "psgo" in spago.dhall to compile/run with psgo

  • add new command spago path that returns the paths used in the project.

    E.g. spago path output returns the output path so that it can be shared with tools such as purs-loader. (#463)

  • spago docs now displays a link to the generated docs' index.html, and opens them in the browser when passed the --open flag (#379, #421)
  • spago init has new --no-comments flag which skips adding tutorial comments to the generated spago.dhall and packages.dhall files (#417, #428)
  • spago verify-set now compiles everything, to detect duplicate module names. This can be disabled with --no-check-modules-unique (#438)
  • spago install purescript-XYZ will now strip purescript- prefix and install XYZ (if it exists in package set) instead of just failing with a warning (#367, #443)
  • spago run now allows to pipe stdin to your running project (#488, #490)

Bugfixes:

  • Fix Ctrl-C handling in REPL when using NPM installation on Windows (#493, #483)
  • Fix confusing warning when trying to spago install a package already present in project dependencies list (#436, #439)
  • Warn (but don't error) when trying to --watch missing directories (#406, #420, #447, #448)
  • Do not watch files in .spago folder when running with --watch (#430, #446)
  • The --clear-screen flag (usable e.g. with spago build --watch) now also resets cursor position, so the rebuild message always appears at top left of the screen (#465, #466)
  • Allow additional fields in the config for local packages (#470)
  • Fix --config option: get the correct paths when config file is in another directory (#478, #484)

Other improvements:

  • Tests: speed up test suite by replacing some end-to-end tests with unit/property tests (#445, #440)
  • Tests: update instructions to run tests (#449)
  • Tests: always run test suites with UTF8 encoding (#482)
  • Docs: various improvements to README (#432, #457, #464, #487)
  • Docs: add "getting started" guides for Parcel, Webpack and Nodemon (#456, #461, #473)
  • Errors: improve cache skipping error (#453, #480, #481)
  • Errors: add a nice error message when trying to run spago test with no test modules (#489, #383, #492)
  • Refactor: fix hlint warnings (#450)
  • Refactor: rewrite Curator for moar maintainability (#458, #419)
  • Deps: update to Dhall 1.27 and Purs 0.13.4 (#469)
  • Deps: revert to GHC 8.4.4 and LTS-12 (#479)
  • CI: fix release code (#494, #495)

[0.10.0] - 2019-09-21

Breaking changes (😱!!!):

  • Flags and arguments that you want to give to purs are now passed with --purs-args (#353, #366)

    The previous behaviour in which all arguments that could not parse as spago arguments were passed along to purs was sometimes confusing (e.g. when using --path and multiple arguments).

New features:

  • Support watching js files (#407, #205)
  • New --no-search flag for spago docs to skip patching the documentation using purescript-docs-search (#400)
  • New -x flag for specifying the config path location (#357, #329)
  • New spago login command, to save a GitHub token to the cache so it can be used for various operations hitting GitHub (#391, #403)

Bugfixes:

  • "Quit" command in watch mode now actually quits (#390, #389)
  • Do not compile files twice when using --watch and Vim (#346, #371)
  • Use git clone instead of git fetch when fetching a package, so all tags can be installed (#373, #374)
  • Fix Windows global cache location; now uses LocalAppData as default (#384, #380)
  • Fix naming clash in short flag for repl dependencies (#352, #350)
  • Fix failure to copy to global cache on a different filesystem (#385, #386)
  • Fix watch function on Windows (issue with paths) (#387, #380, #401)
  • Look up remote imports dynamically when doing frozen check, to always find the right packages.dhall (#349, #402)

Other Improvements:

  • Performance: make no-op spago install faster (#409, #412)
  • CI: remove reviews limitation on mergify (#354)
  • CI: various fixes (#362, #368, #382, #388, #418)
  • Docs: fix syntax errors in template comment (#369, #413, #408)
  • Docs: fix link for package-set from commit (#405)
  • Docs: keep README up to date with new features (#398, #347)
  • Deps: upgrade to lts-14 and GHC-8.6 (#395)
  • Deps: upgrade to dhall-1.26.0, v10 of the standard (#411, #358)

[0.9.0] - 2019-07-30

Breaking changes (!!!):

  • Rename package-set-upgrade to upgrade-set (#336)

    You now have to call spago upgrade-set if you wish to upgrade your package-sets version

  • Move the --jobs flag to be global (#338)

    If you were invoking spago in this way: spago install -j 10, you now have to use spago -j 10 install instead

  • Import local packages as Location (#301, #244)

    Before you'd import a local package in this way:

    let additions =
      { foobar =
          mkPackage
            (../foobar/spago.dhall).dependencies
            "../foobar"
            "local-fix-whatever"
      }
    

    ..but now you'll have to import it using as Location instead:

    let additions =
      { foobar = ../foobar/spago.dhall as Location }
    

New features:

  • Add searchbar to docs generated with spago docs (#340, #333, #89)
  • Add automatic migration of Bower projects when doing spago init (#159, #272, #342)
  • Add bump-version command, for generating bower.json files and making version tags in Git (#203, #289, #324)
  • Use psa for compiling if installed; you can avoid this with the new --no-psa flag (#305, #283, #252, #327)
  • Add support for starting a repl within a folder which has not been setup as a spago project (#168, #280)
  • Add --format flag to spago docs (#294, #299)
  • Add project sources to spago sources output (#276, #287, #308)
  • Watch all sources, including dependencies, when building with filewatch (#172, #309)
  • Add --deps-only flag to build dependencies alone (#330, #331)

Bugfixes:

  • Fix spago install failing when version branch names differ only by case on case-insensitive filesystems (#285)
  • Change --node-args shortcut to -a to avoid clash (#292, #293)
  • Stop reformatting config files if not necessary (#300, #302, #339)
  • Make spago run write a file and execute it so that args are passed correctly (#297, #295)
  • Add fallback for global cache directory (#314, #312)
  • Do not overwrite spago.dhall when doing spago init twice (#318, #321)
  • Catch exceptions when trying to fetch metadata (#325)
  • Generate hashes when doing psc-package-insdhall (#337, #240)

Other Improvements:

  • Curator: log exceptions to file to monitor eventual issues (#284)
  • Docs: update README with newest features (#286)
  • Docs: add docs about switching from Bower (#317)
  • Errors: improve error message for overriding compiler version (#345, #343)
  • Tests: improve failure messages (#298)
  • Tests: fix packages.dhall fixtures manipulation (#307)
  • Tests: add tests for the list-packages command (#304)
  • Tests: add tests for local dependencies (#310)
  • Config: remove mkPackage function in Dhall configs, and switch to package-sets releases for upstream (#322, #320, #319)
  • Config: update test template to use Effect.Class.Console (#328, #334)
  • CI: fix missing "commit since last release" message (#326)
  • CI: add configuration for Mergify (#332)

[0.8.5] - 2019-06-18

ZuriHac edition 🎉

New features:

  • Add sources key to config to customize the sources used in the build (#273, #173)
  • Add --json flag to the list-packages command to optionally output JSON (#263)
  • Add --clear-screen flag to to clear the screen when watching (#271, #209)
  • Add --no-install flag for build to prevent automatic installation (#274, #269)
  • Add --node-args flag to pass arguments to Node in run/test commands (#267, #275)

Bugfixes:

  • Fix spago install failing when version branch name contains /'s (#257, #258)
  • Report all missing packages together when it's not possible to build an install plan (#264, #223)
  • Pull the latest package-sets version when doing init (#254, #279)
  • Fix spago install not adding new dependencies when list is empty (#282, #281)

Other Improvements:

  • Docs: add visual overview of what Spago does "under the hood" in typical project workflow (#211)
  • Docs: fix outdated references in README (#266)
  • Tests: untangle testcases environments (#265, #214)
  • Tests: improve packages test by checking for missing and circular dependencies (#270)

[0.8.4] - 2019-06-12

New features:

  • Add option to clear the screen to spago build/run (#209)
  • Add option to pass args to node when doing spago test/run (#267)

Bugfixes:

  • Produce an error message when asserting directory permissions (#250)
  • Read purs version from inside the set instead of its GitHub tag (#253, #225)
  • Skip copy to global cache when encountering a permissions problem (#220, #260)

Other improvements:

  • Errors: add many debug logs (#251)
  • CI: rewrite Curator in Haskell (#239)
  • CI: build only master and tags on Travis (#247)
  • Dev: add Nix section to stack.yaml (#248)
  • Dev: tidy up the various executables, sources and dependencies (#251)

[0.8.3] - 2019-06-03

Bugfixes:

  • Fix spago psc-package-clean on Windows (#224)
  • Fix spago repl starting on Windows where PureScript was installed with NPM (#235, #227)
  • Fix missing filenames when encountering parse errors in Dhall files (#241, #222)
  • Download packages in local repo instead of global tempdir (#243, #220)

Other improvements:

  • Tests: test suite now works fully on Windows (#224)
  • CI: parametrize LTS version (#236)
  • CI: get PureScript binary for Travis from GitHub releases (#234)
  • Error messages: fix whitespace (#221)

[0.8.1] - 2019-05-29

New features:

  • Add global cache to avoid redownloading dependencies (#188, #133)
  • Add ability to pin a version to a commit hash in addition to branches and tags (#188, #200)

Bugfixes:

  • Another attempt to fix NPM and Yarn installations on Windows (#215, #187)

Other improvements:

  • The test suite is now written in Haskell rather than Python (#212, #177)
  • Add spago-curator tool to generate metadata from the package set (#202)
  • Improve docs (#208, #207, #218, #217)

[0.8.0] - 2019-05-16

Breaking changes:

  • Rename "bundle" to "bundle-app" and "make-module" to "bundle-module" for consistency (#175, #147)

Bugfixes:

  • Don't fail init if a packages.dhall is already there, as it's the case of psc-package projects with local spacchetti (#180)

Other improvements:

  • Remove CI check for package-sets version, add cron script to update it instead (#185)
  • Fill in CHANGELOG from release notes (#186)
  • Fix LICENSE file so GitHub recognizes it (#197)
  • Add a CONTRIBUTING file (#198, #189)
  • Improve README (#199, #194, #196, #201, #193, #192, #187, #178, #191, #150, #142)

[0.7.7] - 2019-04-28

New features:

  • Install "psci-support" on project init (#174)

[0.7.5] - 2019-03-30

Bugfixes:

  • Fix NPM and Yarn installations on Linux and Windows (#157, #167, #166)

[0.7.4] - 2019-03-27

Bugfixes:

  • correctly parse package-set release tag to avoid generating unnecessary warnings (#160, #161)
  • skip 0.7.3.0 as I forgot to update the version field (#164)

[0.7.2] - 2019-03-21

New features:

  • introduce a --verbose flag to print debug information - e.g. purs commands being called by Spago (#154, #155)

[0.7.1] - 2019-03-19

New features:

  • Add --watch flag to build, test, run, bundle and make-module commands (#65, #126, #153)
  • Add spago docs command, to generate documentation from the project and all dependencies (#127)
  • Add spago run command, to run your project (#131, #137)

Other fixes and improvements:

  • Automatically build in commands that require the project to be built (#146, #149)
  • Don't automatically create a configuration if not found (#139, #144)
  • Always ensure that the package-set has a hash on it, for speed and security reasons (#128)
  • Improvements to documentation and FAQ (#132, #125, #119, #123, #104, #135)
  • Improvements to errors, messages and logging (#143, #145, #133, #151, #148, #129, #130, #136)
  • Improvements to tests (#95, #91, #138, #141, #140)
  • Format Dhall files with ASCII instead of Unicode (#124)

[0.7.0] - 2019-03-03

Breaking changes:

  • The NPM package purescript-spago is now deprecated. New releases will be published only to the package spago (#115, #44)
  • Spacchetti has been merged in the official package-set: this means that spago will now use that as the reference package-set. (#120)

    As a result of this, the command spago spacchetti-upgrade has been renamed to spago package-set-upgrade.

New features:

  • Support Windows in NPM install (#121, #109)
  • Add spago freeze command to recompute hashes of the package-set (#113)
  • Add spago verify and spago verify-set commands (#108, #14)
  • Add the --filter flag to spago list-packages, to filter by direct and transitive deps (#106, #108)
  • Check that the version of the installed compiler is at least what the package-set requires (#101, #107, #117, #116)

Other improvements:

  • Improve the installation: do less work and print less useless stuff (#110, #112, #114)
  • Skip the copy of template files if the source directories exist (#102, #105)

[0.6.4] - 2019-02-07

New features:

Bugfixes:

  • Spago would crash if $HOME was not set, now it doesn't anymore (#85, #90)
  • spago test now actually works on Windows (#79)

Other improvements:

  • Maany docs improvements (#83, #76, #93, #96, #99, #100)
  • From this release we are publishing an experimental Windows build (#81)
  • Add a PR checklista, so we don't forgetti (#86)

[0.6.3] - 2019-01-18

New features:

  • spago repl will now spawn a PureScript repl in your project (#46, #62)
  • spago list-packages will list all the packages available in your package-set (#71)

[0.6.2] - 2019-01-07

New features:

  • spago build and spago test now have the --path option to specify custom source paths to include (#68, #69)
  • spago build and spago test can now pass options straight to purs compile (#66, #49)

[0.6.1] - 2018-12-26

New features:

  • Add initial windows support (#47, #48, #58): now spago should run fine on Windows. Unfortunately we're not distributing binaries yet, but the only installation method available is from source (with e.g. stack install)

Bugfixes:

  • Don't overwrite files when doing init, just skip the copy if some file exists (#56)
  • Print git output in case of failure when doing install (#54, #59)
  • Include building src/* when running test (#50, #53)
  • Make file embedding indipendent of the locale when compiling; now we just use Unicode

[0.6.0] - 2018-12-16

First release under the name "spago".

Main changes from the previous "spacchetti-cli" incarnation:

  • Rename spacchetti-clispago (#23)
  • Publish on NPM under the new name purescript-spago (#35)
  • Add some commands from psc-package:
    • init (#12): initialize a new sample project with a spago.dhall and a packages.dhall config files
    • install (#11, #32): concurrently fetch dependencies declared in spago.dhall file
    • sources (#13): print source globs
    • build: compile the project with purs
  • Migrate old commands from spacchetti-cli that are specific to local psc-package projects:
    • local-setup is now psc-package-local-setup
    • insdhall is now psc-package-insdhall
    • clean is now psc-package-clean
  • Add some commands from purp (#26):
    • test: compile and run a module from the test/ folder
    • bundle: bundle all sources in a single file
    • make-module: export the above bundle so it can be required from js
  • Stop depending on dhall and dhall-to-json commands and instead depend on dhall and dhall-json libraries
  • Freeze spacchetti package-set import in packages.dhall, so dhall caching works for subsequent executions
  • Move to v4.0.0 of dhall
  • Add integration tests for most of the commands (#31, #30)