You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I'm having problems using @developmentseed/deck.gl-geotiff from esm.sh
- Tyler
(The following was written by Claude Code and reviewed by Tyler)
Loading @developmentseed/deck.gl-geotiff@0.7.0 from a CDN that aggressively tree-shakes (esm.sh's ?bundle-deps) drops proj4's non-fundamental projection classes from the bundle, so any COG whose CRS isn't merc / longlat / tmerc fails at the first proj4(sourceProjection, "EPSG:4326") call with:
Error: Could not get projection name from: [object Object]
Repro
<script type="module">
import { COGLayer } from "https://esm.sh/@developmentseed/deck.gl-geotiff@0.7.0?bundle-deps";
// Any WGS84 UTM COG — e.g. the same Sentinel-2 TCI used in cog-basic.
const url = "https://sentinel-cogs.s3.us-west-2.amazonaws.com/sentinel-s2-l2a-cogs/18/T/WL/2026/1/S2B_18TWL_20260101_0_L2A/TCI.tif";
// No `epsgResolver` supplied — uses the package default (epsg.io PROJJSON
// + wkt-parser), same as examples/cog-basic.
new COGLayer({ id: "cog", geotiff: url });
</script>
Result: the layer initializes, fetches metadata, calls epsgResolver(32618), gets back a definition with projName: "utm", hands it to proj4(...). proj4 throws — its Projection.projections registry doesn't have an entry for "utm".
Why local builds work and CDN doesn't
The examples/cog-basic app handles UTM, NZTM, EPSG:2056, etc. with no custom epsgResolver and no extra setup. Vite + Rollup keep proj4's projection-class side effects, so the locally-bundled proj4 has a complete Projection.projections registry.
esm.sh's ?bundle-deps runs a more aggressive tree-shaker: from its POV, only proj4's default-exported function is referenced from @developmentseed/proj and cog-layer.ts, so it eliminates the projection-class registrations as dead code.
I verified this is the failure mode by:
Logging the def object returned from a custom resolver: { projName: "utm", zone: 18, datumCode: "WGS84", units: "m" } — well-formed, but bundled proj4 still rejects it.
Switching to ?bundle-deps&external=proj4 plus an HTML import map pointing both the consumer page and the bundled module at the same full proj4 instance — works. Confirms the issue is the proj4 inside the bundle, not the def object.
Substituting an equivalent tmerc def (projName: "tmerc") for UTM — works, because tmerc is a fundamental projection that bundled proj4 retains. (Verified visually correct against the cog-basic example for EPSG:32618.)
Why this matters
CDN consumers can't supply an HTML <script type="importmap"> in every host environment. In particular:
Inline data: URL iframes have null origins; an importmap inside doesn't help with workers, and authoring one per embed is awkward.
A no-build-step CDN flow is the simplest possible adoption path. The package works perfectly in a real build — but right now it silently fails on most projected CRSs when loaded from esm.sh.
Suggested fixes (in increasing order of footprint)
One-line side-effect import in packages/proj/src/index.ts:
import "proj4/lib/projections/index.js";
This is a side-effect-only import; tree-shakers preserve it. It pulls in the same projection registrations proj4's main entry does, but in a form bundlers can't eliminate.
import { Projection } from "proj4/lib/Proj.js";
import utm from "proj4/lib/projections/utm.js";
import lcc from "proj4/lib/projections/lcc.js";
import aea from "proj4/lib/projections/aea.js";
import stere from "proj4/lib/projections/stere.js";
// …whichever set the package commits to supporting.
[utm, lcc, aea, stere /* … */].forEach((p) => Projection.projections.add(p));
Re-export proj4 from the public API so downstream consumers can register custom CRSs against the same instance (and bundlers can see the reference):
Summary
I'm having problems using @developmentseed/deck.gl-geotiff from esm.sh
- Tyler
(The following was written by Claude Code and reviewed by Tyler)
Loading
@developmentseed/deck.gl-geotiff@0.7.0from a CDN that aggressively tree-shakes (esm.sh's?bundle-deps) drops proj4's non-fundamental projection classes from the bundle, so any COG whose CRS isn'tmerc/longlat/tmercfails at the first proj4(sourceProjection, "EPSG:4326") call with:Error: Could not get projection name from: [object Object]Repro
Result: the layer initializes, fetches metadata, calls
epsgResolver(32618), gets back a definition withprojName: "utm", hands it to proj4(...). proj4 throws — itsProjection.projectionsregistry doesn't have an entry for "utm".Why local builds work and CDN doesn't
The examples/cog-basic app handles UTM, NZTM, EPSG:2056, etc. with no custom
epsgResolverand no extra setup. Vite + Rollup keep proj4's projection-class side effects, so the locally-bundled proj4 has a completeProjection.projectionsregistry.esm.sh's
?bundle-depsruns a more aggressive tree-shaker: from its POV, onlyproj4's default-exported function is referenced from@developmentseed/projandcog-layer.ts, so it eliminates the projection-class registrations as dead code.I verified this is the failure mode by:
{ projName: "utm", zone: 18, datumCode: "WGS84", units: "m" }— well-formed, but bundled proj4 still rejects it.?bundle-deps&external=proj4plus an HTML import map pointing both the consumer page and the bundled module at the same fullproj4instance — works. Confirms the issue is the proj4 inside the bundle, not the def object.tmercdef (projName: "tmerc") for UTM — works, becausetmercis a fundamental projection that bundled proj4 retains. (Verified visually correct against the cog-basic example for EPSG:32618.)Why this matters
CDN consumers can't supply an HTML
<script type="importmap">in every host environment. In particular:<head>.data:URL iframes have null origins; an importmap inside doesn't help with workers, and authoring one per embed is awkward.A no-build-step CDN flow is the simplest possible adoption path. The package works perfectly in a real build — but right now it silently fails on most projected CRSs when loaded from esm.sh.
Suggested fixes (in increasing order of footprint)
packages/proj/src/index.ts:import "proj4/lib/projections/index.js";This is a side-effect-only import; tree-shakers preserve it. It pulls in the same projection registrations proj4's main entry does, but in a form bundlers can't eliminate.
export { default as proj4 } from "proj4";Useful regardless of the projections fix.
Environment