Commerce 2.x has been relying on composer_manager for the past few months, and in retrospective, it has been a very painful experience.
Our installation instructions (steps 3/4/5) tell the complete story:
1. Install the latest -dev version of Drupal 8.
2. Install the latest -dev versions of devel* and composer_manager.
3. Enable Commerce (but not any of the submodules!). This will add the Commerce libraries to the global composer.json
4. Go to your sites/default/files/composer directory and run composer install.
This will download the required libraries into your sites/all/vendor directory.
5. Enable the Commerce submodules. Use the admin/modules page, Drush won't work currently**.
At DrupalCon I've spoken to DamZ and EclipseGC and we've tried to enumerate the problems we've noticed, and come up with solutions.
The problems
The first set of problems lies around the fact that the composer.json regeneration only happens on module enable:
- composer_manager can't work as a part of the build process (running after drush make, for example)
- Any code relying on a library must live in a submodule.
The main module can't use a library interface as a part of any classes that must run during Drupal boostrap,
For example, a library defines a CurrencyInterface, defining currency behavior. A drupal entity type class implements that interface.
This entity type class must be in a submodule, so that the main module (commerce.module in our case) can ensure the regeneration of the composer.json file and the presence of the library before the submodule is installed. Otherwise Drupal will rebuild the entity types during bootstrap, and the missing library will crash the system. - Related modules can't be installed all at once (same reason as explained in #2).
The second set of problems lies around the placement of the global composer.json file and vendor/ directory.
Our site ends up with two different vendor directories, one in core/vendor and the second in sites/all/vendor.
Composer wasn't built to be used like this, a site/application must always have one vendor directory.
This triggers a set of (admittedly, solvable) Drupal bugs, where the autoloader isn't swapped early enough, causing Drush incompatibilities and other crashes.
The solutions
The composer.json generation is already neatly contained in its own service and related classes.
The solution to the first set of problems is to untie the service from ModuleHandler by crawling the module directories ourselves.
This would allow the process to be triggered without an active Drupal installation (via drush or by invoking a script manually).
Once we have the new composer.json file, we overwrite core's composer.json file. Thus, the module libraries end up in core/vendor.
The new flow becomes:
1. Get core & modules by running drush make.
2. Regenerate core's composer.json by running drush composer-manager regenerate (or whatever the command name ends up being).
3. Run composer install inside core/vendor.
Installing a new module now requires only going to core/vendor and running composer install again.
EclipseGC suggested implementing a Composer hook so that the composer.json regeneration happens automatically when "composer install" runs.
DamZ has looked into this, Composer has no such hook/event right now, but it can be added.
This would further simplify the process, the separate command wouldn't be needed and Composer Manager wouldn't need to care about module install at all.
Side effects
Libraries will be installed for uninstalled modules, but I'm prepared to live with that (by advising people to delete the modules they don't plan on using).
Each Drupal core update requires regenerating the global composer.json file and rerunning composer install.
This will get easier once Drupal core stops shipping with vendor/
Comments
Comment #1
bojanz commentedComment #2
bojanz commentedComment #3
bojanz commentedThis clearly belongs in core, so I've opened #2350647: Allow contrib to use libraries via Composer.
Comment #4
dawehnerIs there a reason you did not considered https://blog.erdfisch.de/2014/08/composer-based-workflow-drupal-8
Comment #5
cpliakas commentedThanks for enumerating the issues.
I suggest that we schedule a google hangout so that people interested can talk in real time, and then we can summarize the discussion and come up with a plan of action, whether that is to change the way this module is implemented, figure out a solution in core, etc.
Does that sound reasonable?
Comment #6
bojanz commented@dawehner
That blog post is related, but needs to build on top of the work outlined above.
Replacing drush make with composer and vendorizing Drupal core is a worthwhile idea and both DamZ and EclipseGC were in favor of that,
but the initial issues (one vendor/ dir VS multiple, generating the composer.json) remain.
@cpliakas
Sure.
Comment #7
larowlan+1 to #4 as long term and OP as interim solutions
Comment #8
larowlanFYI symfony full stack framework triggers a cache clear on composer changes, can we utilize something like that?
Also extension discovery is decoupled from module handler so should be able to use that.
Comment #9
cpliakas commentedCross-posting #1886820: Packagist for Drupal Projects, as it could potentially kill Composer Manager (which is good!)
Comment #10
bojanz commentedI'm fairly close to having a functional rewrite implementing the described plan.
Thanks to EclipseGC I've been able to implement a "composer drupal-update" command that regenerates the root composer.json file, then runs "composer update".
The community agrees about the need for a single composer.json and vendor/ directory.
Core efforts such as #1975220: Allow a Composer user to manage Drupal, modules, and PHP dependencies with a custom root composer.json help this, and will allow for cleaner composer_manager code.
The end game is this: The root composer.json file is maintained by Composer (if people are using Composer to download modules, ala Drush Make), or by Composer Manager (if people are still manually installing modules and installing dependencies).
Comment #12
bojanz commentedI've committed the initial rewrite. A new readme, tests, other fixes will follow.
Installation:
1. Install Composer Manager.
2 Run "drush composer-manager-init" or the "init.sh" script shipped with the module.
This modifies the root composer.json file in order to register the 'composer drupal-update' command.
When adding new modules:
1) Download modules
2) Run 'composer drupal-update' inside the Drupal root directory.
This scans all modules, gets their composer.json files, overwrites the root composer.json, runs composer update.
3) Enable the modules.
We should be able to do #2 automatically for people using "drush dl" at one point.
This also works when Drupal is not installed:
1) drush make
2) modules/composer_manager/scripts/init.sh
3) composer drupal-update
4) drush site-install
On the core side, #1975220: Allow a Composer user to manage Drupal, modules, and PHP dependencies with a custom root composer.json has landed. Once the other issue lands (index.php and the vendor/ path), we should be able to further simplify the module by not caring about core dependencies.
Comment #13
donquixote commentedComment #14
bojanz commentedNote that because core issue #1975220: Allow a Composer user to manage Drupal, modules, and PHP dependencies with a custom root composer.json has landed, I had to commit a change to composer_manager (13ac4ac), which means that tomorrow's -dev will require the -dev version of Drupal.
Comment #15
joshtaylor commentedI'm thinking that if composer manager automatically downloads composer dependencies regardless if they are enabled or not this could cause issues.
Is there a way just to install enabled?
Comment #16
bojanz commented