Current section

Files

Jump to
ex_webpack lib mix tasks compile_webpack.ex
Raw

lib/mix/tasks/compile_webpack.ex

defmodule Mix.Tasks.Compile.ExWebpack do
use Mix.Task
@recursive true
@moduledoc """
Runs `npm run build` in the current project.
## Configuration
This compiler can be configured through the return value of the `project/0`
function in `mix.exs`; for example:
def project() do
[app: :myapp,
compilers: [:ex_webpack] ++ Mix.compilers,
deps: deps()]
end
"""
@spec run(OptionParser.argv) :: :ok | no_return
def run(args) do
config = Mix.Project.config()
Mix.shell.print_app()
if Keyword.get(config, :watch_webpack, false) do
Phoenix.Endpoint.Watcher.start_link("npm", ["run", "watch"], [])
else
build(config, args)
end
Mix.Project.build_structure()
:ok
end
# This is called by Elixir when `mix clean` is called.
def clean() do
_config = Mix.Project.config()
# TODO(Connor): do web projects have a `clean` step?
end
defp build(config, task_args) do
exec = "npm"
env = Keyword.get(config, :node_env, %{})
args = ["run", "build"]
# In OTP 19, Erlang's `open_port/2` ignores the current working
# directory when expanding relative paths. This means that `:make_cwd`
# must be an absolute path. This is a different behaviour from earlier
# OTP versions and appears to be a bug. It is being tracked at
# http://bugs.erlang.org/browse/ERL-175.
cwd = Path.expand(".", File.cwd!())
error_msg = "Webpack failed"
case cmd(exec, args, cwd, env, "--verbose" in task_args) do
0 ->
:ok
exit_status ->
raise_build_error(exec, exit_status, error_msg)
end
end
# Runs `exec [args]` in `cwd` and prints the stdout and stderr in real time,
# as soon as `exec` prints them (using `IO.Stream`).
defp cmd(exec, args, cwd, env, verbose?) do
opts = [
into: IO.stream(:stdio, :line),
stderr_to_stdout: true,
cd: cwd,
env: env
]
if verbose? do
print_verbose_info(exec, args)
end
{%IO.Stream{}, status} = System.cmd(find_executable(exec), args, opts)
status
end
defp find_executable(exec) do
System.find_executable(exec) || Mix.raise("""
"#{exec}" not found in the path. please make sure it is correct.
""")
end
defp raise_build_error(exec, exit_status, error_msg) do
Mix.raise(~s{Could not compile with "#{exec}" (exit status: #{exit_status}).\n} <> error_msg)
end
defp print_verbose_info(exec, args) do
args = Enum.map_join(args, " ", fn(arg) ->
if String.contains?(arg, " "), do: inspect(arg), else: arg
end)
Mix.shell.info "Compiling: #{exec} #{args}"
end
end