Repository navigation
Serve UI assets from FlexMeasures instead of CDNs - #2711
Conversation
Loading them from CDNs breaks the UI on poor or no internet connections. FlexMeasures moved to CDNs in FlexMeasures#21 as a small speed tweak, to be revisited if CDNs ever failed. BREAKING CHANGE: FLEXMEASURES_JS_VERSIONS no longer has a default and is ignored, so plugins must read the js_versions template variable or flexmeasures.ui.utils.vendor_versions.JS_VERSIONS instead. Refs FlexMeasures#18 Signed-off-by: Stijn van Houwelingen <teadrinkingprogrammer@proton.me>
Signed-off-by: Stijn van Houwelingen <teadrinkingprogrammer@proton.me>
Documentation build overview
27 files changed ·
|
Signed-off-by: Stijn van Houwelingen <teadrinkingprogrammer@proton.me>
|
Thanks for this, @TeaDrinkingProgrammer! Before we go further, I opened #2718 to discuss how we want to ship these libraries in the long run. The macros, |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl>
…ir licences The icons have no fixed release to fetch from, as Iconify renders them on request, so they stay committed under static/icons/. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl>
…their files and hashes Instead of committing ~5 MB of third-party files, record each library's version, files and SHA-256 hashes in flexmeasures/ui/utils/vendor_assets.py. Running python -m flexmeasures.ui.utils.fetch_vendor_assets downloads them, with their licences, and checks each file against its hash. Fetched files are served by FlexMeasures, and files that were not fetched load from their CDN, with the recorded hash as the tag's integrity attribute. Fonts and images which flexmeasures.css referred to move into the vendor.html macros, since a static stylesheet cannot tell whether they were fetched. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl>
… them Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl>
… on one line Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl>
|
Hi @TeaDrinkingProgrammer, following #2718, where @nhoening and I agreed on fetching the libraries from a manifest with a CDN fallback (option B), I pushed a rework of this PR on top of your commits. A lot of your work carried over unchanged: the What changed
How I checked it
Follow-ups, stacked on this branch:
|
…ource copy in the Docker build Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl>
…rsions of the UI's libraries, optionally with the hashes of their files Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl> # Conflicts: # flexmeasures/ui/utils/vendor_assets.py
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl> # Conflicts: # documentation/changelog.rst
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl>
|
@TeaDrinkingProgrammer, one more change: we'd like hosts to keep the option of loading other versions, so How the setting works now
The configuration docs describe the forms, and I updated the changelog entry. I checked it end to end against the CDNs, overriding Vega and Leaflet with hashes and D3 without, and every new test fails when the behaviour it covers is broken. One more follow-up, stacked on this branch: #2746 has FlexMeasures fetch missing library files itself, in the background after the first request a web process serves. Hosts then no longer need to run the command after each upgrade. As before, if you'd rather go another way, please say so on #2718. |
Flix6x
left a comment
There was a problem hiding this comment.
Thanks for this. It was about time we revisited this.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl>
* feat!: serve UI assets from FlexMeasures, not CDNs Loading them from CDNs breaks the UI on poor or no internet connections. FlexMeasures moved to CDNs in #21 as a small speed tweak, to be revisited if CDNs ever failed. BREAKING CHANGE: FLEXMEASURES_JS_VERSIONS no longer has a default and is ignored, so plugins must read the js_versions template variable or flexmeasures.ui.utils.vendor_versions.JS_VERSIONS instead. Refs #18 Signed-off-by: Stijn van Houwelingen <teadrinkingprogrammer@proton.me> * feat: serve asset type icons locally Signed-off-by: Stijn van Houwelingen <teadrinkingprogrammer@proton.me> * docs: link PR #2711 in the changelog entry Signed-off-by: Stijn van Houwelingen <teadrinkingprogrammer@proton.me> * Keep the asset type icons apart from the vendored libraries, with their licences The icons have no fixed release to fetch from, as Iconify renders them on request, so they stay committed under static/icons/. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl> * Load the UI's libraries from CDNs unless fetched, from a manifest of their files and hashes Instead of committing ~5 MB of third-party files, record each library's version, files and SHA-256 hashes in flexmeasures/ui/utils/vendor_assets.py. Running python -m flexmeasures.ui.utils.fetch_vendor_assets downloads them, with their licences, and checks each file against its hash. Fetched files are served by FlexMeasures, and files that were not fetched load from their CDN, with the recorded hash as the tag's integrity attribute. Fonts and images which flexmeasures.css referred to move into the vendor.html macros, since a static stylesheet cannot tell whether they were fetched. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl> * Fetch the UI's libraries into the Docker image, and check that it has them Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl> * Document how to serve the UI's libraries without internet access Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl> * Upgrade Vega to 5.33.1, the latest 5.x release Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl> * Put the comment on VendorLibrary.name above it, where black leaves it on one line Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl> * Add a changelog entry for the Vega upgrade Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl> * Fetch the UI's libraries into the installed package rather than the source copy in the Docker build Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl> * Keep the FLEXMEASURES_JS_VERSIONS setting, so hosts can load other versions of the UI's libraries, optionally with the hashes of their files Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl> --------- Signed-off-by: Stijn van Houwelingen <teadrinkingprogrammer@proton.me> Signed-off-by: F.N. Claessen <felix@seita.nl> Co-authored-by: Stijn van Houwelingen <teadrinkingprogrammer@proton.me> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* feat!: serve UI assets from FlexMeasures, not CDNs Loading them from CDNs breaks the UI on poor or no internet connections. FlexMeasures moved to CDNs in #21 as a small speed tweak, to be revisited if CDNs ever failed. BREAKING CHANGE: FLEXMEASURES_JS_VERSIONS no longer has a default and is ignored, so plugins must read the js_versions template variable or flexmeasures.ui.utils.vendor_versions.JS_VERSIONS instead. Refs #18 Signed-off-by: Stijn van Houwelingen <teadrinkingprogrammer@proton.me> * feat: serve asset type icons locally Signed-off-by: Stijn van Houwelingen <teadrinkingprogrammer@proton.me> * docs: link PR #2711 in the changelog entry Signed-off-by: Stijn van Houwelingen <teadrinkingprogrammer@proton.me> * Keep the asset type icons apart from the vendored libraries, with their licences The icons have no fixed release to fetch from, as Iconify renders them on request, so they stay committed under static/icons/. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl> * Load the UI's libraries from CDNs unless fetched, from a manifest of their files and hashes Instead of committing ~5 MB of third-party files, record each library's version, files and SHA-256 hashes in flexmeasures/ui/utils/vendor_assets.py. Running python -m flexmeasures.ui.utils.fetch_vendor_assets downloads them, with their licences, and checks each file against its hash. Fetched files are served by FlexMeasures, and files that were not fetched load from their CDN, with the recorded hash as the tag's integrity attribute. Fonts and images which flexmeasures.css referred to move into the vendor.html macros, since a static stylesheet cannot tell whether they were fetched. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl> * Fetch the UI's libraries into the Docker image, and check that it has them Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl> * Document how to serve the UI's libraries without internet access Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl> * Put the comment on VendorLibrary.name above it, where black leaves it on one line Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl> * Upgrade DataTables to 1.13.11, the latest 1.x release, and draw its sorting arrows like before DataTables 1.13 draws its sorting arrows as glyphs, rather than with the PNG icons which it no longer ships. Style and place them like those icons were, and keep its new header border from showing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl> * Add a changelog entry for the DataTables upgrade Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl> * Fetch the UI's libraries into the installed package rather than the source copy in the Docker build Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl> * Keep the FLEXMEASURES_JS_VERSIONS setting, so hosts can load other versions of the UI's libraries, optionally with the hashes of their files Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl> --------- Signed-off-by: Stijn van Houwelingen <teadrinkingprogrammer@proton.me> Signed-off-by: F.N. Claessen <felix@seita.nl> Co-authored-by: Stijn van Houwelingen <teadrinkingprogrammer@proton.me> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* feat!: serve UI assets from FlexMeasures, not CDNs Loading them from CDNs breaks the UI on poor or no internet connections. FlexMeasures moved to CDNs in #21 as a small speed tweak, to be revisited if CDNs ever failed. BREAKING CHANGE: FLEXMEASURES_JS_VERSIONS no longer has a default and is ignored, so plugins must read the js_versions template variable or flexmeasures.ui.utils.vendor_versions.JS_VERSIONS instead. Refs #18 Signed-off-by: Stijn van Houwelingen <teadrinkingprogrammer@proton.me> * feat: serve asset type icons locally Signed-off-by: Stijn van Houwelingen <teadrinkingprogrammer@proton.me> * docs: link PR #2711 in the changelog entry Signed-off-by: Stijn van Houwelingen <teadrinkingprogrammer@proton.me> * Keep the asset type icons apart from the vendored libraries, with their licences The icons have no fixed release to fetch from, as Iconify renders them on request, so they stay committed under static/icons/. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl> * Load the UI's libraries from CDNs unless fetched, from a manifest of their files and hashes Instead of committing ~5 MB of third-party files, record each library's version, files and SHA-256 hashes in flexmeasures/ui/utils/vendor_assets.py. Running python -m flexmeasures.ui.utils.fetch_vendor_assets downloads them, with their licences, and checks each file against its hash. Fetched files are served by FlexMeasures, and files that were not fetched load from their CDN, with the recorded hash as the tag's integrity attribute. Fonts and images which flexmeasures.css referred to move into the vendor.html macros, since a static stylesheet cannot tell whether they were fetched. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl> * Fetch the UI's libraries into the Docker image, and check that it has them Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl> * Document how to serve the UI's libraries without internet access Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl> * Check the UI's libraries for known advisories every week Dependabot only reads uv.lock, so it does not know about the UI's third-party libraries. A scheduled workflow now looks up each library's npm package and version in the OSV database, and fails when one has an advisory, listing them in the job summary. It also runs on pull requests that change the libraries. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl> * Ignore the ECharts advisory, which only affects a series type that FlexMeasures does not use Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl> * Put the comment on VendorLibrary.name above it, where black leaves it on one line Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl> * Fetch the UI's libraries into the installed package rather than the source copy in the Docker build Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl> * Keep the FLEXMEASURES_JS_VERSIONS setting, so hosts can load other versions of the UI's libraries, optionally with the hashes of their files Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl> --------- Signed-off-by: Stijn van Houwelingen <teadrinkingprogrammer@proton.me> Signed-off-by: F.N. Claessen <felix@seita.nl> Co-authored-by: Stijn van Houwelingen <teadrinkingprogrammer@proton.me> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…ommand after each upgrade (#2746) * feat!: serve UI assets from FlexMeasures, not CDNs Loading them from CDNs breaks the UI on poor or no internet connections. FlexMeasures moved to CDNs in #21 as a small speed tweak, to be revisited if CDNs ever failed. BREAKING CHANGE: FLEXMEASURES_JS_VERSIONS no longer has a default and is ignored, so plugins must read the js_versions template variable or flexmeasures.ui.utils.vendor_versions.JS_VERSIONS instead. Refs #18 Signed-off-by: Stijn van Houwelingen <teadrinkingprogrammer@proton.me> * feat: serve asset type icons locally Signed-off-by: Stijn van Houwelingen <teadrinkingprogrammer@proton.me> * docs: link PR #2711 in the changelog entry Signed-off-by: Stijn van Houwelingen <teadrinkingprogrammer@proton.me> * Keep the asset type icons apart from the vendored libraries, with their licences The icons have no fixed release to fetch from, as Iconify renders them on request, so they stay committed under static/icons/. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl> * Load the UI's libraries from CDNs unless fetched, from a manifest of their files and hashes Instead of committing ~5 MB of third-party files, record each library's version, files and SHA-256 hashes in flexmeasures/ui/utils/vendor_assets.py. Running python -m flexmeasures.ui.utils.fetch_vendor_assets downloads them, with their licences, and checks each file against its hash. Fetched files are served by FlexMeasures, and files that were not fetched load from their CDN, with the recorded hash as the tag's integrity attribute. Fonts and images which flexmeasures.css referred to move into the vendor.html macros, since a static stylesheet cannot tell whether they were fetched. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl> * Fetch the UI's libraries into the Docker image, and check that it has them Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl> * Document how to serve the UI's libraries without internet access Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl> * Put the comment on VendorLibrary.name above it, where black leaves it on one line Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl> * Fetch the UI's libraries into the installed package rather than the source copy in the Docker build Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl> * Keep the FLEXMEASURES_JS_VERSIONS setting, so hosts can load other versions of the UI's libraries, optionally with the hashes of their files Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl> * Fetch the UI's missing library files in the background once a web process serves its first request Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl> * Add a changelog entry for fetching the UI's libraries in the background Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bawYg67N5T5csiFdwWgZ1 Signed-off-by: F.N. Claessen <felix@seita.nl> --------- Signed-off-by: Stijn van Houwelingen <teadrinkingprogrammer@proton.me> Signed-off-by: F.N. Claessen <felix@seita.nl> Co-authored-by: Stijn van Houwelingen <teadrinkingprogrammer@proton.me> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Description
At the LF Energy summit, @nicburgt ran into the FlexMeasures UI breaking during demos on the spotty wifi: missing styles, tables and charts not rendering (flexmeasures-openadr3#4). The cause: the UI loads almost all of its frontend libraries from CDNs (jsdelivr, unpkg, cdnjs, cdn.datatables.net, ajax.aspnetcdn.com, d3js.org), plus its font from Google Fonts and its logo from artwork.lfenergy.org. The same goes for anyone running FlexMeasures without (reliable) internet access.
We moved to CDNs in #21 (issue #18) as "just a small speed tweak", explicitly open to revisiting "if someone reports a problem with CDNs failing". This is that report. The speed argument has also weakened since: browsers partition their HTTP cache per site, so a library cached by another site no longer helps.
I propose serving everything from FlexMeasures itself:
flexmeasures/ui/static/vendor/<lib>/<version>/, committed, so the wheel and Docker image ship them without a build step (about 5 MB).flexmeasures/ui/utils/vendor_versions.py, available in every template asjs_versions(now a Jinja global, so login and error pages get it too).templates/includes/vendor.htmlholds Jinja macros, the only place a third-party<script>/<link>is written. Templates call those.Cache-Control: max-age=31536000, immutable, since a new version gets a new path.SVG_ICON_MAPPINGare served locally too (separate commit, easy to drop if we'd rather not).While at it I cleaned up the versioning, which had drifted:
v6to 6.7.0, Litepicker to 2.0.12 (today's latest),echarts@5to 5.6.0.Breaking for plugins (the part I'm least happy with):
FLEXMEASURES_JS_VERSIONSis deprecated and ignored, with a warning if a host still sets it, and it no longer has a default. A plugin that readsconfig["FLEXMEASURES_JS_VERSIONS"]directly will get aKeyError. Plugin templates readingjs_versions.vegaetc. keep working, with the same keys.documentation/changelog.rstLook & Feel
Nothing should look different. The only visible changes are minor version alignments: the DataTables sort icons come from 1.10.22 instead of 1.10.0, and asset page maps run Leaflet 1.9.4 like the dashboard already did.
How to test
pytest flexmeasures/ui/tests/test_vendor_assets.py: checks that every vendored file is served, CSS font/image references resolve, no template or stylesheet points at an external host, the login page loads local assets, the deprecation warning fires, and versioned files are cached long.Further Improvements
static/vendor/README.md, or aLICENSESdirectory./ui/static/...), like some existing paths, so they break under a URL-prefix deployment.Related Items
Refs #18, #21. Came up in flexmeasures-openadr3#4.
Sign-off