protomaps / PMTiles

Cloud-optimized + compressed single-file tile archives for vector and raster maps
https://protomaps.com/docs/pmtiles/
BSD 3-Clause "New" or "Revised" License
1.99k stars 116 forks source link

Open to JS code improvements/restructuring #287

Open sachaw opened 11 months ago

sachaw commented 11 months ago

Hi, I use this library quite frequently, would you be open to receiving a PR that includes a bunch of project related improvements;

Use PNPM, modern exports, auto linting etc?

I'll prep the changes and if there there are specifics you don't agree with, I can revert them.

Thanks.

bdon commented 11 months ago
  1. not if it requires all users to use pnpm
  2. for modern exports, do you mean changing the exports? this would be a breaking semver change
  3. I have it on my todo list to add a lint check, do you prefer eslint? Thanks for asking.
sachaw commented 11 months ago
  1. Users would not have to use pnpm, it would be preferred for development only.
  2. Modern exports are not a breaking change, the old usage is still maintained
  3. I have a preference for Biome as the longer, requires only a single config file and not the half dozen eslint plugins to get it working

Additionally, making this a native ESM library would be preferable and if people insist on using cjs they can just transpile this dependency.

bdon commented 11 months ago

Additionally, making this a native ESM library would be preferable and if people insist on using cjs they can just transpile this dependency.

Isn't this already the case? The cjs etc targets are created by esbuild here:

https://github.com/protomaps/PMTiles/blob/main/js/package.json#L14

sachaw commented 10 months ago

There's a few more things required that's outlined well here: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c

Also making it an ESM only package is desirable now to encourage people to stop using cjs as it's a constant burden on the ecosystem. Instead of us transpiring it, let them do it, ESM has support as far back as node 12, we should only be supporting 18, and soon 20 (current LTS).

I also aim to eliminate all usage of the any type

sachaw commented 10 months ago

WIP repo: https://github.com/sachaw/PMTiles

bdon commented 10 months ago

Thanks for the example. We need to stay on Node 18 instead of 20 because AWS Lambda doesn't have Node 20 yet.

In general, I'm OK with the packaging set-up as is although it may not align with every individual developer's preferences. Ideally it should use as few devDependencies as possible to minimize the possibility of situations across all the platforms (all browsers + node + lambda + cloudflare workers + demo).

Is there a specific pain point you intend to resolve with your changes that we might find another solution for?

sachaw commented 10 months ago

I am of the same mindset, minimal dependencies and minimal maintenance burden (reduced dev environment complexity). node 18 is fine, just keeping up with LTS is the important part, not necessarily running the current release.

One thing that needs further looking into is the usage of globals from leaflet as it references AMD modules which are rarely used these days, my proposal would likely be to include leaflet types as a dev dependency so it's not actually bundled, and just mark it as an external dependency so the import is still included.

One of the reasons I think this restructuring is important is in future I believe it would be good to adopt independent exports for different versions of the spec and not piggyback off of the previous version. A prime example of this is https://github.com/auth70/paseto-ts so imports for this package could be

import {PMTiles, TileType} from "pmtiles/v4"
bdon commented 10 months ago
  1. The Leaflet situation should be isolated to adapters.ts - Leaflet does not use ES6 imports, it relies on the global L. It's important for the PMTiles project to support Leaflet version 1.x, because a significant use case is swapping in your own PMTiles to replace an abandoned Z/X/Y tile endpoint, without upgrading the rest of the application (some organizations with maps don't have any capability for this).

Another option would be to put that into pmtiles-leaflet etc but as the maintainer of several packages I would prefer to keep the number of interwoven dependencies low. The adapters.ts code does not benefit from tree shaking but it is quite small relative to the rest of the code.

  1. There are existing clients that have pmtiles v2 files lying around - supporting both v2 and v3 simultaneously was a design goal of the current JS version; this might change in the mid-term future. But this is another downside of binary file format development in general. Again, it means we need to carry around the v2 code but it's not that much.
bdon commented 8 months ago

Added Biome with these rules https://github.com/protomaps/PMTiles/blob/main/js/biome.json to ease the transition from Prettier. useNamingConvention makes things easier and since I'll need to push a breaking major version 3.0 soon, I'm introducing that now.

bdon commented 8 months ago

3.0 will also change to exports: {require:..., import:...} in package.json which should make ES6 modules everywhere the default, but also support CommonJS only for NodeJS.

bdon commented 8 months ago

Reading through your link https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c?permalink_comment_id=3850849#gistcomment-3850849 it looks like there are some risks with the dual exports to support both ESM and CJS. So I'll take another look at going ESM-only for 3.0.0-alpha.1

sachaw commented 8 months ago

ESM only is a good solution, people that require cjs support can just tanslile the module.

bdon commented 8 months ago

This should do it https://github.com/protomaps/PMTiles/commit/0d0b3ee2ada422ff070d76e4673f7d9abb72a2d9

@sachaw what instructions/tools should we give people that need CJS from the new esm-only package?

sachaw commented 8 months ago

Many of the major build tools/bundlers have options. One option outlined here may be a good workaround for most https://adamcoster.com/blog/commonjs-and-esm-importexport-compatibility-examples

sachaw commented 8 months ago

Namely async import

bdon commented 8 months ago

as of https://github.com/protomaps/PMTiles/pull/337/files I have the uses of any reduced to 2:

declare const L: any;: we need to assume L exists in the global environment to make sure IIFE (non-ESM) script includes work like in the examples https://github.com/protomaps/PMTiles/blob/main/js/examples/leaflet.html#L7 as many use cases for PMTiles + leaflet don't use any build step. (typeof (globalThis as any).DecompressionStream === "undefined"): This needs to check the browser for DecompressionStream which was only added to Firefox/Safari in 2023. Also, it needs to handle running in nodeJS 16+ on AWS Lambda, and Cloudflare Workers (custom v8 isolates runtime)

Still haven't figured out a good solution to either.

sachaw commented 8 months ago

What if a seperate package was published to support leaflet?

sachaw commented 8 months ago

Apart from the examples are IIFE's actually still used by people?

bdon commented 8 months ago

Yes, especially with Leaflet, and I need to support that use case. I'm already maintaining ol-pmtiles, protomaps-themes-base, protomaps-leaflet and am trying to minimize the number of NPM packages I need to maintain and keep in sync. needing a pmtiles-maplibre and pmtiles-leaflet feels like overkill and just shipping the ~100 LOC integrations with pmtiles has felt like the best option

bdon commented 8 months ago

I backpedaled on some of the any removals for js v3, but put in linter disables, biome is part of CI now. JS v3.0.0-alpha.2 is out on NPM with a lot of improvements https://github.com/protomaps/PMTiles/blob/main/js/CHANGELOG.md - hoping to get 3.0.0 out by EOW