Spago¶
Intro¶
Spago is a new CLI that can replace your usage of Psc-Package, using Dhall to configure your packages and your project.
See the Spago repo for more: https://github.com/spacchetti/spago
Extracted README 2019-1-12:¶
(IPA: /ˈspaɡo/)
PureScript package manager and build tool powered by Dhall and Spacchetti package-sets.
What does all of this mean?¶
spago
aims to tie together the UX of developing a PureScript project.In this Pursuit (see what I did there) it is heavily inspired by Rust’s Cargo
and Haskell’s Stack, and builds on top of ideas from existing PureScript
infrastructure and tooling, as psc-package
, pulp
and
purp
.
Installation¶
Right, so how can I get this thing?
The recommended installation methods on Linux and macOS are:
npm install -g purescript-spago
(see the latest releases on npm here)- Download the binary from the latest GitHub release
- Compile from source by cloning this repo and running
stack install
Note #1: support for Windows is still basic, and we’re sorry for this - the
reason is that no current maintainer runs it.Currently the only way to install on Windows is with stack
- more info in
#57.If you’d like to help with this that’s awesome! Get in touch by commenting there
or opening another issue :)
Note #2: we assume you already installed the PureScript compiler.
If not, get it with npm install -g purescript
Quickstart¶
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
Convention note: spago
expects your source files to be in src/
and your
test files in test/
.
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 practical terms, it pulls in a Spacchetti package-set as a base, and you are then able to add any package that might not be in the package set, or override esisting ones.spago.dhall
: this is your project configuration. It includes the above package-set, the list of your dependencies, and any other project-wide setting thatspago
will use for builds.
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
}
-- 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 Packages =
{ 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
, packages : Packages -- this is the type we just defined above
}
Commands¶
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.
Package management¶
We initialized a project and saw how to configure dependencies and packages, the next step is fetching its dependencies.
If we run:
$ spago install
..then spago
will download all the dependencies
listed in spago.dhall
(and
store them in the .spago
folder).
Building, bundling and testing a project¶
We can then build the project and its dependencies by running:
$ spago build
This is just a thin layer above the PureScript compiler command purs compile
.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 (src
and test
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 -- -o myOutput/
Anyways, the above will create a whole lot of files, but you might want to get just a single, executable file. You’d then use the following:
# You can specify the main module and the target file, or these defaults will be used
$ spago bundle --main Main --to index.js
Bundle succeeded and output file to index.js
# We can then run it with node:
$ node .
However, you might want to build a module that has been “dead code eliminated” if you plan to make a single module of your PS exports, which can then be required from JS.
Gotcha covered:
# You can specify the main module and the target file, or these defaults will be used
$ spago make-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]
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.
Can I use this with psc-package
?¶
Yes! Though the scope of the integration is limited to helping your psc-package-project to use the Spacchetti package-set.
Here’s what we can do about it:
psc-package-local-setup
¶
This command creates a packages.dhall
file in your project, that points to the
most recent Spacchetti package-set, and lets you override and add arbitrary packages.See the Spacchetti docs about this here.
psc-package-insdhall
¶
Do the Ins-Dhall-ation of the local project setup: that is, generates a local
package-set for psc-package
from your packages.dhall
, and points your
psc-package.json
to it.
Functionally this is equivalent to running:
NAME='local'
TARGET=.psc-package/$NAME/.set/packages.json
mkdir -p .psc-package/$NAME/.set
dhall-to-json --pretty <<< './packages.dhall' > $TARGET
echo wrote packages.json to $TARGET
FAQ¶
Hey wait we have a perfectly functionalpulp
right?
Yees, however:
pulp
is a build tool, so you’ll still have to use it withbower
orpsc-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 Spacchetti 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 usepulp
,psc-package
,purp
, etc.
So if I usespago make-module
this thing will compile all my js deps in the file?
No. We only take care of PureScript land. In particular, make-module
will do the
most we can do on the PureScript side of things (dead code elimination), but will
leave the require
s 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.