Recently, more people who use Node.js, whether it be on their own computers, in some VPS, AWS Lambda, Azure Functions, etc. have been asking about how to get some bare minimum going on PureScript. While there are many people who will readily give their unneeded opinion on Node.js in response to this question, I will attempt to rather give some minimum amount of information that someone would like to have when trying out a small amount of PureScript.
As usual, you can add the purescript
and spago
dependencies to your project.
npm i -D purescript spago
If you prefer, you could install these also globally, and by other methods such as via Nix using https://github.com/justinwoo/easy-purescript-nix.
Spago is a build tool for managing dependencies and building PureScript projects. This means that Spago takes care of the PureScript dependencies, while you continue to use npm to manage node/JS dependencies.
This is something that might eventually change over the years, but the PureScript compiler output is CommonJS. The simplest example of this can be seen when you have an initialized project, such as one you get when you run spago init
. After running spago build
to install the dependencies and build the project, you will get a series of modules built in output/
in your project.
-- src/Main.purs as generated by spago init
module Main where
import Prelude
import Effect (Effect)
import Effect.Console (log)
main :: Effect Unit
main = do
log "This is main in module Main"
// from output/Main/index.js
// Generated by purs version 0.12.5
"use strict";
var Effect_Console = require("../Effect.Console/index.js");
var main = Effect_Console.log("This is main in module Main");
module.exports = {
main: main
};
and as the main function here is simply an Effect Unit
value, this means that this is an effect thunk that can be run. We can prepare a index.js
file and use this output directly:
require('./output/Main').main()
Functions defined in PureScript will simply be a series of functions. For example,
add2 :: Int -> Int -> Int
add2 a b = a + b
add3 :: Int -> Int -> Int -> Int
add3 a b c = a + b + c
is called as the following:
console.log(Main.add2(1)(1));
console.log(Main.add3(1)(1)(1));
Of course, there are some various ways to work with uncurried functions if you want them: https://pursuit.purescript.org/packages/purescript-functions/docs/Data.Function.Uncurried
If you want to call JS from PureScript, you can do one of two things:
- use foreign imports
- use arguments to be passed in from JS (as in
add2
andadd3
above)
Of the two, foreign imports are much simpler to deal with, and will be what you use most. This consists of making a JS file with the same file name as your module:
-- in module Main in src/Main.purs
foreign import foreignJSEffect :: String -> Effect Unit
// in src/Main.js
exports.foreignJSEffect = function (str) {
return function () {
console.log('hello from foreignJSEffect:', str);
};
};
And it's about as simple as that. Now we can use it from PureScript:
main :: Effect Unit
main = do
foreignJSEffect "calling foreignJSEffect"
Keep in mind that FFI for now (as of May 2019) is largely ES5, but you can also use some elements of ES6.
I have more notes on FFI written in my previous posts, some of which are referenced here: https://purescript-resources.readthedocs.io/en/latest/ffi.html
The rest of what you want largely depends on what your interests are. Generally, you shouldn't expect that someone else has packaged up some Node library in a way you want to use them -- people have all kinds of different opinions about how to make libraries that do either a low level or high level binding for popular libraries like Express. However, if you look around in various libraries published on Pursuit (or some of my blog posts), I think you'll find many examples of approaches you might be interested in.
Some examples Node library bindings
- Puppeteer bindings: https://github.com/justinwoo/purescript-toppokki
- Telegram bot API bindings: https://github.com/justinwoo/purescript-node-telegram-bot-api
- Express bindings (one of many): https://github.com/justinwoo/purescript-makkori
- Postgres: https://github.com/epost/purescript-node-postgres
Despite what people will try to tell you, people have been using PureScript on Node to do actual work for years now. The ease of integration of PureScript into JS and JS into PureScript enables many to write simple PureScript code where the low level bindings are made at the edges. However, as PureScript is a language used by a relatively small number of users compared to vanilla Node, you should expect that you might have to write some of your own bindings, for better and for worse.