TYPO3 undertakes the next big step in its capabilities and functionality as a Composer based application. With TYPO3 v11 (optional) and TYPO3 v12 (mandatory) the structure of Composer based TYPO3 projects will change. And it will change for the better.
We are saying "Good Bye" to old friends like typo3conf/ext
and old enemies like the accidental sharing of nonpublic extension files. The web root of a Composer based TYPO3 project will look different and overall web security will increase. Or, as Benni Mack puts it:
We've worked together over the past seven years to achieve this milestone for TYPO3.
(source: TYPO3 and Composer — we've come a long way, Blog Post, 2022)
Before we take a closer look, let's take some moments and look back at how we got here.
Previously on "TYPO3 and Composer"
TYPO3 and Composer have come a long way. I covered the basics way back in 2015 for TYPO3 v7 and v8 with the article TYPO3 and Composer. While some of the things stated there are still valid, many things have further improved and thus, changed. For example the Composer package typo3/cms
is long gone now.
That is, because a big step was taken during TYPO3 v9 times with the so called "subtree split", that made every TYPO3 system extension available as a separate git repository and therefore also as a Composer package (read more about this in the article The TYPO3 Subtree Split and Composer). Also, a policy was communicated to move all extensions to packagist.org to get rid of composer.typo3.org.
As of February 2022, there are about 2.700 packages registered as publicly available TYPO3 extensions (type:typo3-cms-extension
) at packagist. Impressive.
The composer plugin typo3/cms-composer-installers did most of the heavy lifting for composer based TYPO3 projects since the early days. It detected TYPO3 extensions and made sure they ended up in the typo3conf/ext
folder. It also assured that system extensions and entry point scripts like index.php
are at the correct places.
It is the reason we put the following in the composer.json
files of our extensions:
"extra": {
"typo3/cms": {
"extension-key": "my_extension"
}
}
For Composer based TYPO3 installations this is a central piece of software, that is constantly improved and quite well maintained. Kudos to Helmut Hummel, who put a lot of thoughts and work into this package as well as the whole area "TYPO3 and Composer" for years. Without him, TYPO3 for sure would not be where it is today in terms of composer support. So, thank you, Helmut <3
!
When TYPO3 v11 LTS was released, typo3/cms-composer-installers
was required by the TYPO3 core with version 2 or version 3 (^2.0 || ^3.0
, see git tag 11.5.0 at GitHub for reference). But v4 of the package was already at the horizon.
typo3/cms-composer-installers v4
During the development of TYPO3 v12, support for v4 of the composer-installers has been added. But more interestingly, the before mentioned v4 support has also been backported to the 11.5 branch of TYPO3 with this Patch.
Since then, the composer constraint for typo3/cms-composer-installers
looks like this for the TYPO3 core:
"typo3/cms-composer-installers": "^2.0 || ^3.0 || ^4.0",
And this means, that once v4 of the composer-installers is released, a regular composer update 'typo3/*' -W
command will update the package to v4. Be aware of this when you update TYPO3 11 LTS to a new minor patch level and update all dependencies (-W
) as you should.
To say this one more time:
Once v4 of the composer-installers is released, a regular composer update 'typo3/*' -W
command will update the package to v4.
We will see what that actually means in a minute, for now let's make sure that everybody is on the same page for this, or as Helmut put it:
With Helmut asking everybody to spread the word (original tweet), I did my part in saying it twice and now, one more time remind you to read the blue box above.
OK, enough with the word spreading.
Let's finally see why we WANT v4 of the typo3/cms-composer-installers
, shall we?
A new structure for composer based TYPO3 projects
With v4 of typo3/cms-composer-installers
the structure of the publicly available folder (aka document root, aka web root) will change quite a bit. All extensions will be installed into the Composer vendor
folder like every other package loaded by Composer. Extensions will no longer be put or symlinked to typo3conf/ext
.
In fact, there will no longer be a typo3conf/ext
folder.
Instead, all public files of all installed extensions are symlinked into a new folder called _assets
. The extension name is replaced by a hash that can not be translated back to an extension name. Each hash is a symlink to the Resources/Public
folder of the corresponding extension.
All other files are no longer accessible through the web.
And this is the big gain. Security by design.
No more unintended file leakages due to insufficient webserver configuration. Also, it is now much harder to identify installed extensions, because a path to a public asset loaded from extensions does no longer contain the extension name but the before mentioned hash.
If this reminds you of Helmuts typo3-secure-web
package (see at GitHub), you are absolutely right. It is a very similar functionality.
To illustrate what we just said, let's have a look at the resulting folder structure of an example project with a few installed extensions.
The public web root folder looks like this:
tree public -L 3
public
├── _assets
│ ├── 081fa96a07de1dccb64a8a83e1567439 -> ../../vendor/typo3/cms-backend/Resources/Public
│ ├── 0c22fd3d95c93dc31098cc8d4b1d7232 -> ../../vendor/typo3/cms-belog/Resources/Public
│ ├── 14525e5262e0d22d75f200ddba75ef39 -> ../../vendor/typo3/cms-fluid-styled-content/Resources/Public
│ ├── 1c7427e903b0a6ef0b4495f72da0f918 -> ../../vendor/b13/host-variants/Resources/Public
│ ├── 1ee1d3e909b58d32e30dcea666dd3224 -> ../../vendor/typo3/cms-core/Resources/Public
│ ├── 2983062c4310b9f778ca0a360e9a8c05 -> ../../vendor/typo3/cms-recordlist/Resources/Public
│ ├── 2a58d7833cb34b2a67d37f5b750aa297 -> ../../vendor/typo3/cms-frontend/Resources/Public
│ ├── 2f9f1781442d461eab73b573487122ef -> ../../vendor/typo3/cms-form/Resources/Public
│ ├── 34d632057b1a1586dba4464836293c82 -> ../../vendor/typo3/cms-viewpage/Resources/Public
│ ├── 37ee5ba7a97ad859ac99cb8181e0c0e3 -> ../../vendor/typo3/cms-dashboard/Resources/Public
│ ├── 509a7bacf53455dd0e8bc14336b58c3d -> ../../vendor/typo3/cms-extbase/Resources/Public
│ ├── 6104b7f46d656dcf567ead154886bf37 -> ../../vendor/typo3/cms-install/Resources/Public
│ ├── 655b24546496542a156e68040db1973b -> ../../vendor/b13/bolt/Resources/Public
│ ├── 656f1405e34da8aeed0d2793b00aa50a -> ../../vendor/typo3/cms-felogin/Resources/Public
│ ├── 6942460bf1dad5e61e3275534adcf333 -> ../../vendor/typo3/cms-sys-note/Resources/Public
│ ├── 8a66752868b3228c5bb3123a8e469f95 -> ../../vendor/danielgoerz/dummy-plugin/Resources/Public
│ ├── 92d0321322c294e77404bf74cad9c7d4 -> ../../vendor/typo3/cms-beuser/Resources/Public
│ ├── 937be57c7660e085d41e9dabf38b8aa1 -> ../../vendor/typo3/cms-rte-ckeditor/Resources/Public
│ ├── 984e6ee9829f85eb447bb6a36455204a -> ../../vendor/typo3/cms-seo/Resources/Public
│ ├── 9e592a1e5eec5752a1be78133e5e1a60 -> ../../vendor/typo3/cms-setup/Resources/Public
│ ├── a3db3388ff457cff602f74c897474ebb -> ../../vendor/typo3/cms-fluid/Resources/Public
│ ├── b1439bab8f20d76bfa926e2ce031de9d -> ../../vendor/typo3/cms-info/Resources/Public
│ ├── c8e1f76a9cd1146509b84ed6e77f8f60 -> ../../vendor/typo3/cms-t3editor/Resources/Public
│ ├── cddd1dcdf2ba9efa5a1cbf7e00411594 -> ../../vendor/typo3/cms-extensionmanager/Resources/Public
│ ├── eecf5c3877e98efe7b03503e2b450a69 -> ../../vendor/typo3/cms-filelist/Resources/Public
│ ├── faac6516a43fc0a1b5f92bf624a4e449 -> ../../vendor/typo3/cms-tstemplate/Resources/Public
│ └── faf19450e1010c05b9936b975b1457a6 -> ../../vendor/typo3/cms-impexp/Resources/Public
├── fileadmin
│ ├── _temp_
│ │ └── index.html
│ └── user_upload
│ ├── _temp_
│ └── index.html
├── index.php
├── typo3
│ ├── index.php
│ └── install.php
├── typo3conf
│ └── LocalConfiguration.php
└── typo3temp
├── assets
│ ├── _processed_
│ ├── compressed
│ ├── css
│ ├── images
│ └── js
└── index.html
We see that all extensions, i.e. local extensions (EXT:dummy_plugin), 3rd party extensions (EXT:bolt, EXT:host_variants) and system extensions (everything else) have their public assets symlinked into the _assets
folder. The extension names have been obscured and all PHP files are located in the vendor folder outside the publicly accessible document root.
The typo3
folder contains nothing but the entry scripts index.php
and install.php
.
The typo3conf
folder is also almost empty. The configuration files LocalConfiguration.php
and AdditionalConfiguration.php
(absent in the example but if the file existed, it would still be located in the folder typo3conf
) still live here, but they might vanish from the publicly available folders as well until the release of TYPO3 v12 LTS.
Now, that we know why we absolutely want this new structure as soon as possible, let's look on how to deal with potential issues and how to prepare a project to have a smooth transition.
Potential Issues and how to solve them
Some things should be considered before updating the composer-installers in a project.
There also is the option to opt-out of the update for the time being if time, project structure or code base do not allow for a quick update.
Let's have a look.
Omitting the new behavior completely in TYPO3 v11 projects
First of all, there is a simple thing you can do, if you do not want to deal with these changes at all and rather look at them in a future TYPO3 update to v12, when this becomes the new standard.
In that case, just tell Composer to not update to v4 of the typo3/cms-composer-installers
package through your projects root composer.json
and you are done. One command should do the trick:
composer req typo3/cms-composer-installers:^3
With this v4 will not be installed once it is released.
Load local extensions with composer
Most projects contain at least one local extension, developed merely for the projects it lives in, most likely in the same git repository. Make sure that those extensions are loaded by composer as well. This can be achieved by using a path repository configuration in the root composer.json
of the project:
"repositories": [
{
"type": "path",
"url": "src/extension/*"
}
],
All extensions have to be moved to the specified path, and they also mus contain a valid composer.json
file. You can also have multiple path repositories, if you somehow need more than one path.
You probably already do this, so let's move to issues, that might come up.
Remove hardcoded paths containing typo3conf/ext
Depending on your code base and deployment process this might be the biggest workload. Scan your project for occurrences of typo3conf/ext
. Here are some, but certainly not all, possible places where someone could have used the path:
- Specifying some sort of image file path in a fluid template or in typoscript
- Including JavaScript or CSS with the full path
- Pointing to images or fonts from CSS (think background-image or icon fonts)
- Building assets to
Resources/Public
of an extension during the deployment process
Note that the EXT:
syntax is perfectly fine wherever it is resolved by the TYPO3 core. In fact, it is often the correct way to specify any assets:
page.includeCSS {
veryGoodStyles = EXT:my_ext/Resources/Public/CSS/veryGoodStyles.css
}
This will still work.
If for any reason you need to include a file in a fluid template, use the ResourceViewHelper
to resolve the path for you:
<link href="{f:uri.resource(path:'Css/veryGoodStyles.css', extensionName: 'myExt')}" rel="stylesheet" />
When looking for occurrences of hard coded typo3conf/ext
paths, also look for usages of the environment API for that path, as that API may yield the old and now absent path as well:
// this will yield typo3conf/ext as well
\TYPO3\CMS\Core\Core\Environment::getExtensionsPath();
On a side note: referencing nonpublic files with the EXT:
syntax also still works, nothing has to be done in case like the following:
page.inlineLanguageLabelFiles {
veryGoodLabels = EXT:my_ext/Resources/Private/Language/locallang.xlf
}
Last but not least, also make sure, that no extension provides publicly available assets from a different path than Resources/Public
. They absolutely shouldn't, but better be safe than sorry.
And with all that said and considered, you should be able to get a pretty good idea of the efforts you have to put into moving to the new and superior structure in Composer based TYPO3 projects. It is absolutely possible that you do not need to do anything, but a few hours of work are likely. Anyway, it is 100% worth the effort.
If you encounter any further issues please let the core team know by opening issues at forger or GitHub.
Thanks for reading and for supporting the blog!
Further Information
-
TYPO3 and Composer — we've come a long way, Blog Post, 2022 by Benni Mack
-
Comment on the Topic by Helmut Hummel at GitHub