Skip to content

Writing Native

Noah edited this page Nov 1, 2017 · 17 revisions

Should I be writing Native?

The way that Native works in is undocumented on purpose and subject to change. If possible, avoid writing Native. See these two threads here and here for further information. The information in this wiki should come with that warning in mind. It will be very quickly out of date. Native is not an API - there is no guarantee that any of the behaviour described remains in any version.

See this for updated info for Elm 0.18 onwards.

The theory

Every Native module has a standard that it needs to follow. First, it must export itself by attaching to the global Elm object. Native should attach to Elm.Native, non-native should attach to just Elm. We must then define our module, by creating an empty object with the attribute make. make should be a function that takes an instance of the Elm object, and returns an object where each property can be accessed through the Elm code.

It should also check to see if the current module is already defined to have a values property on the instance of Elm passed in. If it does, simply return that instead. These are the values that have been loaded already.

Within the make function, it is possible to to use other modules. To do this, we run the make function, passing in the Elm instance. From there the module's attached properties can be used just as if it were in Elm code itself.

var make = function make(localRuntime) {
    localRuntime.Native = localRuntime.Native || {};
    localRuntime.Native.Http = localRuntime.Native.Http || {};

    if (localRuntime.Native.Http.values) {
        return localRuntime.Native.Http.values;
    }

    var http = require('http');
    var fs = require('fs');
    var mime = require('mime');

    var Task = Elm.Native.Task.make(localRuntime);
    var Utils = Elm.Native.Utils.make(localRuntime);
    var Signal = Elm.Native.Signal.make(localRuntime);
    var Tuple0 = Utils['Tuple0'];
    var Tuple2 = Utils['Tuple2'];

    return {
        'createServer': createServer(fs, http, Tuple2, Task),
        'listen': F3(listen(Task)),
        'on': F2(on(Signal, Tuple0))
    };
};
Elm.Native.Http = {};
Elm.Native.Http.make = make;

Elm internals

There can be considered two parts to Elm:

  • Elm.Native
    • Native code, written by humans!
    • Follows a standard structure
  • Elm
    • Generated code, compiled from code written in Elm the language

This can be broken down further, into

  • The Elm runtime/core
    • Provided by the core library for elm
    • Contains a standard set of modules which are included in every Elm project
    • Also provides bootstrapping and setup for the framework
  • Extra Elm modules
    • Anything that isn't part of core