Permalink
Browse files

Ensure views are compiled for production

  • Loading branch information...
1 parent 7786aa5 commit f1849177226301cb69f0928c62967aed779e5c79 @josevalim josevalim committed Sep 7, 2012
View
10 lib/dynamo/app.ex
@@ -28,7 +28,6 @@ defmodule Dynamo.App do
* `:source_paths` - The paths to search when compiling modules on demand
* `:view_paths` - The paths to find views
* `:root` - The application root
- * `:handler` - The handler used to serve web applications
* `:otp_app` - The otp application associated to this app
## Filters
@@ -91,8 +90,8 @@ defmodule Dynamo.App do
@before_compile { unquote(__MODULE__), :load_env_file }
@before_compile { unquote(__MODULE__), :normalize_options }
@before_compile { unquote(__MODULE__), :define_filters }
- @before_compile { unquote(__MODULE__), :define_view_paths }
@before_compile { unquote(__MODULE__), :define_finishers }
+ @before_compile { unquote(__MODULE__), :define_view_paths }
use Dynamo.Utils.Once
@@ -232,16 +231,17 @@ defmodule Dynamo.App do
if dynamo[:compile_on_demand] do
{ [], view_paths }
else
- Enum.partition(view_paths, fn(path) -> path.compilable? end)
+ Enum.partition(view_paths, fn(path) -> path.eager? end)
end
compiled_initializer =
if compiled != [] do
- view_paths = [dynamo[:compiled_view_paths]|runtime]
+ module = dynamo[:compiled_view_paths]
+ view_paths = [module|runtime]
quote location: :keep do
initializer :ensure_compiled_view_paths_is_available do
- module = Enum.first(view_paths)
+ module = unquote(module)
unless Code.ensure_loaded?(module) do
raise "could not find compiled view paths module #{inspect module}"
end
View
30 lib/dynamo/view/finder.ex
@@ -14,19 +14,12 @@ defmodule Dynamo.View.Finder do
defcallback new(info)
@doc """
- Returns true it provides compiled templates.
+ Returns true if templates can be eager
+ compiled. If so, the behaviour also needs
+ to implement a `all(self)` function that
+ returns all templates hold by the finder.
"""
- defcallback compilable?(self)
-
- @doc """
- Returns all templates for this finder.
-
- This is used for eager template
- compilation in production. In case
- eager compilation is not supported,
- it should simply return nil.
- """
- defcallback all(self)
+ defcallback eager?(self)
@doc """
Attempts to find a template given by
@@ -36,6 +29,13 @@ defmodule Dynamo.View.Finder do
nil in case a template can't be found.
"""
defcallback find(query, self)
+
+ @doc """
+ Returns a filesystem path to be watched
+ if this finder maps to somewhere in the
+ filesystem. Returns nil otherwise.
+ """
+ defcallback to_path(self)
end
defmodule Dynamo.View.PathFinder do
@@ -46,7 +46,7 @@ defmodule Dynamo.View.PathFinder do
{ __MODULE__, File.expand_path(root) }
end
- def compilable?(_) do
+ def eager?(_) do
true
end
@@ -63,6 +63,10 @@ defmodule Dynamo.View.PathFinder do
if path, do: build(key, path)
end
+ def to_path({ __MODULE__, path }) do
+ path
+ end
+
defp build(key, path) do
Dynamo.View.Template[
key: key,
View
23 lib/mix/tasks/compile.dynamo.ex
@@ -39,7 +39,7 @@ defmodule Mix.Tasks.Compile.Dynamo do
if app.config[:dynamo][:compile_on_demand] do
:noop
else
- eager_compilation(app, files, opts)
+ do_compile(app, files, opts)
end
end
@@ -49,13 +49,14 @@ defmodule Mix.Tasks.Compile.Dynamo do
:code.delete(app)
end
- defp eager_compilation(app, files, opts) do
+ defp do_compile(app, files, opts) do
project = Mix.project
dynamo = app.config[:dynamo]
compile_path = project[:compile_path]
compile_exts = project[:compile_exts]
- source_paths = dynamo[:source_paths] ++ dynamo[:view_paths]
+ view_paths = dynamo[:view_paths]
+ source_paths = dynamo[:source_paths] ++ extract_views(view_paths)
app_file = project[:dynamo_app] || "config/app.ex"
env_file = "config/environments/#{Mix.env}.exs"
@@ -75,6 +76,7 @@ defmodule Mix.Tasks.Compile.Dynamo do
Mix.Dynamo.lock_snapshot fn ->
compile_files List.uniq(to_compile), compile_path, dynamo[:root]
+ compile_views dynamo[:compiled_view_paths], view_paths, compile_path
end
:ok
@@ -96,11 +98,26 @@ defmodule Mix.Tasks.Compile.Dynamo do
Enum.filter files, List.member?(paths, &1)
end
+ defp extract_views(view_paths) do
+ lc view_path inlist view_paths, path = view_path.to_path, do: path
+ end
+
defp compile_files(files, to, root) do
Kernel.ParallelCompiler.files_to_path files, to, fn(original) ->
relative = :binary.replace original, root <> "/", ""
Mix.shell.info "Compiled #{relative}"
original
end
end
+
+ defp compile_views(name, view_paths, compile_path) do
+ templates = lc view_path inlist view_paths,
+ view_path.eager?,
+ template inlist view_path.all, do: template
+
+ binary = Dynamo.View.compile_module(name, templates)
+ File.write! File.join(compile_path, "#{name}.beam"), binary
+
+ Mix.shell.info "Generated #{inspect name}"
+ end
end
View
7 lib/mix/tasks/dynamo.ex
@@ -64,6 +64,9 @@ defmodule Mix.Tasks.Dynamo do
create_directory "app/routers"
create_file "app/routers/application_router.ex", app_router_template(assigns)
+ create_directory "app/views"
+ create_file "app/views/hello.html.eex", app_view_template(assigns)
+
create_directory "config"
create_file "config/app.ex", config_app_template(assigns)
@@ -147,6 +150,10 @@ defmodule Mix.Tasks.Dynamo do
end
"""
+ embed_template :app_view, """
+ HELLO!
+ """
+
embed_template :config_app, """
defmodule <%= @mod %> do
use Dynamo.App
View
3 test/mix/tasks/dynamo_test.exs
@@ -29,6 +29,9 @@ defmodule Mix.Tasks.DynamoTest do
assert file =~ %r(otp_app: :my_app)
end
+ assert_file "app/routers/application_router.ex"
+ assert_file "app/views/hello.html.eex"
+
assert_file "config/environments/dev.exs"
assert_file "config/environments/test.exs"
assert_file "config/environments/prod.exs"
View
11 test/mix/tasks_test.exs
@@ -8,7 +8,7 @@ defmodule Mix.TasksTest do
in_tmp "my_compiled_app", fn ->
app_with_dynamo_deps_path
- ## Cannot boot production without compiling
+ # Cannot boot production without compiling
output = System.cmd "MIX_ENV=prod mix server"
assert output =~ %r(could not find endpoint ApplicationRouter, please ensure it was compiled)
@@ -17,6 +17,10 @@ defmodule Mix.TasksTest do
assert output =~ %r(Compiled config/app.ex)
assert output =~ %r(Generated my_compiled_app.app)
+ # Views are also compiled
+ assert output =~ %r(Generated MyCompiledApp.CompiledViews)
+ assert File.regular?("ebin/Elixir-MyCompiledApp-CompiledViews.beam")
+
# Can recompile after changes
File.touch!("app/routers/application_router.ex", { { 2030, 1, 1 }, { 0, 0, 0 } })
output = System.cmd "MIX_ENV=prod mix compile"
@@ -57,7 +61,10 @@ defmodule Mix.TasksTest do
in_tmp "my_run_app", fn ->
app_with_dynamo_deps_path
- output = System.cmd %b{mix run "IO.inspect HelloRouter.__info__(:self)"}
+ output = System.cmd %b{mix run "Dynamo.app.start; IO.inspect HelloRouter.__info__(:self)"}
+ assert output =~ %r(HelloRouter)
+
+ output = System.cmd %b{MIX_ENV=prod mix do compile, run "Dynamo.app.start; IO.inspect HelloRouter.__info__(:self)"}
assert output =~ %r(HelloRouter)
end
end

0 comments on commit f184917

Please sign in to comment.