Skip to content
New issue

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

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

Already on GitHub? # to your account

consider a versioning strategy for package:web #145

Open
devoncarew opened this issue Jan 22, 2024 · 15 comments
Open

consider a versioning strategy for package:web #145

devoncarew opened this issue Jan 22, 2024 · 15 comments

Comments

@devoncarew
Copy link
Member

package:web sits in an interesting design space:

  • the API is generated from the web DOM IDLs
  • it has a very large API surface area - around 1000 classes defined in hundreds of libraries
  • is in a Dart package, versioned using semver; tldr:
    • api additions go out under minor version revs
    • breaking api changes go out under major version revs
  • we want the package to reasonably closely follow the evolving set of web DOM APIs
  • virtually any update to the IDLs (currently at @webref/idl 3.39.1) will remove APIs, add APIs, or change signatures in ways that we would consider breaking

If we just rev. to new IDLs monthly, and follow semver strictly, we'd likely be publishing a new major version of the package every month. That frequency of major version updates could cause issues for the ecosystem - if this package is in a diamond constraint for a solve, and two different package versions are being referred to.

Some ideas for how to treat this:

  1. decide that monthly major releases are not an issue
  2. only update the IDLs quarterly; update the semver based on changes (=> likely 4 major version revs a year)
  3. decide that we will not follow semver for this package; version solves would be easier for users, but any publish could break people's CIs
  4. choose a more narrow range of 'core' APIs that we make semver guarantees about; changes there would follow semver; APIs outside that core set would not have guarantees
  5. break the package into n small packages based on API domain; each small package would follow semver (and would presumably need fewer overall breaking change / major version releases)
  6. introduce a set of customer tests / large web app tests. apis change which break those tests would imply a new major semver release. This would be similar to 4), but with customer tests helping to figure out which APIs we cared about

cc @sigmundch @kevmoo @srujzs for thoughts

@sigmundch
Copy link
Member

I have a leaning towards (4) and (6). I'd like to use a good test suite to validate our assumptions, but I'd also like to properly communicate the policy in a way that can be understood by the community without having to scan through a corpus of tests. Also, I expect for (6) we'd also use internal apps that are not visible to the community.

Regarding (4):

  • can we select a portion of the IDL that is critical to many (e.g. html elements) and is pretty stable over time?
  • can we communicate to developers how to depend on the package (e.g. recommended version constraint) depending on what they are consuming?
  • should we divide web.dart into sub-libraries depending on the version policy? (e.g. package:web/stable.dart vs package:web/unstable.dart)
  • can we build tooling to validate that our policy is working well? (e.g. pub_crawl + analyzer to test how many packages break over time?)

@srujzs
Copy link
Contributor

srujzs commented Jan 22, 2024

I too like 4. I don't see us getting to 6 for a while if we're waiting for customer tests, as the usage of this package is probably minimal right now.

I think part of doing 4 is examining what APIs have changed in the past with a new IDL version and why. I imagine the changed APIs are mostly unstable/experimental. If that's the case, we should either use an import like Siggi suggests or an annotation to signal that those libraries are subject to change without a major version change. I imagine we'll need to have our own versioning policy, we just need to make it obvious to users.

@parlough
Copy link
Member

parlough commented Jan 22, 2024

I think excluding at least non-standard and non-finalized APIs from the full breaking change policy makes sense (with an annotation and/or documentation explaining the status).

I think part of doing 4 is examining what APIs have changed in the past with a new IDL version and why.

Yeah I'm curious what other IDL changes besides non-standard and non-finalized APIs end up breaking on the Dart side. Perhaps there's a way to avoid or circumvent some of them too?


I think a lot of it comes down to what the recommendation for package authors is.

If there are a lot of major releases, I can definitely see it ending up as a world where package developers don't use package:web at all (or they vendor it) so they don't have to keep expanding the upper bound to be compatible with a variety of consumers, and just accept JSAny in the few API boundaries they have.

@devoncarew
Copy link
Member Author

devoncarew commented Jan 22, 2024

OK, for some data, the commits in this PR move this package from webref/idl versions 3.37.0 (published 6 months ago) up through 3.42.0 by minor versions:

Clicking on each commit will show the diffs from the previous minor IDL version.

@natebosch
Copy link
Member

I think we could limit the content of package:web to a very core set of APIs - either manually write an allow list, or use some heuristics to limit what we read from the IDL to the most useful and widely supported set.

I think dart:html had more need to encompass as many APIs as possible because it was not as cross compatible with user authored JS interop code. With the new approach the cost is much lower to locally author interop for less-used JS Apis and use it with the other code. If we cover the 80-90% use case with package:web we can keep most projects unblocked with the easiest path, and only a small bump in complexity for projects that need APIs we don't cover here.

@kevmoo
Copy link
Member

kevmoo commented Jan 24, 2024

@natebosch We could create a mono repo and have pkg:web and pkg:web_all (or similar).

I really hate the idea of hand curating every API...I'm not sure we've found the ideal metadata to pin "stable" on.

@kevmoo
Copy link
Member

kevmoo commented Jan 24, 2024

