<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: totycro</title>
    <description>The latest articles on Forem by totycro (@totycro).</description>
    <link>https://forem.com/totycro</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F253205%2F435feabc-4978-4a5e-9824-8a540b8531b6.jpg</url>
      <title>Forem: totycro</title>
      <link>https://forem.com/totycro</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/totycro"/>
    <language>en</language>
    <item>
      <title>Running elm in docker</title>
      <dc:creator>totycro</dc:creator>
      <pubDate>Fri, 25 Oct 2019 13:21:23 +0000</pubDate>
      <link>https://forem.com/totycro/running-elm-in-docker-5goh</link>
      <guid>https://forem.com/totycro/running-elm-in-docker-5goh</guid>
      <description>&lt;p&gt;So far there doesn't seem to be a nice go-to setup for how to run elm in docker. I would like to have one where it's easy to &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;run an auto-reload development server (elm reactor) and&lt;/li&gt;
&lt;li&gt;start a test-watcher
without needing to think about docker too much.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Basically the environment of the development should be its docker image, but as a developer, you shouldn't have to worry too much about it.&lt;/p&gt;

&lt;p&gt;Hence I &lt;a href="https://github.com/totycro/elm-docker-template"&gt;created a repo&lt;/a&gt; which you can use as baseline for your elm project.&lt;/p&gt;

&lt;p&gt;Let's check out what's inside!&lt;/p&gt;

&lt;h1&gt;
  
  
  Dockerfile
&lt;/h1&gt;

&lt;p&gt;There are already &lt;a href="https://hub.docker.com/r/wunsh/alpine-elm"&gt;some&lt;/a&gt; docker &lt;a href="https://hub.docker.com/r/nacyot/elm-elm"&gt;images&lt;/a&gt; for &lt;a href="https://hub.docker.com/r/codesimple/elm/"&gt;elm&lt;/a&gt;, which usually either install elm via a package management tool such as &lt;code&gt;npm&lt;/code&gt; or &lt;code&gt;cabal&lt;/code&gt;, or build elm from source using a haskell compiler. When using one of them, be careful as to which version of elm they install.&lt;/p&gt;

&lt;p&gt;There is even an &lt;a href="https://hub.docker.com/r/paullamar3/docker-knowthen-elm"&gt;image&lt;/a&gt; which encorporates a full IDE with plugins preconfigured for use with elm. This is not the &lt;em&gt;intended&lt;/em&gt; way of using docker, but it might just work out fine for your use case.&lt;/p&gt;

&lt;p&gt;For our configuration, let's sticking to the one provided by &lt;a href="https://hub.docker.com/r/codesimple/elm/"&gt;codesimple&lt;/a&gt; because its Dockerfile consists of 4 lines and I like simple. Note that it lacks elm-test, so we have to add that manually. It also predetermines the arbitrarily chosen directory &lt;code&gt;/mnt&lt;/code&gt; as work directory to mount the code in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; codesimple/elm:0.19&lt;/span&gt;

&lt;span class="c"&gt;# NOTE: you actually do need unsafe perm to install elm packages with npm&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--unsafe-perm&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; elm-test@0.19.0-rev6

&lt;span class="c"&gt;# NOTE: we need to set HOME, because elm uses $HOME/.elm to save packages.&lt;/span&gt;
&lt;span class="c"&gt;#       if this doesn't persist between runs, you get CORRUPT BINARY errors.&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; HOME /mnt&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /mnt&lt;/span&gt;
&lt;span class="k"&gt;VOLUME&lt;/span&gt;&lt;span class="s"&gt; /mnt&lt;/span&gt;
&lt;span class="c"&gt;# NOTE: docker-compose mounts code in /mnt&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It also fixes a major issue I ran into when running the elm compiler multiple times. Apparently it caches compliation data in the directory &lt;code&gt;elm-stuff&lt;/code&gt; in the repo root directory (as expected), but also expects installed packages to be present in &lt;code&gt;$HOME/.elm&lt;/code&gt;. This is a problem when working in docker as in between runs, the data in &lt;code&gt;$HOME&lt;/code&gt; is not preserved. We fix this issue here using somewhat of a hack: &lt;code&gt;ENV HOME /mnt&lt;/code&gt;. So we pretend that &lt;code&gt;/mnt&lt;/code&gt; is actually our home directory and &lt;code&gt;${HOME}/.elm&lt;/code&gt; ends up in the mounted code directory which persists in between runs.&lt;/p&gt;

