Subiendo api v2
This commit is contained in:
327
deps/esbuild/lib/esbuild.ex
vendored
Normal file
327
deps/esbuild/lib/esbuild.ex
vendored
Normal file
@ -0,0 +1,327 @@
|
||||
defmodule Esbuild do
|
||||
# https://registry.npmjs.org/esbuild/latest
|
||||
@latest_version "0.25.0"
|
||||
|
||||
@moduledoc """
|
||||
Esbuild is an installer and runner for [esbuild](https://esbuild.github.io).
|
||||
|
||||
## Profiles
|
||||
|
||||
You can define multiple esbuild profiles. By default, there is a
|
||||
profile called `:default` which you can configure its args, current
|
||||
directory and environment:
|
||||
|
||||
config :esbuild,
|
||||
version: "#{@latest_version}",
|
||||
default: [
|
||||
args: ~w(js/app.js --bundle --target=es2016 --outdir=../priv/static/assets),
|
||||
cd: Path.expand("../assets", __DIR__),
|
||||
env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)}
|
||||
]
|
||||
|
||||
## Esbuild configuration
|
||||
|
||||
There are four global configurations for the esbuild application:
|
||||
|
||||
* `:version` - the expected esbuild version
|
||||
|
||||
* `:version_check` - whether to perform the version check or not.
|
||||
Useful when you manage the esbuild executable with an external
|
||||
tool (eg. npm)
|
||||
|
||||
* `:path` - the path to find the esbuild executable at. By
|
||||
default, it is automatically downloaded and placed inside
|
||||
the `_build` directory of your current app
|
||||
|
||||
Overriding the `:path` is not recommended, as we will automatically
|
||||
download and manage `esbuild` for you. But in case you can't download
|
||||
it (for example, the npm registry is behind a proxy), you may want to
|
||||
set the `:path` to a configurable system location.
|
||||
|
||||
For instance, you can install `esbuild` globally with `npm`:
|
||||
|
||||
$ npm install -g esbuild
|
||||
|
||||
On Unix, the executable will be at:
|
||||
|
||||
NPM_ROOT/esbuild/node_modules/@esbuild/TARGET/bin/esbuild
|
||||
|
||||
On Windows, it will be at:
|
||||
|
||||
NPM_ROOT/esbuild/node_modules/@esbuild/win32-x(32|64)/esbuild.exe
|
||||
|
||||
Where `NPM_ROOT` is the result of `npm root -g` and `TARGET` is your system
|
||||
target architecture.
|
||||
|
||||
Once you find the location of the executable, you can store it in a
|
||||
`MIX_ESBUILD_PATH` environment variable, which you can then read in
|
||||
your configuration file:
|
||||
|
||||
config :esbuild, path: System.get_env("MIX_ESBUILD_PATH")
|
||||
|
||||
"""
|
||||
|
||||
use Application
|
||||
require Logger
|
||||
|
||||
@doc false
|
||||
def start(_, _) do
|
||||
if Application.get_env(:esbuild, :version_check, true) do
|
||||
unless Application.get_env(:esbuild, :version) do
|
||||
Logger.warning("""
|
||||
esbuild version is not configured. Please set it in your config files:
|
||||
|
||||
config :esbuild, :version, "#{latest_version()}"
|
||||
""")
|
||||
end
|
||||
|
||||
configured_version = configured_version()
|
||||
|
||||
case bin_version() do
|
||||
{:ok, ^configured_version} ->
|
||||
:ok
|
||||
|
||||
{:ok, version} ->
|
||||
Logger.warning("""
|
||||
Outdated esbuild version. Expected #{configured_version}, got #{version}. \
|
||||
Please run `mix esbuild.install` or update the version in your config files.\
|
||||
""")
|
||||
|
||||
:error ->
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
Supervisor.start_link([], strategy: :one_for_one, name: __MODULE__.Supervisor)
|
||||
end
|
||||
|
||||
@doc false
|
||||
# Latest known version at the time of publishing.
|
||||
def latest_version, do: @latest_version
|
||||
|
||||
@doc """
|
||||
Returns the configured esbuild version.
|
||||
"""
|
||||
def configured_version do
|
||||
Application.get_env(:esbuild, :version, latest_version())
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns the configuration for the given profile.
|
||||
|
||||
Returns nil if the profile does not exist.
|
||||
"""
|
||||
def config_for!(profile) when is_atom(profile) do
|
||||
Application.get_env(:esbuild, profile) ||
|
||||
raise ArgumentError, """
|
||||
unknown esbuild profile. Make sure the profile is defined in your config/config.exs file, such as:
|
||||
|
||||
config :esbuild,
|
||||
#{profile}: [
|
||||
args: ~w(js/app.js --bundle --target=es2016 --outdir=../priv/static/assets),
|
||||
cd: Path.expand("../assets", __DIR__),
|
||||
env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)}
|
||||
]
|
||||
"""
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns the path to the executable.
|
||||
|
||||
The executable may not be available if it was not yet installed.
|
||||
"""
|
||||
def bin_path do
|
||||
name = "esbuild-#{target()}"
|
||||
|
||||
Application.get_env(:esbuild, :path) ||
|
||||
if Code.ensure_loaded?(Mix.Project) do
|
||||
Path.join(Path.dirname(Mix.Project.build_path()), name)
|
||||
else
|
||||
Path.expand("_build/#{name}")
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns the version of the esbuild executable.
|
||||
|
||||
Returns `{:ok, version_string}` on success or `:error` when the executable
|
||||
is not available.
|
||||
"""
|
||||
def bin_version do
|
||||
path = bin_path()
|
||||
|
||||
with true <- File.exists?(path),
|
||||
{result, 0} <- System.cmd(path, ["--version"]) do
|
||||
{:ok, String.trim(result)}
|
||||
else
|
||||
_ -> :error
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Runs the given command with `args`.
|
||||
|
||||
The given args will be appended to the configured args.
|
||||
The task output will be streamed directly to stdio. It
|
||||
returns the status of the underlying call.
|
||||
"""
|
||||
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 esbuild"
|
||||
end
|
||||
|
||||
opts = [
|
||||
cd: config[:cd] || File.cwd!(),
|
||||
env: config[:env] || %{},
|
||||
into: IO.stream(:stdio, :line),
|
||||
stderr_to_stdout: true
|
||||
]
|
||||
|
||||
bin_path()
|
||||
|> System.cmd(args ++ extra_args, opts)
|
||||
|> elem(1)
|
||||
end
|
||||
|
||||
defp start_unique_install_worker() do
|
||||
ref =
|
||||
__MODULE__.Supervisor
|
||||
|> Supervisor.start_child(
|
||||
Supervisor.child_spec({Task, &install/0}, restart: :transient, id: __MODULE__.Installer)
|
||||
)
|
||||
|> case do
|
||||
{:ok, pid} -> pid
|
||||
{:error, {:already_started, pid}} -> pid
|
||||
end
|
||||
|> Process.monitor()
|
||||
|
||||
receive do
|
||||
{:DOWN, ^ref, _, _, _} -> :ok
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Installs, if not available, and then runs `esbuild`.
|
||||
|
||||
This task may be invoked concurrently and it will avoid concurrent installs.
|
||||
|
||||
Returns the same as `run/2`.
|
||||
"""
|
||||
def install_and_run(profile, args) do
|
||||
File.exists?(bin_path()) || start_unique_install_worker()
|
||||
|
||||
run(profile, args)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Installs esbuild with `configured_version/0`.
|
||||
|
||||
If invoked concurrently, this task will perform concurrent installs.
|
||||
"""
|
||||
def install do
|
||||
version = configured_version()
|
||||
tmp_opts = if System.get_env("MIX_XDG"), do: %{os: :linux}, else: %{}
|
||||
|
||||
tmp_dir =
|
||||
freshdir_p(:filename.basedir(:user_cache, "phx-esbuild", tmp_opts)) ||
|
||||
freshdir_p(Path.join(System.tmp_dir!(), "phx-esbuild")) ||
|
||||
raise "could not install esbuild. Set MIX_XGD=1 and then set XDG_CACHE_HOME to the path you want to use as cache"
|
||||
|
||||
name =
|
||||
if Version.compare(version, "0.16.0") in [:eq, :gt] do
|
||||
target = target()
|
||||
"@esbuild/#{target}"
|
||||
else
|
||||
# TODO: Remove else clause or raise if esbuild < 0.16.0 don't need to be supported anymore
|
||||
"esbuild-#{target_legacy()}"
|
||||
end
|
||||
|
||||
tar = Esbuild.NpmRegistry.fetch_package!(name, version)
|
||||
|
||||
case :erl_tar.extract({:binary, tar}, [:compressed, cwd: to_charlist(tmp_dir)]) do
|
||||
:ok -> :ok
|
||||
other -> raise "couldn't unpack archive: #{inspect(other)}"
|
||||
end
|
||||
|
||||
bin_path = bin_path()
|
||||
File.mkdir_p!(Path.dirname(bin_path))
|
||||
|
||||
case :os.type() do
|
||||
{:win32, _} ->
|
||||
File.cp!(Path.join([tmp_dir, "package", "esbuild.exe"]), bin_path)
|
||||
|
||||
_ ->
|
||||
File.cp!(Path.join([tmp_dir, "package", "bin", "esbuild"]), bin_path)
|
||||
end
|
||||
end
|
||||
|
||||
defp freshdir_p(path) do
|
||||
with {:ok, _} <- File.rm_rf(path),
|
||||
:ok <- File.mkdir_p(path) do
|
||||
path
|
||||
else
|
||||
_ -> nil
|
||||
end
|
||||
end
|
||||
|
||||
# Available targets: https://github.com/evanw/esbuild/tree/main/npm/@esbuild
|
||||
defp target do
|
||||
case :os.type() do
|
||||
# Assuming it's an x86 CPU
|
||||
{:win32, _} ->
|
||||
wordsize = :erlang.system_info(:wordsize)
|
||||
|
||||
if wordsize == 8 do
|
||||
"win32-x64"
|
||||
else
|
||||
"win32-ia32"
|
||||
end
|
||||
|
||||
{:unix, osname} ->
|
||||
arch_str = :erlang.system_info(:system_architecture)
|
||||
[arch | _] = arch_str |> List.to_string() |> String.split("-")
|
||||
|
||||
case arch do
|
||||
"amd64" -> "#{osname}-x64"
|
||||
"x86_64" -> "#{osname}-x64"
|
||||
"i686" -> "#{osname}-ia32"
|
||||
"i386" -> "#{osname}-ia32"
|
||||
"aarch64" -> "#{osname}-arm64"
|
||||
"riscv64" -> "#{osname}-riscv64"
|
||||
# TODO: remove when we require OTP 24
|
||||
"arm" when osname == :darwin -> "darwin-arm64"
|
||||
"arm" -> "#{osname}-arm"
|
||||
"armv7" <> _ -> "#{osname}-arm"
|
||||
_ -> raise "esbuild is not available for architecture: #{arch_str}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# TODO: Remove if esbuild < 0.16.0 don't need to be supported anymore
|
||||
# Available targets: https://github.com/evanw/esbuild/tree/v0.15.18/npm
|
||||
defp target_legacy do
|
||||
case :os.type() do
|
||||
{:win32, _} ->
|
||||
"windows-#{:erlang.system_info(:wordsize) * 8}"
|
||||
|
||||
{:unix, osname} ->
|
||||
arch_str = :erlang.system_info(:system_architecture)
|
||||
[arch | _] = arch_str |> List.to_string() |> String.split("-")
|
||||
|
||||
case arch do
|
||||
"amd64" -> "#{osname}-64"
|
||||
"x86_64" -> "#{osname}-64"
|
||||
"i686" -> "#{osname}-32"
|
||||
"i386" -> "#{osname}-32"
|
||||
"aarch64" -> "#{osname}-arm64"
|
||||
# TODO: remove when we require OTP 24
|
||||
"arm" when osname == :darwin -> "darwin-arm64"
|
||||
"arm" -> "#{osname}-arm"
|
||||
"armv7" <> _ -> "#{osname}-arm"
|
||||
_ -> raise "esbuild is not available for architecture: #{arch_str}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
162
deps/esbuild/lib/esbuild/npm_registry.ex
vendored
Normal file
162
deps/esbuild/lib/esbuild/npm_registry.ex
vendored
Normal file
@ -0,0 +1,162 @@
|
||||
defmodule Esbuild.NpmRegistry do
|
||||
@moduledoc false
|
||||
require Logger
|
||||
|
||||
# source: https://registry.npmjs.org/-/npm/v1/keys
|
||||
@public_keys %{
|
||||
"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA" => """
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1Olb3zMAFFxXKHiIkQO5cJ3Yhl5i
|
||||
6UPp+IhuteBJbuHcA5UogKo0EWtlWwW6KSaKoTNEYL7JlCQiVnkhBktUgg==
|
||||
-----END PUBLIC KEY-----
|
||||
""",
|
||||
"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U" => """
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEY6Ya7W++7aUPzvMTrezH6Ycx3c+H
|
||||
OKYCcNGybJZSCJq/fd7Qa8uuAKtdIkUQtQiEKERhAmE5lMMJhP8OkDOa2g==
|
||||
-----END PUBLIC KEY-----
|
||||
"""
|
||||
}
|
||||
|
||||
@base_url "https://registry.npmjs.org"
|
||||
|
||||
def fetch_package!(name, version) do
|
||||
url = "#{@base_url}/#{name}/#{version}"
|
||||
scheme = URI.parse(url).scheme
|
||||
Logger.debug("Downloading esbuild from #{url}")
|
||||
|
||||
{:ok, _} = Application.ensure_all_started(:inets)
|
||||
{:ok, _} = Application.ensure_all_started(:ssl)
|
||||
|
||||
if proxy = proxy_for_scheme(scheme) do
|
||||
%{host: host, port: port} = URI.parse(proxy)
|
||||
Logger.debug("Using #{String.upcase(scheme)}_PROXY: #{proxy}")
|
||||
set_option = if "https" == scheme, do: :https_proxy, else: :proxy
|
||||
:httpc.set_options([{set_option, {{String.to_charlist(host), port}, []}}])
|
||||
end
|
||||
|
||||
%{
|
||||
"_id" => id,
|
||||
"dist" => %{
|
||||
"integrity" => integrity,
|
||||
"signatures" => signatures,
|
||||
"tarball" => tarball
|
||||
}
|
||||
} =
|
||||
fetch_file!(url)
|
||||
|> Jason.decode!()
|
||||
|
||||
%{"keyid" => keyid, "sig" => signature} =
|
||||
signatures
|
||||
|> Enum.find(fn %{"keyid" => keyid} -> is_map_key(@public_keys, keyid) end) ||
|
||||
raise "missing signature"
|
||||
|
||||
verify_signature!("#{id}:#{integrity}", keyid, signature)
|
||||
tar = fetch_file!(tarball)
|
||||
|
||||
[hash_alg, checksum] =
|
||||
integrity
|
||||
|> String.split("-")
|
||||
|
||||
verify_integrity!(tar, hash_alg, Base.decode64!(checksum))
|
||||
|
||||
tar
|
||||
end
|
||||
|
||||
defp fetch_file!(url, retry \\ true) do
|
||||
case {retry, do_fetch(url)} do
|
||||
{_, {:ok, {{_, 200, _}, _headers, body}}} ->
|
||||
body
|
||||
|
||||
{true, {:error, {:failed_connect, [{:to_address, _}, {inet, _, reason}]}}}
|
||||
when inet in [:inet, :inet6] and
|
||||
reason in [:ehostunreach, :enetunreach, :eprotonosupport, :nxdomain] ->
|
||||
:httpc.set_options(ipfamily: fallback(inet))
|
||||
fetch_file!(url, false)
|
||||
|
||||
other ->
|
||||
raise """
|
||||
couldn't fetch #{url}: #{inspect(other)}
|
||||
|
||||
You may also install the "esbuild" executable manually, \
|
||||
see the docs: https://hexdocs.pm/esbuild
|
||||
"""
|
||||
end
|
||||
end
|
||||
|
||||
defp fallback(:inet), do: :inet6
|
||||
defp fallback(:inet6), do: :inet
|
||||
|
||||
defp do_fetch(url) do
|
||||
scheme = URI.parse(url).scheme
|
||||
url = String.to_charlist(url)
|
||||
|
||||
:httpc.request(
|
||||
:get,
|
||||
{url, []},
|
||||
[
|
||||
ssl: [
|
||||
verify: :verify_peer,
|
||||
# https://erlef.github.io/security-wg/secure_coding_and_deployment_hardening/inets
|
||||
cacerts: :public_key.cacerts_get(),
|
||||
depth: 2,
|
||||
customize_hostname_check: [
|
||||
match_fun: :public_key.pkix_verify_hostname_match_fun(:https)
|
||||
]
|
||||
]
|
||||
]
|
||||
|> maybe_add_proxy_auth(scheme),
|
||||
body_format: :binary
|
||||
)
|
||||
end
|
||||
|
||||
defp proxy_for_scheme("http") do
|
||||
System.get_env("HTTP_PROXY") || System.get_env("http_proxy")
|
||||
end
|
||||
|
||||
defp proxy_for_scheme("https") do
|
||||
System.get_env("HTTPS_PROXY") || System.get_env("https_proxy")
|
||||
end
|
||||
|
||||
defp maybe_add_proxy_auth(http_options, scheme) do
|
||||
case proxy_auth(scheme) do
|
||||
nil -> http_options
|
||||
auth -> [{:proxy_auth, auth} | http_options]
|
||||
end
|
||||
end
|
||||
|
||||
defp proxy_auth(scheme) do
|
||||
with proxy when is_binary(proxy) <- proxy_for_scheme(scheme),
|
||||
%{userinfo: userinfo} when is_binary(userinfo) <- URI.parse(proxy),
|
||||
[username, password] <- String.split(userinfo, ":") do
|
||||
{String.to_charlist(username), String.to_charlist(password)}
|
||||
else
|
||||
_ -> nil
|
||||
end
|
||||
end
|
||||
|
||||
defp verify_signature!(message, key_id, signature) do
|
||||
:public_key.verify(
|
||||
message,
|
||||
:sha256,
|
||||
Base.decode64!(signature),
|
||||
public_key(key_id)
|
||||
) or raise "invalid signature"
|
||||
end
|
||||
|
||||
defp verify_integrity!(binary, hash_alg, checksum) do
|
||||
binary_checksum =
|
||||
hash_alg
|
||||
|> hash_alg_to_erlang()
|
||||
|> :crypto.hash(binary)
|
||||
|
||||
binary_checksum == checksum or raise "invalid checksum"
|
||||
end
|
||||
|
||||
defp public_key(key_id) do
|
||||
[entry] = :public_key.pem_decode(@public_keys[key_id])
|
||||
:public_key.pem_entry_decode(entry)
|
||||
end
|
||||
|
||||
defp hash_alg_to_erlang("sha512"), do: :sha512
|
||||
end
|
||||
65
deps/esbuild/lib/mix/tasks/esbuild.ex
vendored
Normal file
65
deps/esbuild/lib/mix/tasks/esbuild.ex
vendored
Normal file
@ -0,0 +1,65 @@
|
||||
defmodule Mix.Tasks.Esbuild do
|
||||
@moduledoc """
|
||||
Invokes esbuild with the given args.
|
||||
|
||||
Usage:
|
||||
|
||||
$ mix esbuild TASK_OPTIONS PROFILE ESBUILD_ARGS
|
||||
|
||||
Example:
|
||||
|
||||
$ mix esbuild default assets/js/app.js --bundle --minify --target=es2016 --outdir=priv/static/assets
|
||||
|
||||
If esbuild is not installed, it is automatically downloaded.
|
||||
Note the arguments given to this task will be appended
|
||||
to any configured arguments.
|
||||
|
||||
## Options
|
||||
|
||||
* `--runtime-config` - load the runtime configuration
|
||||
before executing command
|
||||
|
||||
Note flags to control this Mix task must be given before the
|
||||
profile:
|
||||
|
||||
$ mix esbuild --runtime-config default assets/js/app.js
|
||||
|
||||
"""
|
||||
|
||||
@shortdoc "Invokes esbuild with the profile and args"
|
||||
@compile {:no_warn_undefined, Mix}
|
||||
|
||||
use Mix.Task
|
||||
|
||||
@impl true
|
||||
def run(args) do
|
||||
switches = [runtime_config: :boolean]
|
||||
{opts, remaining_args} = OptionParser.parse_head!(args, switches: switches)
|
||||
|
||||
if function_exported?(Mix, :ensure_application!, 1) do
|
||||
Mix.ensure_application!(:inets)
|
||||
Mix.ensure_application!(:ssl)
|
||||
end
|
||||
|
||||
if opts[:runtime_config] do
|
||||
Mix.Task.run("app.config")
|
||||
else
|
||||
Mix.Task.run("loadpaths")
|
||||
Application.ensure_all_started(:esbuild)
|
||||
end
|
||||
|
||||
Mix.Task.reenable("esbuild")
|
||||
install_and_run(remaining_args)
|
||||
end
|
||||
|
||||
defp install_and_run([profile | args] = all) do
|
||||
case Esbuild.install_and_run(String.to_atom(profile), args) do
|
||||
0 -> :ok
|
||||
status -> Mix.raise("`mix esbuild #{Enum.join(all, " ")}` exited with #{status}")
|
||||
end
|
||||
end
|
||||
|
||||
defp install_and_run([]) do
|
||||
Mix.raise("`mix esbuild` expects the profile as argument")
|
||||
end
|
||||
end
|
||||
67
deps/esbuild/lib/mix/tasks/esbuild.install.ex
vendored
Normal file
67
deps/esbuild/lib/mix/tasks/esbuild.install.ex
vendored
Normal file
@ -0,0 +1,67 @@
|
||||
defmodule Mix.Tasks.Esbuild.Install do
|
||||
@moduledoc """
|
||||
Installs esbuild under `_build`.
|
||||
|
||||
```bash
|
||||
$ mix esbuild.install
|
||||
$ mix esbuild.install --if-missing
|
||||
```
|
||||
|
||||
By default, it installs #{Esbuild.latest_version()} but you
|
||||
can configure it in your config files, such as:
|
||||
|
||||
config :esbuild, :version, "#{Esbuild.latest_version()}"
|
||||
|
||||
## Options
|
||||
|
||||
* `--runtime-config` - load the runtime configuration
|
||||
before executing command
|
||||
|
||||
* `--if-missing` - install only if the given version
|
||||
does not exist
|
||||
"""
|
||||
|
||||
@shortdoc "Installs esbuild under _build"
|
||||
@compile {:no_warn_undefined, Mix}
|
||||
|
||||
use Mix.Task
|
||||
|
||||
@impl true
|
||||
def run(args) do
|
||||
valid_options = [runtime_config: :boolean, if_missing: :boolean]
|
||||
|
||||
case OptionParser.parse_head!(args, strict: valid_options) do
|
||||
{opts, []} ->
|
||||
if opts[:runtime_config] do
|
||||
Mix.Task.run("app.config")
|
||||
else
|
||||
Mix.Task.run("loadpaths")
|
||||
end
|
||||
|
||||
if opts[:if_missing] && latest_version?() do
|
||||
:ok
|
||||
else
|
||||
if function_exported?(Mix, :ensure_application!, 1) do
|
||||
Mix.ensure_application!(:inets)
|
||||
Mix.ensure_application!(:ssl)
|
||||
end
|
||||
|
||||
Esbuild.install()
|
||||
end
|
||||
|
||||
{_, _} ->
|
||||
Mix.raise("""
|
||||
Invalid arguments to esbuild.install, expected one of:
|
||||
|
||||
mix esbuild.install
|
||||
mix esbuild.install --runtime-config
|
||||
mix esbuild.install --if-missing
|
||||
""")
|
||||
end
|
||||
end
|
||||
|
||||
defp latest_version?() do
|
||||
version = Esbuild.configured_version()
|
||||
match?({:ok, ^version}, Esbuild.bin_version())
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user