Implement watch support for build system
This commit is contained in:
parent
6e589dd5a9
commit
5af3350fc0
14 changed files with 236 additions and 112 deletions
|
@ -6,12 +6,11 @@ defmodule Mix.Tasks.Frontend.Build.Css.Compile do
|
|||
|
||||
def bin(), do: node_bin("node-sass")
|
||||
|
||||
def out_path(:prod), do: "#{tmp_path()}/compiled/css"
|
||||
def out_path(_), do: "#{dist_path()}/css"
|
||||
def out_path(), do: "#{tmp_path()}/compiled/css"
|
||||
|
||||
def args(), do: [
|
||||
"-o",
|
||||
out_path(Mix.env()),
|
||||
out_path(),
|
||||
"--source-map",
|
||||
"true",
|
||||
"--include-path",
|
||||
|
|
20
lib/mix/tasks/frontend.build.css.copy.ex
Normal file
20
lib/mix/tasks/frontend.build.css.copy.ex
Normal file
|
@ -0,0 +1,20 @@
|
|||
defmodule Mix.Tasks.Frontend.Build.Css.Copy do
|
||||
use Mix.Task
|
||||
import MebeWeb.{TaskUtils, FrontendConfs}
|
||||
|
||||
@shortdoc "Copy compiled CSS to target dir"
|
||||
|
||||
def do_copy() do
|
||||
# Ensure target path exists
|
||||
out_path = "#{dist_path()}/css"
|
||||
File.mkdir_p!(out_path)
|
||||
|
||||
File.cp_r!(Mix.Tasks.Frontend.Build.Css.Compile.out_path(), out_path)
|
||||
end
|
||||
|
||||
def run(_) do
|
||||
run_task("frontend.build.css.compile")
|
||||
|
||||
do_copy()
|
||||
end
|
||||
end
|
|
@ -7,7 +7,7 @@ defmodule Mix.Tasks.Frontend.Build.Css do
|
|||
def run(_) do
|
||||
task = case Mix.env() do
|
||||
:prod -> "frontend.build.css.minify"
|
||||
_ -> "frontend.build.css.compile"
|
||||
_ -> "frontend.build.css.copy"
|
||||
end
|
||||
|
||||
run_task(task)
|
||||
|
|
|
@ -8,7 +8,7 @@ defmodule Mix.Tasks.Frontend.Build.Css.Minify do
|
|||
def run(_) do
|
||||
run_task("frontend.build.css.compile")
|
||||
|
||||
in_path = "#{tmp_path()}/compiled/css"
|
||||
in_path = Mix.Tasks.Frontend.Build.Css.Compile.out_path()
|
||||
in_file = "#{in_path}/app.css"
|
||||
out_path = "#{dist_path()}/css"
|
||||
out_file = "#{out_path}/app.css"
|
||||
|
|
|
@ -6,17 +6,16 @@ defmodule Mix.Tasks.Frontend.Build.Js.Bundle do
|
|||
|
||||
def bin(), do: node_bin("rollup")
|
||||
|
||||
def out_path(:prod), do: "#{tmp_path()}/bundled/js"
|
||||
def out_path(_), do: "#{dist_path()}/js"
|
||||
def out_path(), do: "#{tmp_path()}/bundled/js"
|
||||
|
||||
def args() do
|
||||
op = out_path(Mix.env())
|
||||
op = out_path()
|
||||
|
||||
[
|
||||
"--config",
|
||||
"rollup.config.js",
|
||||
"--input",
|
||||
"#{tmp_path()}/transpiled/js/app.js",
|
||||
"#{Mix.Tasks.Frontend.Build.Js.Transpile.out_path()}/app.js",
|
||||
"--output",
|
||||
"#{op}/app.js",
|
||||
"--format",
|
||||
|
@ -26,9 +25,13 @@ defmodule Mix.Tasks.Frontend.Build.Js.Bundle do
|
|||
]
|
||||
end
|
||||
|
||||
def do_bundle() do
|
||||
bin() |> exec(args()) |> listen()
|
||||
end
|
||||
|
||||
def run(_) do
|
||||
run_task("frontend.build.js.transpile")
|
||||
|
||||
bin() |> exec(args()) |> listen()
|
||||
do_bundle()
|
||||
end
|
||||
end
|
||||
|
|
20
lib/mix/tasks/frontend.build.js.copy.ex
Normal file
20
lib/mix/tasks/frontend.build.js.copy.ex
Normal file
|
@ -0,0 +1,20 @@
|
|||
defmodule Mix.Tasks.Frontend.Build.Js.Copy do
|
||||
use Mix.Task
|
||||
import MebeWeb.{TaskUtils, FrontendConfs}
|
||||
|
||||
@shortdoc "Copy bundled JS to target dir"
|
||||
|
||||
def do_copy() do
|
||||
# Ensure target path exists
|
||||
out_path = "#{dist_path()}/js"
|
||||
File.mkdir_p!(out_path)
|
||||
|
||||
File.cp_r!(Mix.Tasks.Frontend.Build.Js.Bundle.out_path(), out_path)
|
||||
end
|
||||
|
||||
def run(_) do
|
||||
run_task("frontend.build.js.bundle")
|
||||
|
||||
do_copy()
|
||||
end
|
||||
end
|
|
@ -7,7 +7,7 @@ defmodule Mix.Tasks.Frontend.Build.Js do
|
|||
def run(_) do
|
||||
task = case Mix.env() do
|
||||
:prod -> "frontend.build.js.minify"
|
||||
_ -> "frontend.build.js.bundle"
|
||||
_ -> "frontend.build.js.copy"
|
||||
end
|
||||
|
||||
run_task(task)
|
||||
|
|
|
@ -8,7 +8,7 @@ defmodule Mix.Tasks.Frontend.Build.Js.Minify do
|
|||
def run(_) do
|
||||
run_task("frontend.build.js.bundle")
|
||||
|
||||
in_path = "#{tmp_path()}/bundled/js"
|
||||
in_path = Mix.Tasks.Frontend.Build.Js.Bundle.out_path()
|
||||
in_file = "#{in_path}/app.js"
|
||||
out_path = "#{dist_path()}/js"
|
||||
out_file = "#{out_path}/app.js"
|
||||
|
|
|
@ -6,10 +6,12 @@ defmodule Mix.Tasks.Frontend.Build.Js.Transpile do
|
|||
|
||||
def bin(), do: node_bin("babel")
|
||||
|
||||
def out_path(), do: "#{tmp_path()}/transpiled/js"
|
||||
|
||||
def args(), do: [
|
||||
"#{src_path()}/js",
|
||||
"--out-dir",
|
||||
"#{tmp_path()}/transpiled/js",
|
||||
out_path(),
|
||||
"--source-maps",
|
||||
"inline"
|
||||
]
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
defmodule Mix.Tasks.Frontend.Watch do
|
||||
use Mix.Task
|
||||
import MebeWeb.{TaskUtils, FrontendConfs}
|
||||
import MebeWeb.{TaskUtils}
|
||||
alias Mix.Tasks.Frontend.Build.Js.Transpile, as: TranspileJS
|
||||
alias Mix.Tasks.Frontend.Build.Js.Bundle, as: BundleJS
|
||||
alias Mix.Tasks.Frontend.Build.Js.Copy, as: CopyJS
|
||||
alias Mix.Tasks.Frontend.Build.Css.Compile, as: CompileCSS
|
||||
alias Mix.Tasks.Frontend.Build.Css.Copy, as: CopyCSS
|
||||
|
||||
@shortdoc "Watch frontend and rebuild when necessary"
|
||||
|
||||
|
@ -16,9 +18,16 @@ defmodule Mix.Tasks.Frontend.Watch do
|
|||
TranspileJS.args() ++ ["-w"]
|
||||
),
|
||||
|
||||
exec(
|
||||
BundleJS.bin(),
|
||||
BundleJS.args() ++ ["-w"]
|
||||
watch(
|
||||
"JSBundle",
|
||||
TranspileJS.out_path(),
|
||||
fn _, _ -> Task.start_link(BundleJS, :do_bundle, []) end
|
||||
),
|
||||
|
||||
watch(
|
||||
"JSCopy",
|
||||
BundleJS.out_path(),
|
||||
fn _, _ -> CopyJS.do_copy() end
|
||||
),
|
||||
|
||||
exec(
|
||||
|
@ -27,7 +36,13 @@ defmodule Mix.Tasks.Frontend.Watch do
|
|||
"-w",
|
||||
CompileCSS.scss_file()
|
||||
]
|
||||
),
|
||||
|
||||
watch(
|
||||
"CSSCopy",
|
||||
CompileCSS.out_path(),
|
||||
fn _, _ -> CopyCSS.do_copy() end
|
||||
)
|
||||
] |> watch()
|
||||
] |> listen(watch: true)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -9,9 +9,9 @@ defmodule MebeWeb.TaskUtils do
|
|||
|
||||
@default_task_timeout 60000
|
||||
|
||||
defmodule Program do
|
||||
defmodule ProgramSpec do
|
||||
@moduledoc """
|
||||
Program to execute with arguments. Name is used for prefixing logs.
|
||||
Program that is executed with arguments. Name is used for prefixing logs.
|
||||
"""
|
||||
defstruct [
|
||||
name: "",
|
||||
|
@ -20,6 +20,22 @@ defmodule MebeWeb.TaskUtils do
|
|||
]
|
||||
end
|
||||
|
||||
defmodule WatchSpec do
|
||||
@moduledoc """
|
||||
Watch specification, target to watch and callback to execute on events.
|
||||
Name is used for prefixing logs.
|
||||
|
||||
Callback must have arity 2, gets filename/path and list of events as arguments.
|
||||
"""
|
||||
defstruct [
|
||||
name: "",
|
||||
path: "",
|
||||
callback: nil,
|
||||
pid: nil,
|
||||
name_atom: nil
|
||||
]
|
||||
end
|
||||
|
||||
@doc """
|
||||
Get configuration value.
|
||||
"""
|
||||
|
@ -56,19 +72,13 @@ defmodule MebeWeb.TaskUtils do
|
|||
|
||||
Tasks should be tuples {task_name, args} or binaries (no args).
|
||||
"""
|
||||
def run_tasks(tasks, timeout \\ 60000) do
|
||||
run_and_log = fn task, args ->
|
||||
Logger.info("[Started] #{task}")
|
||||
Mix.Task.run(task, args)
|
||||
Logger.info("[Finished] #{task}")
|
||||
end
|
||||
|
||||
def run_tasks(tasks, timeout \\ @default_task_timeout) do
|
||||
tasks
|
||||
|> Enum.map(fn
|
||||
task when is_binary(task) ->
|
||||
fn -> run_and_log.(task, []) end
|
||||
fn -> Mix.Task.run(task, []) end
|
||||
{task, args} ->
|
||||
fn -> run_and_log.(task, args) end
|
||||
fn -> Mix.Task.run(task, args) end
|
||||
end)
|
||||
|> run_funs(timeout)
|
||||
end
|
||||
|
@ -80,7 +90,7 @@ defmodule MebeWeb.TaskUtils do
|
|||
Functions can either be anonymous functions or tuples of
|
||||
{module, fun, args}.
|
||||
"""
|
||||
def run_funs(funs, timeout \\ 60000) when is_list(funs) do
|
||||
def run_funs(funs, timeout \\ @default_task_timeout) when is_list(funs) do
|
||||
funs
|
||||
|> Enum.map(fn
|
||||
fun when is_function(fun) ->
|
||||
|
@ -103,6 +113,8 @@ defmodule MebeWeb.TaskUtils do
|
|||
|
||||
- name: Use as name for logging, otherwise name of binary is used.
|
||||
- cd: Directory to change to before executing.
|
||||
|
||||
Returns ProgramSpec for the started program.
|
||||
"""
|
||||
def exec(executable, args, opts \\ []) do
|
||||
name = Keyword.get(
|
||||
|
@ -122,9 +134,9 @@ defmodule MebeWeb.TaskUtils do
|
|||
cd -> Keyword.put(options, :cd, cd)
|
||||
end
|
||||
|
||||
Logger.debug("[Spawned] #{name}")
|
||||
Logger.debug("[Spawned] Program #{name}")
|
||||
|
||||
%Program{
|
||||
%ProgramSpec{
|
||||
name: name,
|
||||
pending_output: "",
|
||||
port: Port.open(
|
||||
|
@ -135,84 +147,117 @@ defmodule MebeWeb.TaskUtils do
|
|||
end
|
||||
|
||||
@doc """
|
||||
Listen to messages from programs and print them to the screen.
|
||||
Start watching a path. Name is used for prefixing logs.
|
||||
|
||||
Also listens to input from user and returns if input is given.
|
||||
Path can point to a file or a directory in which case all subdirs will be watched.
|
||||
|
||||
Returns a WatchSpec.
|
||||
"""
|
||||
def listen(programs, task \\ nil, opts \\ [])
|
||||
def watch(name, path, fun) do
|
||||
name_atom = String.to_atom(name)
|
||||
{:ok, pid} = :fs.start_link(name_atom, String.to_charlist(path))
|
||||
:fs.subscribe(name_atom)
|
||||
|
||||
def listen([], _, _), do: nil
|
||||
Logger.debug("[Spawned] Watch #{name}")
|
||||
|
||||
def listen(%Program{} = program, task, opts) do
|
||||
listen([program], task, opts)
|
||||
%WatchSpec{
|
||||
name: name,
|
||||
path: path,
|
||||
callback: fun,
|
||||
pid: pid,
|
||||
name_atom: name_atom
|
||||
}
|
||||
end
|
||||
|
||||
def listen(programs, task, opts) do
|
||||
@doc """
|
||||
Listen to messages from specs and print them to the screen.
|
||||
|
||||
If watch: true is given in the options, will listen for user's enter key and
|
||||
kill programs if enter is pressed.
|
||||
"""
|
||||
def listen(specs, opts \\ [])
|
||||
|
||||
# If there are no specs, stop running
|
||||
def listen([], _), do: :ok
|
||||
|
||||
def listen(spec, opts) when not is_list(spec) do
|
||||
listen([spec], opts)
|
||||
end
|
||||
|
||||
def listen(specs, opts) when is_list(specs) do
|
||||
# Start another task to ask for user input if we are in watch mode
|
||||
task = with \
|
||||
true <- Keyword.get(opts, :watch, false),
|
||||
nil <- task,
|
||||
nil <- Keyword.get(opts, :task),
|
||||
{:ok, task} <- Task.start_link(__MODULE__, :wait_for_input, [self()])
|
||||
do
|
||||
Logger.info("Programs/watches started, press ENTER to exit.")
|
||||
task
|
||||
end
|
||||
|
||||
programs = receive do
|
||||
specs = receive do
|
||||
# User pressed enter
|
||||
:user_input_received ->
|
||||
Logger.info("ENTER received, killing tasks.")
|
||||
Enum.each(specs, &kill/1)
|
||||
[]
|
||||
|
||||
# Program sent output with end of line
|
||||
{port, {:data, {:eol, msg}}} ->
|
||||
program = Enum.find(programs, get_port_checker(port))
|
||||
program = Enum.find(specs, program_checker(port))
|
||||
msg = :unicode.characters_to_binary(msg, :unicode)
|
||||
|
||||
prefix = "[#{program.name}] #{program.pending_output}"
|
||||
|
||||
Logger.debug(prefix <> msg)
|
||||
|
||||
programs
|
||||
|> Enum.reject(get_port_checker(port))
|
||||
specs
|
||||
|> Enum.reject(program_checker(port))
|
||||
|> Enum.concat([
|
||||
%{program | pending_output: ""}
|
||||
])
|
||||
|
||||
# Program sent output without end of line
|
||||
{port, {:data, {:noeol, msg}}} ->
|
||||
program = Enum.find(programs, get_port_checker(port))
|
||||
program = Enum.find(specs, program_checker(port))
|
||||
msg = :unicode.characters_to_binary(msg, :unicode)
|
||||
|
||||
programs
|
||||
|> Enum.reject(get_port_checker(port))
|
||||
specs
|
||||
|> Enum.reject(program_checker(port))
|
||||
|> Enum.concat([
|
||||
%{program | pending_output: "#{program.pending_output}#{msg}"}
|
||||
])
|
||||
|
||||
# Port was closed normally after being told to close
|
||||
{port, :closed} ->
|
||||
handle_closed(programs, port)
|
||||
handle_closed(specs, port)
|
||||
|
||||
# Port closed because the program closed by itself
|
||||
{port, {:exit_status, 0}} ->
|
||||
handle_closed(programs, port)
|
||||
handle_closed(specs, port)
|
||||
|
||||
# Program closed with error status
|
||||
{port, {:exit_status, status}} ->
|
||||
program = Enum.find(programs, get_port_checker(port))
|
||||
program = Enum.find(specs, program_checker(port))
|
||||
Logger.error("Program #{program.name} returned status #{status}.")
|
||||
raise "Failed status #{status} from #{program.name}!"
|
||||
|
||||
# Port crashed
|
||||
{:EXIT, port, _} ->
|
||||
handle_closed(programs, port)
|
||||
handle_closed(specs, port)
|
||||
|
||||
# FS watch sent file event
|
||||
{_, {:fs, :file_event}, {file, events}} ->
|
||||
handle_events(specs, file, events)
|
||||
end
|
||||
|
||||
if not Enum.empty?(programs) do
|
||||
listen(programs, task, opts)
|
||||
end
|
||||
listen(specs, Keyword.put(opts, :task, task))
|
||||
end
|
||||
|
||||
@doc """
|
||||
Kill a running program returned by exec().
|
||||
"""
|
||||
def kill(%Program{name: name, port: port}) do
|
||||
def kill(%ProgramSpec{name: name, port: port}) do
|
||||
if name != nil do
|
||||
Logger.debug("[Killing] #{name}")
|
||||
end
|
||||
|
@ -221,21 +266,11 @@ defmodule MebeWeb.TaskUtils do
|
|||
end
|
||||
|
||||
@doc """
|
||||
Print output from given programs to screen until user input is given.
|
||||
|
||||
When user input is given, kill programs and return.
|
||||
Kill a running watch.
|
||||
"""
|
||||
def watch(%Program{} = program), do: watch([program])
|
||||
|
||||
def watch(programs) when is_list(programs) do
|
||||
Logger.info("Programs started, press ENTER to exit.")
|
||||
|
||||
listen(programs, nil, watch: true)
|
||||
|
||||
Logger.info("ENTER received, killing tasks.")
|
||||
|
||||
Enum.each(programs, &kill/1)
|
||||
:ok
|
||||
def kill(%WatchSpec{name: name, pid: pid}) do
|
||||
Logger.debug("[Killing] #{name}")
|
||||
Process.exit(pid, :kill)
|
||||
end
|
||||
|
||||
@doc """
|
||||
|
@ -291,23 +326,57 @@ defmodule MebeWeb.TaskUtils do
|
|||
|
||||
defp size_with_unit(size, unit), do: "#{size} #{unit}"
|
||||
|
||||
defp get_port_checker(port) do
|
||||
fn %Program{port: program_port} ->
|
||||
program_port == port
|
||||
# Utility to find program in spec list based on port
|
||||
defp program_checker(port) do
|
||||
fn
|
||||
%ProgramSpec{port: program_port} ->
|
||||
program_port == port
|
||||
|
||||
%WatchSpec{} ->
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
defp handle_closed(programs, port) do
|
||||
case Enum.find(programs, get_port_checker(port)) do
|
||||
%Program{} = program ->
|
||||
# Utility to find watch in spec list based on path
|
||||
defp watch_checker(path) do
|
||||
fn
|
||||
%ProgramSpec{} ->
|
||||
false
|
||||
|
||||
%WatchSpec{path: watch_path} ->
|
||||
# If given path is relative to (under) the watch path or is the same
|
||||
# path completely, it's a match.
|
||||
path != watch_path and Path.relative_to(path, watch_path) != path
|
||||
end
|
||||
end
|
||||
|
||||
defp handle_closed(specs, port) do
|
||||
case Enum.find(specs, program_checker(port)) do
|
||||
%ProgramSpec{} = program ->
|
||||
Logger.debug("[Stopped] #{program.name}")
|
||||
|
||||
programs
|
||||
|> Enum.reject(get_port_checker(port))
|
||||
specs
|
||||
|> Enum.reject(program_checker(port))
|
||||
|
||||
nil ->
|
||||
# Program was already removed
|
||||
programs
|
||||
specs
|
||||
end
|
||||
end
|
||||
|
||||
defp handle_events(specs, file, events) do
|
||||
file = to_string(file)
|
||||
case Enum.find(specs, watch_checker(file)) do
|
||||
%WatchSpec{name: name, callback: callback} ->
|
||||
Logger.debug("[#{name}] Changed #{inspect(events)}: #{file}")
|
||||
|
||||
callback.(file, events)
|
||||
|
||||
nil ->
|
||||
# Watch was maybe removed for some reason
|
||||
Logger.debug("[Error] Watch sent event but path was not in specs list: #{inspect(events)} #{file}")
|
||||
end
|
||||
|
||||
specs
|
||||
end
|
||||
end
|
||||
|
|
17
mix.exs
17
mix.exs
|
@ -1,7 +1,7 @@
|
|||
defmodule MebeWeb.Mixfile do
|
||||
use Mix.Project
|
||||
|
||||
def project do
|
||||
def project() do
|
||||
[app: :mebe_web,
|
||||
version: "1.1.0",
|
||||
elixir: "~> 1.4.0",
|
||||
|
@ -15,9 +15,13 @@ defmodule MebeWeb.Mixfile do
|
|||
# Configuration for the OTP application
|
||||
#
|
||||
# Type `mix help compile.app` for more information
|
||||
def application do
|
||||
[mod: {MebeWeb, []},
|
||||
applications: [:phoenix, :cowboy, :logger, :phoenix_html, :earmark, :calendar, :tzdata]]
|
||||
def application() do
|
||||
[
|
||||
mod: {MebeWeb, []},
|
||||
extra_applications: [
|
||||
:logger
|
||||
]
|
||||
]
|
||||
end
|
||||
|
||||
# Specifies which paths to compile per environment
|
||||
|
@ -27,7 +31,7 @@ defmodule MebeWeb.Mixfile do
|
|||
# Specifies your project dependencies
|
||||
#
|
||||
# Type `mix help deps` for examples and options
|
||||
defp deps do
|
||||
defp deps() do
|
||||
[
|
||||
{:phoenix, "~> 1.2.1"},
|
||||
{:phoenix_live_reload, "~> 1.0.7", only: :dev},
|
||||
|
@ -35,7 +39,8 @@ defmodule MebeWeb.Mixfile do
|
|||
{:cowboy, "~> 1.0.4"},
|
||||
{:earmark, "~> 1.0.3"},
|
||||
{:slugger, github: "h4cc/slugger", ref: "ef864669cdaae18d475600589c19c74e92ef67b4"},
|
||||
{:calendar, "~> 0.17.1"}
|
||||
{:calendar, "~> 0.17.1"},
|
||||
{:fs, "~> 2.12.0", override: true, only: :dev}
|
||||
]
|
||||
end
|
||||
end
|
||||
|
|
33
mix.lock
33
mix.lock
|
@ -1,31 +1,22 @@
|
|||
%{"bbmustache": {:hex, :bbmustache, "1.0.4"},
|
||||
"calendar": {:hex, :calendar, "0.17.1", "5c7dfffde2b68011c2d6832ff1a15496292de965a3b57b3fad32405f1176f024", [:mix], [{:tzdata, "~> 0.5.8 or ~> 0.1.201603", [hex: :tzdata, optional: false]}]},
|
||||
"certifi": {:hex, :certifi, "0.7.0", "861a57f3808f7eb0c2d1802afeaae0fa5de813b0df0979153cbafcd853ababaf", [:rebar3], []},
|
||||
"cf": {:hex, :cf, "0.2.1"},
|
||||
"conform": {:hex, :conform, "1.0.0-rc8"},
|
||||
%{"calendar": {:hex, :calendar, "0.17.2", "d6b7bccc29c72203b076d4e488d967780bf2d123a96fafdbf45746fdc2fa342c", [:mix], [{:tzdata, "~> 0.5.8 or ~> 0.1.201603", [hex: :tzdata, optional: false]}]},
|
||||
"certifi": {:hex, :certifi, "1.0.0", "1c787a85b1855ba354f0b8920392c19aa1d06b0ee1362f9141279620a5be2039", [:rebar3], []},
|
||||
"cowboy": {:hex, :cowboy, "1.0.4", "a324a8df9f2316c833a470d918aaf73ae894278b8aa6226ce7a9bf699388f878", [:make, :rebar], [{:cowlib, "~> 1.0.0", [hex: :cowlib, optional: false]}, {:ranch, "~> 1.0", [hex: :ranch, optional: false]}]},
|
||||
"cowlib": {:hex, :cowlib, "1.0.2", "9d769a1d062c9c3ac753096f868ca121e2730b9a377de23dec0f7e08b1df84ee", [:make], []},
|
||||
"earmark": {:hex, :earmark, "1.0.3", "89bdbaf2aca8bbb5c97d8b3b55c5dd0cff517ecc78d417e87f1d0982e514557b", [:mix], []},
|
||||
"erlware_commons": {:hex, :erlware_commons, "0.18.0"},
|
||||
"exrm": {:hex, :exrm, "1.0.0-rc8"},
|
||||
"fs": {:hex, :fs, "2.12.0", "ad631efacc9a5683c8eaa1b274e24fa64a1b8eb30747e9595b93bec7e492e25e", [:rebar3], []},
|
||||
"getopt": {:hex, :getopt, "0.8.2"},
|
||||
"hackney": {:hex, :hackney, "1.6.5", "8c025ee397ac94a184b0743c73b33b96465e85f90a02e210e86df6cbafaa5065", [:rebar3], [{:certifi, "0.7.0", [hex: :certifi, optional: false]}, {:idna, "1.2.0", [hex: :idna, optional: false]}, {:metrics, "1.0.1", [hex: :metrics, optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, optional: false]}, {:ssl_verify_fun, "1.1.1", [hex: :ssl_verify_fun, optional: false]}]},
|
||||
"idna": {:hex, :idna, "1.2.0", "ac62ee99da068f43c50dc69acf700e03a62a348360126260e87f2b54eced86b2", [:rebar3], []},
|
||||
"fwatch": {:hex, :fwatch, "0.5.0", "c61d9c1653ef5958770165315552e560c01202edd21ec05be9ba737ed44166e0", [:mix], [{:earmark, ">= 0.0.0", [hex: :earmark, optional: false]}, {:fs, "~> 0.9.1", [hex: :fs, optional: false]}]},
|
||||
"hackney": {:hex, :hackney, "1.7.1", "e238c52c5df3c3b16ce613d3a51c7220a784d734879b1e231c9babd433ac1cb4", [:rebar3], [{:certifi, "1.0.0", [hex: :certifi, optional: false]}, {:idna, "4.0.0", [hex: :idna, optional: false]}, {:metrics, "1.0.1", [hex: :metrics, optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, optional: false]}, {:ssl_verify_fun, "1.1.1", [hex: :ssl_verify_fun, optional: false]}]},
|
||||
"idna": {:hex, :idna, "4.0.0", "10aaa9f79d0b12cf0def53038547855b91144f1bfcc0ec73494f38bb7b9c4961", [:rebar3], []},
|
||||
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], []},
|
||||
"mime": {:hex, :mime, "1.0.1", "05c393850524767d13a53627df71beeebb016205eb43bfbd92d14d24ec7a1b51", [:mix], []},
|
||||
"mime": {:hex, :mime, "1.1.0", "01c1d6f4083d8aa5c7b8c246ade95139620ef8effb009edde934e0ec3b28090a", [:mix], []},
|
||||
"mimerl": {:hex, :mimerl, "1.0.2", "993f9b0e084083405ed8252b99460c4f0563e41729ab42d9074fd5e52439be88", [:rebar3], []},
|
||||
"neotoma": {:hex, :neotoma, "1.7.3"},
|
||||
"phoenix": {:hex, :phoenix, "1.2.1", "6dc592249ab73c67575769765b66ad164ad25d83defa3492dc6ae269bd2a68ab", [:mix], [{:cowboy, "~> 1.0", [hex: :cowboy, optional: true]}, {:phoenix_pubsub, "~> 1.0", [hex: :phoenix_pubsub, optional: false]}, {:plug, "~> 1.1", [hex: :plug, optional: false]}, {:poison, "~> 1.5 or ~> 2.0", [hex: :poison, optional: false]}]},
|
||||
"phoenix_html": {:hex, :phoenix_html, "2.9.2", "371160b30cf4e10443b015efce6f03e1f19aae98ff6487620477b13a5b2ef660", [:mix], [{:plug, "~> 1.0", [hex: :plug, optional: false]}]},
|
||||
"phoenix_live_reload": {:hex, :phoenix_live_reload, "1.0.7", "167ab0942e88d1d4a597996cf7dd8d2b014cc14d3f9472b58858cde8dd9ac2e4", [:mix], [{:fs, "~> 2.12.0", [hex: :fs, optional: false]}, {:phoenix, "~> 1.0 or ~> 1.2-rc", [hex: :phoenix, optional: false]}]},
|
||||
"phoenix": {:hex, :phoenix, "1.2.3", "b68dd6a7e6ff3eef38ad59771007d2f3f344988ea6e658e9b2c6ffb2ef494810", [:mix], [{:cowboy, "~> 1.0", [hex: :cowboy, optional: true]}, {:phoenix_pubsub, "~> 1.0", [hex: :phoenix_pubsub, optional: false]}, {:plug, "~> 1.4 or ~> 1.3.3 or ~> 1.2.4 or ~> 1.1.8 or ~> 1.0.5", [hex: :plug, optional: false]}, {:poison, "~> 1.5 or ~> 2.0", [hex: :poison, optional: false]}]},
|
||||
"phoenix_html": {:hex, :phoenix_html, "2.9.3", "1b5a2122cbf743aa242f54dced8a4f1cc778b8bd304f4b4c0043a6250c58e258", [:mix], [{:plug, "~> 1.0", [hex: :plug, optional: false]}]},
|
||||
"phoenix_live_reload": {:hex, :phoenix_live_reload, "1.0.8", "4333f9c74190f485a74866beff2f9304f069d53f047f5fbb0fb8d1ee4c495f73", [:mix], [{:fs, "~> 0.9.1", [hex: :fs, optional: false]}, {:phoenix, "~> 1.0 or ~> 1.2-rc", [hex: :phoenix, optional: false]}]},
|
||||
"phoenix_pubsub": {:hex, :phoenix_pubsub, "1.0.1", "c10ddf6237007c804bf2b8f3c4d5b99009b42eca3a0dfac04ea2d8001186056a", [:mix], []},
|
||||
"plug": {:hex, :plug, "1.3.0", "6e2b01afc5db3fd011ca4a16efd9cb424528c157c30a44a0186bcc92c7b2e8f3", [:mix], [{:cowboy, "~> 1.0.1 or ~> 1.1", [hex: :cowboy, optional: true]}, {:mime, "~> 1.0", [hex: :mime, optional: false]}]},
|
||||
"plug": {:hex, :plug, "1.3.4", "b4ef3a383f991bfa594552ded44934f2a9853407899d47ecc0481777fb1906f6", [:mix], [{:cowboy, "~> 1.0.1 or ~> 1.1", [hex: :cowboy, optional: true]}, {:mime, "~> 1.0", [hex: :mime, optional: false]}]},
|
||||
"poison": {:hex, :poison, "2.2.0", "4763b69a8a77bd77d26f477d196428b741261a761257ff1cf92753a0d4d24a63", [:mix], []},
|
||||
"providers": {:hex, :providers, "1.6.0"},
|
||||
"ranch": {:hex, :ranch, "1.2.1", "a6fb992c10f2187b46ffd17ce398ddf8a54f691b81768f9ef5f461ea7e28c762", [:make], []},
|
||||
"relx": {:hex, :relx, "3.17.0"},
|
||||
"ranch": {:hex, :ranch, "1.3.2", "e4965a144dc9fbe70e5c077c65e73c57165416a901bd02ea899cfd95aa890986", [:rebar3], []},
|
||||
"slugger": {:git, "https://github.com/h4cc/slugger.git", "ef864669cdaae18d475600589c19c74e92ef67b4", [ref: "ef864669cdaae18d475600589c19c74e92ef67b4"]},
|
||||
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.1", "28a4d65b7f59893bc2c7de786dec1e1555bd742d336043fe644ae956c3497fbe", [:make, :rebar], []},
|
||||
"ssl_verify_hostname": {:hex, :ssl_verify_hostname, "1.0.5"},
|
||||
"tzdata": {:hex, :tzdata, "0.5.10", "087e8dfe8c0283473115ad8ca6974b898ecb55ca5c725427a142a79593391e90", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, optional: false]}]}}
|
||||
"tzdata": {:hex, :tzdata, "0.5.11", "3d5469a9f46bdf4a8760333dbdabdcc4751325035c454b10521f71e7c611ae50", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, optional: false]}]}}
|
||||
|
|
14
package.json
14
package.json
|
@ -6,19 +6,19 @@
|
|||
"description": "Minimalistic Elixir Blog Engine",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"babel-cli": "~6.22.2",
|
||||
"babel-core": "~6.22.1",
|
||||
"babel-polyfill": "~6.22.0",
|
||||
"babel-preset-es2015": "~6.22.0",
|
||||
"babel-cli": "~6.24.0",
|
||||
"babel-core": "~6.24.0",
|
||||
"babel-polyfill": "~6.23.0",
|
||||
"babel-preset-es2015": "~6.24.0",
|
||||
"babel-preset-es2016": "~6.22.0",
|
||||
"babel-preset-es2017": "~6.22.0",
|
||||
"bootstrap-sass": "~3.3.7",
|
||||
"cssnano": "~3.10.0",
|
||||
"cssnano-cli": "~1.0.5",
|
||||
"node-sass": "~4.3.0",
|
||||
"rollup": "~0.41.4",
|
||||
"node-sass": "~4.5.0",
|
||||
"rollup": "~0.41.6",
|
||||
"rollup-plugin-sourcemaps": "~0.4.1",
|
||||
"rollup-watch": "~3.2.2",
|
||||
"uglify-js": "~2.7.5"
|
||||
"uglify-js": "~2.8.13"
|
||||
}
|
||||
}
|
||||
|
|
Reference in a new issue