EXT:vhs a.k.a. 'the Swiss army knife for Fluid templates' comes with flexible and powerful means of including and processing JavaScript and CSS with Assets. In this blog post I will demonstrate the basic usage of Assets and some nice advanced tricks.

Let's assume a FluidTYPO3 provider extension with a page template and some content elements (in case you don't know what I'm talking about here you might have a look at my earlier blog post. As vhs has no dependencies you can of course use it in any other extension as well - there's no limitation to FluidTYPO3.

Global assets

First of all we want to add some global Javascript like jQuery and some global stylesheet that should always be included. This can be achieved by adding those to our extension's static TypoScript file:

plugin.tx_vhs.settings.asset {
    script {
        name = script
        path = EXT:myext/Resources/Public/js/script.js
    }
    styles {
        name = styles
        path = EXT:myext/Resources/Public/css/styles.css
    }
}

As you can see plugin.tx_vhs.settings.asset is an array of arrays representing assets to be included. The array keys are actually random but should be chosen to simplify overriding values at a later stage and the minimum to provide are a machine readable name and a path. Paths can be relative like fileadmin/css/styles.css, a resource path like in the above example or an URL to an external resource. In the latter case it is required to declare the asset external:

plugin.tx_vhs.settings.asset {
    font {
        name = font
        path = http://fonts.googleapis.com/css?family=Roboto
        type = css
        external = 1
    }
    styles {
        name = styles
        path = EXT:myext/Resources/Public/css/styles.css
    }
    jquery {
        name = jquery
        path = http://code.jquery.com/jquery-1.10.1.min.js
        external = 1
    }
    script {
        name = script
        path = EXT:myext/Resources/Public/js/script.js
    }
}

In addition we explicitly provided type = css because Assets wouldn't be able to determine the type from the URL.

What happens?

With the above code Assets will copy - or download when declared external - the resources to typo3temp, concatenate those of the same type and insert according tags into the page HTML source like so:

<html>
<head>
    ...
    <link rel="stylesheet" href="/typo3temp/vhs-assets-font-styles.css?1388233911" />
    ...
</head>
<body>
    ...
    <script type="text/javascript" src="/typo3temp/vhs-assets-jquery-script.js?1388233911"></script>
</body>
</html>

The names of the copied/concatenated files are constructed out of the assets' names in order of inclusion. In case that's not desired - filenames can become quite long - we can instruct Assets to create hashed filenames instead by setting plugin.tx_vhs.assets.mergedAssetsUseHashedFilename = 1.

To avoid caching a query string with the current timestamp is appended to all assets URLs. By setting $TYPO3_CONF_VARS['FE']['versionNumberInFilename'] = 'embed' this timestamp won't be appended but embedded in the filename.

If a resource shouldn't be copied, downloaded, concatenated or processed in any way but instead included directly as is (typically CDN located resources) set rewrite = 0, external = 1 and standalone = 1 (yes, all three) on that resource:

plugin.tx_vhs.settings.asset {
    ...
    jquery {
        name = jquery
        path = http://code.jquery.com/jquery-1.10.1.min.js
        external = 1
        standalone = 1
        rewrite = 0
    }
    ...
}

Assets will now create a single tag pointing to the provided URL for this resource:

...
<script type="text/javascript" src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
...

Header/Footer

It is considered best practice to place all CSS into the page header whereas all JavaScripts should be placed at the bottom of the page and Assets will do that by default. In some cases you might want to override this behavior for example when using Modernizr which should be loaded early:

plugin.tx_vhs.settings.asset {
    ...
    modernizr {
        name = modernizr
        path = EXT:myext/Resources/Public/js/vendor/modernizr.custom.js
        movable = 0
        standalone = 1
    }
    ...
}

By setting movable = 0 the script won't be moved to the bottom of the page, standalone = 1 will exclude it from concatenation. The resulting HTML source now looks like this:

<html>
<head>
    ...
    <script type="text/javascript" src="/typo3temp/vhs-assets-modernizr.js?1388238782"></script>
    <link rel="stylesheet" href="/typo3temp/vhs-assets-font-styles.css?1388233911" />
    ...
</head>
<body>
    ...
    <script type="text/javascript" src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
    <script type="text/javascript" src="/typo3temp/vhs-assets-script.js?1388233911"></script>
