Webpack 3 and Phoenix 1.3
Phoenix 1.3 changes the asset directory structure which results in most tutorials and examples for adding elm or webpack to phoenix obsolete.
This post shows an example configuration that uses Elm 0.18, Phoenix 1.3 and Webpack 3. It is used in FreeChat a modern Elixir/Elm IRC Client.
Elm code is placed in assets/elm (just like JavaScript code is in assets/js/). Thus directory is assumed in the following webpack configuration.
Setting up Webpack and Elm
Generate your phoenix app
Example:
mix phx.new free_chat
cd free_chat
mix ecto.create
Remove brunch-config.js
rm brunch-config.js
Add webpack to phoenix config (to automatically compile assets)
add watchers: [npm: ["start", cd: Path.expand("../assets/", __DIR__)]]
to your config/dev.exs
Add Webpack configuration
webpack.config.js
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const elmSource = __dirname + "/elm";
const env = process.env.MIX_ENV || "dev";
const isProduction = env === "prod";
const path = require("path");
module.exports = {
devtool: "source-map",
entry: {
app: ["./css/app.scss", "./js/app.js", "./elm/Main.elm"]
},
output: {
path: path.resolve(__dirname, "../priv/static/"),
filename: "js/app.js"
},
resolve: {
extensions: [".css", ".scss", ".js", ".elm"],
alias: {
phoenix: __dirname + "/deps/phoenix/assets/js/phoenix.js"
}
},
module: {
rules: [
{
test: /\.(sass|scss)$/,
include: /css/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: [
{ loader: "css-loader" },
{
loader: "sass-loader",
options: {
sourceComments: !isProduction
}
}
]
})
},
{
test: /\.(js)$/,
include: /js/,
use: [{ loader: "babel-loader" }]
},
{
test: /\.elm$/,
exclude: ["/elm-stuff/", "/node_modules"],
loader: "elm-webpack-loader",
options: { maxInstances: 2, debug: true, cwd: elmSource }
}
],
noParse: [/\.elm$/]
},
plugins: [
new ExtractTextPlugin("css/app.css"),
new CopyWebpackPlugin([{ from: "./static" }])
]
};
Add a minimal package.json
assets/package.json
{
"repository": {},
"license": "GPLv3",
"scripts": {
"start": "webpack --watch --color"
},
"dependencies": {
"phoenix": "file:../deps/phoenix",
"phoenix_html": "file:../deps/phoenix_html"
},
"devDependencies": {
"webpack": "^3.5.5",
"copy-webpack-plugin": "^4.2.0"
}
}
Install javascript packages
Run yarn install
To avoid outdated versions the above package.json is almost empty. Please run the following command to add the necessary dependencies:
yarn add --dev babel-core babel-loader babel-preset-es2015
yarn add --dev css-loader style-loader extract-text-webpack-plugin
yarn add --dev node-sass sass-loader
yarn add --dev elm-webpack-loader
Now the package json should includes all the package and they are already installed as well.
Add a dummy (or minimal) Main.elm
Create a directory for your elm files:
mkdir assets/elm
assets/elm/Main.elm
module Main exposing (..)
import Html exposing (text)
main =
text "hello, phoenix"
Install basic elm packages
cd asset/elm/
elm-package install
This command should generate a elm-package.json if not yet present
Add elm to your app.js
Minimal Elm snippet for your phoenix app.js
import "phoenix_html";
import { Socket } from "phoenix";
const Elm = require('../../elm/Main');
Elm.Main.embed(document.getElementById('elm-main'));
Add a container to your html
To render the elm app in your html you need to add an element with the above id elm-main
to your markup.
For the free_chat example it means adding <div id="elm-main"></div>
to the index file lib/free_chat_web/templates/page/index.html.eex
.
Final steps
With this configuration running mix phx.server
will also automatically recompile all assets including your Elm code.
Now you can see the compilation result in the console and visit your webapp in the browser. For a full working example
take a look at the FreeChat project.
Helpful resources (older webpack or phoenix versions)
- FreeChat Elixir/Elm app
- https://www.dailydrip.com/topics/elixirsips/drips/webpack-phoenix-and-elm (webpack 1, phoenix 1.2)
- https://blog.exertion.io/using-webpack-with-phoenix-and-elm/ (webpack 1, phoenix 1.2)
- Elm webpack loader