この記事は (bouzuya) PureScript Advent Calendar 2016 の 3 日目。 (bouzuya) PureScript Advent Calendar 2016 は bouzuya の PureScript 学習の記録だ。
- ← 2 日目 『 PureScript の Interactive mode (
psci
) を動かしてみる - Qiita 』 - → 4 日目 『 PureScript の Getting Started を読む & 続
psci
を試す - Qiita 』
概要
今日は PureScript のためのビルドツール pulp
を試してみる。
pulp
の repository は bodil/pulp だ。こんな記事を読むより 1 次ソースを参照するほうが早そうだ。
pulp
をインストール
$ # Node.js がインストールされている前提で
$ mkdir project2/
$ cd project2/
$ npm init -y
$ npm install -D pulp purescript bower
$ npm list --depth 0
project2@1.0.0 /Users/bouzuya/project2
├── bower@1.8.0
├── pulp@10.0.0
└── purescript@0.10.2
今回は pulp@10.0.0
のようだ。とりあえず動かしてみる。
$ $(npm bin)/pulp
* Error: Expected command
Usage: pulp [global-options] <command> [command-options]
Global options:
--before <string> Run a shell command before the operation begins. Useful with `--watch`, eg. `--watch --before clear`.
--bower-file -b <file> Read this bower.json file instead of autodetecting it.
--else <string> Run a shell command if an operation finishes. Useful with `--watch`, eg. `--watch --then 'say Done' --else 'say Failed'`
--help -h Show this help message.
--monochrome Don't colourise log output.
--then <string> Run a shell command after the operation finishes successfully. Useful with `--watch`, eg. `--watch --then 'say Done'`
--version -v Show current pulp version.
--watch -w Watch source directories and re-run command if something changes.
Commands:
browserify Produce a deployable bundle using Browserify.
build Build the project.
docs Generate project documentation.
init Generate an example PureScript project.
login Obtain and store a token for uploading packages to Pursuit.
psci Launch a PureScript REPL configured for the project.
publish Publish a previously tagged version to Bower and Pursuit.
run Compile and run the project.
server Launch a development server.
test Run project tests.
version Bump and tag a new version in preparation for release.
Use `pulp <command> --help` to learn about command specific options.
README とは違って、今回はインストール時に npm install --global
にしていないので、このまま pulp
を使うと、次のようなエラーが表示される。
$ $(npm bin)/pulp --version
* ERROR: `psc` executable not found.
pulp
は npm install --global purescript bower
を前提にしているので、 PATH に psc
などを含めるよう注意が必要だ。ぼくは global を維持でも回避したいので、ここは npm run-scripts を活用して PATH に psc
などを含めることにする。
package.json
の scripts
に次のように設定する。
{
"name": "project2",
"version": "1.0.0",
"author": "bouzuya <m@bouzuya.net> (http://bouzuya.net/)",
"devDependencies": {
"bower": "^1.8.0",
"pulp": "^10.0.0",
"purescript": "^0.10.2"
},
"keywords": [],
"license": "MIT",
"main": "index.js",
"scripts": {
"pulp": "pulp",
"pulp:browserify": "pulp browserify",
"pulp:build": "pulp build",
"pulp:docs": "pulp docs",
"pulp:init": "pulp init",
"pulp:login": "pulp login",
"pulp:psci": "pulp psci",
"pulp:publish": "pulp publish",
"pulp:run": "pulp run",
"pulp:server": "pulp server",
"pulp:test": "pulp test",
"pulp:version": "pulp version"
}
}
これで改めて動かしてみる。
$ npm run pulp -- --version
> project2@1.0.0 pulp /Users/bouzuya/project2
> pulp "--version"
Pulp version 10.0.0
psc version 0.10.2 using /Users/bouzuya/project2/node_modules/.bin/psc
よさそう。
pulp init
pulp
はいくつかのコマンドがあるようだが、まずはいかにも最初に実行すべきっぽい pulp init
を実行してみる。
Generate an example PureScript project.
とのことなので PureScript プロジェクトの例を生成してくれるのだろう。
$ npm run pulp:init
> project2@1.0.0 pulp:init /Users/bouzuya/project2
> pulp init
* Generating project skeleton in /Users/bouzuya/project2
bower purescript-prelude#* cached https://github.com/purescript/purescript-prelude.git#2.1.0
bower purescript-prelude#* validate 2.1.0 against https://github.com/purescript/purescript-prelude.git#*
bower purescript-console#* cached https://github.com/purescript/purescript-console.git#2.0.0
bower purescript-console#* validate 2.0.0 against https://github.com/purescript/purescript-console.git#*
bower purescript-eff#^2.0.0 cached https://github.com/purescript/purescript-eff.git#2.0.0
bower purescript-eff#^2.0.0 validate 2.0.0 against https://github.com/purescript/purescript-eff.git#^2.0.0
bower purescript-console#^2.0.0 install purescript-console#2.0.0
bower purescript-prelude#^2.1.0 install purescript-prelude#2.1.0
bower purescript-eff#^2.0.0 install purescript-eff#2.0.0
purescript-console#2.0.0 bower_components/purescript-console
└── purescript-eff#2.0.0
purescript-prelude#2.1.0 bower_components/purescript-prelude
purescript-eff#2.0.0 bower_components/purescript-eff
└── purescript-prelude#2.1.0
bower purescript-psci-support#* cached https://github.com/purescript/purescript-psci-support.git#2.0.0
bower purescript-psci-support#* validate 2.0.0 against https://github.com/purescript/purescript-psci-support.git#*
bower purescript-psci-support#^2.0.0 install purescript-psci-support#2.0.0
purescript-psci-support#2.0.0 bower_components/purescript-psci-support
└── purescript-console#2.0.0
何やら bower
が動いているようだ。調べた感じ、いくつかのファイルが生成され、bower install
が動いたようだ。
pulp init
で生成されたファイル
pulp init
で生成されたファイルは次のとおりだ。たったの 4 つ。
.gitignore
bower.json
src/Main.purs
test/Main.purs
$ cat .gitignore
/bower_components/
/node_modules/
/.pulp-cache/
/output/
/.psc*
/.psa*
ふむ。
$ cat bower.json
{
"name": "project2",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"output"
],
"dependencies": {
"purescript-prelude": "^2.1.0",
"purescript-console": "^2.0.0"
},
"devDependencies": {
"purescript-psci-support": "^2.0.0"
}
}
ふむふむ。 purescript-prelude#2.1.0
/ purescript-console#2.0.0
/ purescript-psci-support#2.0.0
はとても一般的な依存関係のようだ。
$ cat src/Main.purs
module Main where
import Prelude
import Control.Monad.Eff (Eff)
import Control.Monad.Eff.Console (CONSOLE, log)
main :: forall e. Eff (console :: CONSOLE | e) Unit
main = do
log "Hello sailor!"
ふむふむふむ。
ファイル名は大文字から開始 (モジュール名と一致している (?)) され、.purs
という拡張子を持っているみたいだ。
Main
というモジュールに main
関数が生えている。
import Prelude
は purescript-prelude
が提供するモジュールだろう。
import Control.Monad.Eff.Console
はおそらく purescript-console
が提供するモジュールだろう。
まあ、後回しかな。
$ cat test/Main.purs
module Test.Main where
import Prelude
import Control.Monad.Eff (Eff)
import Control.Monad.Eff.Console (CONSOLE, log)
main :: forall e. Eff (console :: CONSOLE | e) Unit
main = do
log "You should add some tests."
ふむふむふむふむ。特にテストフレームワークなどは組み込まれないっぽい。
pulp build
bodil/pulp の 10.0.0 の README に従って、次は pulp build
してみよう。
$ npm run pulp:build
> project2@1.0.0 pulp:build /Users/bouzuya/project2
> pulp build
* Building project in /Users/bouzuya/project2
Compiling Data.NaturalTransformation
Compiling Data.Show
Compiling Control.Semigroupoid
Compiling Data.Boolean
Compiling Control.Category
Compiling Data.Void
Compiling Data.Function
Compiling Data.Unit
Compiling Data.HeytingAlgebra
Compiling Data.Eq
Compiling Data.Semiring
Compiling Data.Semigroup
Compiling Data.Functor
Compiling Data.Ring
Compiling Data.Ordering
Compiling Data.BooleanAlgebra
Compiling Data.CommutativeRing
Compiling Data.Ord.Unsafe
Compiling Data.Ord
Compiling Data.EuclideanRing
Compiling Control.Apply
Compiling Data.Field
Compiling Control.Applicative
Compiling Control.Bind
Compiling Data.Bounded
Compiling Control.Monad
Compiling Control.Monad.Eff
Compiling Prelude
Compiling Control.Monad.Eff.Class
Compiling Control.Monad.Eff.Unsafe
Compiling Control.Monad.Eff.Console
Compiling PSCI.Support
Compiling Main
* Build successful.
ビルドされた (雑) 。
output/
にコンパイルされたファイルがあるようだ。
$ ls output/
Control.Applicative/
Control.Apply/
Control.Bind/
Control.Category/
Control.Monad/
Control.Monad.Eff/
Control.Monad.Eff.Class/
Control.Monad.Eff.Console/
Control.Monad.Eff.Unsafe/
Control.Semigroupoid/
Data.Boolean/
Data.BooleanAlgebra/
Data.Bounded/
Data.CommutativeRing/
Data.Eq/
Data.EuclideanRing/
Data.Field/
Data.Function/
Data.Functor/
Data.HeytingAlgebra/
Data.NaturalTransformation/
Data.Ord/
Data.Ord.Unsafe/
Data.Ordering/
Data.Ring/
Data.Semigroup/
Data.Semiring/
Data.Show/
Data.Unit/
Data.Void/
Main/
PSCI.Support/
Prelude/
モジュール単位でコンパイル済みの JavaScript ファイルがあるようだ。
$ cat output/Main/index.js
// Generated by psc version 0.10.2
"use strict";
var Prelude = require("../Prelude");
var Control_Monad_Eff = require("../Control.Monad.Eff");
var Control_Monad_Eff_Console = require("../Control.Monad.Eff.Console");
var main = Control_Monad_Eff_Console.log("Hello sailor!");
module.exports = {
main: main
};
なるほど、commonjs 。
pulp run
次は pulp run
で動かしてみる。
$ npm run pulp:run
> project2@1.0.0 pulp:run /Users/bouzuya/project2
> pulp run
* Building project in/Users/bouzuya/project2
* Build successful.
Hello sailor!
動くぞ! node
に渡しているだけっぽい。 --runtime phantomjs
のように別のコマンドも指定できるようだ。
pulp browserify
いかにもな pulp browserify
は……
$ npm run pulp:browserify -- --to output/bundle.js
> project2@1.0.0 pulp:browserify /Users/bouzuya/project2
> pulp browserify "--to" "output/bundle.js"
* Browserifying project in /Users/bouzuya/project2
* Building project in /Users/bouzuya/project2
* Build successful.
* Browserifying...
* Browserified.
思ったよりは短い感じだけど、ここに貼るのは厳しいかな。普通に browserify
しただけっぽい。
--optimise
というオプションで未使用コードを削れるらしい。
$ npm run pulp:browserify -- --optimise --to output/bundle.min.js
> project2@1.0.0 pulp:browserify /Users/bouzuya/project2
> pulp browserify "--optimise" "--to" "output/bundle.min.js"
* Browserifying project in /Users/bouzuya/project2
* Building project in /Users/bouzuya/project2
* Build successful.
* Browserifying...
* Browserified.
$ cat output/bundle.min.js
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
// Generated by psc-bundle 0.10.2
var PS = {};
(function(exports) {
"use strict";
exports.log = function (s) {
return function () {
console.log(s);
return {};
};
};
})(PS["Control.Monad.Eff.Console"] = PS["Control.Monad.Eff.Console"] || {});
(function(exports) {
// Generated by psc version 0.10.2
"use strict";
var $foreign = PS["Control.Monad.Eff.Console"];
var Control_Monad_Eff = PS["Control.Monad.Eff"];
var Data_Show = PS["Data.Show"];
var Data_Unit = PS["Data.Unit"];
exports["log"] = $foreign.log;
})(PS["Control.Monad.Eff.Console"] = PS["Control.Monad.Eff.Console"] || {});
(function(exports) {
// Generated by psc version 0.10.2
"use strict";
var Prelude = PS["Prelude"];
var Control_Monad_Eff = PS["Control.Monad.Eff"];
var Control_Monad_Eff_Console = PS["Control.Monad.Eff.Console"];
var main = Control_Monad_Eff_Console.log("Hello sailor!");
exports["main"] = main;
})(PS["Main"] = PS["Main"] || {});
PS["Main"].main();
},{}]},{},[1]);
確かに縮む。
pulp docs
$ npm run pulp:docs
> project2@1.0.0 pulp:docs /Users/bouzuya/project2
> pulp docs
* Generating documentation in /Users/bouzuya/project2
* Documentation generated.
ふむ。出力先を書いてほしいところだけど……、docs/
っぽい。
$ cat docs/Main.md
## Module Main
#### `main`
``` purescript
main :: forall e. Eff (console :: CONSOLE | e) Unit
```
Markdown だ。
pulp psci
REPL 。
npm run pulp:psci
> project2@1.0.0 pulp:psci /Users/bouzuya/project2
> pulp psci
PSCi, version 0.10.2
Type :? for help
>
引数に *.purs
を指定しなくてもなんとかしてくれている。良い。
pulp server
/app.js
に bundle したファイルを置いて server を立ててくれるっぽい。あまり凝ったことはできなさそうだけど、手軽でいいかも。
npm run pulp:server
> project2@1.0.0 pulp:server /Users/bouzuya/project2
> pulp server
* Server listening on http://localhost:1337/
* Building project in /Users/bouzuya/project2
* Build successful.
* Bundling JavaScript...
* Bundled.
$ curl http://localhost:1337/app.js
# (中略)
PS["Main"].main();
たしかに。 root は package.json
のあるディレクトリみたいなので index.html
を置くと普通に見れる。
pulp test
npm run pulp:test
> project2@1.0.0 pulp:test /Users/bouzuya/project2
> pulp test
* Building project in /Users/bouzuya/project2
Compiling Test.Main
* Build successful.
* Running tests...
You should add some tests.
* Tests OK.
うん。なるほど。
その他
pulp build
や pulp test
あたりは --watch
や --before
/ --then
/ --else
などのオプションを取れるようだ。
ほかのオプションも結構スルーしているので、詳しくは README を参照。
まとめ
$ npm run pulp -- -h
> project2@1.0.0 pulp /Users/bouzuya/project2
> pulp "-h"
Usage: pulp [global-options] <command> [command-options]
Global options:
--before <string> Run a shell command before the operation begins. Useful with `--watch`, eg. `--watch --before clear`.
--bower-file -b <file> Read this bower.json file instead of autodetecting it.
--else <string> Run a shell command if an operation finishes. Useful with `--watch`, eg. `--watch --then 'say Done' --else 'say Failed'`
--help -h Show this help message.
--monochrome Don't colourise log output.
--then <string> Run a shell command after the operation finishes successfully. Useful with `--watch`, eg. `--watch --then 'say Done'`
--version -v Show current pulp version.
--watch -w Watch source directories and re-run command if something changes.
Commands:
browserify Produce a deployable bundle using Browserify.
build Build the project.
docs Generate project documentation.
init Generate an example PureScript project.
login Obtain and store a token for uploading packages to Pursuit.
psci Launch a PureScript REPL configured for the project.
publish Publish a previously tagged version to Bower and Pursuit.
run Compile and run the project.
server Launch a development server.
test Run project tests.
version Bump and tag a new version in preparation for release.
Use `pulp <command> --help` to learn about command specific options.
参考
次回以降の TODO
-
psc-package
を試す -
psci
の未使用コマンドを試す - PureScript ドキュメントを読む