elm-reactor icon indicating copy to clipboard operation
elm-reactor copied to clipboard

Elm Reactor + External CSS

Open PedroSena opened this issue 8 years ago • 23 comments

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

PedroSena avatar Aug 09 '15 17:08 PedroSena

Maybe some of the solution(s) here would help you in the meantime, in the absence of the specific feature you ask for?

jvoigtlaender avatar Aug 09 '15 20:08 jvoigtlaender

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

PedroSena avatar Aug 10 '15 12:08 PedroSena

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.

Warry avatar Oct 06 '15 12:10 Warry

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?

mordrax avatar May 14 '16 05:05 mordrax

Try this: https://github.com/moarwick/elm-webpack-starter

fluxxu avatar May 21 '16 23:05 fluxxu

@fluxxu loving it

aaronwhite avatar May 22 '16 03:05 aaronwhite

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 avatar Aug 19 '16 06:08 oz123

@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: &#39;Source Sans Pro&#39;;">
                        <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 :)

therustmonk avatar Aug 19 '16 06:08 therustmonk

@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 avatar Aug 19 '16 06:08 oz123

@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>

therustmonk avatar Aug 19 '16 07:08 therustmonk

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.

n1k0 avatar Sep 11 '16 07:09 n1k0

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 avatar Sep 24 '16 09:09 flip111

@flip111 You can use the following in the meantime: for development, for production

MeinAccount avatar Sep 24 '16 10:09 MeinAccount

@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 avatar Sep 24 '16 10:09 flip111

@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.

MeinAccount avatar Sep 24 '16 10:09 MeinAccount

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

stuartnelson3 avatar Nov 02 '16 18:11 stuartnelson3

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>

fiatjaf avatar Nov 02 '16 20:11 fiatjaf

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:

  1. add the --include-css flag to the flags record
  2. add the css file to the static assets
  3. 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

ghost avatar Nov 10 '16 21:11 ghost

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 avatar Jan 13 '17 06:01 mathphreak

@mathphreak Where do you put style.css locally?

stoivo avatar Feb 03 '17 21:02 stoivo

@stoivo Same directory as my Main.elm file. That way it gets resolved properly as a relative path.

mathphreak avatar Feb 03 '17 22:02 mathphreak

Is any progression?

djyde avatar May 11 '17 02:05 djyde

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"]

hawk78 avatar Sep 03 '17 02:09 hawk78