Vite AssetCollector

Extension key

vite_asset_collector

Package name

praetorius/vite-asset-collector

Version

main

Language

en

Author

Simon Praetorius

License

This document is published under the Creative Commons BY 4.0 license.

Rendered

Wed, 10 Sep 2025 16:55:16 +0000


Vite AssetCollector allows you to use the modern frontend bundler Vite to build your TYPO3 project's frontend assets.


Table of Contents:

Introduction

What does it do?

Vite AssetCollector allows you to use the modern frontend bundler Vite to build your TYPO3 project's frontend assets.

Vite supports all common CSS processors and TypeScript out-of-the-box and has a wide range of well-supported plugins for popular frontend frameworks. Its hot module replacement feature allows you to develop your frontend assets without constantly reloading the browser to see your changes. As a bonus, Vite offers a simple configuration and is easy to use.

The extension is necessary both on development and on production systems because it needs to treat these environments differently.

It is recommended to use this extension together with a corresponding Vite plugin, however it's also possible to configure Vite manually.

Components

There are two additional projects that can be used in combination with the TYPO3 extension. When used together, the setup experience is seamless and requires almost no configuration.

Vite AssetCollector

(this TYPO3 extension)

  • switches between Development and Production integration
  • brings tools to embed assets from Vite in TYPO3 (like ViewHelpers)

Vite Plugin

(vite-plugin-typo3)

  • configures Vite for TYPO3
  • discovers and bundles TYPO3 extensions in composer project

DDEV Add-On

(ddev-vite-sidecar)

  • allows to run the Vite development server inside ddev setups
  • supports Apache and Nginx

Credits

This extension is inspired by typo3-vite-demo which was created by Florian Geierstanger.

Installation

Vite AssetCollector can be installed with composer:

composer req praetorius/vite-asset-collector
Copied!

Make sure to run this command inside of your DDEV container if you're using DDEV.

Vite and the TYPO3 plugin can be installed with the frontend package manager of your choice:

npm install --save-dev vite vite-plugin-typo3
Copied!

Make sure to execute this inside of your DDEV container if you want to use the DDEV add-on afterwards.

pnpm add --save-dev vite vite-plugin-typo3
Copied!

Make sure to execute this inside of your DDEV container if you want to use the DDEV add-on afterwards.

yarn add --dev vite vite-plugin-typo3
Copied!

Make sure to execute this inside of your DDEV container if you want to use the DDEV add-on afterwards.

Getting Started

Follow these steps to get a basic Vite setup for your frontend assets in a sitepackage extension.

Vite Setup

To get things started, you need to create a vite.config.js in the root of your project to activate the TYPO3 plugin:

vite.config.js
import { defineConfig } from "vite";
import typo3 from "vite-plugin-typo3";

export default defineConfig({
    plugins: [typo3()],
});
Copied!

For more information about the Vite plugin, have a look at its dedicated documentation.

TYPO3 Setup

Vite uses so-called entrypoints, which are your frontend source files you want to process and bundle with vite. For each extension, you can define one or multiple Vite entrypoints in a json file:

sitepackage/Configuration/ViteEntrypoints.json
[
    "../Resources/Private/Styles.entry.css",
    "../Resources/Private/Main.entry.js"
]
Copied!

It is also possible to define a glob pattern like this: "../Resources/Private/*.entry.{js,ts,css,scss}". Inside of each entrypoint file you can import all frontend assets you want to bundle.

Then you can use the included ViewHelper to embed your assets. If you use the default configuration, you only need to specify your entrypoint.

Layouts/Default.html
<html
    data-namespace-typo3-fluid="true"
    xmlns:vite="http://typo3.org/ns/Praetorius/ViteAssetCollector/ViewHelpers"
>

...

<vite:asset entry="EXT:sitepackage/Resources/Private/Styles.entry.css" />
<vite:asset entry="EXT:sitepackage/Resources/Private/Main.entry.js" />
Copied!

Start Vite Server

For local development, you need a running Vite server that serves your frontend assets alongside the normal webserver. On production systems, this is no longer necessary.

First, TYPO3 needs to run in Development context for the extension to recognize the correct mode automatically.

You have several options to run the dev server:

Prerequisite is an add-on for DDEV called ddev-vite-sidecar. For DDEV v1.23.5 or above run:

ddev add-on get s2b/ddev-vite-sidecar
ddev restart
Copied!

