Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for JS modules (+module for URLs handling) #1463

Merged
merged 10 commits into from
Jan 15, 2024

Conversation

almet
Copy link
Member

@almet almet commented Dec 13, 2023

This is a test for how we could use JS modules in uMap.

Because modules are not used everywhere, we need to bind the loaded modules to window fr now. Also, the mocha test runner needs to be run inside a server, to avoid CORS limitations for local file systems.

I'm not really sure it's the direction we should take, but I hope it could bring good discussions :-)

<script type="text/javascript">
let MAP = new L.U.Map("map", {{ map_settings|notag|safe }})
<script defer type="text/javascript">
window.addEventListener('load', (event) => {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had to add this, otherwise the objects wouldn't be exported to window.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I understand:

  • defer will not work for local script (i.e. without a src attribute)
  • module type scripts are executed in defer mode, which means after the DOM is ready

I guess this explain why you needed the load event here. Maybe we could use DomContentLoaded instead ?

One other option to consider (but not for this PR I'd say), is to have a dedicated script (/map/xxxx/load.js), which could then make it work in defer mode, and could be an elegant way for other people to include a uMap map in their HTML ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting, defer is not useful here then. DomContentLoaded seems the way (if it works), and will allow us to run the script without having to wait for other resources to be ready (images, etc).

@almet almet force-pushed the almet/js/client-routing branch 4 times, most recently from 146f040 to e124b3f Compare December 15, 2023 10:34
Copy link

@vinyll vinyll left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to pretend I know 🤓

umap/static/umap/js/bindModules.mjs Outdated Show resolved Hide resolved
umap/static/umap/js/modules/urls.mjs Outdated Show resolved Hide resolved
umap/static/umap/js/modules/urls.mjs Outdated Show resolved Hide resolved
umap/static/umap/js/modules/urls.mjs Outdated Show resolved Hide resolved
umap/static/umap/js/modules/urls.mjs Outdated Show resolved Hide resolved
umap/static/umap/js/umap.js Outdated Show resolved Hide resolved
umap/static/umap/js/umap.layer.js Outdated Show resolved Hide resolved
umap/static/umap/test/URLs.mjs Outdated Show resolved Hide resolved
umap/static/umap/test/URLs.mjs Outdated Show resolved Hide resolved
umap/static/umap/test/URLs.mjs Outdated Show resolved Hide resolved
@almet almet force-pushed the almet/js/client-routing branch 3 times, most recently from f65b49c to c782a69 Compare December 15, 2023 15:32
@almet almet changed the title [refactor] Use JS modules for client URL routing refactor: Use JS modules for client URL routing Dec 16, 2023
@yohanboniface
Copy link
Member

Great work, thanks!
I'm fine with the direction and the implementation. Though, for this to be merged, I've two concerns:

  • it seems to me that we are loading twice the Leaflet code, I think this is a no go (but I may miss something)
  • the event listener on "load" seems weird to me, I wonder which impacts this can have and if there isn't a "better" way to deal with the initial issue

About loading Leaflet twice, I guess the only way to prevent this is to make a full switch, and loading only the esm version. So that would mean either:

  • changing all Leaflet usage to switch to importing module
  • reexposing "manually" a global L with all the needed property, until the full switch is done

Given the later is more gradual and we use a lot of plugins we do not control, I'd be in favor of the second option.

Thoughts ?

@yohanboniface
Copy link
Member

WIP of plugin status:

plugin importable last commit maintainers
leaflet-contextmenu no 4 years ago others
leaflet-editable no last year Leaflet
leaflet-editinosm no 5 years ago us
leaflet-formbuilder no last month us
leaflet-fullscreen no 5 years ago Leaflet
leaflet-hash no 10 years ago others
leaflet-i18n no 4 months ago us
leaflet-iconlayers no 5 years ago others
leaflet-loading no 2 years ago others
leaflet-measurable no 8 months ago us
leaflet-minimap no 4 years ago others
leaflet-toolbar no 5 years ago Leaflet
leaflet.heat no 2 months ago Leaflet
leaflet.locatecontrol no 2 months ago others
leaflet.markercluster no 7 months ago Leaflet
leaflet.path.drag no 6 years ago Leaflet
leaflet.photon no 5 days ago us

@yohanboniface
Copy link
Member

This are the L. properties expected by uMap code (not the plugins; some properties of the list do not come from Leaflet but from some plugins OR from uMap itself):

{'L.Bounds',
 'L.Browser',
 'L.Control',
 'L.DomEvent',
 'L.DomUtil',
 'L.Editable',
 'L.FeatureGroup',
 'L.FormBuilder',
 'L.GeoJSON',
 'L.GeoUtil',
 'L.HeatLayer',
 'L.Icon',
 'L.LatLng',
 'L.LineUtil',
 'L.Map',
 'L.Marker',
 'L.MarkerCluster',
 'L.MarkerClusterGroup',
 'L.MeasureControl',
 'L.Path',
 'L.PhotonSearch',
 'L.Point',
 'L.Polygon',
 'L.Polyline',
 'L.Popup',
 'L.TileLayer',
 'L.Toolbar',
 'L.ToolbarAction',
 'L.U',
 'L.UmapSingleton',
 'L.Util',
 'L._',
 'L.bind',
 'L.control',
 'L.createObjectURL',
 'L.extend',
 'L.lang',
 'L.latLng',
 'L.latLngBounds',
 'L.locale',
 'L.setLocale',
 'L.setOptions',
 'L.stamp',
 'L.svg'}

@yohanboniface
Copy link
Member

And here is the full list, including those expected/set by the plugins:

{'L.Bounds',
 'L.Browser',
 'L.Canvas',
 'L.Circle',
 'L.Class',
 'L.Control',
 'L.DistanceGrid',
 'L.DivIcon',
 'L.DomEvent',
 'L.DomUtil',
 'L.Draggable',
 'L.Editable',
 'L.Evented',
 'L.FeatureGroup',
 'L.FormBuilder',
 'L.GeoJSON',
 'L.GeoUtil',
 'L.Handler',
 'L.Hash',
 'L.HeatLayer',
 'L.Icon',
 'L.LatLng',
 'L.LatLngBounds',
 'L.LayerGroup',
 'L.LineUtil',
 'L.Map',
 'L.Marker',
 'L.MarkerCluster',
 'L.MarkerClusterGroup',
 'L.MarkerClusterNonAnimated',
 'L.Measurable',
 'L.MeasureControl',
 'L.MeasureLine',
 'L.MeasureVertex',
 'L.Mixin',
 'L.Path',
 'L.PathDraggable',
 'L.PhotonBase',
 'L.PhotonBaseSearch',
 'L.PhotonReverse',
 'L.PhotonSearch',
 'L.Point',
 'L.Polygon',
 'L.Polyline',
 'L.Popup',
 'L.Projection',
 'L.QuickHull',
 'L.Rectangle',
 'L.TileLayer',
 'L.Toolbar',
 'L.ToolbarAction',
 'L.U',
 'L.UmapSingleton',
 'L.Util',
 'L._',
 'L.bind',
 'L.control',
 'L.createObjectURL',
 'L.extend',
 'L.featureGroup',
 'L.hash',
 'L.i18n',
 'L.lang',
 'L.latLng',
 'L.latLngBounds',
 'L.locale',
 'L.locales',
 'L.map',
 'L.markerClusterGroup',
 'L.point',
 'L.polyline',
 'L.prototype',
 'L.rectangle',
 'L.registerLocale',
 'L.setLocale',
 'L.setOptions',
 'L.stamp',
 'L.svg',
 'L.toolbar',
 'L.toolbarAction'}

@yohanboniface
Copy link
Member

yohanboniface commented Dec 29, 2023

Properties set by plugins

Leaflet.MarkerCluster

  • L.DistanceGrid
  • L.MarkerCluster
  • L.MarkerClusterGroup
  • L.MarkerClusterNonAnimated
  • L.QuickHull
  • L.markerClusterGroup

Leaflet.Editable

  • L.Editable

Leaflet.FormBuilder

  • L.FormBuilder

Leaflet.Hash

  • L.Hash
  • L.hash

Leaflet.Heat

  • L.HeatLayer

Leaflet.Measurable

  • L.Measurable
  • L.MeasureControl
  • L.MeasureLine
  • L.MeasureVertex
  • L.GeoUtil

leaflet.path.drag

  • L.PathDraggable

Leaflet.Photon

  • L.PhotonBase
  • L.PhotonBaseSearch
  • L.PhotonReverse
  • L.PhotonSearch

Leaflet.Toolbar

  • L.Toolbar
  • L.ToolbarAction
  • L.toolbar
  • L.toolbarActio

uMap

  • L.U
  • L.UmapSingleton
  • L.lang

Leaflet.i18n

  • L._
  • L.i18n
  • L.locale
  • L.locales
  • L.registerLocale
  • L.setLocale

Properties from Leaflet

{
 'L.Bounds',
 'L.Browser',
 'L.Canvas',
 'L.Circle',
 'L.Class',
 'L.Control',
 'L.DivIcon',
 'L.DomEvent',
 'L.DomUtil',
 'L.Draggable',
 'L.Evented',
 'L.FeatureGroup',
 'L.GeoJSON',
 'L.Handler',
 'L.Icon',
 'L.LatLng',
 'L.LatLngBounds',
 'L.LayerGroup',
 'L.LineUtil',
 'L.Map',
 'L.Marker',
 'L.Mixin',
 'L.Path',
 'L.Point',
 'L.Polygon',
 'L.Polyline',
 'L.Popup',
 'L.Projection',
 'L.Rectangle',
 'L.TileLayer',
 'L.Util',
 'L.bind',
 'L.control',
 'L.extend',
 'L.featureGroup',
 'L.latLng',
 'L.latLngBounds',
 'L.map',
 'L.point',
 'L.polyline',
 'L.rectangle',
 'L.setOptions',
 'L.stamp',
 'L.svg',
 }

So, with my understanding, I'm expecting that exposing the global L plus all those properties before loading umap and plugins files should work.

(Weird, it seems that this is the second comment that is created when I click on preview then write again…)

@yohanboniface
Copy link
Member

It is not that simple: a type=module script is loaded asynchronously, so it cannot expose the L. (and properties) before classic script will need it.

@@ -0,0 +1,29 @@
import { Util } from './vendors.js'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not fan of this import, as we lose the origin of the Util variable in the process.

I'd suggest, either:

  • loading Util (and such) from path/to/leaflet.esm.js everywhere
  • exposing namespace in vendors, not variables; so one would type import L from './vendors and then use L.Util, just like in classic mode

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, I like the second one better, and I agree 👍

Copy link
Contributor

@davidbgk davidbgk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did we check that it still works fine with embedded maps?

umap/templates/umap/map_init.html Outdated Show resolved Hide resolved
umap/templates/umap/map_init.html Show resolved Hide resolved
Set a umap-fragment web component for lists
@yohanboniface
Copy link
Member

It seems we need to better escape the settings (" in the description that makes the HTML invalid):

<umap-fragment data-settings="{&quot;type&quot;: &quot;Feature&quot;, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [6.173458099365235, 49.114866157159355]}, &quot;properties&quot;: {&quot;name&quot;: &quot;Diaporama des arbres remarquables \u00e0 Metz&quot;, &quot;zoom&quot;: 14, &quot;easing&quot;: false, &quot;zoomTo&quot;: 19, &quot;licence&quot;: &quot;&quot;, &quot;miniMap&quot;: false, &quot;overlay&quot;: null, &quot;showLabel&quot;: true, &quot;slideshow&quot;: {}, &quot;tilelayer&quot;: {&quot;tms&quot;: false, &quot;name&quot;: &quot;OSM-eu&quot;, &quot;maxZoom&quot;: 18, &quot;minZoom&quot;: 0, &quot;attribution&quot;: &quot;Map data ODbL © OSM contributors / tiles CC-by-SA © OSM-FR&quot;, &quot;url_template&quot;: &quot;https://tile.openstreetmap.bzh/eu/{z}/{x}/{y}.png&quot;}, &quot;captionBar&quot;: false, &quot;longCredit&quot;: &quot;&quot;, &quot;popupShape&quot;: &quot;Default&quot;, &quot;description&quot;: &quot;Cette carte en cours de r\u00e9alisation int\u00e8gre \n- Le fichier des arbres remarquables d\u00e9pos\u00e9 par Metz M\u00e9tropole en open data sur le portail [[https://www.data.gouv.fr/fr/organizations/metz-metropole/|data.gouv.fr]]\n- Des images des [[https://archives.metz.fr|Archives de la Ville de Metz]]\n(autorisation sans utilisation commerciale)\n- Des photographies et films personnels\n\n- Cette carte est pr\u00e9sent\u00e9e sur \n[[https://insidemap.eu/faire-sa-carte-diaporama-darbre-en-arbre-a-metz/|Insidemap.eu]]\n- Pour suivre sa fabrication, avec vinber et cartograf, voir l" excellent="" forum="" d'osm="" :\n[[http:="" forum.openstreetmap.fr="" viewtopic.php?t="7094|Tuto" de="" diaporama="" pour="" umap="" ?]]\n\n*seul="" un="" calque="" est="" compl\u00e9t\u00e9*="" :="" celui="" les="" arbres="" remarquables="" jardin="" des="" r\u00e9gates="" -="" boufflers="" et="" square="" giraud.="" en="" jaune="" pas="" encore="" photographie="" ni="" film.="" \n\n**un="" sujet="" d'actualit\u00e9**="" \nenvoy\u00e9="" sp\u00e9cial.="" le="" secret="" \n{{{https:="" youtube.com="" embed="" eh6rnaqspto}}}\n\n\n\n\n",="" "limitbounds":="" {},="" "morecontrol":="" true,="" "onloadpanel":="" "none",="" "zoomcontrol":="" "captionmenus":="" "embedcontrol":="" "scalecontrol":="" "searchcontrol":="" "measurecontrol":="" "scrollwheelzoom":="" false,="" "datalayerscontrol":="" "fullscreencontrol":="" "tilelayerscontrol":="" "displaypopupfooter":="" "popupcontenttemplate":="" "#="" {name}\n{description}",="" "permanentcreditbackground":="" "tilelayers":="" [{"id":="" 1,="" "name":="" "positron",="" "url_template":="" "https:="" cartodb-basemaps-{s}.global.ssl.fastly.net="" light_all="" {z}="" {x}="" {y}.png",="" "minzoom":="" 0,="" "maxzoom":="" 18,="" "attribution":="" "&copy;="" [[http:="" www.openstreetmap.org="" copyright|openstreetmap]]="" contributors,="" &copy;="" [[https:="" carto.com="" attributions|carto]]",="" "rank":="" "tms":="" false}],="" "datalayers":="" [{"name":="" "calque="" 1",="" "editmode":="" "disabled",="" "browsable":="" "incaption":="" "displayonload":="" "id":="" 42,="" "permissions":="" {"edit_status":="" 0}},="" {"name":="" "c="" botanique",="" "color":="" "cadetblue",="" "iconclass":="" "drop",="" "popupshape":="" "panel",="" "remotedata":="" 43,="" "b="" epars="" (\u00e0="" d\u00e9sactiver)",="" 44,="" (en="" cours)",="" 45,="" "a="" citadelle="" hypercentre",="" "showlabel":="" 46,="" 0}}],="" "urls":="" {"map_short_url":="" "="" m="" {pk}="" ",="" "ajax-proxy":="" ajax-proxy="" "password_change":="" change-password="" "password_change_done":="" change-password-done="" "map_download":="" map="" {map_id}="" download="" "stats":="" stats="" "login":="" fr="" login="" "login_popup_end":="" popup="" end="" "logout":="" logout="" "map_geojson":="" geojson="" "map_anonymous_edit_url":="" anonymous-edit="" {signature}",="" "pictogram_list_json":="" pictogram="" json="" "datalayer_view":="" datalayer="" "datalayer_versions":="" versions="" "datalayer_version":="" {name}",="" "map":="" {slug}_{map_id}",="" "map_new":="" new="" "map_create":="" create="" "map_star":="" star="" "user_dashboard":="" me",="" "user_profile":="" me="" profile",="" "map_update":="" update="" settings="" "map_update_permissions":="" permissions="" "map_attach_owner":="" owner="" "map_delete":="" delete="" "map_clone":="" clone="" "datalayer_create":="" "datalayer_delete":="" "datalayer_permissions":="" "map_send_edit_link":="" send-edit-link="" "datalayer_update":="" "routing":="" "http:="" directions?engine="osrm_car&amp;route={lat},{lng}&amp;locale={locale}#map={zoom}/{lat}/{lng}&quot;," "ajax_proxy":="" ?url="{url}&amp;ttl={ttl}&quot;," "search":="" photon.komoot.io="" api="" ?"},="" "static_url":="" static="" "hash":="" "attributioncontrol":="" "umapattributioncontrol":="" "nocontrol":="" "umap_id":="" 10,="" "default_iconurl":="" img="" marker.png",="" "prefix":="" "",="" "page":="" "2"}}'="">
  <div id="map2_10" class="map_fragment"></div>
</umap-fragment>

@almet almet changed the title refactor: Use JS modules for client URL routing refactor: Add support for JS modules (and refactor client URL routing in a separate class) Jan 15, 2024
@almet almet changed the title refactor: Add support for JS modules (and refactor client URL routing in a separate class) refactor: Add support for JS modules (+module for URLs handling) Jan 15, 2024
@almet almet changed the title refactor: Add support for JS modules (+module for URLs handling) Add support for JS modules (+module for URLs handling) Jan 15, 2024
@almet
Copy link
Member Author

almet commented Jan 15, 2024

To me we're ready to introduce these changes!

@yohanboniface yohanboniface merged commit 9054d35 into master Jan 15, 2024
12 checks passed
@yohanboniface yohanboniface deleted the almet/js/client-routing branch January 15, 2024 13:46
@yohanboniface
Copy link
Member

🎉 💣 🚀

@davidbgk
Copy link
Contributor

Maybe we need a release with just that change 😅 😇

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants