Serve Chart.js and other vendor assets locally

The app uses Chart.js (and may use other JS/CSS libraries) for charts. By default these can be loaded from a CDN; for offline use, air-gapped deployments, or to avoid external requests, serve them from the app’s static folder.

Why serve locally

  • Offline / air-gapped: No CDN dependency; app works without internet.
  • Stability: Version is fixed in the repo; CDN changes don’t affect you.
  • Privacy / compliance: No requests to third-party domains.
  • Performance: One less origin; optional caching under your control.

Where assets live

  • JS: app/static/js/ (e.g. chart.umd.min.js)
  • CSS: app/static/css/ for app styles; vendor CSS can go in app/static/css/vendor/ or app/static/js/ alongside the library if it ships as a bundle.

Templates reference them via Flask’s url_for('static', filename='...'), e.g.:

<script src="{{ url_for('static', filename='js/chart.umd.min.js') }}"></script>

How to add or update Chart.js

  1. Download the vendor bundle (run from project root):

    uv run python scripts/download_vendor_assets.py all
    

    This script downloads the pinned Chart.js UMD build into app/static/js/chart.umd.min.js.

  2. Commit the file (so deploys don’t need network):

    git add app/static/js/chart.umd.min.js
    git commit -m "chore: vendor Chart.js for local serving"
    
  3. Templates already use the local URL; no CDN link remains once the file is present.

Adding another JS or CSS library

  1. Choose a build: Prefer a single minified file (UMD/IIFE for JS) so the app doesn’t depend on a bundler.

  2. Put it under app/static/:

    • JS → app/static/js/<library>.min.js
    • CSS → app/static/css/vendor/<library>.min.css (or next to the JS if you prefer).
  3. Optionally extend the download script in scripts/download_vendor_assets.py (e.g. add a URL and output path for the new library) so one command fetches all vendor assets.

  4. Reference in templates:

    <script src="{{ url_for('static', filename='js/<library>.min.js') }}"></script>
    <!-- or -->
    <link rel="stylesheet" href="{{ url_for('static', filename='css/vendor/<library>.min.css') }}">
    

Version pinning

Chart.js version is pinned in scripts/download_vendor_assets.py (e.g. 4.4.1). To upgrade:

  1. Change the version in the script (and optionally the CDN URL if the path changed).
  2. Run uv run python scripts/download_vendor_assets.py.
  3. Test the app (Graph and Capacity charts).
  4. Commit the updated app/static/js/chart.umd.min.js (and script if changed).

Checklist

  • [ ] Run uv run python scripts/download_vendor_assets.py all so app/static/js/chart.umd.min.js exists.
  • [ ] Templates use url_for('static', filename='js/chart.umd.min.js') (no CDN).
  • [ ] Commit the vendor file so CI and production serve it without network.