Important: #98484 - Extensions and assets outside of document root for Composer-based TYPO3 installations
See forge#98484
Description
TYPO3 v12 requires the Composer plugin typo3/
with v5,
which automatically installs extensions into Composer's vendor/
directory, just like any other regular dependency. This increases the default
security, so that files from extensions can no longer be accessed directly via
HTTP.
In order to allow serving assets (images/icons, CSS, JavaScript) from the
public web folder, every directory Resources/
of any
installed extension is symlinked from their original location to
a directory called _assets/
within the public web folder (public/
by
default).
The name of a symlinked directory is created as a MD5 hash to prevent possible information disclosure. As of now, this hash depends on the extension name and its Composer project path, so it will not change upon deployment. The specific hashing is an implementation detail that may be subject to change with future TYPO3 major versions.
For example, a file that was previously accessible as
public/
will
now be stored in vendor/
and be symlinked to public/_
.
Impact
Please note that this only affects TYPO3 installations in Composer mode:
- Any references from your Fluid templates, CSS/JavaScript files (or similar)
that pointed to
typo3conf/
must now be changed (search your extension code forext/... typo3conf/
). Ideally change code within Fluid or TypoScript, so that you can use aext/ EXT:
reference. Those will automatically point to the rightmy_ extension/ Resources/ Public/... _assets
directory. For example, thef:
ViewHelper will help you with this, as well as the TypoScript stdWrap insertData and data path or typolink / IMG_RESOURCE functionality. Also, in most YAML definitions you can use theuri. resource EXT:
notation.my_ extension/ Resources/ Public/... - Adjust possible frontend build pipelines which previously wrote files into
typo3conf/
so that they are now put into your extension source directory (for example,ext/... packages/
).my- extension/... - Any other static links to these files (like PHP API endpoints) must be changed to either utilize dynamic routes, middleware endpoints or static files/directories from custom directories in your project's public web path.
- References within the same extension should use relative links, for example use
background-
instead ofimage: url ('../ Images/ logo. jpg') background-
.image: url ('/ typo3conf/ ext/ my_ extension/ Resources/ Public/ Images/ logo. jpg') - You can use TypoScript/PHP/Fluid as mentioned above to create variables with
resolved asset URI locations. These variables can utilize the
EXT:
notation, and can be passed along to a JavaScript variable or a HTML DOM/data attribute, so it can be further evaluated.my_ extension/ Resources/ Public/... -
If one extension links to an asset from another extension, and you cannot use the
EXT:
syntax (for example, background images in a CSS file) you should either:my_ extension/ Resources/ Public/... - Create a central, sitepackage-like extension that can take care of delivering
all assets. CSS classes could be defined that refer to assets, and then other
extensions could use the CSS class, instead of utilizing
their own
background-
directives. Ideally, use a bundler for your CSS/JavaScript (for example Vite, webpack, grunt/gulp, encore, ...) so that you only have a single extension that is responsible for shared assets. Bundlers can also help you to have a central asset storage, and distribute copies of these assets to all dependencies/sub-packages that depend on these assets.image: url (...) - Utilize a PSR middleware or dynamic routes to "listen" on a specific URL like
dynamic
and create a wrapper that returns specific files, resolved via the TYPO3 methodAssets/ logo. jpg Path
.Utility:: get Absolute Web Path (General Utility:: get File Abs File Name ('EXT: my- extension/ Resources/ Public/ logo. jpg') - If all else fails: You can link to the full MD5 hashed URL, like
background-
(or create a custom stable symlink, for example within your deployment, that points to the hashed directory name). The caveat of this: the hashing method may change in future TYPO3 major versions, and since the hash is based on a Composer project directory, this is only a suitable workaround for custom projects, and not publicly available extensions that need to work in all installations. Changes to the location/name of theimage: url ('/_ assets/ 9e592a1e5eec5752a1be78133e5e1a60/ Images/ logo. jpg') vendor/
directory would then break frontend functionality.
- Create a central, sitepackage-like extension that can take care of delivering
all assets. CSS classes could be defined that refer to assets, and then other
extensions could use the CSS class, instead of utilizing
their own
For more details and the background about the change, read more: