Composer Best Practices for TYPO3
By Mike Street
I revel in reading about other peoples processes, file structures and best practices. I soak up their standards, seeing if I can optimise, tweak or evolve my own to seek that golden chalice of efficiency.
Following in the same vein of Daniel Siepmann's TYPO3 Composer Best Practices, I thought I would outline the file structure and conventions for our TYPO3 composer-based projects. We look after more than 60 TYPO3 sites, so our methodology is based on being able to switch between projects and have consistency between them. This helps speed up development as we don't have to familiarise ourselves with different project layouts.
In our top-level, we have an
app for our site packages & custom extensions:
│ ├── sites/
│ │ └── site1
│ └── ext/
│ └── custom_extension
The thing you will notice is different is that the sites are then in an second sub-folder. This helps differentiate extensions which are sites, compared to packages which are built purely for this TYPO3 install.
sites sub-folder in
app is required, and the folder/extension name must match that of the
config/sites folder - this helps us marry up the code based extension with the site's YAML config.
If the TYPO3 install is a multi-site, we tend to include a
app/sites/site_package folder, which includes code shared between the sites (e.g. TypoScript, CSS or TCA)
ext folder is optional, and only used if there is a custom extension for this site. Not only does it separate it from the site packages, it helps us quickly identify patterns where local extensions are re-used or could be published.
We also allow a couple of other folders in the
composer for local non-TYPO3 but composer based packages and
npm, should we require a local node package.
For local packages, we have a few conventions to help our developers quickly identify and separate functionality
- All local packages have
"version": "0.0.0"- we then know any packages of this version (if you see it in the Extension list or composer output) are local to the site
- Any package in
sitesshould be in the
app/liquidlight) - this identifies it as a site package
- Any package in
npm, is namespaced with
liquidlight/cool-extension) - this means we can more easily port it between installs or make it globally more easily
All our PHP classes are namespaced with
LiquidLight - regardless of if they are local sites, local extensions or our published packages.
The top level composer should require the site packages and any install level packages (e.g. for deployment). Any packages for each site should be in the site's composer file.
Our composer/TYPO3 packages can come from 3 different locations: locally, our private Gitlab instance or Packagist.
As Packagist is assumed by default, this doesn't need to be specified in the
repositories section of the Composer file, however the other two do. You'll notice the
path looks in
./app/*/* as we want to look in the
As we want to prioritise the local packages, these are specified first, followed by the Gitlab private package URL:
All our sites are checked and kept up-to-date with Renovate which runs between 8am and 4pm every weekday. Bug fixes are auto deployed while minor package releases get a merge request raised for a developer to review. During this process, the Composer files are linted and checked to make sure packages are compatible. Renovate knows to ignore any packages with the version number of
0.0.0 - which is another reason for having local packages fixed to this.
Thanks to Daniel Siepmann for inspiring this post (and all the work he does for TYPO3)!