Skip to content

OzTK/elm-view-engine

Repository files navigation

elm-view-engine npm Build Status Coverage Status Known Vulnerabilities

Renders elm views from a directory of elm modules. This can and is meant to be plugged into Express as a template engine.

The 2 simple goals of this project are:

  • Allowing to reuse elm views when rendering the page the first time, avoiding to have a duplicate html view in the case of a multi-page app doing server-side rendering

  • Building views uniformly with the same technology (Elm!) and avoid having another template language in the stack.

BREAKING CHANGE

Elm views format changed in v2.0! see corresponding section

Getting Started

Prerequisites

Elm needs to be installed either globally or locally in the project.

> npm i -g elm

or

> npm i elm

Installing

> npm i elm-view-engine

Usage

You can use the view engine by itself to being able to render a directory of elm views, or you can plug it in to express as a view engine.

Standalone use

Typescript:

import { configure, Options } from "elm-view-engine";

configure(new Options("path/to/my/views", "path/to/elm/root")).then((engine) => {
  const someContext = {
    arrayOfUsers: [ "Paul", "Jack", "Barbara" ];
  };
  const viewContent = engine.getView("UsersView", someContext);
  // Do something with the html
}));

Javascript:

var eve = require('elm-view-engine');

var options = {
  viewsDirPath: 'path/to/my/views',
  projectRoot: 'path/to/elm/root',
};

eve.configure(options).then((engine) => {
  const someContext = {
    arrayOfUsers: [ 'Paul', 'Jack', 'Barbara' ],
  };
  const viewContent = engine.getView('UsersView', someContext);
  // Do something with the html
}));

Express integration

Just call the configure function passing your express app in the options:

Typescript:

import { configure, Options } from "elm-view-engine";
import * as express from "express";

const app = express();

configure(new Options("path/to/my/views", "path/to/elm/root", app)).then(() => {
  // app template engine is ready
  app.use(...);
}));

Javascript:

var eve = require('elm-view-engine');
var express = require('express');

var app = express();

var options = {
  viewsDirPath: 'path/to/my/views',
  projectRoot: 'path/to/elm/root',
  expressApp: app,
};

eve.configure(options).then(() => {
  // app template engine is ready
  app.use(...);
}));

Views

Your elm views must expose 2 functions with the following signatures:

view : MyContext -> Html MyMsg
context : Json.Decode.Decoder MyContext

If they don't, views compilation will fail.

  • MyContext is a record defining the structure of the context passed to the view. If you don't need any context for your view, you can use the following template:
context : Json.Decode.Decoder ()
context =
    decode ()


view : () -> Html Never
view _ =
    -- Code for your view
  • context returns a decoder for the context that will deserialize the json context internally to the engine
  • Passing an invalid context when requesting a view will result in an error from the engine
Example

A view with a simple context:

module Greeter exposing (view, context)

import Html exposing (Html, h1, div, text)
import Json.Encode
import Json.Decode exposing (decodeValue, string)
import Json.Decode.Pipeline exposing (decode, required)


-- Model


type alias SimpleContext =
    { simpleName : String }


context : Json.Decode.Decoder SimpleContext
context =
    decode SimpleContext
        |> required "simpleName" string



-- View


view : SimpleContext -> Html Never
view ctx =
    div
        []
        [ h1 []
            [ text ("Hello " ++ ctx.simpleName ++ "!")
            ]
        ]

Pre-compiling

The views get compiled once when calling configure(). They are then cached and reused. This causes 2 inconveniences:

  • The initial compilation can take some time and clog your server if you compile at startup.
  • When a view is modified, it doesn't change right away: A new compilation is needed

To overcome this, it is possible to compile your views with the CLI by using the elm-view-engine command. It will compile the views right away, and can be done before or after the server has started. The views can now be compiled beforehand or during server execution for development (See example for integration in npm scripts).

Running elm-view-engine -h gives more info about the command.

Running the tests

Just git clone https://github.com/OzTK/elm-view-engine and run the npm test command from the root of the project. You can check the coverage by running npm run coverage:local.

Built With

Because of the dynamic nature of the project, I had to generate elm code (the template for the module is src/MainTemplate.elm). I also needed to compile this generated elm code on the fly (when you call configure()) and render elm views into html strings. I relied on the following libraries for this purpose:

Contributing

Please feel free to open issues for any concerns. PRs welcome!