For earlier versions of DDEV run:

ddev get s2b/ddev-vite-sidecar
ddev restart
Copied!

Then you can start the server inside DDEV:

ddev vite
Copied!

For more information about the add-on, have a look at its dedicated documentation.

Prerequisite is a local node setup and installed dependencies outside of Docker setups. Also, you need to configure the extension to use the correct server url:

config/system/additional.php
$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['vite_asset_collector']['devServerUri'] = 'http://localhost:5173';
Copied!

Then you can start the server, which usually launches on port 5173:

npm exec vite
Copied!

Prerequisite is a local node setup and installed dependencies outside of Docker setups.

config/system/additional.php
$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['vite_asset_collector']['devServerUri'] = 'http://localhost:5173';
Copied!

Then you can start the server, which usually launches on port 5173:

pnpm exec vite
Copied!

Prerequisite is a local node setup and installed dependencies outside of Docker setups.

config/system/additional.php
$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['vite_asset_collector']['devServerUri'] = 'http://localhost:5173';
Copied!

Then you can start the server, which usually launches on port 5173:

yarn exec vite
Copied!

Build for Production

During deployment, the following command builds static asset files that can be used in Production:

npm exec vite build
Copied!
pnpm exec vite build
Copied!
yarn exec vite -- build
Copied!

Next Steps

Project Structure

Learn about the ideal TYPO3 folder structure when using Vite in your project

CSS Preprocessors

Learn how to setup the CSS preprocessor of your choice with Vite

Best Practices

Project Structure

It is recommended to put your package.json and your vite.config.js next to the composer.json in the project root. Vite will be responsible for your whole project, so it makes sense to treat your frontend dependencies similar to your PHP dependencies.

There are multiple ways to structure your frontend assets in TYPO3 projects. If you want to use the Vite plugin, it is recommended to place all your frontend assets inside TYPO3 extensions, from where they can automatically get picked up, for example:

  • node_modules
  • packages
    • sitepackage
      • Configuration
        • ViteEntrypoints.json
      • Resources
        • Private
          • Main.entry.js
          • Slider.entry.js
    • my_custom_ext
      • Configuration
        • ViteEntrypoints.json
      • Resources
        • Private
          • MyCustomExt.entry.js
  • vendor
  • composer.json
  • package.json
  • vite.config.js

Different Folder Structures

If you want to put your frontend assets separately, for example in a frontend/ folder in your project root, you are better off configuring Vite yourself and not using the Vite plugin. The TYPO3 extension doesn't require a specific folder structure, as long as you take care to set the paths correctly both in vite.config.js and in the extension configuration.

Entrypoint Files

It is recommended to name your entrypoint files differently from other asset files to clarify their usage. It might also make sense to use entrypoint files only to create a collection of assets that should become one bundle:

Slider.entry.js
import "path/to/Slider.js"
import "swiper/css"
import "path/to/Slider.css"
Copied!

An entrypoint file is usually a JavaScript or TypeScript file, which then imports other assets. However, it is also possible to use other file types as entrypoints, such as StyleSheets or even SVG images.

Glob Imports

It is possible to use glob patterns to import/collect several assets at once. This can make your setup much more flexible. Glob can be used both in ViteEntrypoints.json and in your entrypoint files:

sitepackage/Configuration/ViteEntrypoints.json
[
    "../Resources/Private/*.entry.js"
]
Copied!

In entrypoint files, you can use { eager: true } to force Vite to collect everything:

Main.entry.js
// Import all CSS files
import.meta.glob(
    "path/to/*.css",
    { eager: true }
)
Copied!

More complex expressions are also possible, like negative patterns:

Main.entry.js
// Import everything except Slider
import.meta.glob([
    "Components/**/*.{css,js}",
    "!**/Organism/Slider/*"
], { eager: true })
Copied!

CSS Preprocessors

If you want to use Vite to compile your SCSS or LESS files, you need to install the required JavaScript libraries as well. No further configuration is necessary.

npm install --save-dev sass-embedded
npm install --save-dev less
npm install --save-dev stylus
Copied!
pnpm add --save-dev sass-embedded
pnpm add --save-dev less
pnpm add --save-dev stylus
Copied!
yarn add --dev sass-embedded
yarn add --dev less
yarn add --dev stylus
Copied!

Referencing Assets in CSS

If you use the Vite plugin, it automatically registers aliases for each TYPO3 extension, which allows you to reference other assets (like webfonts, svg images...) easily in your CSS files. This also works for CSS preprocessors. Each extension gets an EXT: alias as well as an @ alias, for example:

  • EXT:my_extension
  • @my_extension

These can be used both in CSS files and in JavaScript import statements.

_Fonts.scss
@font-face {
    font-family: 'MyFont';
    src: url(
        'EXT:sitepackage/Resources/.../MyFont.eot'
    );
}
Copied!

Configuration for Functional Tests

If you use the extension in a project that utilizes TYPO3's testing framework to validate the HTML output for certain pages, the following adjustments need to be made:

  • Make sure that vite_asset_collector is loaded in your testing setup by adding it to the list in $testExtensionsToLoad
  • To get a consistent frontend output, it is recommended to use the dev server configuration. Because tests are run in TYPO3_CONTEXT=Testing, it might be necessary to specify this option explicitly within your testing setup:
$this->get(\TYPO3\CMS\Core\Configuration\ExtensionConfiguration::class)->set('vite_asset_collector', [
    'useDevServer' => '1',
]);
Copied!

Configuration

If you use the default setup, no configuration should be necessary. However, you can customize almost everything to create your individual development setup.

Adjust Vite Dev Server

The extension has two configuration options to setup the Vite dev server. By default, both are set to auto, which means:

  • Dev server will only be used in Development context
  • Dev server uri will be determined automatically for environments with vite-sidecar or vite-serve for DDEV set up

You can adjust both options in your $TYPO3_CONF_VARS, for example:

config/system/additional.php
// Setup Vite dev server based on configuration in .env file
// TYPO3_VITE_DEV_SERVER='https://localhost:1234'
$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['vite_asset_collector']['useDevServer'] = (bool) getenv('TYPO3_VITE_DEV_SERVER');
$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['vite_asset_collector']['devServerUri'] = (string) getenv('TYPO3_VITE_DEV_SERVER');
Copied!

Change Location of manifest.json

You can specify the path to Vite's manifest.json in the extension configuration. By default, this is set to _assets/vite/.vite/manifest.json, so it will run out-of-the-box with Vite 5 and the Vite TYPO3 plugin.

If you still use Vite < 5, you should change this to _assets/vite/manifest.json.

config/system/additional.php
$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['vite_asset_collector']['defaultManifest'] = 'EXT:sitepackage/Resources/Public/Vite/.vite/manifest.json';
Copied!

If you change the path here, please be aware that you may need to adjust outDir in your vite.config.js as well:

vite.config.js
export default defineConfig({
    // ...
    build: {
        // ...
        outDir: 'path/to/sitepackage/Resources/Public/Vite/',
    }
})
Copied!

Manual Vite Configuration

If you don't want or can't use the Vite plugin, you can configure Vite yourself to work together with the TYPO3 extension. In that case, it is highly recommended to install vite-plugin-auto-origin:

npm install --save-dev vite-plugin-auto-origin
Copied!
pnpm add --save-dev vite-plugin-auto-origin
Copied!
yarn add --dev vite-plugin-auto-origin
Copied!

The manual Vite configuration could look something like this:

vite.config.js
import { defineConfig, defaultAllowedOrigins } from "vite"
import { dirname, resolve } from "node:path"
import { fileURLToPath } from "node:url"
import autoOrigin from "vite-plugin-auto-origin"

// TYPO3 root path (relative to this config file)
const VITE_TYPO3_ROOT = "./";

// Vite input files (relative to TYPO3 root path)
const VITE_ENTRYPOINTS = [

];

// Output path for generated assets
const VITE_OUTPUT_PATH = "public/_assets/vite/";

const currentDir = dirname(fileURLToPath(import.meta.url));
const rootPath = resolve(currentDir, VITE_TYPO3_ROOT);
export default defineConfig({
    base: "",
    server: {
        allowedHosts: [".ddev.site"],
        cors: {
            origin: [defaultAllowedOrigins, /^https?:\/\/.*\.ddev\.site(:\d+)?$/],
        },
    },
    build: {
        manifest: true,
        rollupOptions: {
            input: VITE_ENTRYPOINTS.map(entry => resolve(rootPath, entry)),
        },
        outDir: resolve(rootPath, VITE_OUTPUT_PATH),
    },
    css: {
        devSourcemap: true,
    },
    plugins: [ autoOrigin() ],
    publicDir: false,
});
Copied!