&lt;p&gt;A nicer fix would be to configure elm to use this directory as cache explicitly, but I'm not aware of such a configuration option.&lt;/p&gt;

&lt;p&gt;As a side-effect of this fix, the &lt;code&gt;.bash_history&lt;/code&gt; also ends up in the mounted directory (since it's saved in &lt;code&gt;$HOME&lt;/code&gt; as well), so you can use the shell history as expected.&lt;/p&gt;

&lt;h1&gt;
  
  
  docker-compose
&lt;/h1&gt;

&lt;p&gt;Moving on to &lt;code&gt;docker-compose.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: '3.7'
services:
  elm:
    build: .
    volumes:
    - .:/mnt
    ports:
    - 8000
    # we need init to kill elm-test when run with "make test"
    init: true
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It's very basic and merely sets up the volume mount and exposes port 8000. It also fixes an annoying issue with elm-test:&lt;/p&gt;

&lt;p&gt;I found that when running in docker, elm-test ignores &lt;code&gt;SIGINT&lt;/code&gt;, so you can't kill it via &lt;code&gt;ctrl-c&lt;/code&gt;. This has to be a problem in the way elm-test is run, since when running elm-test in a shell, it reacts as expected to &lt;code&gt;ctrl-c&lt;/code&gt;. However by setting &lt;code&gt;init: true&lt;/code&gt;, docker-compose will make sure that signals are handled and will kill elm-test on &lt;code&gt;ctrl-c&lt;/code&gt;. Please let me know if you're aware of a more elegant solution to this issue.&lt;/p&gt;

&lt;h1&gt;
  
  
  Makefile
&lt;/h1&gt;

&lt;p&gt;At this point, we are basically done and can run commands as we like with docker-compose. Since I'm old already I like to have my commands in a Makefile to be able to run every one conveniently. Since only basic shell commands are executed there you can feel free to convert this to your favorite package script runner :-)&lt;/p&gt;

&lt;p&gt;Make sure not to confuse the elm container in docker-compose (named &lt;code&gt;elm&lt;/code&gt;) with the &lt;code&gt;elm&lt;/code&gt; command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;all&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;reactor&lt;/span&gt;

&lt;span class="nv"&gt;RUN_IN_DOCKER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; docker-compose run &lt;span class="nt"&gt;--user&lt;/span&gt; &lt;span class="err"&gt;$$&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="nl"&gt;build&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    docker-compose build elm

&lt;span class="nl"&gt;compile&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;build&lt;/span&gt;
    &lt;span class="nv"&gt;${RUN_IN_DOCKER}&lt;/span&gt; elm make src/Main.elm

&lt;span class="nl"&gt;reactor&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;build&lt;/span&gt;
    &lt;span class="c"&gt;# NOTE: elm is the container, not the command&lt;/span&gt;
    &lt;span class="nv"&gt;${RUN_IN_DOCKER}&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 8000:8000 elm reactor

&lt;span class="nl"&gt;test&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;build&lt;/span&gt;
    &lt;span class="nv"&gt;${RUN_IN_DOCKER}&lt;/span&gt; &lt;span class="nt"&gt;--entrypoint&lt;/span&gt; elm-test elm

&lt;span class="nl"&gt;test-watch&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;build&lt;/span&gt;
    &lt;span class="nv"&gt;${RUN_IN_DOCKER}&lt;/span&gt; &lt;span class="nt"&gt;--entrypoint&lt;/span&gt; elm-test elm &lt;span class="nt"&gt;--watch&lt;/span&gt;

&lt;span class="nl"&gt;bash&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;build&lt;/span&gt;
    &lt;span class="nv"&gt;${RUN_IN_DOCKER}&lt;/span&gt; &lt;span class="nt"&gt;--entrypoint&lt;/span&gt; bash elm
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;For day to day development, it should suffice to start the dev-server via &lt;code&gt;make reactor&lt;/code&gt; and have your tests running with &lt;code&gt;make test-watch&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can integrate the command &lt;code&gt;make test&lt;/code&gt; in your favorite CI pipeline.&lt;/p&gt;

&lt;p&gt;So clone/fork the base template from &lt;a href="https://github.com/totycro/elm-docker-template"&gt;github&lt;/a&gt; and enjoy your encapsulated elm environment!&lt;/p&gt;

</description>
      <category>elm</category>
      <category>docker</category>
    </item>
  </channel>
</rss>
