IdahoEv / cowboy-elixir-example

Examples of using Cowboy with Elixir
MIT License
216 stars 23 forks source link

Static file compilation? #1

Closed ghost closed 9 years ago

ghost commented 9 years ago

Don't see an answer to this anywhere on the net, was wondering if you had any idea...

Whenever I edit a file in /priv, it doesn't update when I restart iex -S mix. I have to delete _build or change the project version number in mix.exs.

Anyway to get around this?

Another thing I'm doing is using r.js to minify and compile.

IO.puts Sh.node("r.js", "-o", "build.js") # using the devinus/sh module

Which compiles files from /priv/src and puts them in /priv/min, which is what the routing uses to access. On first run _build/deps/ .... /priv/min doesn't exist obviously, because it's minifying after compilation.

Ideally I'd like to just get rid of the files in _build and prevent cowboy from using those. Lastly, any idea how cowboy handles caching? I'd like to keep this stuff loaded in RAM.

ghost commented 9 years ago

Okay, I have a cool little solution to this...

1) Install node, grab r.js from http://requirejs.org/docs/download.html#rjs 2) Put r.js in root, and make a build.js

({
    appDir: "priv/src",
    baseUrl: "src/js",
    dir: "_build/dev/lib/projectname/priv/min",
    optimize: "uglify2",
})

3a) Add this to the project in mix.exs

compilers: Mix.compilers ++ [:minify]

3b) Optional dep (looks nice, can add code in future to detect if node is installed):

{:sh, github: "devinus/sh", tag: :master}

4) Create a compiler file (lib/minify.ex)

defmodule Mix.Tasks.Compile.Minify do
    use Mix.Task
    def run(args) do
        IO.puts "Building files..."
        IO.puts Sh.node("r.js", "-o", "build.js")
    end
end

The minifier compiles every time the project is ran. There's an option for compilation without actual minification, so it can completely replace the old static compiler:

IO.puts Sh.node("r.js", "-o", "build.js", "optimize=none")

The files are located in _build/dev/lib/projectname/priv/min and can be accessed normally -- with the cool addition that there are no files except for src files inside the standard priv directory..

{"/", :cowboy_static, {:priv_file, :projectname, "min/index.html"}}

Just need to use a env variable so it can be ran as prod or dev... if dev then optimize=none, otherwise default compression.

http://requirejs.org/docs/optimization.html#turbo

Next step would be to add hot code reloading, coffee/jade/stylus compilers, and then we've got a good production framework (with minification!!)

Edit: On second thought, I can just have r.js overrite all the files in the build directory, with the new minified files. I have to reason to use the uncompressed because r.js allows source maps. The environment variable would choose whether to compress or not, as well.

IdahoEv commented 9 years ago

zvxy, I must confess you have me a bit confused. I'm assuming you've added some static JS files in /priv? My example has no JS files in priv/ to minify. _build/ is only used for the compiled .ex files and isn't involved with the html/css static files (or JS, if you've added some) at all.

I can't reproduce your error; I don't even need to restart iex to see new content. If I edit the files in priv, the new contents are visible on the next page load.

My first guess would be that you're suffering from browser caching of the resources. Short of your full solution, does the browser dev tools show the resources retrieved from cache? Does a force-reload of the page bring up the newly-edited resource?

If I read it correctly, you're essentially using r.js to implement a cachebusting mechanism. (But I'm not sure I'm reading it correctly). A full web framework would indeed include such a thing, but that's way beyond the intended scope of this example. I'd look into Phoenix, for that.

For myself, I would try to do that task with elixir/erlang tools, however. I'm not personally a fan of running JS on the server. That's just personal taste, though, YMMV. :-)

ghost commented 9 years ago

Very odd!

For some reason it's throwing the priv/ files into _build for me... I've made sure there's no browser caching... I wasn't even aware you COULD change the files and refresh the browser -- I had assumed that they were cached into _build (??), that's why I was mentioning hot code reloading.

As for the r.js.. Yeah I don't really enjoy the MVC method for small projects where I just want to compile and serve, so I'm skipping phoenix. Maybe I'll just create my own framework, heh. You're right on me using it for cachebusting (kind of). I'm using require.js to create a dependency framework for the frontend app and then condensing them down to singular files, and minifying the code in the process. There really are no erlang solutions for minifying files, unfortunately (as far as I'm aware), which is why I'm using r.js.

I added plug and threw in my own gzip method to my custom compiler, cached the binaries in memory and am serving it. Just gotta sort this weird _build thing out, hmm.. The only difference is that I'm deving on a windows machine, I wonder if it's a bug with the beam compiler picking up extraneous files.

Thanks!

Edit: http://puu.sh/dmte4/743f685a91.png <--- cloned your example and it's happening there too