Composer Vendor Directory
A common question in composer support is to install packages into a directory
other than vendor
. I want to explain why that is a bad idea.
Achtung: Might be a little ranty.
One True Vendor
You don’t own your vendor directory. When you use composer, you are waiving your right to decide where things go. This is for your own good. You should not know where composer puts stuff, and frankly, you should not care.
Composer makes it extremely hard for you to install a package anywhere else than the one true vendor directory. And this is by design. And there is a good reason for that.
Composer targets the PHP community. It aims to grow the library space. Libraries should be small, focused, flexible and avoid side-effects. The user should be in control.
What sort of side-effects? Don’t create files unless the user asked for them. Don’t use global state such as superglobals. Don’t call echo, header or exit. Don’t depend on the location of things in the filesystem, the network or otherwise.
Autoloading
The loading of classes (and functions, etc.) is no exception to this rule. As a user, I want to specify my dependencies, run one command, include one file, and be done with it. I don’t want to care about where stuff is located, set up include paths, manually include files, define my own autoload mappings.
Autoloading solves this problem. If every library defines its own rules for autoloading, PHP takes care of the rest. Libraries don’t have to know where they or other libs are located. The user is in control.
A composer-managed application should have exactly one single include
statement. A require vendor/autoload.php
in the front controller.
A library should have zero.
Single directory
Putting everything into one directory just makes sense.
First off, debugging composer issues. Composer has come a long way, but strange things can happen sometimes. Maybe some files are in an inconsistent state, maybe someone deleted something accidentally, maybe there was a bug in the solver. The point is, composer is not operating correctly due to the state of the vendor directory.
You can just try again by rm -rf vendor && composer install
. You don’t have
to keep track of zillions of possible directories, it’s all in one place.
Second, deployment. When deploying, I want the stuff right there. I want it in
the right place, I want to be able to push it all at once. With a single
directory it doesn’t even matter where I run composer install
, because the
result is consistent and easy to manage as part of the build and deployment
process.
Third, version control. No need to litter your gitignore with random garbage.
Isolation
Remember PEAR? Not only was PEAR itself installed into some global-ish location (if you were lucky enough to actually successfully install it), but all libraries installed via PEAR were global. If you had two projects depending on conflicting versions of the same package, you were screwed.
Enough of that. That’s why composer is a dependency manager and not a package manager. It manages deps per-project, it isolates them. It disallows sharing the same package directory between projects.
Yes, that means you potentially get two copies, but trust me, it’s totally worth it.
Excuses
Here are some reasons why you would need to move your packages to a specific location:
-
Legacy: You have some legacy project that heavily relies on the location of files. You cannot break BC. Recommendation: Let it die.
-
Frontend: You have some CSS or JS files that must go to the web directory. Recommendation: Use symlinks or copy them over.
-
I want to: No you don’t. Now play nice, and autoload.
If you must, there are some tricks such as custom installers or scripts.
But remember, if you use them you are hurting the ecosystem. And I will get mad.
Conclusion
The vendor directory is a black box. The public API is vendor/autoload.php
.