You can also create aliases yourself to refer to other assets in CSS files:

vite.config.js
//...
export default defineConfig({
    // ...
    resolve: {
        alias: [
            { find: "@frontend", replacement: resolve(currentDir, "frontend/") }
        ]
    }
});
Copied!

Backend Usage

RTE styling

You can use Vite to process your CSS files intended for the Rich-Text editor. Note that this uses the production build, the dev server is not available in that context.

  1. Register a new entrypoint in your Vite setup:
EXT:sitepackage/Configuration/ViteEntrypoints.json
[
    "../Resources/Private/Css/Rte.css"
]
Copied!
  1. Embed that entrypoint in your RTE yaml configuration:
MyPreset.yaml
editor:
    config:
        contentsCss:
            - "%vite('EXT:sitepackage/Resources/Private/Css/Rte.css')%"
Copied!
  1. Run the production build (optionally as a watcher):
# Build once
vite build

# Watch for file changes
vite build --watch
Copied!

You can learn more about this in the Yaml Processor documentation as well as the RTE Configuration Examples.

Backend Modules

In the context of a custom backend module, Vite can be used in almost exactly the same way as in the frontend context:

MyModule.html
<html
    data-namespace-typo3-fluid="true"
    xmlns:vite="http://typo3.org/ns/Praetorius/ViteAssetCollector/ViewHelpers"
>

...

<vite:asset entry="EXT:sitepackage/Resources/Private/Backend.entry.js" />
Copied!

However, if you want to use some of TYPO3's included JavaScript modules, like for example a date picker, you may need to extend your Vite configuration:

npm install --save-dev vite-plugin-externalize-dependencies
Copied!
vite.config.js
import { defineConfig } from "vite";
import typo3 from "vite-plugin-typo3";
import externalize from "vite-plugin-externalize-dependencies";

const external = [
    /^@typo3\/.*/
];

export default defineConfig({
    plugins: [
        typo3(),
        externalize({ externals: external }),
    ],
    build: {
        rollupOptions: {
            external: external,
        },
    },
});
Copied!

The additional Vite plugin vite-plugin-externalize-dependencies tells the Vite dev server to ignore all modules starting with @typo3/, the configuration within rollupOptions does the same for the production build.

Within your Fluid template, you can use the Be.pageRenderer ViewHelper <f:be.pageRenderer> to define additional modules that should be added to TYPO3's own import map. For more details, see TYPO3's documentation about ES6 in the TYPO3 Backend.

Library Mode as Workaround

There might be cases where it's not possible to use any of the already mentioned workflows. As a last resort, it is possible to enable Vite's library mode, in which case Vite behaves just like a regular bundler without a dev server and a manifest file.

The Vite plugin already supports this on extension level, which makes it possible to bundle your assets into files with predictable file names an then use those for example in TYPO3's own import map:

EXT:sitepackage/vite.config.js
import { defineConfig } from "vite";
import typo3 from "vite-plugin-typo3";

export default defineConfig({
    plugins: [typo3({ target: "extension" })],
});
Copied!
EXT:sitepackage/Configuration/ViteEntrypoints.json
[
    "../Resources/Private/JavaScript/Backend.entry.js"
]
Copied!
EXT:sitepackage/Configuration/JavaScriptModules.php
<?php

return [
    'dependencies' => ['backend'],
    'imports' => [
        '@vendor/sitepackage/backend' => 'EXT:sitepackage/Resources/Public/Vite/Backend.entry.js',
    ],
];
Copied!
# Build once
vite build

# Watch for file changes
vite build --watch
Copied!

If you use DDEV together with the ddev-vite-sidecar add-on, you have to run the vite build command inside the extension directory (e.g. packages/sitepackage) depending of the node package manager of your choose (e.g. pnpm):

# Build once
ddev pnpm exec vite

# Watch for file changes
ddev pnpm exec vite --watch
Copied!

In all cases you have (of course) to add a dedicated package.json inside the extension and have to install all packages first!

Asset ViewHelper <vite:asset>

The vite:asset ViewHelper embeds all JavaScript and CSS belonging to the specified vite entry using TYPO3's AssetCollector API.

Example

<html
    data-namespace-typo3-fluid="true"
    xmlns:vite="http://typo3.org/ns/Praetorius/ViteAssetCollector/ViewHelpers"
>

