webpack loader for webpackifying asset references in Elm.
$ npm install --save elm-assets-loader
elm-assets-loader is intended to be chained after elm-webpack-loader, and with a loader to load static assets like file-loader or url-loader. elm-asset-path is a companion Elm package that provides types and functions for working with asset paths.
Suppose we have a union type for tagging asset paths:
module My.Assets exposing (AssetPath(..))
type AssetPath
= AssetPath String
star =
AssetPath "star.png"
Tell elm-assets-loader to look for strings tagged with AssetPath:
rules: [
{
test: /\.elm$/,
exclude: [/elm-stuff/, /node_modules/],
use: [
{
loader: 'elm-assets-loader',
options: {
module: 'My.Assets',
tagger: 'AssetPath'
}
},
'elm-webpack-loader'
]
},
{
test: /\.(jpe?g|png|gif|svg)$/i,
loader: 'file-loader',
options: {
name: '[name]-[hash].[ext]'
}
}
]
Then at runtime, the value of My.Assets.star will be something like
AssetPath "star-038a1253d7a9e4682deb72cd68c3a328.png".
To actually use this string value, define a helper like so:
-- say, in My.Assets
path : AssetPath -> String
path (AssetPath str) =
str
Usage example:
viewStar : Html Msg
viewStar =
img [ src <| My.Assets.path <| My.Assets.star ] []
elm-asset-path includes a reference
implementation of this AssetPath type with support for resolving to a URL on a CDN.
"AssetPath"<tagger> String that's used to tag asset paths in your code."My.Assets""user/project""NoRedInk/myapp"elm-package.json.
"repository": "https://github.com/user/project.git" -> package should be "user/project""repository": "https://github.com/NoRedInk/myapp.git" -> package should be "NoRedInk/myapp"Default: "warn"
Possible values: "error" | "warn" | "ok"
What to do with dynamically constructed asset paths.
Dynamic requires is not supported. This option simply controls whether or not to raise an error or skip over expressions like:
example iconName =
AssetPath ("icon-" ++ iconName ++ ".png")
Function to transform tagged strings to a path that can be resolved by webpack. For example, you may want to tag URL paths, which may not be resolvable to a filesystem path, so that your code works without being webpacked.
star = AssetPath "/public/images/star.png"
img [ src (toUrl star) ] []
webpack config (for webpack 2):
module.exports = {
...
module: {
rules: [
{
test: /\.elm$/,
use: [
{
loader: 'elm-assets-loader',
options: {
localPath: function(url) {
// transform `url` to a local path that resolves to a file
return url.replace(/^\/public\//, "");
}
}
},
'elm-webpack-loader?cwd=' + fixturesPath + '&pathToMake=' + elmMakePath
]
},
{
test: /\.svg$/,
use: {
loader: 'file-loader',
options: {
publicPath: function(path) {
// transform `path` to a URL that the web server can understand and serve
return "/public/" + url;
}
}
}
}
}
}
}
Don't set noParse on .elm files. Otherwise, requires won't be processed.
Let's walk through what happens to the example above when processed by webpack.
This Elm code:
AssetPath "star.png"
will be compiled to JavaScript by elm-webpack-loader:
_user$project$My_Assets$AssetPath("star.png")
elm-assets-loader turns this into:
_user$project$My_Assets$AssetPath(require("star.png"))
webpack parses this require call, determines it to be a file-loader module, resulting in:
_user$project$My_Assets$AssetPath(__webpack_require__(30))
The module loaded by __webpack_require__(30) will look like:
30:
function(module, exports) {
module.exports = "star-038a1253d7a9e4682deb72cd68c3a328.png";
}
Which means, effectively, the JavaScript code we saw originally has been rewritten as:
_user$project$My_Assets$AssetPath("star-038a1253d7a9e4682deb72cd68c3a328.png")
See .travis.yml to see supported combinations of the Elm Compiler & Webpack.