defmodule VitePhoenix do
@default_config %{
default: [
args: ~w(vite build --outDir=../../../priv/static --target=$JS_VERSION),
cd: Path.expand("../../../assets/js/$PROJECT_NAME", __DIR__)
]
}
@default_js_version "esnext"
@moduledoc """
An experimental light-weight module to help with integrating [Vite](https://vitejs.dev/) into your Phoenix project and watching for any code change in Vite's side.
This module is basically a simplified version of the [esbuild](https://github.com/phoenixframework/esbuild) module that comes with Phoenix framework.
## Profiles
To simplify the usage, while vite_phoenix retains the ability to let user define multiple profiles, it also comes with a default config hard-coded inside the module, so that users won't need to provide the whole profile in their config.exs.
## Project name
That being said, in order to make it work with arbitrary project names set up by Vite during `npm create vite@latest`, users still need to define the project name in `config.exs` that matches the folder name under `assets/js`. The config should look like this:
```elixir
config :vite_phoenix, project_name: "my-vite-project"
```
"""
use Application
require Logger
@doc false
def start(_, _) do
unless Application.get_env(:vite_phoenix, :project_name) do
Logger.error("""
Project name is not configured for vite_phoenix. Please set it in your config files:
config :vite_phoenix, project_name: "my-vite-project"
""")
end
Supervisor.start_link([], strategy: :one_for_one)
end
@spec config_for(atom) :: Keyword.t()
def config_for(profile) when is_atom(profile) do
project_name =
Application.get_env(:vite_phoenix, :project_name) ||
raise ArgumentError,
"You need to at least set the project_name environment variable in your config.exs!"
js_version = Application.get_env(:vite_phoenix, :js_version) || @default_js_version
config = Application.get_env(:vite_phoenix, profile) || @default_config[:default]
target_index = Enum.find_index(config[:args], &String.contains?(&1, "--target"))
Keyword.put(config, :cd, String.replace(config[:cd], "$PROJECT_NAME", project_name))
|> Keyword.put(:args, List.replace_at(config[:args], target_index, "--target=#{js_version}"))
end
@spec run(atom, [binary]) :: non_neg_integer
def run(profile, extra_args) when is_atom(profile) and is_list(extra_args) do
config = config_for(profile)
args = config[:args] || []
if args == [] and extra_args == [] do
raise "no arguments passed to vite_phoenix"
end
opts = [
cd: config[:cd] || File.cwd!(),
env: config[:env] || %{},
into: IO.stream(:stdio, :line),
stderr_to_stdout: true
]
System.cmd("npx", args ++ extra_args, opts)
|> elem(1)
end
end