</body>
</html>

Ordering and dependencies

By default assets defined like in the above code are included in 'order of appearance' which is not always what we want. But fear not: We can define an asset's dependencies to make sure those get loaded beforehand:

plugin.tx_vhs.settings.asset {
    font {
        name = font
        path = http://fonts.googleapis.com/css?family=Roboto
        type = css
        external = 1
    }
    styles {
        name = styles
        path = EXT:myext/Resources/Public/css/styles.css
        dependencies = font
    }
    modernizr {
        name = modernizr
        path = EXT:myext/Resources/Public/js/vendor/modernizr.custom.js
        movable = 0
        standalone = 1
    }
    anotherscript {
        name = anotherscript
        path = EXT:myext/Resources/Public/js/anotherscript.js
        dependencies = jquery,script
    }
    jquery {
        name = jquery
        path = http://code.jquery.com/jquery-1.10.1.min.js
        external = 1
        standalone = 1
        rewrite = 0
    }
    script {
        name = script
        path = EXT:myext/Resources/Public/js/script.js
        dependencies = jquery
    }
}

Independent from the order of appearance in the above code all assets will now be included in the correct order to meet all dependencies:

<html>
<head>
    ...
    <script type="text/javascript" src="/typo3temp/vhs-assets-modernizr.js?1388238782"></script>
    <link rel="stylesheet" href="/typo3temp/vhs-assets-font-styles.css?1388233911" />
    ...
</head>
<body>
    ...
    <script type="text/javascript" src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
    <script type="text/javascript" src="/typo3temp/vhs-assets-script-anotherscript.js?1388233911"></script>
</body>
</html>

ViewHelpers

All of the above features are also available as ViewHelpers to let you add Javascript or CSS per content element or page template. Say we have created this nice content element - a slider for instance - that needs some extra JavaScript and CSS and we want to add those only on pages where the slider is rendered. Piece of cake:

<v:asset.script path="EXT:myext/Resources/Public/js/vendor/slider/lib.js" name="sliderjs" dependencies="jquery,script" />
<v:asset.style path="EXT:myext/Resources/Public/js/vendor/slider/lib.css" name="slidercss" dependencies="font" />

By adding this line to the content element's template the required JavaScript will only be included on pages containig the content element while respecting dependencies and being concatenated into one single file:

<html>
<head>
    ...
    <script type="text/javascript" src="/typo3temp/vhs-assets-modernizr.js?1388238782"></script>
    <link rel="stylesheet" href="/typo3temp/vhs-assets-font-slidercss-styles.css?1388233911" />
    ...
</head>
<body>
    ...
    <script type="text/javascript" src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
    <script type="text/javascript" src="/typo3temp/vhs-assets-script-sliderjs-anotherscript.js?1388233911"></script>
</body>
</html>

Nifty, huh?

Inline JavaScript or CSS can be included as well and again all mentioned features also apply:

<v:asset.script name="inlinejs" dependencies="jquery">
    $(function(){
        alert('Foobar!');
    })
</v:asset.script>

The JavaScript code would be merged into the other concatenated scripts respecting dependencies. Don't want that? use standalone="TRUE".

Fluid parsing

Inline JavaScript or CSS is often added to introduce some dynamic values like a global JS variable. Using Fluid rendering we can seamlessly 'mix' those with Fluid variables:

<v:asset.script name="inlinejs" dependencies="jquery" fluid="TRUE">
    var foobar = "<f:format.raw>{foobar}</f:format.raw>";
    $(function(){
        alert('Foobar is ' + foobar);
    })
</v:asset.script>

The argument fluid="TRUE" enables Fluid parsing on the content of the ViewHelper or the included file.

We need to wrap Fluid variables into <f:format.raw /> to distinguish them from JavaScript code (the curly brackets, you know)

Integrators gonna dig this

I think it's worth noting that each and every's asset's configuration can be overriden with TypoScript - especially those included with ViewHelpers - which is kind of interesting for integrators: Create your templates with sensible defaults and let integrators tune them to their requirements without having to touch your extension.

Questions?

Well, that's about all for the basic and a little more advanced usage. For any questions please visit us on IRC, channel #fedext on Freenode.