<vite:asset
    entry="EXT:sitepackage/Resources/Private/JavaScript/Main.entry.js"
/>
Copied!

Advanced Example

<html
    data-namespace-typo3-fluid="true"
    xmlns:vite="http://typo3.org/ns/Praetorius/ViteAssetCollector/ViewHelpers"
>

<vite:asset
    manifest="EXT:sitepackage/Resources/Public/Vite/.vite/manifest.json"
    entry="EXT:sitepackage/Resources/Private/JavaScript/Main.entry.js"
    scriptTagAttributes="{
        type: 'text/javascript',
        async: 1
    }"
    cssTagAttributes="{
        media: 'print'
    }"
    priority="1"
/>
Copied!

Arguments

The following arguments are available for the asset ViewHelper:

addCss

addCss
Type
boolean
Default
true
If set to "false", CSS files associated with the entry point won't be added to the asset collector

cssTagAttributes

cssTagAttributes
Type
array
Default
array ( )
Additional attributes for css link tags.

devTagAttributes

devTagAttributes
Type
array
Default
array ( )
HTML attributes that should be added to script tags that point to the vite dev server

entry

entry
Type
string
Identifier of the desired vite entrypoint; this is the value specified as "input" in the vite configuration file. Can be omitted if manifest file exists and only one entrypoint is present.

manifest

manifest
Type
string
Path to your manifest.json file. If omitted, default manifest from extension configuration will be used instead.

priority

priority
Type
boolean
Default
false
Include assets before other assets in HTML

scriptTagAttributes

scriptTagAttributes
Type
array
Default
array ( )
HTML attributes that should be added to script tags for built JavaScript assets

useNonce

useNonce
Type
bool
Default
false
Whether to use the global nonce value

Asset.vite ViewHelper <vite:asset.vite>

Resource.vite ViewHelper <vite:resource.vite>

Asset ViewHelper <vite:uri>

The vite:uri ViewHelper extracts the uri to one specific asset file from a vite manifest file. If the dev server is used, the dev server uri to the resource is returned.

Example

This can be used to preload certain assets in the HTML <head> tag.

First, add a Fluid template to your TypoScript setup, for example:

page.headerData {
    10 = FLUIDTEMPLATE
    10 {
        file = EXT:sitepackage/Resources/Private/Templates/HeaderData.html
    }
}
Copied!

Then create the HeaderData template:

EXT:sitepackage/Resources/Private/Templates/HeaderData.html
<html
    data-namespace-typo3-fluid="true"
    xmlns:vite="http://typo3.org/ns/Praetorius/ViteAssetCollector/ViewHelpers"
>

<link
    rel="preload"
    href="{vite:uri(file: 'EXT:sitepackage/Resources/Private/Fonts/webfont.woff2')}"
    as="font"
    type="font/woff2"
    crossorigin
/>

</html>
Copied!

Arguments

The following arguments are available for the uri ViewHelper:

file

file
Type
string
Required
1
Identifier of the desired asset file for which a uri should be generated

manifest

manifest
Type
string
Path to vite manifest file; if omitted, default manifest from extension configuration will be used instead

TYPO3 Icon API

The extension includes a custom SvgIconProvider for the TYPO3 Icon API which allows you to register SVG icon files generated by Vite. This works both in frontend and backend context.

To register a new icon, add the following to the Configuration/Icons.php file:

Configuration/Icons.php
return [
    'site-logo' => [
        'provider' => \Praetorius\ViteAssetCollector\IconProvider\SvgIconProvider::class,
        'source' => 'assets/Image/Icon/typo3.svg',
        'manifest' => 'path/to/manifest.json', // optional, defaults to defaultManifest
    ],
];
Copied!

Then you can use the Icon ViewHelper <core:icon> to use the icon in your templates.

Vite Assets in Yaml Files

Besides ViewHelpers, the extension includes a processor for Yaml files, which allows you to use assets generated by Vite in your configuration files. This is especially useful for custom RTE styling.

Note that this does not support the Vite dev server, but rather uses the files generated by the production build.

MyYamlFile.yaml
# Using the default manifest file
cssFile: "%vite('EXT:sitepackage/Resources/Private/Css/Rte.css')%"

# Using another manifest.json
otherCssFile: "%vite('EXT:sitepackage/Resources/Private/Css/Rte.css', 'path/to/manifest.json')%"
Copied!

Sitemap