assetic
@kriswallsmith
things are pretty good
things could be better
problems
solutions
past
present
future
kriswallsmith/assetic
inspired by python’s webassets
http://github.com/miracle2k/webassets
2,500+ stars
400+ forks
2.4 million installs
the team
• kriswallsmith
• stof
• schmittjoh
• everzet
• 88 other contributors
boring
css
javascript
such assets
so wait
wow
model the problem
assets
images stylesheets javascripts
• path
• last modified
• content
an object-oriented api
interface AssetInterface!
{!
function getContent();!
function getSourceRoot();!
function getSourcePath();!
function getTargetPath();!
function getLastModified();!
!
// ...!
}
interface AssetInterface!
{!
// ...!
!
function load();!
function dump();!
!
// ...!
}
implementations
• StringAsset
• FileAsset
• HttpAsset
use AsseticAssetStringAsset;!
!
$a = new StringAsset('alert("hi!")');!
$a->load();!
echo $a->dump();
use AsseticAssetStringAsset;!
!
$a = new StringAsset('alert("hi!")');!
$a->load();!
echo $a->dump();
use AsseticAssetStringAsset;!
!
$a = new StringAsset('alert("hi!")');!
!
echo $a->dump();
use AsseticAssetFileAsset;!
!
$a = new FileAsset('/path/to/hi.js');!
!
echo $a->dump();
use AsseticAssetHttpAsset;!
!
$a = new HttpAsset('//example.com/hi.js');!
!
echo $a->dump();
special implementations
• AssetCollection
• GlobAsset
• AssetCache
• AssetReference
use AsseticAssetAssetCollection;!
use AsseticAssetFileAsset;!
use AsseticAssetStringAsset;!
!
$a = new AssetCollection(array(!
new StringAsset('// (c) me'),!
new FileAsset('/path/to/main.js'),!
));!
!
echo $a->dump();
use AsseticAssetGlobAsset;!
!
$a = new GlobAsset('/path/to/js/*.js');!
!
echo $a->dump();
use AsseticAssetAssetCache;!
use AsseticAssetHttpAsset;!
use AsseticCacheApcCache;!
!
$a = new AssetCache(!
new HttpAsset(‘//example.com/hi.js'),!
new ApcCache()!
);!
!
echo $a->dump();
use AsseticAssetAssetReference;!
use AsseticAssetStringAsset;!
use AsseticAssetManager;!
!
$am = new AssetManager();!
$am->set('hi', new StringAsset('...'));!
!
$a = new AssetReference($am, 'hi');!
!
echo $a->dump();
slow
fewer requests
smaller responses
tools
• CssEmbed
• Google Closure
• jpegoptim
• jpegtran
• JSMin
• JSqueeze

• optipng
• PhpCssEmbed
• pngout
• UglifyCSS
• UglifyJS
• YUI Compressor
tedious
more tools
• CoffeeScript
• Compass
• Dart
• Less
• Lessphp
• Packager

• Roole
• SASS
• Scssphp
• Sprockets
• Stylus
• TypeScript
model the problem
use AsseticAssetAssetInterface as Asset;!
!
interface FilterInterface!
{!
function filterLoad(Asset $asset);!
function filterDump(Asset $asset);!
}
var myVariable var _a
dumpload
coffeescript javascript
load javascript
• CoffeeScriptFilter
• DartFilter
• EmberPrecompileFilter
• HandlebarsFilter

• PackagerFilter
• SprocketsFilter
• TypeScriptFilter
load css
• CompassFilter
• CssImportFilter
• GssFilter
• LessFilter
• LessphpFilter
• PhpCssEmbedFilter
• RooleFilter
• SassSassFilter
• SassScssFilter
• ScssphpFilter
• StylusFilter
dump javascript
• GoogleCompilerApiFilter
• GoogleCompilerJarFilter
• JSMinFilter
• JSMinPlusFilter
• JSqueezeFilter

• PackerFilter
• UglifyJsFilter
• UglifyJs2Filter
• YuiJsCompressorFilter
dump css
• CssEmbedFilter
• CssMinFilter
• CssRewriteFilter
• UglifyCssFilter
• YuiCssCompressorFilter
dump images
• JpegoptimFilter
• JpegtranFilter
• OptiPngFilter
• PngoutFilter
use AsseticFilterFilterInterface;!
!
interface AssetInterface!
{!
function ensureFilter(!
FilterInterface $filter);!
!
// ...!
}
use AsseticAssetFileAsset;!
use AsseticFilterCoffeeScriptFilter;!
use AsseticFilterUglifyJs2Filter;!
!
$a = new FileAsset('/path/to/app.coffee');!
$a->ensureFilter(new CoffeeScriptFilter());!
$a->ensureFilter(new UglifyJs2Filter());!
!
echo $a->dump();
use AsseticAssetFileAsset;!
use AsseticFilterCoffeeScriptFilter;!
use AsseticFilterUglifyJs2Filter;!
!
$a = new FileAsset(!
'/path/to/app.coffee',!
array(!
new CoffeeScriptFilter(),!
new UglifyJs2Filter(),!
)!
);
serve
# /path/to/web/js/app.php!
!
$a = new FileAsset('/path/to/app.coffee');!
$a->ensureFilter(new CoffeeScriptFilter());!
$a->ensureFilter(new UglifyJs2Filter());!
!
header('Content-Type: text/javascript');!
echo $a->dump();
# /path/to/web/js/app.php!
!
use AsseticAssetAssetCache;!
use AsseticCacheApcCache;!
!
// ...!
!
$a = new AssetCache($a, new ApcCache());!
!
header('Content-Type: text/javascript');!
echo $a->dump();
flat
use AsseticAssetFileAsset;!
use AsseticAssetManager;!
use AsseticAssetWriter;!
!
$a = new FileAsset('/path/to/app.js');!
$a->setTargetPath('js/app.js');!
!
$am = new AssetManager();!
$am->set('app_js', $a);!
!
$writer = new AssetWriter('/path/to/web');!
$writer->writeManagerAssets($am);
reference
<script src="/js/app.php"></script>
<script src="/js/app.js"></script>
<script src="<?= asset('app_js') ?>"></scri
template as configuration
<script src="<?=!
assetic_javascripts(!
array('js/app.coffee'),!
array('coffee', 'uglifyjs2'),!
array('output' => 'js/app.js')!
)!
?>"></script>
use AsseticFilterCoffeeScriptFilter;!
use AsseticFilterManager;!
!
$fm = new FilterManager();!
$fm->set(!
'coffee',!
new CoffeeScriptFilter()!
);
use AsseticFactoryAssetFactory;!
!
$factory = new AssetFactory('/www');!
$factory->setFilterManager($fm);
use ...LoaderFunctionCallsFormulaLoader;!
use ...ResourceDirectoryResource;!
!
$ldr = new FunctionCallsFormulaLoader();!
$rsc = new DirectoryResource(!
'/path/to/views',!
'/.php$/'!
);
use AsseticFactoryLazyAssetManager;!
!
$am = new LazyAssetManager($factory);!
$am->setLoader('php', $ldr);!
$am->addResource($rsc, 'php');
detect
includes
references
while (true) {!
foreach ($am->getNames() as $name) {!
// ...!
}!
!
sleep(1);!
}
push
henrikbjorn/lurker
use LurkerResourceWatcher;!
!
$watcher = new ResourceWatcher();!
$watcher->track('twig', '/path/to/views');!
$watcher->addListener('twig', function($e) {!
// ...!
});!
!
$watcher->start();
respond
_colors.sass
foreach ($am->getNames() as $name) {!
$asset = $am->get($name);!
// ...!
!
if ($match) {!
// ...!
}!
}
graph
profile.sass
_colors.sass background.gif
home.sass
includes
includes
references
references
included by
included by
referenced by
referenced by
nodes
edges
profile.sass
_colors.sass background.gif
home.sass
includes
includes
references
references
included by
included by
referenced by
referenced by
profile.sass
_colors.sass background.gif
home.sass
includes
includes
references
references
included by
included by
referenced by
referenced by
profile.sass
_colors.sass background.gif
home.sass
includes
includes
references
references
included by
included by
referenced by
referenced by
use AsseticAssetHttpAsset;!
!
$a = new HttpAsset('//example.com/hi.js');
• proxy
• authentication
• errors
• ssl
• mock

• test

• logging
• profiling
• curl
• guzzle
represent
separate
• load
• filter
• reflection
• optimization
maintain
~40 filters
ping
opinion
• engines
• javascript optimizer
• css optimizer
• jpeg optimizer
• png optimizer
sponsor
follow
@kriswallsmith
hire
• workshops
• architecture
• audits
• performance

• symfony
• phpunit
• twig
• doctrine
questions?
kris.wallsmith@gmail.com

Drupal, meet Assetic