om-elm-2.1.0.0: Haskell utilities for building embedded Elm programs.
Safe HaskellSafe-Inferred
LanguageHaskell2010

System.Elm.Compile

Description

Core compile-time utilities for embedding Elm programs in Haskell.

This module runs the elm compiler during Template Haskell splices and returns the compiled output as a String. It is the low-level building block used by higher-level modules such as System.Elm.Middleware.

Quick start

1) Ensure elm is available when GHC runs Template Haskell. If you use Cabal, add requireElm to your Setup.hs (see System.Elm.Middleware for details).

2) Call compileElm from a Template Haskell splice:

import Language.Haskell.TH
import System.Elm.Compile

embeddedJs :: Q String
embeddedJs = compileElm Dev JavaScript "frontend/Main.elm"

3) Splice the result into your program:

myJs :: String
myJs = $(embeddedJs)

Choosing a Mode

Mode controls which flags are passed to elm make:

  • Dev — no extra flags (the default for local development)
  • Debug — passes --debug (debug runtime, better errors)
  • Optimize — passes --optimize (smaller, faster output)

Examples:

compileElm Dev JavaScript "frontend/Main.elm"

compileElm Debug JavaScript "frontend/Main.elm"

compileElm Optimize JavaScript "frontend/Main.elm"

Choosing an ElmOutputFormat

ElmOutputFormat selects whether elm make produces a standalone JavaScript bundle or a complete HTML page:

  • JavaScript — compile to .js (typical for SPAs loaded by your own HTML template)
  • Html — compile to a self-contained .html page

Examples:

-- JavaScript bundle for a custom HTML shell
compileElm Dev JavaScript "frontend/Main.elm"

-- Full HTML page served as-is
compileElm Dev Html "frontend/Main.elm"

Embedding in other types

compileElm returns a plain String. Convert it however your application needs:

import qualified Data.Text as T

embeddedText :: Q T.Text
embeddedText = T.pack <$> compileElm Dev JavaScript "frontend/Main.elm"
import qualified Data.ByteString.Char8 as BS8

embeddedBytes :: Q BS8.ByteString
embeddedBytes = BS8.pack <$> compileElm Dev JavaScript "frontend/Main.elm"

Using with typed splices

For a typed expression splice, bind the compiled content in Q and lift it:

import Language.Haskell.TH

myJs :: String
myJs = $(do
  js <- compileElm Optimize JavaScript "frontend/Main.elm"
  [| js |]
  )

Recompilation

compileElm registers the .elm source file as a Template Haskell dependency via addDependentFile. GHC can re-run the splice when that file changes, but that only effectively works if the .elm file is also listed under extra-source-files in your .cabal file — otherwise Cabal may not rebuild the Haskell module when the Elm source changes.

Example:

extra-source-files:
  frontend/Main.elm

Relationship to System.Elm.Middleware

If you want to serve compiled Elm as WAI Middleware, use System.Elm.Middleware instead — it wraps compileElm for that purpose. Use this module when you want the compiled output directly (for example, embedding JavaScript in a HTML template you write yourself, or serving it through your own HTTP layer).

Synopsis

Documentation

data Mode Source #

Constructors

Optimize 
Dev 
Debug 

Instances

Instances details
Show Mode Source # 
Instance details

Defined in System.Elm.Compile

Methods

showsPrec :: Int -> Mode -> ShowS

show :: Mode -> String

showList :: [Mode] -> ShowS

Eq Mode Source # 
Instance details

Defined in System.Elm.Compile

Methods

(==) :: Mode -> Mode -> Bool

(/=) :: Mode -> Mode -> Bool

data ElmOutputFormat Source #

Constructors

JavaScript 
Html 

Instances

Instances details
Show ElmOutputFormat Source # 
Instance details

Defined in System.Elm.Compile

Methods

showsPrec :: Int -> ElmOutputFormat -> ShowS

show :: ElmOutputFormat -> String

showList :: [ElmOutputFormat] -> ShowS

Eq ElmOutputFormat Source # 
Instance details

Defined in System.Elm.Compile

compileElm :: Mode -> ElmOutputFormat -> FilePath -> Q String Source #

Compile an Elm program at Template Haskell time.

This function invokes elm make, reads the compiler output from a temporary build directory, and returns the contents as a String. The caller is responsible for interpreting the result — for example, choosing an HTTP content type or converting to Text.

Parameters

  • mode — compiler flags (Dev, Debug, or Optimize)
  • format — output shape (JavaScript or Html)
  • elmFile — path to the .elm entrypoint, relative to the project root (same path you would pass to elm make on the command line)

Basic examples

Compile a JavaScript bundle with default (dev) settings:

compileElm Dev JavaScript "frontend/Main.elm"

Compile an optimized JavaScript bundle:

compileElm Optimize JavaScript "frontend/Main.elm"

Compile a self-contained HTML page:

compileElm Dev Html "frontend/Main.elm"

Splicing into top-level definitions

myJs :: String
myJs = $(compileElm Dev JavaScript "frontend/Main.elm")
myHtml :: String
myHtml = $(compileElm Dev Html "frontend/Main.elm")

Splicing into a larger Template Haskell computation

import Language.Haskell.TH

myJs :: String
myJs = $(do
  js <- compileElm Optimize JavaScript "frontend/Main.elm"
  [| js |]
  )

Combining mode and format

-- Debug runtime, JavaScript output
compileElm Debug JavaScript "frontend/Main.elm"

-- Optimized production build, HTML output
compileElm Optimize Html "frontend/Main.elm"

-- Dev build, JavaScript output (most common for SPAs)
compileElm Dev JavaScript "frontend/Main.elm"

Requirements

  • The elm executable must be on PATH when GHC runs this splice.
  • The elmFile path must exist at compile time.
  • GHC can re-run the splice when elmFile changes (via addDependentFile), but that only effectively works if elmFile is also listed under extra-source-files in your .cabal file (see the module documentation for an example).

See the module documentation for setup instructions and more embedding examples.