pkg:web/unstable.dart is convenient, certainly, but we still risk outright breaking folks with pub upgrade even if we warn folks. We could split out the generator logic into a seperate (unpublished) package that targets both pkg:web and pkg:web_all (or similar).

@srujzs
Copy link
Contributor

srujzs commented Jan 24, 2024

Short-term: I think Nate is right and we should cut out all the APIs that are not standard/marked experimental or don't have all browsers supporting it. The usage of such APIs is almost certainly low, and the priority should be to get this package to a stable enough version such that we can publish a v1. I think this is more tractable than changing our semantic versioning policy and making it obvious to users.

Long-term: We can split the non-standard APIs and tooling into a separate unpublished package like Kevin proposes.

I do want to see if we can use the Web IDL data to make that determination of what to cut still, but if that seems like a dead-end, MDN compatibility data will get use close. I'll respond back if I can find more info there.

@natebosch
Copy link
Member

We could create a mono repo and have pkg:web and pkg:web_all (or similar).

I think our first choice should be to not publish pkg:web_all until we find clear demand for it.

Maintenance of dart:html did not scale well. We're hopefully starting off we a cheaper process here, but still we should limit the surface area we need to maintain to the smallest set of APIs that will satisfy a large enough set of use cases. The costs to our users of a missing API here is much lower than it was in the dart:html approach. I suspect there are very few projects in the small gap between "I need esoteric or experimental browser APIs" and "I need some other JS library so I have to learn interop syntax anyway".

The other costly-to-maintain (so now we don't) libraries like dart:web_gl have ~0 usage in the ecosystem, but it's still expensive for us to validate that we can remove them and do so, so they've just stuck around. I hope we can avoid paying some ongoing maintenance cost for APIs that no one is using.

@parlough
Copy link
Member

parlough commented Jan 24, 2024

Instead of pkg:web_all, could the tooling we use to generate the bindings be published to be used as a dev dependency? That way packages can generate only the subset they need and end up with an API compatible with their package:web code? I imagine most packages only need a very specific subset on top of the core portion.

That would help enable a more consistent developer experience and provide a solution for those looking to use experimental or niche APIs. While also providing the flexibility to update it as often as they need.

@natebosch
Copy link
Member

Publishing a code generator could be valuable, but I don't think we should make it a primary goal. In some cases authors would be better off hand-writing the interop anyway when an API feels non-idiomatic in Dart. I think effort spent in documenting and making full JS interop easy to use will have more pay-off than trying to build tooling to keep more users from having to learn JS interop.

Potentially slightly off topic: Do we have a comparison against dart:html of the places where we made Dart specific tweaks where package:web will be more JS idiomatic?

@srujzs
Copy link
Contributor

srujzs commented Jan 24, 2024

+1 to getting users to write the new interop as needed instead of trying to use our generator somehow. It is likely very rare that a user wants enough experimental APIs that are missing that it's easier for them to hack our generator than to write the definitions themselves.

Potentially slightly off topic: Do we have a comparison against dart:html of the places where we made Dart specific tweaks where package:web will be more JS idiomatic?

Informally, yes. Devon has been working to get dart fixes to map dart:html types to their package:web equivalents (because we used Dart-y names before). A similar analysis applies for many of the native APIs within those types.

@devoncarew
Copy link
Member Author

Potentially slightly off topic: Do we have a comparison against dart:html of the places where we made Dart specific tweaks where package:web will be more JS idiomatic?

This has info about the class name differences: https://github.com/dart-lang/web/blob/main/tool/renames.md. It would be great to know the 1/2 dozen - 2 dozen most common method name differences, so we can add those refactors to the dart fix data file.

@devoncarew
Copy link
Member Author

I don't think this is any different than what's said above, but I like the idea of having a small, core package:web - few, high-value, high-usage APIs. We could also refactor this repo into a mono-repo, and support some additional dom generated packages; they could publish independently of package:web, and expose another tier of APIs. And I'd avoid publishing anything w/ low usage - it would increase maintenance costs here, w/o really providing much value to users.

@srujzs
Copy link
Contributor

srujzs commented Jan 29, 2024

I do want to see if we can use the Web IDL data to make that determination of what to cut still, but if that seems like a dead-end, MDN compatibility data will get use close. I'll respond back if I can find more info there.

I think it's a bit of a pain to use https://www.npmjs.com/package/web-specs. We have code to parse it currently in package:web, but I'm not sure if we can reliably map every member to the spec/draft that can be looked up in browser-specs. The member naming scheme is a bit weird too e.g. requestPersistentHandle, so I'm not confident we'll use the syntax correctly everywhere. I'm not sure if this is what you came across Kevin when you last looked at it.

We can do better with the MDN compatibility data, where the mapping is much easier and has info on experimental, whether it's on track to be a standard, and deprecated. This can be a bit weird too when we look at object literals/options objects, as the compatibility info only exists for the experimental options and have a slightly different naming scheme e.g. _option, but that's just a matter of being careful.

If we land a PR to parse the compatibility data, I think we can start using it to eliminate experimental and possibly deprecated APIs. If Baseline becomes more useful in the future, we could consider migrating to use that instead.

parlough referenced this issue Feb 6, 2024
* reduce the number of DOM APIs we generate code for

* regenerate the dom libraries

* review comments

* update comments
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants