aprs.me/mix.exs
Graham McIntire 63a87f3be1
Fix Docker build JavaScript import errors with vendor bundle
Fixed the esbuild errors during Docker build where npm packages couldn't
be resolved. The issue was caused by node_modules being excluded from
the Docker build context in .dockerignore.

Implemented a proper vendor bundle strategy following Phoenix 1.7+ patterns:

- Created vendor.js that bundles all npm dependencies (Leaflet, Chart.js,
  topbar) and their CSS files into a single pre-built bundle
- Added vendor esbuild profile in config.exs with proper CSS/image loaders
- Updated mix.exs to build vendor bundle before app bundle in assets.deploy
- Modified JavaScript imports to use globally loaded libraries from vendor
  bundle instead of importing from node_modules
- Added vendor.js script tag to root.html.heex before app.js

This approach avoids Docker build failures by pre-bundling all vendor
dependencies, eliminating the need for node_modules during production builds.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-21 12:32:39 -05:00

175 lines
5.3 KiB
Elixir

defmodule Aprsme.MixProject do
use Mix.Project
def project do
[
app: :aprsme,
version: "0.2.0",
elixir: "~> 1.17",
archives: [mix_gleam: "~> 0.6"],
compilers: Mix.compilers(),
elixirc_paths: elixirc_paths(Mix.env()),
erlc_paths: erlc_paths(Mix.env()),
erlc_include_path: "build/#{Mix.env()}/erlang/aprsme/include",
start_permanent: Mix.env() == :prod,
aliases: aliases(),
deps: deps(),
listeners: [Phoenix.CodeReloader],
dialyzer: [
ignore_warnings: ".dialyzer_ignore.exs",
plt_file:
{:no_warn,
"_build/dev/dialyxir_erlang-#{:erlang.system_info(:otp_release)}_elixir-#{System.version()}_deps-dev.plt"}
],
releases: [
aprsme: [
steps: [:assemble, &copy_gleam_files/1]
]
]
]
end
def cli do
[
preferred_cli_env: [
coveralls: :test,
"coveralls.detail": :test,
"coveralls.post": :test,
"coveralls.html": :test
]
]
end
# Configuration for the OTP application.
#
# Type `mix help compile.app` for more information.
def application do
[
mod: {Aprsme.Application, []},
extra_applications: [:hackney, :logger, :runtime_tools, :os_mon]
]
end
# Specifies which paths to compile per environment.
defp elixirc_paths(:test), do: ["lib", "test/support"]
defp elixirc_paths(_), do: ["lib"]
# Specifies erlc paths per environment for Gleam compilation
defp erlc_paths(_env) do
# Only include src directory to avoid compiling Gleam's internal scripts
["src"]
end
# Specifies your project dependencies.
#
# Type `mix help deps` for examples and options.
defp deps do
[
{:error_tracker, "~> 0.6"},
{:bcrypt_elixir, "~> 3.0"},
{:certifi, "~> 2.9"},
{:ecto_psql_extras, "~> 0.8.8"},
{:ecto_sql, "~> 3.11"},
{:geo, "~> 4.0.1"},
{:geo_postgis, "~> 3.4"},
{:geocalc, "~> 0.8"},
{:gen_stage, "~> 1.2"},
{:gettext, "~> 0.26.2"},
{:hackney, "~> 1.24"},
{:jason, "~> 1.4"},
{:libcluster, "~> 3.3"},
{:oban, "~> 2.11"},
{:phoenix, "~> 1.8.0-rc.3", override: true},
{:phoenix_ecto, "~> 4.4"},
{:phoenix_html, "~> 4.0"},
{:phoenix_live_dashboard, "~> 0.8"},
{:phoenix_live_reload, "~> 1.2", only: :dev},
{:phoenix_live_view, "~> 1.0.17"},
{:postgrex, ">= 0.0.0"},
{:swoosh, "~> 1.16"},
{:resend, "~> 0.4.1"},
{:telemetry_metrics, "~> 1.0"},
{:telemetry_poller, "~> 1.0"},
aprs_dep(),
{:esbuild, "~> 0.9", runtime: Mix.env() == :dev},
{:tailwind, "~> 0.3", runtime: Mix.env() == :dev},
{:heroicons,
github: "tailwindlabs/heroicons", tag: "v2.1.1", sparse: "optimized", app: false, compile: false, depth: 1},
{:bandit, "~> 1.5"},
{:req, "~> 0.5"},
{:gridsquare, "~> 0.2.0"},
{:credo, "~> 1.7", only: [:dev, :test], runtime: false},
{:dialyxir, "~> 1.0", only: :dev, runtime: false},
{:exvcr, "~> 0.15", only: :test},
{:faker, "~> 0.18", only: [:dev, :test]},
{:floki, ">= 0.30.0", only: :test},
{:mix_test_watch, "~> 1.1", only: [:dev, :test]},
{:sobelow, "~> 0.8", only: :dev},
{:stream_data, "~> 1.2.0", only: [:dev, :test]},
{:igniter, "~> 0.6", only: [:dev, :test]},
{:mox, "~> 1.2", only: :test},
{:styler, "~> 1.5.0", only: [:dev, :test], runtime: false},
{:httpoison, "~> 1.8"},
{:hammer, "~> 7.0"},
{:cachex, "~> 4.1"},
{:gettext_pseudolocalize, "~> 0.1"},
{:sentry, "~> 11.0"},
# Gleam dependencies
{:gleam_stdlib, ">= 0.60.0 and < 1.0.0", app: false, compile: false, override: true},
{:gleeunit, "~> 1.0", only: [:dev, :test], runtime: false, app: false, compile: false}
]
end
# Aliases are shortcuts or tasks specific to the current project.
# For example, to install project dependencies and perform other setup tasks, run:
#
# $ mix setup
#
# See the documentation for `Mix` for more info on aliases.
defp aliases do
[
setup: ["setup_gleam", "deps.get", "ecto.setup", "gleam_compile"],
compile: ["gleam_compile", "compile"],
"ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"],
"ecto.reset": ["ecto.drop", "ecto.setup"],
test: ["gleam_compile", "ecto.create --quiet", "ecto.migrate --quiet", "test"],
"assets.deploy": [
"tailwind default --minify",
"esbuild vendor",
"esbuild default --minify",
"phx.digest"
]
]
end
defp aprs_dep do
{:aprs, path: "vendor/aprs"}
# if Mix.env() in [:dev] do
# {:aprs, path: "vendor/aprs"}
# else
# {:aprs, github: "aprsme/aprs", branch: "main"}
# end
end
# Copy Gleam BEAM files to the release
defp copy_gleam_files(release) do
app_dir = Path.join([release.path, "lib", "aprsme-#{release.version}", "ebin"])
File.mkdir_p!(app_dir)
# Copy from priv/gleam if available
priv_gleam = "priv/gleam"
if File.exists?(priv_gleam) do
priv_gleam
|> File.ls!()
|> Enum.filter(&String.ends_with?(&1, ".beam"))
|> Enum.each(fn beam_file ->
src = Path.join(priv_gleam, beam_file)
dest = Path.join(app_dir, beam_file)
File.copy!(src, dest)
end)
end
release
end
end