Drupal Commerce Blog

What's happening in the world of Drupal Commerce.

Installing Commerce 2.x without Composer, with Ludwig

The average Drupal Commerce site depends on many external PHP libraries. Address needs commerceguys/addressing and Commerce needs commerceguys/intl. GeoIP needs geoip2/geoip2 and Search API Solr needs solarium/solarium. Each payment gateway needs a matching SDK. These libraries must be downloaded separately, because license constraints prevent us from committing their code to drupal.org itself. For the past 5 years, the primary and only way to download and use PHP libraries has been Composer, a command line tool.

Composer works per-project, meaning each Drupal install has one folder for all PHP libraries it requires, regardless of which module needs which. This allows Composer to detect and prevent conflicts such as incompatible library versions. Composer also recursively resolves dependencies, automatically installing and updating packages required by other packages. This is a major benefit to Drupal site administrators compared to previous tools like Drush Make. However, Drupal's reliance on the Composer-generated autoloader makes it impossible to upload manually downloaded libraries, making Composer non-optional.

When we started developing Commerce 2.x 2.5 years ago, our setup instructions looked like this:

  1. Download Commerce and the 6 required modules (Address, Entity API, Entity Reference Revisions, Inline Entity Form, Profile, State Machine).
  2. Run Composer to download libraries required by those modules.
  3. Install the modules.

We soon realized that if Composer was required anyway, we could use it to download Commerce itself, relying on its dependency resolution to bring in the other modules and libraries. After years of community effort, Drupal core contribution, and drupal.org improvements, and our idea became possible! Our install instructions are now just a single command, composer require drupal/commerce ~2.0, which downloads all required modules and libraries automatically.

Another single command, composer update drupal/commerce --with-dependencies, updates Commerce and its dependencies. Updating Drupal core is done the same way. Patches can be applied against both core and contributed modules by listing them in the root composer.json file. This represented unprecedented power and simplicity to us, but not everyone was as happy.

Complaints against Composer

Initial complaints against Composer related to its speed and memory usage, but these have both drastically improved since then. Another common complaint is lack of support in shared hosting environments, which actually misunderstands the idea that Composer must be run on the server instead of running on a local machine with the fully composed codebase itself being uploaded to the server. However, there are two problems that are not easy to fix:

  1. Using Composer to download a full project in China can easily take an hour due to most CDNs being blocked and developers being forced into using proxies.
  2. Many people are almost religiously opposed to learning how to use the command line.

The command line problem is exacerbated by the fact that Composer is not very user friendly - running it in the wrong directory or with incorrect parameters can produce cryptic failures. Furthermore, the Drupal core tarball is much less suited for Composer usage than the Drupal Composer project (or our own Project Base), not supporting patches or updating core without fixing the default composer.json. The core update problem is especially important since the manual core update methods now crash the site (due to people replacing the vendor directory with one that doesn't contain only core's dependencies).

We believe that the right solution to the user friendliness problem is creating a Composer GUI, perhaps one optimized for Drupal. We built Conductor, an Electron app, as a proof of concept, but it received little support from the community. The reason is simple: developers who have the capacity to contribute are already users and fans of the command line. We alone don't have the resources to design and implement such a tool. We needed a temporary band-aid..

Ludwig

Many people asked, "Can't I just download libraries to a folder inside the module and somehow add them to the class autoloader?" We tried and we failed, because we couldn't hook into the autoloader early enough. Last week we stumbled into the magic incantation that allowed us to do precisely that, and Ludwig was born.

Here's how Ludwig works. A module defines a ludwig.json file listing its dependencies:

{
  "require": {
    "doctrine/collections": {
      "version" : "v1.4.0",
      "url": "https://github.com/doctrine/collections/archive/v1.4.0.zip"
    },
    "commerceguys/enum": {
      "version" : "v1.0",
      "url": "https://github.com/commerceguys/enum/archive/v1.0.zip"
    },
    "commerceguys/addressing": {
      "version" : "v1.0.0-beta3",
      "url": "https://github.com/commerceguys/addressing/archive/v1.0.0-beta3.zip"
    }
  }
}

This list must also include the libraries' dependencies, since no resolving takes place. In our example, the first two libraries are required by commerceguys/addressing.

The site administrator downloads and installs Ludwig then downloads the modules in question (but doesn't install them yet). They can then go to admin/reports/packages and see their status:

The Ludwig reports UI.

The Packages page provides a download link for each missing library along with the paths where they should be placed. The administrator can download the libraries, then clear the cache to make them available.

If the administrator wants to avoid Composer but isn't afraid of the command line they can do everything with a single Console command:

The Ludwig command line interface.

This downloads the missing libraries automatically.

Thus, with Ludwig the installation instructions for Commerce once again become:

  1. Download Commerce and the 6 required modules (Address, Entity API, Entity Reference Revisions, Inline Entity Form, Profile, State Machine).
  2. Use Ludwig to download libraries required by those modules.
  3. Install the modules.

This becomes potentially painful once it's time to update Commerce, since all 7 modules need to be downloaded again, and then all of their libraries need to be downloaded again as well.
If using Drush or Drupal Console the process is painless, but if everything is done manually, the process becomes long and potentially painful.
Site administrators also need to be careful when combining modules that depend on external libraries, since there are no safeguards against incompatible library versions or overlapping requirements.

Final notes

You will need -dev versions of Commerce and Address for this to work. Other modules (such as payment gateways) haven't been updated with ludwig.json files yet. Commerce documentation will be updated soon, but Composer will stay the recommended way to install and maintain a site.

Bojan Zivanovic
Posted: Jun 2, 2017

Comments

slewazimuth slewazimuth on July 3, 2017

I'm glad so see that I can still use composer as it has worked for me all along. As I took a bit of a break from a project I got a chance this week to look again at Drupal Commerce 2.x. Its come a long way and I can say the work the whole team has accomplished is excellent. I added the commerce_paypal module and all I can say is KUDOS to everyone. Everything works perfectly. I was able to go from zero to a set of products including all the taxes and had everything going in less than 30 minutes including successfully completing the payment transactions.WOW!!! This is the best working commerce system I've ever used.

jbeall on September 10, 2017

I use Ludwig and my view does not make a block for my cart. I'm not sure how to find it. I also do not have this Package "doctrine/collections" in Ludwig. any help?