elm-reactor
elm-reactor copied to clipboard
Elm Reactor + External CSS
Hi,
I'd like to know if it is possible to use the reactor(by using I mean keep it recompiling the code at every change, debug and time-travel) with an external CSS being loaded with the Elm file. Let's say my entire project is just a single Elm file(or centralized on a main Elm file) and I want to use the reactor with an external CSS source, is this possible ?
My current "solution" is to use grunt and make it recompile the code but obviously I lose the debug and time-travel abilities from reactor, I'm willing to implement this myself, just want to collect some feedback first and maybe some initial guidance.
My idea is to simply add a <link>
reference in the header of the auto generated HTML based on some commmand line argument, something like that:
elm reactor --include-css main.css
It would be up to the person to generate this single CSS containing everything he needs but I believe this wouldn't be an issue(at least not so big as having to choose between CSS and debug+time-travel).
Thanks
Maybe some of the solution(s) here would help you in the meantime, in the absence of the specific feature you ask for?
Thanks for pointing that out @jvoigtlaender , I'll give them a try, but it is good to see that other people had similar needs in the past
I drop this here, it could be nice if in addition to Html
and Element
return types for main we could have something like Document
that'd look like this:
type alias Document =
{ title : String
, metas : List Meta
, scripts : List Script
, stylesheets : List Stylesheet
, body : List Html
, className : String
}
People are constantly asking on the ML or here how to achieve this, it must reflect a real need.
I'm surprised that something simple like having a bootstrap/semantic UI css along side elm has taken me half an hour to get to this point with no results...
elm-css
wouldn't be my first solution as I don't want to spend months rewriting styling for my simple project needs. Is it still not possible to include css in a elm project?
Try this: https://github.com/moarwick/elm-webpack-starter
@fluxxu loving it
I am trying to learn elm, coming only with basic experience with js Html and CSS. I don't want to work with less, scss or sass or other tools like webpack. Trying to solve the problem of including external CSS in my elm project I keep getting search results about elm-reactor and elm-css.
For people like me, it would be just great to have and example minimal as html with one external CSS file.
@oz123 You could use workaround like this. Add index.html
to your src
forder with styles.css
file. Contents of index.html
:
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="styles.css"><!-- Put your styles in folder with index.html -->
</head>
<body>
<div style="width: 100%; height: 100%; display: flex; flex-direction: column; justify-content: center; align-items: center; color: #9A9A9A; font-family: 'Source Sans Pro';">
<div style="font-size: 3em;">Building your project!</div>
<img src="/_reactor/waiting.gif">
<div style="font-size: 1em">With new projects, I need a bunch of extra time to download packages.</div>
</div>
</body>
<!-- Fonts and external JS and styles are available, I've put Ace for example -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.4/ace.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.4/theme-chrome.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.4/worker-lua.js"></script>
<!-- Put the name of your app here (my sources place in `src` forder) -->
<script type="text/javascript" src="/_compile/src/YourApp.elm"></script>
<!-- Removes splash and starts elm app. -->
<script type="text/javascript">
while (document.body.firstChild) {
document.body.removeChild(document.body.firstChild);
}
runElmProgram();
</script>
</html>
Now, open it with reactor :)
@DenisKolodin, wow! Thanks for the quick response. So this will also work with elm-make
?
Like I said, currently I am interested in final build products and not the how to add CSS in the reactor.
@oz123 I use different for testing and production. But minimal changes you need:
<!-- Head is the same -->
<body>
<div id="my-app"></div>
</body>
<!-- Fonts and external JS and styles are available -->
<!-- Your source after making -->
<script type="text/javascript" src="YourApp.js"></script>
<!-- Removes splash and starts elm app. -->
<script type="text/javascript">
var node = document.getElementById('my-app');
var app = Elm.YourApp.embed(node);
</script>
Suggestion: could we have support for a "stylesheets"
directive added to elm-package.json
which would load these from the generated html page? I must admit I have no idea of the technical implications and limitations here, so just discard if this doesn't make any sense.
I tried elm a year ago, had this problem too. Now i just came back in the elm irc channel and i see people who still have this exact same problem. Makes me believe urgency is high on this one ^^
@flip111 You can use the following in the meantime: for development, for production
@MeinAccount. Thx i will forward your solution when i see someone else asking about it again. Perhaps it's worthwhile too include it in the reactor documentation or website
@flip111 I'd suggest a section on using a custom HTML-file. That's useful for including CSS, JS as well as custom HTML-Code. The other option would be the suggested --include-css
option for Elm Reactor, although that has less possibilities.
Starting with the advice in https://github.com/elm-lang/elm-reactor/issues/138#issuecomment-240945527, I made a bootstrap repo that (for me) is the simplest way to serve custom CSS while developing. Golang is required, however. Maybe someone will find it helpful.
https://github.com/stuartnelson3/elm-bootstrap
Here's the solution I use to keep using Elm Reactor while messing with external CSS, flags and ports from the Javascript side:
<!doctype html>
<meta charset=utf-8>
<title>a title</title>
<link href=/bundle.css rel=stylesheet>
<body></body>
<script src="/_compile/Main.elm"></script> <!-- this will fail in production -->
<script src="/elm-bundle.js"></script> <!-- this will fail in development -->
<script>
var app
var flags = {}
try {
app = Elm.App.fullscreen(flags)
/* app.ports is now available */
} catch (e) {
// this will run in case there are compile errors:
var stylesheets = document.querySelectorAll('link')
for (var i = 0; i < stylesheets.length; i++) {
stylesheets[i].parentNode.removeChild(stylesheets[i])
}
runElmProgram()
}
</script>
I've been compiling down to index.html and using a separate stylesheet but it would be nice to run something like elm-reactor --include-css styles/
and have link
elements inserted into the DOM whenever viewing an elm file.
Will see if I can do this, this is a very useful feature.
Just some ideas on how to implement this:
- add the --include-css flag to the flags record
- add the css file to the static assets
- before the html is compiled/rendered we have to inject the stylesheet and then serve it, this can be done in serveHtml; the function is by serveElm, which also uses
Generate.makeElmHtml
Having --include-css
would be handy, but in the meantime I'm just throwing in
Html.node "link" [ Html.Attributes.rel "stylesheet", Html.Attributes.href "style.css" ] []
as another child returned from Main.view
and that works fine (unless there's a browser cache issue on style.css, which happens surprisingly often). It's probably not a production-ready solution, but for rapid prototyping without leaving elm-reactor
it's simpler than most of the workarounds in this thread.
@mathphreak Where do you put style.css locally?
@stoivo Same directory as my Main.elm
file. That way it gets resolved properly as a relative path.
Is any progression?
I'm using the following function in my code. I have to use a trick to avoid flickering. Is there any downside to this technique? It generates a script that adds the stylesheet link into the header. (inspired by @mathphreak)
cssAdder : String -> (a -> List (Html msg) -> Html msg) -> (a -> List (Html msg) -> Html msg)
cssAdder css f = \a html ->
f a (Html.node "script" [ Html.Attributes.type_ "text/javascript", Html.Attributes.id "scriptToRemove"]
[text ("""
document.body.hidden=true;
var link=document.createElement('link');
link.href='"""++css++"""'; link.rel='stylesheet';
document.getElementsByTagName('head')[0].appendChild(link);
window.setTimeout(function () { document.body.hidden=false; }, 0);
var rem=document.getElementById('scriptToRemove');
rem.parentNode.removeChild(rem);
""")] :: html)
view : Model -> Html Msg
view model =
(cssAdder "style.css" div) [] [text "ok now"]