Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Prefix Composer dependencies #1867

Closed
westonruter opened this issue Feb 17, 2019 · 13 comments
Closed

Prefix Composer dependencies #1867

westonruter opened this issue Feb 17, 2019 · 13 comments
Labels
Infrastructure Changes impacting testing infrastructure or build tooling P1 Medium priority WS:Core Work stream for Plugin core

Comments

@westonruter
Copy link
Member

We can eliminate the problem of PHP-CSS-Parser and other Composer dependencies conflicting with copies included on other plugins (e.g. Mailpoet) by using Mozart to prefix the namespaces: /~https://github.com/coenjacobs/mozart

@swissspidy
Copy link
Collaborator

Warning: This package is very experimental and breaking changes are very likely until version 1.0.0 is tagged. Use with caution, always wear a helmet when using this in production environments.

😕

@westonruter
Copy link
Member Author

westonruter commented Feb 23, 2019

It looks like Mailpoet has implemented prefixing for PHP-CSS-Parser already: mailpoet/mailpoet#1776

But instead of Mozart they are using PHP-Scoper: mailpoet/mailpoet#1655

Apparently PHP-Scoper is better maintained.

@westonruter westonruter changed the title Use Mozart to scope Composer dependencies Prefix Composer dependencies Feb 23, 2019
@swissspidy
Copy link
Collaborator

Here's another one: /~https://github.com/TypistTech/imposter-plugin

@swissspidy swissspidy added the Infrastructure Changes impacting testing infrastructure or build tooling label Jun 6, 2019
@westonruter
Copy link
Member Author

Article I just came across about PHP-Scoper: https://deliciousbrains.com/php-scoper-namespace-composer-depencies/

@swissspidy
Copy link
Collaborator

Coen Jacobs also just shared a post about the differences between PHP Scoper and Mozart: https://coenjacobs.me/2019/07/05/why-i-felt-there-was-a-need-for-mozart/

@westonruter
Copy link
Member Author

An alternative to prefixing is to consider something that @gravityrail has shared: Jetpack Autoloader. This will ensure the latest version of the package is used from among the plugins that incorporate this custom Composer autoloader.

@swissspidy
Copy link
Collaborator

Jetpack's autoloader is still quite new and I am not sure if their approach would work in all cases, i.e. when two versions of a package are incompatible and another plugin relies on the older version. But I guess we can keep an eye on it.

@gravityrail
Copy link
Contributor

Jetpack's autoloader is not ideal but probably the best of a bunch of bad choices, until we get proper dependency management in WP Core.

As @swissspidy points out, sometimes there is no good dependency choice (in which case we want to detect before enabling a plugin that will break another plugin), or in some cases the best dependency choice is something between two shipped versions (in which case WP should perhaps detect the "good" choice, download it, and enable it in preference to the shipped versions).

The improvements I described above are only really possible if/when Core ships with explicit support for composer.json dependencies.

Alternatively, plugins could declare dependencies on each other, but I dislike that approach for a couple of reasons:

  1. you could potentially end up installing a lot of plugins at the same time
  2. testing becomes difficult
  3. we would have to invent a whole new dependency management system, when a well-maintained and widely adopted packaging system for PHP already exists - Composer.

@gravityrail
Copy link
Contributor

gravityrail commented Aug 8, 2019

Just to be clear here, the thing I dislike about the randomised namespacing of classes in composer dependencies is that you can potentially have multiple initialisation - e.g. if your package dependency hooks some actions (therefore runs multiple times, if you have multiple instances of the dependency) and/or fires actions (in which case they may be fired multiple times). There are all kinds of other edge cases I could imagine creeping in, and debugging becomes horrific. Better to have one instance of a class than multiple with different randomised names.

@swissspidy
Copy link
Collaborator

The improvements I described above are only really possible if/when Core ships with explicit support for composer.json dependencies.

Unfortunately we are far away from such a scenario, which at the moment I think is very unlikely.

Just to be clear here, the thing I dislike about the randomised namespacing of classes in composer dependencies is that you can potentially have multiple initialisation - e.g. if your package dependency hooks some actions (therefore runs multiple times, if you have multiple instances of the dependency) and/or fires actions (in which case they may be fired multiple times).

If N plugins all use the same dependency, each with their own custom prefix, then you will get at most N instances of said dependency, without any conflicts between them. So I don't see a problem here.

@gravityrail
Copy link
Contributor

gravityrail commented Aug 9, 2019

If N plugins all use the same dependency, each with their own custom prefix, then you will get at most N instances of said dependency, without any conflicts between them. So I don't see a problem here.

Hm. I think I was not clear before. Let me give some concrete examples.

Imagine we have a package which offers an API, mounted at /my-plugin-api. This package is included by multiple plugins. Now you have a conflict and the packages are competing for which one actually receives requests at that path.

Imagine a package has singleton classes to prevent multiple instances of a class being instantiated, because there are side-effects. Those singletons no longer actually work, since now there can be one instance per plugin.

Imagine a package which modifies post_content by appending ... bdm-tish!. Assuming both instances get initialised, each post will render with that content twice. Singleton patterns and even instanceof no longer work, because the classes have been separately namespaced.

I could go on and on. Basically, the approach of namespacing (or randomising classnames) breaks down as soon as the packages start to hook into WordPress itself, mounting APIs and hooking actions and filters. This is because the name (or namespace) of a class is only ONE dimension of MANY ways that a package must be "namespaced" before it can truly be considered free of conflicts with other instances of the same package. Any shared resource, whether it's a hook or a path or wp-options or anything else, suddenly also needs to be namespaced. It's a neverending rabbit hole. Resolving dependencies globally across plugins is actually a much easier problem to solve.

One of the most useful things that becomes possible with a package management system is the possibility of plugins adopting shared functionality before it's available in core, e.g. the PWA plugin. Having multiple instances of the PWA plugin functionality, each competing to mount the service worker in the same context, would be unworkable.

@westonruter
Copy link
Member Author

Yeah, prefixing only works reliably for pure PHP libraries that do not extend WordPress directly, for example PHP-CSS-Parser.

@swissspidy
Copy link
Collaborator

Site Kit ended up using PHP-Scoper: google/site-kit-wp#696

@amedina amedina added the P1 Medium priority label Apr 13, 2020
@kmyram kmyram added the WS:Core Work stream for Plugin core label Aug 5, 2020
@westonruter westonruter closed this as not planned Won't fix, can't repro, duplicate, stale Jul 28, 2022
@github-project-automation github-project-automation bot moved this to Backlog in Ongoing Aug 28, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Infrastructure Changes impacting testing infrastructure or build tooling P1 Medium priority WS:Core Work stream for Plugin core
Projects
Archived in project
Development

No branches or pull requests

6 participants