Skip to content

Expose Leaflet global for UMD version only#9880

Closed
jonkoops wants to merge 1 commit into
Leaflet:mainfrom
jonkoops:no-global-esm
Closed

Expose Leaflet global for UMD version only#9880
jonkoops wants to merge 1 commit into
Leaflet:mainfrom
jonkoops:no-global-esm

Conversation

@jonkoops

Copy link
Copy Markdown
Collaborator

Changes the build so the Leaflet global (L) is only exposed for the UMD version of Leaflet. The exposing of the global, and the noConflict() mode, is now also handled fully by Rollup, instead of our own custom implementation. A bug where another global called leaflet was accidentally exposed (also present in v1.x), is now fixed.

Other notable changes:

  • In the ESM version, namespaces are now frozen, meaning extending Leaflet built-ins is no longer possible (e.g. L.Util.foo = 'bar';), the UMD version still allows this for backwards compatibility.
  • The code generated by Rollup is compatible with ES2015 and up, and no longer includes ES5 compatible code (just like Leaflet itself).
  • All relevant documentation and code referring to the Leaflet global has been migrated to exclusively use named imports.

Closes #9842

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull Request Overview

This PR modernizes Leaflet's build system to expose the global L variable only for UMD builds while exclusively using named imports for ESM versions. The changes include removing custom global handling code in favor of Rollup's built-in functionality, freezing namespaces in ESM builds to prevent extension, and updating all documentation and examples to use named imports instead of global references.

  • Removes custom global handling code and leverages Rollup's UMD output configuration
  • Updates all documentation examples and references to use named imports instead of global L references
  • Adds comprehensive test coverage for global variable exposure in UMD builds

Reviewed Changes

Copilot reviewed 60 out of 60 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/LeafletWithGlobals.js Completely removed custom global handling implementation
build/rollup-config.js Updated to use Rollup's built-in UMD global handling with noConflict option
spec/suites/core/GlobalSpec.js Added new test suite for global variable functionality
spec/suites/core/GeneralSpec.js Removed old namespace extension tests
Multiple documentation files Updated all examples to use named imports instead of global L references
spec/context.html Removed leaflet-bundle import mapping

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment thread docs/examples/accessibility/example.md
Comment thread docs/examples/overlays/example-video.md

@Falke-Design Falke-Design left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I’m not particularly fond of these changes, as they significantly alter the behavior of the current alpha and affect compatibility with the plugins.

I would only change applying L to globalThis. In my view, everything else should be kept (except for the docs changes L.)

Comment thread build/rollup-config.js
format: 'es',
banner,
sourcemap: true,
freeze: false

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why not keeping freeze: false?

Comment thread src/LeafletWithGlobals.js
import * as L from './Leaflet.js';
export * from './Leaflet.js';

export default L;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm not sure, but I would keep exporting L


<script type="module">
import L, {Map, TileLayer, Marker, Icon} from 'leaflet';
import {Map, TileLayer, Marker} from 'leaflet';

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I still would export L for "debugging" purpose

Comment on lines -19 to -20
globalThis.L = L; // only for debugging in the developer console
globalThis.map = map; // only for debugging in the developer console

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I want to keep this for debugging, as I added it explicitly for that purpose

@jonkoops

Copy link
Copy Markdown
Collaborator Author

Let's take this one at a time, otherwise we risk having a bunch of async discussion. Firstly, let's talk about the default L export, I am a firm believer we should get rid of it. It is a legacy that exists because historically, Leaflet was attached to a single global in a pre-module world. If we were to create a new library today, this would not be a pattern you'd see.

It also makes it significantly harder for tooling to do proper dead-code elimination trough tree-shaking, once the default import is consumed, it is no longer possible for a bundler such as WebPack or Vite to determine which parts of the module are used, so it must assume that all of them are used, meaning the entirety of Leaflet is bundled. Some other dead code elimination methods can still apply, but the initial pass cannot be used to shake out dead code.

I don't think the fact that we're currently shipping alphas should factor in whether API changes can still be made, that is what an alpha is for. Once we get to a release candidate phase, we should strive to no longer make any changes that could impact API stability.

@jonkoops

Copy link
Copy Markdown
Collaborator Author

In regard to tree-shaking, I also see a user already reported #9814 that confirms v2 in its current state is not tree-shakable.

Closes Leaflet#9842

Signed-off-by: Jon Koops <jonkoops@gmail.com>
@jonkoops jonkoops reopened this Sep 15, 2025
@Falke-Design

Copy link
Copy Markdown
Member

Firstly, let's talk about the default L export, I am a firm believer we should get rid of it. It is a legacy that exists because historically, Leaflet was attached to a single global in a pre-module world. If we were to create a new library today, this would not be a pattern you'd see.

Of course, the goal should be to remove the global L, but the number of users which are migrating to v2 will naturally decrease once we remove L. We are an old plugin with a large fan base, and we should not make it to hard for them.

It also makes it significantly harder for tooling to do proper dead-code elimination trough tree-shaking, once the default import is consumed, it is no longer possible for a bundler such as WebPack or Vite to determine which parts of the module are used, so it must assume that all of them are used, meaning the entirety of Leaflet is bundled. Some other dead code elimination methods can still apply, but the initial pass cannot be used to shake out dead code.

Tree Shaking is still possible if the bundler would accesses the build file without global L (if we are able to provide a UMD script with global L and a ESM script without L)

I don't think the fact that we're currently shipping alphas should factor in whether API changes can still be made, that is what an alpha is for. Once we get to a release candidate phase, we should strive to no longer make any changes that could impact API stability.

Sure, but I'm against removing something that users would expect us to provide, especially since I already informed them that we plan to make the release in November. We have enough time to remove these things in another major release.

@jonkoops

Copy link
Copy Markdown
Collaborator Author

Closing this PR, as it has too many conflicts. It could be used as a foundation for landing #10036

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.

Global L is exported via ESM

3 participants