defmodule Mix.Tasks.Grf.Server do
@shortdoc "Generates a static website and listens for changes."
@moduledoc """
Starts up a local development server using plug_cowboy.
The local server watches for file changes and re-runs grf.build
on file change, but does not reload the file in the browser.
This server is NOT meant to be run in production.
"""
use Mix.Task
require Logger
@requirements ["app.config", "grf.build"]
@default_port "4123"
@switches [
port: :integer
]
@aliases [
p: :port
]
@impl Mix.Task
def run(args) do
{opts, _parsed} = OptionParser.parse!(args, strict: @switches, aliases: @aliases)
opts = Map.new(opts)
# load code and start dependencies, including cowboy
{:ok, _} = Application.ensure_all_started([:griffin_ssg])
port = http_port(opts)
input_directories =
[
Application.get_env(:griffin_ssg, :input, "src"),
Application.get_env(:griffin_ssg, :layouts, "lib/layouts")
] ++ Application.get_env(:griffin_ssg, :additional_watch_directories, [])
live_reload_watch_dirs = [
~r"#{Application.get_env(:griffin_ssg, :output, "_site")}/*"
]
Application.put_env(:plug_live_reload, :patterns, live_reload_watch_dirs)
on_file_change_callback = fn ->
# Can we do more clever builds here? (e.g. building only changed files)
Mix.Tasks.Grf.Build.run([])
end
children = [
{Plug.Cowboy, scheme: :http, plug: GriffinSSG.Web.Plug, options: [port: port, dispatch: dispatch()]},
{GriffinSSG.Filesystem.Watcher, [input_directories, on_file_change_callback]}
]
# disable debug logs from plug_live_reload
Logger.configure(level: :info)
Mix.shell().info("Starting webserver on http://localhost:#{port}")
Supervisor.start_link(children, strategy: :one_for_one, name: Grf.Server.Supervisor)
Process.sleep(:infinity)
end
# refactor: consider having a centralized place for reading configuration values
# that are overridable in different ways.
def http_port(opts) do
Map.get(opts, :port) || Application.get_env(:griffin_ssg, :http_port) ||
parse_int(System.get_env("GRIFFIN_HTTP_PORT", @default_port))
end
defp parse_int(string) do
{integer, _remainder} = Integer.parse(string)
integer
end
defp dispatch do
[
{:_,
[
{"/plug_live_reload/socket", PlugLiveReload.Socket, []},
{:_, Plug.Cowboy.Handler, {GriffinSSG.Web.Plug, []}}
]}
]
end
end