Refine Mapbox scripts to modern ESM standards
Motivation
The mapbox scripts feel very heavy, and don't comply with modern coding standards, all we see is one big chunk of code, no matter the complexity, this should be functionally programmed, and the UI layer should be taken out for the controls.
Treeshaking needs to be made available.
Since we are stubbornly being ignored in a topic where people are basically begging for a solution and to reopen, I do it this way. It's not okay to simply ignore the people using your project, while there is obviously a lot of improvements possible.
Sometimes you need to rethink and reengineer for a moment to be able to move forward again.
#6320
+1
I tried the new Claude Sonnet 3.7 Thinking LLM with the problem, here are the result if it can be useful:
Reducing Bundle Size through ESM Migration
- Mapbox-GL: Reducing Bundle Size through ESM Migration
- Current Challenges
- Architecture Analysis
- Dependency Mapping Process
- 1. Static Analysis Tools: Use tools like Madge to generate dependency graphs
- Dependency Mapping Process
- ESM Migration Strategy
- 1. Module Structure Design
- 2. Export Management
- 3. Subpath Exports Configuration
- Modular Design Implementation
- 1. Feature Flag System
- 2. Lazy Loading Implementation
- 3. Plugin Architecture
- Build System Modernization
- 1. Build Pipeline Architecture
- 2. Build Configuration for Multiple Entry Points
- 3. Side-Effects Management
- Practical Implementation Path
- Phase 1: Analysis & Planning (1-2 months)
- Phase 2: Infrastructure Setup (2-4 weeks)
- Phase 3: Core Refactoring (2-3 months)
- Phase 4: Feature Modularization (3-4 months)
- Phase 5: Testing & Optimization (2-3 months)
- Backward Compatibility
- 1. Compatibility Layer
- 2. Version-Specific Imports
- 3. Feature Detection and Warnings
- Performance Monitoring
- 1. Bundle Size Tracking
- 2. Runtime Performance Tracking
- Community Engagement Strategy
- Example Migration Guide Section
- 1. Before
- 2. After
- Example Migration Guide Section
- Conclusion
Current Challenges
The Mapbox-GL library faces a critical issue: oversized builds that include unnecessary code for specific use cases. For instance, users who only need 2D map rendering capabilities are forced to include 3D rendering, advanced shader support, and other features they may never use.
The root causes of this problem are:
- Non-ESM Module Structure: The codebase doesn't leverage modern ESM standards
- Monolithic Architecture: Features are tightly coupled rather than modularized
- Limited Tree-Shaking: Current build tools cannot effectively eliminate unused code
- Single Entry Point: Limited options for partial imports of the library
Architecture Analysis
The first step is conducting a thorough architecture analysis to understand dependencies and identify modularization opportunities.
flowchart TD
subgraph Core["Core (Essential)"]
A[Map Rendering Engine]
B[Projection Systems]
C[Event System]
D[Basic UI Controls]
end
subgraph Features["Feature Modules"]
E[2D Rendering]
F[3D Rendering]
G[Advanced Shaders]
H[Animation System]
I[Interaction Handlers]
J[Data Processing]
K[Performance Optimizations]
end
subgraph Optional["Optional Components"]
L[Custom Layers]
M[Advanced Styling]
N[External Data Sources]
O[Terrain Rendering]
P[Globe View]
end
A --> B
A --> C
A --> E
A --> F
E --> G
F --> G
F --> O
F --> P
H --> E
H --> F
I --> C
J --> E
J --> F
K --> A
L --> A
M --> E
M --> F
N --> J
Dependency Mapping Process
1. Static Analysis Tools: Use tools like Madge to generate dependency graphs
Show summary
➜ mapbox-gl-js git:(main) ✗ madge ./src/** --extensions ts --summary
Processed 586 files (5.9s) (26 warnings)
94 shaders/shaders.ts
66 render/painter.ts
65 style/style.ts
56 ui/map.ts
49 terrain/terrain.ts
48 source/tile.ts
43 data/bucket/symbol_bucket.ts
41 index.ts
34 data/bucket/fill_extrusion_bucket.ts
32 data/bucket/line_bucket.ts
31 source/worker_tile.ts
30 style-spec/expression/definitions/index.ts
29 style-spec/validate/validate.ts
28 ../3d-style/render/draw_model.ts
26 ../3d-style/render/shadow_renderer.ts
26 render/draw_symbol.ts
26 source/image_source.ts
25 render/draw_fill_extrusion.ts
24 data/bucket/circle_bucket.ts
24 data/bucket/fill_bucket.ts
24 data/feature_index.ts
24 render/draw_raster_particle.ts
24 render/program/program_uniforms.ts
24 style-spec/expression/index.ts
23 ../3d-style/data/bucket/model_bucket.ts
23 ../3d-style/data/bucket/tiled_3d_model_bucket.ts
23 data/program_configuration.ts
23 symbol/symbol_layout.ts
22 source/source.ts
22 ui/handler_manager.ts
21 geo/transform.ts
21 render/draw_raster.ts
21 source/vector_tile_source.ts
21 source/worker.ts
21 style/style_layer/symbol_style_layer.ts
20 render/program.ts
20 style/style_layer/circle_style_layer.ts
20 style/style_layer/heatmap_style_layer.ts
20 style/style_layer/line_style_layer.ts
20 symbol/placement.ts
20 terrain/draw_terrain_raster.ts
19 ../3d-style/style/style_layer/model_style_layer.ts
19 render/draw_atmosphere.ts
19 source/worker_source.ts
19 style/create_style_layer.ts
19 style/style_layer.ts
18 ../3d-style/data/model.ts
18 render/draw_circle.ts
18 source/raster_tile_source.ts
18 source/source_cache.ts
18 style-spec/style-spec.ts
18 ui/camera.ts
17 ../3d-style/source/tiled_3d_model_source.ts
17 geo/projection/globe_util.ts
17 render/draw_line.ts
17 style/fog.ts
16 render/draw_collision_debug.ts
16 render/draw_heatmap.ts
16 source/geojson_source.ts
16 style-spec/expression/parsing_context.ts
16 style/style_layer/fill_extrusion_style_layer.ts
15 ../3d-style/source/tiled_3d_model_worker_source.ts
15 data/bucket.ts
15 data/bucket/clip_bucket.ts
15 precipitation/draw_rain.ts
15 render/image_manager.ts
15 source/raster_array_tile_source.ts
15 style-spec/validate_style.min.ts
15 style/style_layer/fill_style_layer.ts
14 precipitation/draw_snow.ts
14 source/raster_dem_tile_source.ts
14 style/query_geometry.ts
13 geo/projection/globe.ts
13 gl/context.ts
13 render/draw_fill.ts
13 render/draw_hillshade.ts
13 render/draw_sky.ts
13 symbol/collision_index.ts
12 render/draw_debug.ts
12 style/style_layer/raster_particle_style_layer.ts
12 style/style_layer/sky_style_layer.ts
12 symbol/quads.ts
12 ui/marker.ts
12 util/mapbox.ts
11 ../3d-style/source/model_source.ts
11 geo/projection/index.ts
11 precipitation/vignette.ts
11 source/custom_source.ts
11 source/geojson_worker_source.ts
11 source/source_types.ts
11 style-spec/expression/definitions/coercion.ts
11 style-spec/validate/validate_source.ts
11 style/rain.ts
11 style/snow.ts
11 symbol/shaping.ts
11 ui/popup.ts
11 util/web_worker_transfer.ts
10 ../3d-style/source/model_loader.ts
10 ../3d-style/util/model_util.ts
10 render/draw_background.ts
10 render/program/hillshade_program.ts
10 source/building_index.ts
10 source/query_features.ts
10 source/vector_tile_worker_source.ts
10 style-spec/expression/definitions/interpolate.ts
10 style-spec/function/index.ts
10 style/pauseable_placement.ts
10 style/properties.ts
10 style/style_layer/raster_style_layer.ts
10 ui/control/geolocate_control.ts
9 ../3d-style/util/loaders.ts
9 render/draw_custom.ts
9 render/glyph_manager.ts
9 render/program/background_program.ts
9 render/program/circle_program.ts
9 render/program/heatmap_program.ts
9 render/program/line_program.ts
9 render/raster_particle_state.ts
9 source/raster_array_tile.ts
9 style-spec/validate/validate_function.ts
9 style-spec/validate/validate_layer.ts
9 style/light.ts
9 symbol/projection.ts
8 ../3d-style/render/model_manager.ts
8 geo/projection/projection.ts
8 precipitation/common.ts
8 render/image_rasterizer.ts
8 render/program/fill_extrusion_program.ts
8 render/program/symbol_program.ts
8 source/load_tilejson.ts
8 source/video_source.ts
8 style-spec/expression/definitions/config.ts
8 style-spec/expression/definitions/distance.ts
8 style-spec/validate/validate_filter.ts
8 style-spec/validate/validate_property.ts
8 style/style_layer/clip_style_layer.ts
8 style/style_layer/typed_style_layer.ts
8 terrain/elevation.ts
8 ui/events.ts
8 ui/handler/scroll_zoom.ts
8 ui/interactions.ts
7 ../3d-style/render/lights.ts
7 ../3d-style/render/program/model_program.ts
7 ../3d-style/source/replacement_source.ts
7 ../3d-style/style/lights.ts
7 data/debug_viz.ts
7 data/dem_data.ts
7 data/elevation_feature.ts
7 geo/projection/tile_transform.ts
7 render/image_atlas.ts
7 render/program/pattern.ts
7 style-spec/expression/definitions/comparison.ts
7 style-spec/expression/definitions/within.ts
7 style-spec/feature_filter/index.ts
7 style/load_sprite.ts
7 style/style_layer/symbol_style_layer_properties.ts
7 symbol/cross_tile_symbol_index.ts
7 symbol/symbol_size.ts
7 types/deprecated-aliases.ts
7 util/actor.ts
7 util/ajax.ts
7 util/lut.ts
6 ../3d-style/style/style_layer/model_style_layer_properties.ts
6 data/bucket/pattern_bucket_features.ts
6 data/load_geometry.ts
6 render/atmosphere_buffer.ts
6 render/fog.ts
6 render/program/collision_program.ts
6 render/program/fill_program.ts
6 render/skybox_geometry.ts
6 source/canvas_source.ts
6 source/tile_mesh.ts
6 style-spec/expression/definitions/assertion.ts
6 style-spec/expression/definitions/at.ts
6 style-spec/expression/definitions/format.ts
6 style-spec/expression/definitions/image.ts
6 style-spec/expression/definitions/in.ts
6 style-spec/expression/definitions/index_of.ts
6 style-spec/expression/definitions/length.ts
6 style-spec/expression/definitions/slice.ts
6 style-spec/expression/evaluation_context.ts
6 style-spec/validate/validate_expression.ts
6 style-spec/validate/validate_import.ts
6 style/format_section_override.ts
6 style/indoor_manager.ts
6 style/load_iconset.ts
6 style/style_layer/background_style_layer.ts
6 style/style_layer/background_style_layer_properties.ts
6 style/style_layer/circle_style_layer_properties.ts
6 style/style_layer/clip_style_layer_properties.ts
6 style/style_layer/custom_style_layer.ts
6 style/style_layer/fill_extrusion_style_layer_properties.ts
6 style/style_layer/fill_style_layer_properties.ts
6 style/style_layer/heatmap_style_layer_properties.ts
6 style/style_layer/hillshade_style_layer.ts
6 style/style_layer/hillshade_style_layer_properties.ts
6 style/style_layer/line_style_layer_properties.ts
6 style/style_layer/raster_particle_style_layer_properties.ts
6 style/style_layer/raster_style_layer_properties.ts
6 style/style_layer/sky_style_layer_properties.ts
6 style/style_layer/slot_style_layer_properties.ts
6 style/style_layer_index.ts
6 style/terrain.ts
6 util/debug.ts
5 geo/projection/adjustments.ts
5 geo/projection/albers.ts
5 geo/projection/cylindrical_equal_area.ts
5 geo/projection/equirectangular.ts
5 geo/projection/lambert.ts
5 render/cutoff.ts
5 render/program/raster_program.ts
5 render/raster_fade.ts
5 source/rtl_text_plugin.ts
5 style-spec/expression/compound_expression.ts
5 style-spec/expression/definitions/coalesce.ts
5 style-spec/expression/definitions/collator.ts
5 style-spec/expression/definitions/literal.ts
5 style-spec/expression/definitions/match.ts
5 style-spec/expression/definitions/step.ts
5 style-spec/expression/is_constant.ts
5 style-spec/expression/values.ts
5 style-spec/migrate/expressions.ts
5 style-spec/validate/validate_style.ts
5 style-spec/validate_mapbox_api_supported.ts
5 style/fog_helpers.ts
5 style/load_glyph_range.ts
5 ui/control/attribution_control.ts
5 ui/handler/touch_pan.ts
5 ui/handler_inertia.ts
5 util/dispatcher.ts
4 ../3d-style/style/ambient_light_properties.ts
4 ../3d-style/style/directional_light_properties.ts
4 ../3d-style/style/flat_light_properties.ts
4 data/segment.ts
4 data/usvg/usvg_pb_renderer.ts
4 geo/mercator_coordinate.ts
4 geo/projection/equal_earth.ts
4 geo/projection/mercator.ts
4 geo/projection/natural_earth.ts
4 geo/projection/projection_util.ts
4 geo/projection/winkel_tripel.ts
4 render/glyph_atlas.ts
4 render/vertex_array_object.ts
4 source/geojson_rt.ts
4 source/load_vector_tile.ts
4 source/pixels_to_tile_units.ts
4 source/raster_array_tile_worker_source.ts
4 source/source_state.ts
4 style-spec/expression/definitions/case.ts
4 style-spec/expression/definitions/let.ts
4 style-spec/expression/definitions/number_format.ts
4 style-spec/expression/definitions/var.ts
4 style-spec/validate/validate_formatted.ts
4 style-spec/validate/validate_image.ts
4 style-spec/validate/validate_lights.ts
4 style-spec/validate/validate_terrain.ts
4 style-spec/validate_style.ts
4 style/query_utils.ts
4 style/style_layer/slot_style_layer.ts
4 style/validate_style.ts
4 symbol/get_anchors.ts
4 symbol/transform_text.ts
4 ui/control/logo_control.ts
4 ui/control/navigation_control.ts
4 ui/free_camera.ts
4 ui/handler/box_zoom.ts
4 ui/handler/map_event.ts
4 ui/handler/touch_zoom_rotate.ts
4 util/color_ramp.ts
4 util/scheduler.ts
4 util/worker_performance_utils.ts
3 ../3d-style/style/rain_properties.ts
3 ../3d-style/style/snow_properties.ts
3 data/bucket/heatmap_bucket.ts
3 data/dem_tree.ts
3 gl/framebuffer.ts
3 gl/index_buffer.ts
3 gl/value.ts
3 gl/vertex_buffer.ts
3 render/line_atlas.ts
3 render/program/debug_program.ts
3 render/program/skybox_capture_program.ts
3 render/program/skybox_program.ts
3 render/wireframe_cache.ts
3 source/raster_dem_tile_worker_source.ts
3 source/tile_bounds.ts
3 style-spec/expression/expression.ts
3 style-spec/validate/validate_array.ts
3 style-spec/validate/validate_boolean.ts
3 style-spec/validate/validate_color.ts
3 style-spec/validate/validate_enum.ts
3 style-spec/validate/validate_fog.ts
3 style-spec/validate/validate_glyphs_url.ts
3 style-spec/validate/validate_light.ts
3 style-spec/validate/validate_model.ts
3 style-spec/validate/validate_number.ts
3 style-spec/validate/validate_object.ts
3 style-spec/validate/validate_projection.ts
3 style-spec/validate/validate_rain.ts
3 style-spec/validate/validate_snow.ts
3 style-spec/validate/validate_string.ts
3 style-spec/visit.ts
3 style/evaluation_parameters.ts
3 style/style_image.ts
3 tracked-parameters/tracked_parameters.ts
3 ui/control/fullscreen_control.ts
3 ui/control/scale_control.ts
3 ui/handler/tap_zoom.ts
3 ui/hash.ts
3 util/image.ts
3 util/performance.ts
3 util/tile_request_cache.ts
2 ../3d-style/render/program/ground_shadow_program.ts
2 ../3d-style/render/shadow_uniforms.ts
2 ../3d-style/util/conflation.ts
2 data/array_types.ts
2 data/elevation_feature_parser.ts
2 data/mrt_data.ts
2 geo/edge_insets.ts
2 geo/line_geometry.ts
2 geo/lng_lat.ts
2 geo/projection/far_z.ts
2 gl/color_mode.ts
2 precipitation/rain_program.ts
2 precipitation/snow_program.ts
2 precipitation/vignette_program.ts
2 render/program/clipping_mask_program.ts
2 render/program/occlusion_program.ts
2 render/program/raster_particle_program.ts
2 render/texture.ts
2 render/uniform_binding.ts
2 source/tile_cache.ts
2 style-spec/deref.ts
2 style-spec/diff.ts
2 style-spec/expression/stops.ts
2 style-spec/expression/types/formatted.ts
2 style-spec/expression/types/resolved_image.ts
2 style-spec/feature_filter/convert.ts
2 style-spec/function/convert.ts
2 style-spec/group_by_layout.ts
2 style-spec/migrate.ts
2 style-spec/util/color.ts
2 style-spec/util/color_spaces.ts
2 style-spec/validate/validate_layout_property.ts
2 style-spec/validate/validate_paint_property.ts
2 style/parse_glyph_pbf.ts
2 terrain/globe_raster_program.ts
2 terrain/stars_program.ts
2 terrain/terrain_raster_program.ts
2 tracked-parameters/tracked_parameters_base.ts
2 types/worker.ts
2 ui/handler.ts
2 ui/handler/click_zoom.ts
2 ui/handler/keyboard.ts
2 ui/handler/mouse.ts
2 ui/handler/shim/dblclick_zoom.ts
2 ui/handler/shim/drag_pan.ts
2 ui/handler/shim/touch_zoom_rotate.ts
2 ui/handler/tap_drag_zoom.ts
2 util/browser.ts
2 util/live_performance.ts
2 util/primitives.ts
2 util/smart_wrap.ts
2 util/triangle_grid_index.ts
2 util/util.ts
2 util/vectortile_to_geojson.ts
1 ../3d-style/data/model_attributes.ts
1 data/bounds_attributes.ts
1 data/bucket/circle_attributes.ts
1 data/bucket/dash_attributes.ts
1 data/bucket/fill_attributes.ts
1 data/bucket/fill_extrusion_attributes.ts
1 data/bucket/line_attributes.ts
1 data/bucket/line_attributes_ext.ts
1 data/bucket/line_attributes_pattern.ts
1 data/bucket/pattern_attributes.ts
1 data/bucket/symbol_attributes.ts
1 data/evaluation_feature.ts
1 data/feature_position_map.ts
1 data/index_array_type.ts
1 data/particle_attributes.ts
1 data/pos_attributes.ts
1 data/usvg/usvg_pb_decoder.ts
1 geo/projection/globe_constants.ts
1 gl/cull_face_mode.ts
1 gl/depth_mode.ts
1 gl/query.ts
1 gl/stencil_mode.ts
1 precipitation/precipitation_reveal_params.ts
1 precipitation/rain_attributes.ts
1 precipitation/snow_attributes.ts
1 precipitation/vignette_attributes.ts
1 render/atmosphere_attributes.ts
1 render/occlusion_params.ts
1 render/skybox_attributes.ts
1 render/stars_attributes.ts
1 shaders/encode_attribute.ts
1 source/geojson_wrapper.ts
1 source/tile_id.ts
1 style-spec/empty.ts
1 style-spec/expression/scope.ts
1 style-spec/expression/types/image_id_with_options.ts
1 style-spec/format.ts
1 style-spec/migrate/v8.ts
1 style-spec/migrate/v9.ts
1 style-spec/read_style.ts
1 style-spec/reference/latest.ts
1 style-spec/types.ts
1 style-spec/types/config_options.ts
1 style-spec/util/interpolate.ts
1 style-spec/util/properties.ts
1 style/style_changes.ts
1 style/style_glyph.ts
1 symbol/anchor.ts
1 symbol/check_max_angle.ts
1 symbol/mergelines.ts
1 symbol/opacity_state.ts
1 symbol/path_interpolator.ts
1 terrain/globe_attributes.ts
1 types/tilejson.ts
1 ui/handler/shim/drag_rotate.ts
1 ui/handler/tap_recognizer.ts
1 util/classify_rings.ts
1 util/eased_variable.ts
1 util/evented.ts
1 util/find_pole_of_inaccessibility.ts
1 util/intersection_tests.ts
1 util/mapbox_url.ts
1 util/polygon_clipping.ts
1 util/script_detection.ts
1 util/struct_array.ts
1 util/verticalize_punctuation.ts
1 util/web_worker.ts
1 util/worker_class.ts
1 util/worker_pool.ts
1 util/worker_pool_factory.ts
0 ../3d-style/render/texture_slots.ts
0 ../3d-style/shaders/_prelude_shadow.fragment.glsl
0 ../3d-style/shaders/_prelude_shadow.vertex.glsl
0 ../3d-style/shaders/fill_extrusion_depth.fragment.glsl
0 ../3d-style/shaders/fill_extrusion_depth.vertex.glsl
0 ../3d-style/shaders/ground_shadow.fragment.glsl
0 ../3d-style/shaders/ground_shadow.vertex.glsl
0 ../3d-style/shaders/model.fragment.glsl
0 ../3d-style/shaders/model.vertex.glsl
0 ../3d-style/shaders/model_depth.fragment.glsl
0 ../3d-style/shaders/model_depth.vertex.glsl
0 ../3d-style/util/draco_decoder_gltf.ts
0 ../3d-style/util/meshopt_decoder.ts
0 ../package.json
0 data/elevation_constants.ts
0 data/mrt/mrt.esm.js
0 geo/projection/resample.ts
0 gl/types.ts
0 render/raster.ts
0 shaders/_prelude.fragment.glsl
0 shaders/_prelude.glsl
0 shaders/_prelude.vertex.glsl
0 shaders/_prelude_fog.fragment.glsl
0 shaders/_prelude_fog.vertex.glsl
0 shaders/_prelude_lighting.glsl
0 shaders/_prelude_raster_array.glsl
0 shaders/_prelude_raster_particle.glsl
0 shaders/_prelude_terrain.vertex.glsl
0 shaders/atmosphere.fragment.glsl
0 shaders/atmosphere.vertex.glsl
0 shaders/background.fragment.glsl
0 shaders/background.vertex.glsl
0 shaders/background_pattern.fragment.glsl
0 shaders/background_pattern.vertex.glsl
0 shaders/circle.fragment.glsl
0 shaders/circle.vertex.glsl
0 shaders/clipping_mask.fragment.glsl
0 shaders/clipping_mask.vertex.glsl
0 shaders/collision_box.fragment.glsl
0 shaders/collision_box.vertex.glsl
0 shaders/collision_circle.fragment.glsl
0 shaders/collision_circle.vertex.glsl
0 shaders/debug.fragment.glsl
0 shaders/debug.vertex.glsl
0 shaders/fill.fragment.glsl
0 shaders/fill.vertex.glsl
0 shaders/fill_extrusion.fragment.glsl
0 shaders/fill_extrusion.vertex.glsl
0 shaders/fill_extrusion_ground_effect.fragment.glsl
0 shaders/fill_extrusion_ground_effect.vertex.glsl
0 shaders/fill_extrusion_pattern.fragment.glsl
0 shaders/fill_extrusion_pattern.vertex.glsl
0 shaders/fill_outline.fragment.glsl
0 shaders/fill_outline.vertex.glsl
0 shaders/fill_outline_pattern.fragment.glsl
0 shaders/fill_outline_pattern.vertex.glsl
0 shaders/fill_pattern.fragment.glsl
0 shaders/fill_pattern.vertex.glsl
0 shaders/globe_raster.fragment.glsl
0 shaders/globe_raster.vertex.glsl
0 shaders/heatmap.fragment.glsl
0 shaders/heatmap.vertex.glsl
0 shaders/heatmap_texture.fragment.glsl
0 shaders/heatmap_texture.vertex.glsl
0 shaders/hillshade.fragment.glsl
0 shaders/hillshade.vertex.glsl
0 shaders/hillshade_prepare.fragment.glsl
0 shaders/hillshade_prepare.vertex.glsl
0 shaders/line.fragment.glsl
0 shaders/line.vertex.glsl
0 shaders/line_pattern.fragment.glsl
0 shaders/line_pattern.vertex.glsl
0 shaders/occlusion.fragment.glsl
0 shaders/occlusion.vertex.glsl
0 shaders/rain_particle.fragment.glsl
0 shaders/rain_particle.vertex.glsl
0 shaders/raster.fragment.glsl
0 shaders/raster.vertex.glsl
0 shaders/raster_particle.fragment.glsl
0 shaders/raster_particle.vertex.glsl
0 shaders/raster_particle_draw.fragment.glsl
0 shaders/raster_particle_draw.vertex.glsl
0 shaders/raster_particle_texture.fragment.glsl
0 shaders/raster_particle_texture.vertex.glsl
0 shaders/raster_particle_update.fragment.glsl
0 shaders/raster_particle_update.vertex.glsl
0 shaders/skybox.fragment.glsl
0 shaders/skybox.vertex.glsl
0 shaders/skybox_capture.fragment.glsl
0 shaders/skybox_capture.vertex.glsl
0 shaders/skybox_gradient.fragment.glsl
0 shaders/snow_particle.fragment.glsl
0 shaders/snow_particle.vertex.glsl
0 shaders/stars.fragment.glsl
0 shaders/stars.vertex.glsl
0 shaders/symbol.fragment.glsl
0 shaders/symbol.vertex.glsl
0 shaders/terrain_depth.fragment.glsl
0 shaders/terrain_depth.vertex.glsl
0 shaders/terrain_raster.fragment.glsl
0 shaders/terrain_raster.vertex.glsl
0 shaders/vignette.fragment.glsl
0 shaders/vignette.vertex.glsl
0 style-spec/composite.ts
0 style-spec/data/extent.ts
0 style-spec/error/parsing_error.ts
0 style-spec/error/validation_error.ts
0 style-spec/expression/parsing_error.ts
0 style-spec/expression/runtime_error.ts
0 style-spec/expression/types.ts
0 style-spec/expression/types/collator.ts
0 style-spec/reference/v8.json
0 style-spec/types/lut.ts
0 style-spec/types/tile_id.ts
0 style-spec/union-to-intersection.ts
0 style-spec/util/deep_equal.ts
0 style-spec/util/extend.ts
0 style-spec/util/geometry_util.ts
0 style-spec/util/get_type.ts
0 style-spec/util/random.ts
0 style-spec/util/ref_properties.ts
0 style-spec/util/result.ts
0 style-spec/util/unbundle_jsonlint.ts
0 symbol/clip_line.ts
0 symbol/grid_index.ts
0 symbol/one_em.ts
0 types/callback.ts
0 types/cancelable.ts
0 types/class.ts
0 types/grid-index.ts
0 types/import-meta.d.ts
0 types/point-like.ts
0 types/transferable.ts
0 ui/anchor.ts
0 ui/default_locale.ts
0 ui/handler/handler_util.ts
0 util/config.ts
0 util/dictionary_coder.ts
0 util/dom.ts
0 util/fqid.ts
0 util/is_char_in_unicode_block.ts
0 util/lru.ts
0 util/offscreen_canvas_supported.ts
0 util/resolve_tokens.ts
0 util/sku_token.ts
0 util/task_queue.ts
0 util/throttle.ts
0 util/throttled_invoker.ts
0 util/url.ts
0 util/webp_supported.ts
- Import/Export Analysis: Review all import/export statements to identify module relationships
- Feature Categorization: Classify features into "core," "common," and "specialized" categories
- Circular Dependency Detection: Identify and resolve circular dependencies that would complicate modularization
ESM Migration Strategy
Converting to ESM requires a strategic approach to maintain compatibility while enabling future optimization:
1. Module Structure Design
mapbox-gl/
├── core/
│ ├── map.js
│ ├── events.js
│ ├── projection.js
│ └── index.js
├── render/
│ ├── 2d/
│ │ ├── renderer.js
│ │ └── index.js
│ ├── 3d/
│ │ ├── renderer.js
│ │ ├── terrain.js
│ │ └── index.js
│ └── index.js
├── shaders/
│ ├── basic.js
│ ├── advanced.js
│ └── index.js
├── controls/
│ ├── navigation.js
│ ├── scale.js
│ └── index.js
└── index.js
2. Export Management
// core/index.js
export { Map } from './map.js';
export { EventManager } from './events.js';
export { Projection } from './projection.js';
// No re-export of internal utilities
// render/index.js
export { Renderer2D } from './2d/index.js';
// Only export 3D if explicitly imported
// export { Renderer3D } from './3d/index.js';
// Main index.js - Full backward compatible export
export * from './core/index.js';
export * from './render/index.js';
export * from './shaders/index.js';
export * from './controls/index.js';
3. Subpath Exports Configuration
// package.json
{
"name": "mapbox-gl",
"type": "module",
"exports": {
".": {
"import": "./dist/esm/index.js",
"require": "./dist/cjs/index.js"
},
"./core": {
"import": "./dist/esm/core/index.js",
"require": "./dist/cjs/core/index.js"
},
"./render/2d": {
"import": "./dist/esm/render/2d/index.js",
"require": "./dist/cjs/render/2d/index.js"
},
"./render/3d": {
"import": "./dist/esm/render/3d/index.js",
"require": "./dist/cjs/render/3d/index.js"
},
"./controls/*": {
"import": "./dist/esm/controls/*.js",
"require": "./dist/cjs/controls/*.js"
}
},
"sideEffects": false
}
Modular Design Implementation
1. Feature Flag System
Implement a feature flag system to enable/disable components at build time:
// config.js
export const FEATURES = {
ENABLE_3D: true,
ENABLE_TERRAIN: true,
ENABLE_ADVANCED_SHADERS: true
};
// Usage example
import { FEATURES } from '../config.js';
export class Renderer {
constructor() {
// Basic renderer setup
if (FEATURES.ENABLE_3D) {
this.setup3DCapabilities();
}
}
setup3DCapabilities() {
// Only included in builds with 3D enabled
}
}
2. Lazy Loading Implementation
// map.js
export class Map {
async enableTerrain() {
if (!this.terrain) {
// Dynamically import terrain module only when needed
const { TerrainHandler } = await import('./terrain.js');
this.terrain = new TerrainHandler(this);
}
return this.terrain;
}
}
3. Plugin Architecture
flowchart LR
A[Core Map Object] --> B[Plugin Registry]
B --> C[Plugin Interface]
C --> D[3D Plugin]
C --> E[Terrain Plugin]
C --> F[Advanced Shader Plugin]
C --> G[Custom Layer Plugin]
Implementation example:
// plugin-system.js
export class PluginRegistry {
constructor() {
this.plugins = new Map();
}
register(name, plugin) {
this.plugins.set(name, plugin);
plugin.onRegister();
return this;
}
get(name) {
return this.plugins.get(name);
}
}
// Usage
import { Map } from 'mapbox-gl/core';
import { TerrainPlugin } from 'mapbox-gl/plugins/terrain';
const map = new Map({ /* config */ });
map.plugins.register('terrain', new TerrainPlugin());
// Later use
map.plugins.get('terrain').setElevation(elevation);
Build System Modernization
1. Build Pipeline Architecture
flowchart TB
A[Source Code] --> B[ESBuild/Rollup]
B --> C{Output Formats}
C --> D[ESM Bundle]
C --> E[CommonJS Bundle]
C --> F[UMD Bundle]
G[Bundle Analyzer] --> B
H[TreeShaking] --> B
I[Minification] --> B
D --> J[Core Package]
D --> K[Feature Packages]
D --> L[Full Package]
2. Build Configuration for Multiple Entry Points
// rollup.config.js
import resolve from '@rollup/plugin-node-resolve';
import { terser } from 'rollup-plugin-terser';
import analyze from 'rollup-plugin-analyzer';
// Define the different bundles we want to create
const bundles = [
{
name: 'core',
input: 'src/core/index.js',
output: 'dist/mapbox-gl-core.js'
},
{
name: 'render-2d',
input: 'src/render/2d/index.js',
output: 'dist/mapbox-gl-render-2d.js'
},
{
name: 'render-3d',
input: 'src/render/3d/index.js',
output: 'dist/mapbox-gl-render-3d.js'
},
{
name: 'full',
input: 'src/index.js',
output: 'dist/mapbox-gl.js'
}
];
export default bundles.map(bundle => ({
input: bundle.input,
output: [
{
file: bundle.output.replace('.js', '.esm.js'),
format: 'esm'
},
{
file: bundle.output.replace('.js', '.cjs.js'),
format: 'cjs'
},
{
file: bundle.output.replace('.js', '.umd.js'),
format: 'umd',
name: 'mapboxgl' + (bundle.name !== 'full' ? '.' + bundle.name : '')
}
],
plugins: [
resolve(),
terser(),
analyze({ summaryOnly: true })
]
}));
3. Side-Effects Management
Properly marking files without side effects is crucial for tree-shaking:
// package.json
{
"sideEffects": [
"./src/polyfills.js",
"./src/initialize.js"
]
}
Practical Implementation Path
Breaking this down into achievable milestones:
gantt
title Mapbox-GL Modernization Roadmap
dateFormat YYYY-MM-DD
section Analysis
Dependency Analysis :a1, 2023-07-01, 14d
Module Boundary Definition :a2, after a1, 14d
Architecture Design :a3, after a2, 21d
section Infrastructure
Build System Setup :b1, after a3, 14d
CI/CD Integration :b2, after b1, 7d
Bundle Analysis Tools :b3, after b2, 7d
section Implementation
Core Module Conversion :c1, after b3, 30d
Render Module Separation :c2, after c1, 30d
Plugin System :c3, after c2, 21d
Feature Flagging :c4, after c3, 14d
section Testing
Test Infrastructure :d1, after c4, 14d
Compatibility Testing :d2, after d1, 21d
Performance Benchmarking :d3, after d2, 14d
section Release
Documentation :e1, after d3, 21d
Beta Release :e2, after e1, 14d
Stable Release :e3, after e2, 14d
Phase 1: Analysis & Planning (1-2 months)
- Create comprehensive dependency maps
- Identify module boundaries
- Create architectural design documents
- Establish performance metrics and benchmarks
Phase 2: Infrastructure Setup (2-4 weeks)
- Configure build tooling (ESBuild/Rollup)
- Set up multiple bundle outputs
- Implement bundle analysis tools
- Configure CI/CD for multiple builds
Phase 3: Core Refactoring (2-3 months)
- Convert core modules to ESM
- Implement proper exports
- Create package entry points
- Refactor circular dependencies
Phase 4: Feature Modularization (3-4 months)
- Separate 2D and 3D rendering paths
- Implement plugin architecture
- Create feature flags system
- Implement lazy loading for heavy components
Phase 5: Testing & Optimization (2-3 months)
- Create comprehensive tests for each module
- Benchmark performance of different configurations
- Test browser compatibility
- Optimize critical rendering paths
Backward Compatibility
To ensure a smooth transition for existing users:
1. Compatibility Layer
// compat.js - For users still using the old import style
import * as core from './core/index.js';
import * as render2d from './render/2d/index.js';
import * as render3d from './render/3d/index.js';
import * as shaders from './shaders/index.js';
import * as controls from './controls/index.js';
// Recreate the old structure
export const mapboxgl = {
...core,
...render2d,
...render3d,
...shaders,
...controls
};
// In UMD build, expose as global
if (typeof window !== 'undefined') {
window.mapboxgl = mapboxgl;
}
2. Version-Specific Imports
// package.json
{
"exports": {
"./v1": {
"import": "./dist/v1/index.js",
"require": "./dist/v1/index.cjs"
},
"./v2": {
"import": "./dist/v2/index.js",
"require": "./dist/v2/index.cjs"
}
}
}
3. Feature Detection and Warnings
// terrain.js
export class TerrainControl {
constructor(map) {
// Check if 3D rendering is available
if (!map.renderer.supports3D) {
console.warn(
'TerrainControl requires 3D rendering support. ' +
'Please import the 3D renderer: import "mapbox-gl/render/3d"'
);
return;
}
// Initialize terrain control
}
}
Performance Monitoring
Establish metrics to measure success:
1. Bundle Size Tracking
// build-analyzer.js
const fs = require('fs');
const path = require('path');
const zlib = require('zlib');
// Get all bundles
const bundles = fs.readdirSync('./dist')
.filter(file => file.endsWith('.js'));
// Measure and report
bundles.forEach(bundle => {
const filePath = path.join('./dist', bundle);
const content = fs.readFileSync(filePath);
const gzipped = zlib.gzipSync(content);
console.log(`${bundle}:`);
console.log(` Raw size: ${(content.length / 1024).toFixed(2)} KB`);
console.log(` Gzipped: ${(gzipped.length / 1024).toFixed(2)} KB`);
});
2. Runtime Performance Tracking
// performance-metrics.js
export class PerformanceMonitor {
constructor() {
this.metrics = {};
this.markers = {};
}
startMeasure(name) {
this.markers[name] = performance.now();
}
endMeasure(name) {
if (this.markers[name]) {
const duration = performance.now() - this.markers[name];
if (!this.metrics[name]) {
this.metrics[name] = [];
}
this.metrics[name].push(duration);
delete this.markers[name];
}
}
getAverages() {
const averages = {};
for (const [name, measurements] of Object.entries(this.metrics)) {
averages[name] = measurements.reduce((sum, val) => sum + val, 0) / measurements.length;
}
return averages;
}
}
Community Engagement Strategy
To ensure adoption and gather feedback:
- RFC Process: Create a detailed RFC (Request for Comments) document outlining the modernization plan
- Migration Guide: Provide comprehensive documentation with examples for different use cases
- Preview Releases: Offer alpha/beta builds for early adopters to test
- Telemetry (opt-in): Add optional telemetry to understand which modules are most used
- Examples Repository: Create a repository with examples showcasing the new module structure
Example Migration Guide Section
1. Before
import mapboxgl from 'mapbox-gl';
const map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v11'
});
// Add 3D terrain
map.addTerrain({ source: 'terrain' });
2. After
// Option 1: Full bundle (same as before)
import mapboxgl from 'mapbox-gl';
// Option 2: Only what you need
import { Map } from 'mapbox-gl/core';
import 'mapbox-gl/render/3d'; // Needed for terrain
const map = new Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v11'
});
// Add 3D terrain (works because 3D renderer was imported)
map.addTerrain({ source: 'terrain' });
Conclusion
Modernizing Mapbox-GL for more efficient builds requires a multi-faceted approach focusing on:
- ESM Module Structure: Proper exports and subpath configuration
- Feature Modularization: Clear boundaries between core and optional features
- Optimized Build System: Multiple bundle outputs with effective tree-shaking
- Backward Compatibility: Ensure existing applications continue working
- Progressive Implementation: Phased approach to maintain stability
By following this roadmap, the Mapbox-GL library can significantly reduce bundle sizes for users who only need specific features, while maintaining the comprehensive capabilities for those who need them. The result will be a more efficient, flexible library that aligns with modern JavaScript best practices.
Since we are stubbornly being ignored in a topic where people are basically begging for a solution
Hey everyone, just wanted to say on behalf of the GL JS core team that you are not being ignored — we are working hard to make this happen, and there will be more news about this later this year.
One important misconception to clear up is that while exposing a ESM bundle will be a step forward, it will not yet reduce the bundle size that much by itself — tree shaking doesn't work for GL JS because by definition, it eliminates code based on what is statically imported. Most of the weight of GL JS code is carried by its rendering features (while UI code is a tiny fraction), and GL JS determines whether a certain rendering feature will be used at runtime, after loading and processing the style for the map. To enable smaller bundles that load code dynamically based on what layers and rendering features are used, we need to work on large changes to GL JS architecture based around dynamic imports — this will take time with many challenges to overcome.
Also, having to expose worker code alongside the main thread without complicated bundling setups on the user side adds a lot of complexity. One issue we've recently discovered is that we can't serve a potential ESM bundle through CDN, unlike the current bundle where we embed worker code inside — module workers can't be cross-origin because of WHATWG spec limitations. So we'll have to maintain both the current bundle architecture and the new one when it's released to keep compatibility.
Hey everyone,
We've just published GL JS v3.17.0-beta.1 with experimental ESM support. You can now use Mapbox GL JS as a native ES module directly in the browser—no bundler required. We'd appreciate your feedback as we continue developing this.
Using the ESM build via CDN
<!DOCTYPE html>
<html>
<head>
<link href="https://api.mapbox.com/mapbox-gl-js/v3.17.0-beta.1/mapbox-gl.css" rel="stylesheet">
</head>
<body>
<div id="map" style="width: 100%; height: 100vh;"></div>
<script type="module">
import mapboxgl from 'https://api.mapbox.com/mapbox-gl-js/v3.17.0-beta.1/esm-min/mapbox-gl.js';
mapboxgl.accessToken = 'YOUR_MAPBOX_TOKEN';
const map = new mapboxgl.Map({
container: 'map',
center: [-122.42, 37.78],
zoom: 12
});
</script>
</body>
</html>
Using the ESM build via NPM
For now, you'll need to use a direct path import. We plan to make the default import work in a future releases.
import mapboxgl from 'mapbox-gl/dist/esm-min/mapbox-gl.js';
mapboxgl.accessToken = 'YOUR_MAPBOX_TOKEN';
const map = new mapboxgl.Map({
container: 'map',
center: [-122.42, 37.78],
zoom: 12
});
Note: The current ESM build uses code splitting with three modules (mapbox-gl.js, shared.js, and worker.js) but does not yet support proper tree shaking. This is something we plan to work on in future iterations.
Please share your feedback on what works well and what doesn't. This will help us determine the best path forward for ESM support in GL JS. You can also track this in https://github.com/mapbox/mapbox-gl-js/issues/8676