elm-pages
Scripts
The elm-pages run
command lets you use BackendTask
's to do scripting tasks with Elm. The goal is to make it as simple as possible to write a Script in Elm and run it from the command line. You can use any of the techniques from BackendTask's to read files, make HTTP requests, get environment variables, or async NodeJS functions through BackendTask.Custom.run
.
Quick Start
The elm-pages starter repo comes with a script/
folder that is setup with an elm.json
with elm-pages
as a dependency, but you can also create the script/
folder from scratch:
mkdir script
cd script
elm init
elm install dillonkearns/elm-pages-v3-beta
Now we can write our Script Module. Create a file called script/src/Hello.elm
that exposes a top-level value run
of type Script
.
module Hello exposing (run)
import Pages.Script as Script exposing (Script)
run : Script
run =
Script.withoutCliOptions
(Script.log "Hello from elm-pages Scripts!")
Now we can run our Hello.elm
Script Module from the command line:
npx elm-pages run script/src/Hello.elm
# Hello from elm-pages Scripts!
As a shorthand, you can run scripts from the folder ./script/src/
by passing in the Elm module name (without the .elm
extension) instead of the file path of the module name.
npx elm-pages run Hello
# Hello from elm-pages Scripts!
Script Folder
The script/
folder is a regular Elm project folder. That means it will need to have an elm.json
file, and an Elm module in the src/
folder (or whichever source-directories
path you define in your elm.json
). It will also need elm-pages
installed as a dependency.
If you use BackendTask.Custom.run
from your Script, it will use the custom-backend-task.ts
(or .js
) file defined in your script/
project folder.
The name script/
is a convention and is not required. You can execute the elm-pages run
command on any file as long as it is part of an Elm project (in its source-directories
), and that project has elm-pages
installed as a dependency.
Running Scripts from Different Directories
You can pass any absolute or relative path to an elm-pages
Script module to the elm-pages run
command. It will find the elm.json
for the Script module automatically.
elm-pages run ~/my-projects/elm-pages-scripts/src/Hello.elm
Adding Command Line Options
Scripts can define command line options with a config from dillonkearns/elm-cli-options-parser
.
Here is an example that takes optional keyword arguments --username
and --repo
.
module Stars exposing (run)
import BackendTask exposing (BackendTask)
import BackendTask.Http
import Cli.Option as Option
import Cli.OptionsParser as OptionsParser
import Cli.Program as Program
import Json.Decode as Decode
import Pages.Script as Script exposing (Script)
run : Script
run =
Script.withCliOptions program
(\{ username, repo } ->
BackendTask.Http.getJson
("https://api.github.com/repos/dillonkearns/" ++ repo)
(Decode.field "stargazers_count" Decode.int)
|> BackendTask.andThen
(\stars ->
Script.log ("🤩" ++ (String.fromInt stars))
)
|> BackendTask.allowFatal
)
type alias CliOptions =
{ username : String
, repo : String
}
program : Program.Config CliOptions
program =
Program.config
|> Program.add
(OptionsParser.build CliOptions
|> OptionsParser.with
(Option.optionalKeywordArg "username"
|> Option.withDefault "dillonkearns")
|> OptionsParser.with
(Option.optionalKeywordArg "repo"
|> Option.withDefault "elm-pages")
)
Our Cli.Program.Config
that we defined automatically gives us a --help
option.
npx elm-pages run script/src/Stars.elm --help
# elm-pages run Stars [--username <username>] [--repo <repo>]
Now let's run our script with some options.
npx elm-pages run script/src/Stars.elm --repo elm-graphql
# 🤩 757
Now let's try running it with an invalid option.
run script/src/Stars.elm --user elm --name json
# -- Invalid CLI arguments ---------------
# The `--name` flag was not found. Maybe it was one of these typos?
#
# `--name` <> `--username`
FatalError
's
If the BackendTask
in your script resolves to a FatalError
, the script will print the error message and exit with a non-zero exit code. As with any BackendTask
, if you want to ensure that your script will not encounter a FatalError
, you can ensure that you have handled every possible error by using a value with the type BackendTask Never ()
.
Scaffolding a Route Module
The elm-pages
package includes some modules that help you generate Elm files.
elm-pages run
will automatically run elm-codegen install
for you if you have a ./codegen/
folder next to your ./script/
project.
elm-codegen
is a project that helps you write Elm code that generate Elm code. In our case, we are going to generate some scaffolding to help us add new Routes to our elm-pages
app.
elm-codegen
helps ensure that you are generating valid code by generating functions that mirror the code they will generate, giving you an extra layer of type safety. elm-pages
Scripts are general-purpose, so you can do what you want with them, but there are some built-in helpers to make it easy for you to scaffold code for your elm-pages
app that work well with elm-codegen
.
Take a look at the AddRoute.elm
Script from the elm-pages
starter repo. This Script is a great starting point for customizing your own scaffolding Scripts for your project. It is designed to lock in the essential details for defining a Route Module and a Form, while leaving the rest up to you to customize in the script. See Scaffold.Route
and Scaffold.Form
in the docs.
Compiling Scripts to an Executable JavaScript File
You can compile your script (options parsing and all) to a single minified and optimized JavaScript file that you can run in any NodeJS environment.
elm-pages bundle-script script/src/Stars.elm