diff --git a/.gitignore b/.gitignore
index d5dd622..d92d502 100644
--- a/.gitignore
+++ b/.gitignore
@@ -25,6 +25,10 @@ aprsme-*.tar
# Ignore assets that are produced by build tools.
/priv/static/assets/
+# Ignore vendor JavaScript/CSS files (downloaded from CDNs)
+/assets/vendor/*.js
+/assets/vendor/*.css
+
# Ignore digested assets cache.
/priv/static/cache_manifest.json
diff --git a/assets/css/app.css b/assets/css/app.css
index e084e31..8040096 100644
--- a/assets/css/app.css
+++ b/assets/css/app.css
@@ -3,6 +3,11 @@
@source "../js";
@source "../../lib/aprsme_web";
+/* Import vendor CSS files */
+@import "../vendor/leaflet.css";
+@import "../vendor/MarkerCluster.css";
+@import "../vendor/MarkerCluster.Default.css";
+
/* A Tailwind plugin that makes "hero-#{ICON}" classes available.
The heroicons installation itself is managed by your mix.exs */
@plugin "../vendor/heroicons";
diff --git a/assets/download-vendor-files.sh b/assets/download-vendor-files.sh
new file mode 100755
index 0000000..fe5efdb
--- /dev/null
+++ b/assets/download-vendor-files.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+
+# Script to download vendor JavaScript and CSS files
+# Run this from the project root: ./assets/download-vendor-files.sh
+
+set -e
+
+echo "Downloading vendor files..."
+
+# Ensure vendor directory exists
+mkdir -p assets/vendor
+
+cd assets/vendor
+
+# Download JavaScript files
+echo "Downloading Leaflet..."
+curl -L -o leaflet.js https://unpkg.com/leaflet@1.9.4/dist/leaflet.js
+
+echo "Downloading Leaflet Heat..."
+curl -L -o leaflet-heat.js https://cdn.jsdelivr.net/npm/leaflet.heat@0.2.0/dist/leaflet-heat.js
+
+echo "Downloading Chart.js..."
+curl -L -o chart.umd.js https://cdn.jsdelivr.net/npm/chart.js@4.5.0/dist/chart.umd.js
+
+echo "Downloading Chart.js date adapter..."
+curl -L -o chartjs-adapter-date-fns.bundle.min.js https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns@3.0.0/dist/chartjs-adapter-date-fns.bundle.min.js
+
+echo "Downloading Leaflet MarkerCluster..."
+curl -L -o leaflet.markercluster.js https://unpkg.com/leaflet.markercluster@1.5.3/dist/leaflet.markercluster.js
+
+echo "Downloading OverlappingMarkerSpiderfier..."
+curl -L -o oms.min.js https://cdnjs.cloudflare.com/ajax/libs/OverlappingMarkerSpiderfier-Leaflet/0.2.6/oms.min.js
+
+# Download CSS files
+echo "Downloading Leaflet CSS..."
+curl -L -o leaflet.css https://unpkg.com/leaflet@1.9.4/dist/leaflet.css
+
+echo "Downloading MarkerCluster CSS..."
+curl -L -o MarkerCluster.css https://unpkg.com/leaflet.markercluster@1.5.3/dist/MarkerCluster.css
+curl -L -o MarkerCluster.Default.css https://unpkg.com/leaflet.markercluster@1.5.3/dist/MarkerCluster.Default.css
+
+echo "All vendor files downloaded successfully!"
+echo "Run 'mix esbuild vendor' to build the vendor bundle."
\ No newline at end of file
diff --git a/assets/js/vendor.js b/assets/js/vendor.js
new file mode 100644
index 0000000..f198665
--- /dev/null
+++ b/assets/js/vendor.js
@@ -0,0 +1,23 @@
+// Vendor libraries bundle
+// This file loads all external libraries and makes them available globally
+
+// Load Leaflet first (required by plugins)
+import '../vendor/leaflet.js';
+
+// Load Leaflet plugins (they expect window.L to exist)
+import '../vendor/leaflet-heat.js';
+import '../vendor/leaflet.markercluster.js';
+import '../vendor/oms.min.js';
+
+// Load Chart.js
+import '../vendor/chart.umd.js';
+
+// Load Chart.js adapter (requires Chart to be loaded first)
+import '../vendor/chartjs-adapter-date-fns.bundle.min.js';
+
+// Ensure global availability
+if (typeof window !== 'undefined') {
+ // Leaflet should already be on window.L from the library
+ // Chart should already be on window.Chart from the library
+ console.log('Vendor libraries loaded: Leaflet', !!window.L, 'Chart.js', !!window.Chart);
+}
\ No newline at end of file
diff --git a/assets/vendor/README.md b/assets/vendor/README.md
new file mode 100644
index 0000000..1b6d44c
--- /dev/null
+++ b/assets/vendor/README.md
@@ -0,0 +1,56 @@
+# Vendor JavaScript Libraries
+
+This directory contains third-party JavaScript and CSS libraries that are bundled locally instead of loading from CDNs.
+
+## Required Files
+
+The following files need to be downloaded:
+
+### JavaScript Files
+- `leaflet.js` - from https://unpkg.com/leaflet@1.9.4/dist/leaflet.js
+- `leaflet-heat.js` - from https://cdn.jsdelivr.net/npm/leaflet.heat@0.2.0/dist/leaflet-heat.js
+- `chart.umd.js` - from https://cdn.jsdelivr.net/npm/chart.js@4.5.0/dist/chart.umd.js
+- `chartjs-adapter-date-fns.bundle.min.js` - from https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns@3.0.0/dist/chartjs-adapter-date-fns.bundle.min.js
+- `leaflet.markercluster.js` - from https://unpkg.com/leaflet.markercluster@1.5.3/dist/leaflet.markercluster.js
+- `oms.min.js` - from https://cdnjs.cloudflare.com/ajax/libs/OverlappingMarkerSpiderfier-Leaflet/0.2.6/oms.min.js
+
+### CSS Files
+- `leaflet.css` - from https://unpkg.com/leaflet@1.9.4/dist/leaflet.css
+- `MarkerCluster.css` - from https://unpkg.com/leaflet.markercluster@1.5.3/dist/MarkerCluster.css
+- `MarkerCluster.Default.css` - from https://unpkg.com/leaflet.markercluster@1.5.3/dist/MarkerCluster.Default.css
+
+## Download Script
+
+To download all vendor files, run:
+
+```bash
+# From the project root
+cd assets/vendor
+
+# Download JavaScript files
+curl -L -o leaflet.js https://unpkg.com/leaflet@1.9.4/dist/leaflet.js
+curl -L -o leaflet-heat.js https://cdn.jsdelivr.net/npm/leaflet.heat@0.2.0/dist/leaflet-heat.js
+curl -L -o chart.umd.js https://cdn.jsdelivr.net/npm/chart.js@4.5.0/dist/chart.umd.js
+curl -L -o chartjs-adapter-date-fns.bundle.min.js https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns@3.0.0/dist/chartjs-adapter-date-fns.bundle.min.js
+curl -L -o leaflet.markercluster.js https://unpkg.com/leaflet.markercluster@1.5.3/dist/leaflet.markercluster.js
+curl -L -o oms.min.js https://cdnjs.cloudflare.com/ajax/libs/OverlappingMarkerSpiderfier-Leaflet/0.2.6/oms.min.js
+
+# Download CSS files
+curl -L -o leaflet.css https://unpkg.com/leaflet@1.9.4/dist/leaflet.css
+curl -L -o MarkerCluster.css https://unpkg.com/leaflet.markercluster@1.5.3/dist/MarkerCluster.css
+curl -L -o MarkerCluster.Default.css https://unpkg.com/leaflet.markercluster@1.5.3/dist/MarkerCluster.Default.css
+```
+
+## Building
+
+The vendor files are bundled using esbuild:
+
+```bash
+# Build vendor bundle
+mix esbuild vendor
+
+# Build with minification (for production)
+mix esbuild vendor --minify
+```
+
+The vendor bundle is automatically included in the asset deployment pipeline.
\ No newline at end of file
diff --git a/config/config.exs b/config/config.exs
index 9830370..664f0a0 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -85,6 +85,12 @@ config :esbuild,
~w(js/app.js --bundle --target=es2017 --outdir=../priv/static/assets --external:/fonts/* --external:/images/* --external:chart.js/auto --define:global.L=window.L),
cd: Path.expand("../assets", __DIR__),
env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)}
+ ],
+ vendor: [
+ args:
+ ~w(js/vendor.js --bundle --target=es2017 --outdir=../priv/static/assets --minify),
+ cd: Path.expand("../assets", __DIR__),
+ env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)}
]
config :gettext, :plural_forms, GettextPseudolocalize.Plural
diff --git a/config/dev.exs b/config/dev.exs
index 37809d2..6b3debe 100644
--- a/config/dev.exs
+++ b/config/dev.exs
@@ -53,6 +53,12 @@ config :aprsme, AprsmeWeb.Endpoint,
:default,
~w(--sourcemap=inline --watch --loader:.ts=ts)
]},
+ esbuild_vendor:
+ {Esbuild, :install_and_run,
+ [
+ :vendor,
+ ~w(--sourcemap=inline --watch)
+ ]},
tailwind: {Tailwind, :install_and_run, [:default, ~w(--watch)]}
]
diff --git a/lib/aprsme_web/components/layouts/root.html.heex b/lib/aprsme_web/components/layouts/root.html.heex
index e583c06..f111dc2 100644
--- a/lib/aprsme_web/components/layouts/root.html.heex
+++ b/lib/aprsme_web/components/layouts/root.html.heex
@@ -26,41 +26,8 @@
{assigns[:page_title] || "Aprs"}
-
-
- <%!-- Load Leaflet.heat after Leaflet is loaded --%>
-
-
-
diff --git a/lib/aprsme_web/live/map_live/index.ex b/lib/aprsme_web/live/map_live/index.ex
index c8cc2d6..afb8fb7 100644
--- a/lib/aprsme_web/live/map_live/index.ex
+++ b/lib/aprsme_web/live/map_live/index.ex
@@ -774,24 +774,7 @@ defmodule AprsmeWeb.MapLive.Index do
@impl true
def render(assigns) do
~H"""
-
-
-
-
-
-
+ <%!-- All vendor libraries are now loaded from vendor.js bundle --%>