Sugar Assets

Sugar Assets

Documentation & API

Adding Assets

You can do this with the <asset /> template tag (or <F3:asset />).

The tag itself accepts some attributes:


<F3:asset src="path/to/file.js" priority="10" group="head" type="js" />

The type attribute is optional - the plugin tries to guess the filetype based on your src filename. The group attribute defines, if the asset should go into the html <head> section or to the footer of your <body>. The default way, using this template tag, is to put CSS files into the head group, and JS files into the footer group.

Dynamic attributes? No problem:


<F3:asset src="{{ 'css/'.@theme }}" />

There is also the config option ASSETS.greedy. When you set this TRUE, this plugin begins to rewrite all your existing css and js includes (script, style and link tags), so you don't have to change that much in your existing templates.

You can also add files within your controller, see the add method.

Adding Filters

A filter is used to process a whole asset collection of the same type. The plugin comes with two build-in filters: combine and minify. The combine filter will just merge every assets in one group into a single file, and the minify filter just minifies the given file and returns its new file path.

You can customize which filters should be used for each file type with the configuration variables at ASSETS.filter:


[ASSETS]
filter.js = combine
filter.css = minify, combine

This setup would only call the combine filter to javascript files, but the minify and the combine filter to css files (in the order that's given). You can also create and add own filters.

In case you want to skip particular files being processed in a filter, you'll find some general exclude options down below, where you can define a regex pattern. If you just want to exclude some single files, you can also use the exclude tag attribute to define which filters to skip for this asset:
<F3:asset src="do/not/minify/this/file.js" exclude="minify" />

Configuration

The Assets plugin stores its configuration in the F3 ASSETS variable. The following settings are available, which you can put in your existing config.ini:


[ASSETS]
;# when this is false, you need to manually put the group markers like
;# <!-- assets-head --> and <!-- assets-footer --> into your template
;# default: true
auto_include = true

;# be greedy and also fetch all <link>, <script> and <style> tags
;# overwise only <asset> tags are processed
;# default: false
greedy = true

;# add some filters to the file type renderer
filter.js = minify, combine
filter.css = minify, combine

;# a writable public path, where filters can put files (relative to webroot)
public_path = ui/compressed/

;# combine filter final public path, overwrites .public_path
;combine.public_path = ui-assets/compressed/

;# exclude certain files from being combined, regex i.e. ".*(\/widgets\/).*"
combine.exclude = ".*(\/plugin\/).*"

;# register custom slot position, unregistered starts at 50++, default are:
;# 10:top 20:external 40:internal 60:excluded 80:inline
;combine.slots.30 = custom

;# merge additional attributes into the bundled tag
;# default: false
;combine.merge_attributes = true

;# minify filter final public path, overwrites ASSETS.public_path
;minify.public_path = ui-assets/compressed/

;# exclude files from minification, regex i.e. ".*(.min.).*"
minify.exclude = ".*(.min.).*"

;# when handle_inline is on, also minify inline elements [ experimental & slow ]
;minify.inline = true

;# overwrite default minify compiler, callable/string
;minify.compiler.js =
;minify.compiler.css =

;# add the mtime to the final resource URI, to aid in asset caching
;# default: false
timestamps = true

;# strategy how to rewrite relative url paths in CSS files,
;# methods: [relative,absolute,FALSE], default: relative
;fixRelativePaths = relative

;# if true, all <style> and <script> tags that contains inline data are collected too.
;# default: false
;handle_inline = true

;# if true, all internal asset paths are prepended by the BASE path
;# default: false
;prepend_base = true

;# turn this when your application root path is not your public html / web root path
;# default: false
;trim_public_root = true

Details

ASSETS.auto_include

This is true by default and adds body and head tag renderer to place the asset groups at the appropriate locations. That doesn't hurt much, but maybe leads to weird things when rendering two different templates at once, i.e. one html-email and one html-frontend for the client. Toggle this off if you're unsure and call the render method at the locations of your choice.

ASSETS.greedy

This option can be seen as a drop-in trigger for existing projects. You don't have to change the way how to add assets, and you don't need to rewrite a thing when you decide to no longer use this plugin. It just tries to fetch everything relevant, but could also lead to some false positives or inefficient compiling.

ASSETS.filter

You can define all filters for each file type in a sorted array. Each result of a filter is passed into the next filter.

ASSETS.public_path

We need that path to place newly created files here, which are public accessible. Relative paths in your CSS files are going to be rewritten to fit into that new path. Make sure this directory is writable.

ASSETS.combine.exclude

If you have a certain amount of files you want to exclude from being combined in general, you can set a regex pattern here to skip those files.

ASSETS.combine.slots

Assets are automatically grouped into slots by default. Each slot is processed separately and could create a combined file from internal assets. If you want to set a different slot to assets, add the slot="custom" attribute to the tag.

This array defines the default slots and their positions. You can pre-define custom slots here (otherwise they will start at 50) and there are 5 internal slots that must be present, but can be rearranged:

  • 10 = top
  • 20 = external
  • 40 = internal
  • 60 = excluded
  • 80 = inline
ASSETS.combine.merge_attributes

In case you want to add some additional attributes to the final tag of the combined file, turn this setting on and it'll merge all present attributes into the final one.

ASSETS.minify.exclude

Already minified files doesn't really need to be minified again. That would only cost performance and could lead to broken files. That's why we skip .min. files by default.

ASSETS.minify.inline

This will put all contents of your inline style & script contents into a minified file. This is experimental and probably slow - use with care.

ASSETS.minify.compiler.js
ASSETS.minify.compiler.css

With these options, you can setup a different css/js compiler alternative to the default, which uses F3's Web->minify.
You can set an anonymous function to this option, or a callable string. The callback receives 2 parameters, 1st the $fileName and 2nd the $path and should return the final minified code.

Some examples:

  • Using: composer require tedivm/jshrink:
    $f3->set('ASSETS.minify.compiler.js', function($fileName,$path){
    	return \JShrink\Minifier::minify(\Base::instance()->read($path.$fileName));
    });
  • Using: composer require matthiasmullie/minify:
    $f3->set('ASSETS.minify.compiler.js', function($fileName,$path){
    	$minifier = new \MatthiasMullie\Minify\JS($path.$fileName);
    	return $minifier->minify();
    });
    or as callable string:
    $f3->set('ASSETS.minify.compiler.css', 'MyUtilityClass::minifyCSSAlternative');
    
    // within class MyUtilityClass
    static function minifyCSSAlternative($fileName,$path) {
    	$minifier = new \MatthiasMullie\Minify\CSS($path.$fileName);
    	return $minifier->minify();
    }
ASSETS.timestamps

When you turn this on, all asset paths are appended with their modification time (like j1einyb0jaul.min.css?1438682851. This helps you to deliver the latest changes to your users and work around their browser cache. This is highly recommended.

ASSETS.fixRelativePaths

When combined CSS files are created and moved into the public_path, the CSS url paths, that were used in those files, are going to be rewritten to match the new path.

For instance your css file contains background: url(../img/logo.jpg) but the final stylesheet file went from theme/css/main.css to tmp/compressed/main.min.css, so these url paths needs to be updated. This setting is used to select the new path strategy:

  • relative (default): will create relative paths like ../../theme/img/logo.jpg
  • absolute: web root based absolute paths are created, i.e. /myApp/theme/img/logo.jpg
  • FALSE: disable this feature completely
ASSETS.handle_inline

If you have a to deal with lots of inline styles or scripts, this option helps you to get them sorted. This option is a bit costly, as inline scripts cannot be cached the usual way.

In case you only have a single script than you don't want to be processed, you can set an attribute like handle="false" to bypass any processing.

ASSETS.prepend_base

Usually the final paths returned are only relative to your F3 directory. This is sufficient when your app lives on the web root or you use a <base>-Tag in your html markup. In case you need the full relative web root path added to the file paths, switch this setting to TRUE.

ASSETS.trim_public_root

When your application path (current working dir) is not the web root as well, you can turn this option on to trim the path offset to your public_html directory automatically.


API Instantiate
$assets = \Assets::instance();

When creating the first Asset instance, the plugin will register an afterrender callback, that is triggered after template compilation and looks for any placeholders with a syntax like <!-- assets-head -->. Those placeholders will be replaced with the result of collecting and processing the asset files that were registered in the currently used template files or your controller. The Assets plugin uses the ASSETS hive var for its configuration. It's best to load a configuration file before initializing this plugin, but you can also change those config options on the fly in your controller or elsewhere.

add add an asset file
add( string $path, string $type [, string $group='head' [, string $slot=null [, int $priority=5 ]]]);

This adds a file to a render group. The $path filepath should be relative to an existing path defined in your UI system variable OR can be an absolute external URI. If the internal file was not found, the ASSETS.onFileNotFound handler is called.

With the type parameter, you can set the file type of the asset file. Usually this value is either css or js.

The group parameter is used to allocate assets a specific section of your html document. The two default groups are head and footer. The head group is located at the bottom of the <head> element in your html document and the is the recommended option for all CSS assets. The footer group is located at the bottom of the <body> element, and should be used for most JS assets files.

You can also add own groups. Therefore just place the appropriate group placeholder into your template, like <!-- assets-groupname -->, to render your custom group, or check the render method.

Files are sorted in each group by a numeric priority value, from high priority to low, 0 being the lowest priority. All asset files can use the same priority value, so you do not need to give every file a unique priority.

$assets = \Assets::instance();
$assets->add('css/style.css','css','head');
$assets->add('foo/bar/main.js','js','footer');
addJs add a javascript asset
addJs( string $path [, int $priority=5 [, string $group='footer' [, string $slot=null ]]]);

This method is a little shortcut to the add method, including defaults for javascript files.

$assets = \Assets::instance();
$assets->addJs('vendor/bootstrap.min.js');
$assets->addJs('http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js',8);
addCss add a stylesheet asset
addCss( string $path [, int $priority=5 [, string $group='head' [, string $slot=null ]]]);

This method is a little shortcut to the add method, including defaults for stylesheet files.

$assets = \Assets::instance();
$assets->addCss('//fonts.googleapis.com/css?family=Roboto:400,500');
$assets->addCss('css/main.css',1);
addInline add inline asset
addInline( string $path, string $type [, string $group='head' [, string $slot='inline' ]]);

This method adds some inline stylesheet or javascript code to the page.

$assets = \Assets::instance();
$assets->addInline('body { background: #f00 !important; }','css');
$assets->addInline('alert(123);','js');
getAssets get sorted, unique assets from group
getAssets([ string $group="head" [, $type=NULL ]]);

This returns an assoc array, keyed by file type, each including an array of sorted assets that belong to this group.

getGroups get all defined groups
getGroups();

Simply returns an array of all used groups.

render return placeholder for pending afterrender event
render([ string $group='head' ]);

When you are using the View or Preview template engines, you might find it more useful to put php code into your templates, or when you have the ASSETS.auto_include option disabled. To add the assets group manually to your templates, you can use this:

{{ \Assets::instance()->render('footer'); }}
reset reset file groups
reset();

In case you render multiple different templates, you can call this reset function to clear the assets collector once before rendering the next template.

clear delete all css and js files in temp dir
clear();

If you want to remove all temporary files that were generated, just call this method to initiate regeneration of them.

It returns an integer with the number of deleted files.

formatter set custom type formatter
formatter( string $type, string|callback $func);

A formatter is used to render one single asset of the given $type. You can use this method to extend the renderer for processing file types different from the defaults (js/css). The callback method receives one parameter $asset, being an array with path, type, origin and data keys, and should return a string.

filter set custom group filter
filter( string $name, string|callback $func);

Custom filters are great to extend this plugins capabilities. In example, you could prepend a LESS or SASS filter, or append a filter that uploads your assets to a CDN and replaces the needed file paths on the fly.

$assets = \Assets::instance();
$assets->filter('less','\Helpers->renderLESS');
$assets->filter('cloud',function($collection){
	foreach($collection as $asset) {
		// add magic
	}
	return $collection;
});

Events onFileNotFound error handler
$f3->set('ASSETS.onFileNotFound', function($filePath) {
	print_r('file not found: '.$filePath);
});