SlideShare a Scribd company logo
1 of 127
Download to read offline
Introducing Assetic
Asset Management for PHP 5.3

Kris Wallsmith (OpenSky)
July 29, 2011
@kriswallsmith
•   Symfony Guru at

•   Symfony core team member

•   Doctrine contributor

•   Author of Assetic

•   10+ years experience with PHP and web development

•   Open source evangelist and international speaker
OpenSky connects you with innovators,
trendsetters and tastemakers.You choose
   the ones you like and each week they
  invite you to their private online sales.
OpenSky connects you with innovators,
trendsetters and tastemakers.You choose
   the ones you like and each week they
  invite you to their private online sales.
opensky.com

•   PHP 5.3 + Symfony2

•   MongoDB + Doctrine MongoDB ODM

•   MySQL + Doctrine2 ORM

•   Less CSS

•   jQuery
We all want to be FAST
We use good open source tools
 that encourage best practices
Best practices like…
•   Dependency injection (DI)

•   Proper caching, edge side includes (ESI)

•   Test-driven development (TDD)

•   Don't repeat yourself (DRY)

•   Keep it simple, SVP (KISS)

•   Performance
If you haven’t optimized your
frontend, you haven’t optimized
Get your assets in line.
A poorly optimized frontend
     can destroy UX
…and SEO!


http://googlewebmastercentral.blogspot.com/2010/04/using-site-speed-in-web-search-ranking.html
Asset Management
Lots of awesome tools:
Lots of awesome tools:
•   CoffeeScript              •   OptiPNG

•   Compass Framework         •   Packager

•   CSSEmbed                  •   SASS & SCSS

•   Google Closure Compiler   •   Sprockets

•   jpegoptim                 •   Stylus

•   JSMin                     •   YUI Compressor

•   LESS
Integrating these tools cleanly
     is a difficult problem
Assetic makes it easy
as•cet•i•cism
describes a lifestyle characterized by abstinence from various sorts of worldly
     pleasures often with the aim of pursuing religious and spiritual goals
No B.S.
Enough talk
# /path/to/web/js/core.php

$core = new FileAsset('/path/to/jquery.js');
$core->load();

header('Content-Type: text/javascript');
echo $core->dump();
# /path/to/web/js/core.php

$core = new AssetCollection(array(
    new FileAsset('/path/to/jquery.js'),
    new GlobAsset('/path/to/js/core/*.js'),
));
$core->load();

header('Content-Type: text/javascript');
echo $core->dump();
# /path/to/web/js/core.php

$core = new AssetCollection(array(
    new FileAsset('/path/to/jquery.js'),
    new GlobAsset('/path/to/js/core/*.js'),
));
$core->load();many files into one == fewer HTTP requests
         Merge
header('Content-Type: text/javascript');
echo $core->dump();
# /path/to/web/js/core.php

$core = new AssetCollection(array(
    new FileAsset('/path/to/jquery.js'),
    new GlobAsset('/path/to/js/core/*.js'),
), array(
    new YuiCompressorJsFilter('/path/to/yui.jar'),
));
$core->load();

header('Content-Type: text/javascript');
echo $core->dump();
# /path/to/web/js/core.php

$core = new AssetCollection(array(
    new FileAsset('/path/to/jquery.js'),
    new GlobAsset('/path/to/js/core/*.js'),
), array(
    new YuiCompressorJsFilter('/path/to/yui.jar'),
));
$core->load();
   Compress the merged asset == less data over the wire

header('Content-Type: text/javascript');
echo $core->dump();
<script src="js/core.php"></script>
Assetic is
Assets & Filters
Inspired by Python’s webassets


        https://github.com/miracle2k/webassets
Assets have lazy, mutable content
A filter acts on an asset’s contents
    during “load” and “dump”
Assets can be gathered in
       collections
A collection is an asset
Asset
Filter
Asset
Filter
Filter
Asset
Load
   Filter
   Filter
   Asset
Filter
Filter
Asset




         Dump
Filter
Filter
Asset
Asset Collection
Filter              Filter
Filter              Filter
Asset               Asset
Asset Collection   Filter
                                 Filter
     Asset Collection            Asset
Filter              Filter
Filter              Filter
Asset               Asset
                                 Filter
                                 Filter
                                 Asset
# /path/to/web/css/styles.php

$styles = new FileAsset('/path/to/main.sass', array(
    new SassFilter(),
));

header('Content-Type: text/css');
echo $styles->dump();
# /path/to/web/css/styles.php

$styles = new AssetCollection(array(
    new FileAsset('/path/to/main.sass', array(
        new SassFilter(),
    )),
    new FileAsset('/path/to/more.css'),
));

header('Content-Type: text/css');
echo $styles->dump();
# /path/to/web/css/styles.php

$styles = new AssetCollection(array(
    new FileAsset('/path/to/main.sass', array(
        new SassFilter(),
    )),
    new FileAsset('/path/to/more.css'),
), array(
    new YuiCompressorCss('/path/to/yui.jar'),
));

header('Content-Type: text/css');
echo $styles->dump();
# /path/to/web/css/styles.php

$styles = new AssetCollection(array(
    new FileAsset('/path/to/main.sass', array(
          new SassFilter(),
    )),
    new FileAsset('/path/to/more.css'),
), array(
    new YuiCompressorCss('/path/to/yui.jar'),
));
     Lazy! The filesystem isn't touched until now
header('Content-Type: text/css');
echo $styles->dump();
Basic Asset Classes
•   AssetCollection

•   AssetReference

•   FileAsset

•   GlobAsset

•   HttpAsset

•   StringAsset
Core Filter Classes
•   CoffeeScriptFilter                •   GoogleClosureCompilerJarFilter

•   CompassFilter                     •   JpegoptimFilter

•   CssEmbedFilter                    •   JpegtranFilter

•   CssImportFilter                   •   LessFilter

•   CssMinFilter                      •   LessphpFilter

•   CssRewriteFilter                  •   OptiPngFilter

•   GoogleClosureCompilerApiFilter   •   PackagerFilter
Core Filter Classes
•   PngoutFilter                •   More to come…

•   SassSassFilter

•   SassScssFilter

•   SprocketsFilter

•   StylusFilter

•   YuiCssCompressorFilter

•   YuiJsCompressorFilter
Asset Manager
$am = new AssetManager();
$am->set('jquery',
    new FileAsset('/path/to/jquery.js'));
$plugin = new AssetCollection(array(
    new AssetReference($am, 'jquery'),
    new FileAsset('/path/to/jquery.plugin.js'),
));
$core = new AssetCollection(array(
    $jquery,
    $plugin1,
    $plugin2,
));

header('text/javascript');
echo $core->dump();
jQuery will only be included once
       $core = new AssetCollection(array(
           $jquery,
           $plugin1,
           $plugin2,
       ));

       header('text/javascript');
       echo $core->dump();
Filter Manager
$yui = new YuiCompressorJs();
$yui->setNomunge(true);

$fm = new FilterManager();
$fm->set('yui_js', $yui);
$jquery = new FileAsset('/path/to/core.js');
$jquery->ensureFilter($fm->get('yui_js'));

$core = new AssetCollection(array(
    $jquery,
    new GlobAsset('/path/to/js/core/*.js'),
));
$core->ensureFilter($fm->get('yui_js'));
jQuery will only be compressed once

   $jquery = new FileAsset('/path/to/core.js');
   $jquery->ensureFilter($fm->get('yui_js'));

   $core = new AssetCollection(array(
       $jquery,
       new GlobAsset('/path/to/js/core/*.js'),
   ));
   $core->ensureFilter($fm->get('yui_js'));
Asset Factory
$fm = new FilterManager();
$fm->set('coffee', new CoffeeScriptFilter());
$fm->set('closure', new ClosureFilter());

$factory = new AssetFactory('/path/to/web');
$factory->setFilterManager($fm);
$asset = $factory->createAsset(
    array('js/src/*.coffee'),
    array('coffee', 'closure')
);

header('Content-Type: text/javascript');
echo $asset->dump();
Debug Mode
Debugging compressed
   Javascript sucks
Mark filters for omission
in debug mode using a “?”
// new AssetFactory('/path/to/web', $debug = true);

$asset = $factory->createAsset(
    array('js/src/*.coffee'),
    array('coffee', 'closure')
);

header('Content-Type: text/javascript');
echo $asset->dump();
// new AssetFactory('/path/to/web', true);

$asset = $factory->createAsset(
    array('js/src/*.coffee'),
    array('coffee', '?closure')
);

header('Content-Type: text/javascript');
echo $asset->dump();
// new AssetFactory('/path/to/web', false);

$asset = $factory->createAsset(
    array('js/src/*.coffee'),
    array('coffee', '?closure'),
    array('debug' => true)
);

header('Content-Type: text/javascript');
echo $asset->dump();
Good: Basic Caching
# /path/to/web/css/styles.php

$styles = new AssetCollection(
    array(new FileAsset('/path/to/main.sass')),
    array(new SassFilter())
);

echo $styles->dump();
# /path/to/web/css/styles.php

$styles = new AssetCache(new AssetCollection(
    array(new FileAsset('/path/to/main.sass')),
    array(new SassFilter())
), new FilesystemCache('/path/to/cache'));

echo $styles->dump();
# /path/to/web/css/styles.php

$styles = new AssetCache(new AssetCollection(
    array(new FileAsset('/path/to/main.sass')),
    array(new SassFilter())
), new FilesystemCache('/path/to/cache'));
          Run the filters once and cache the content

echo $styles->dump();
Better: HTTP Caching
// $core = new AssetCache(...

$mtime = gmdate('D, d M y H:i:s',
    $core->getLastModified()).' GMT';

if ($mtime == $_SERVER['HTTP_IF_MODIFIED_SINCE']) {
    header('HTTP/1.0 304 Not Modified');
    exit();
}

header('Content-Type: text/javascript');
header('Last-Modified: '.$mtime);
echo $core->dump();
Best: Static Assets
# /path/to/deploy/scripts/dump_assets.php

$am = new AssetManager();
$am->set('foo', $foo);
// etc...

$writer = new AssetWriter('/path/to/web');
$writer->writeManagerAssets($am);
Best-est:
Content Distribution Network
new AssetWriter('s3://my-bucket')
new AssetWriter('s3://my-bucket')

                 A CloudFront S3 bucket
Custom Stream Wrappers


$s3 = new Zend_Service_Amazon_S3($key, $secret);
$s3->registerStreamWrapper();
Not Lazy Enough?
Asset Formulae and the
 Lazy Asset Manager
$asset = $factory->createAsset(
    array('js/src/*.coffee'),
    array('coffee', '?closure'),
    array('output' => 'js/all.js')
);
$formula = array(
    array('js/src/*.coffee'),
    array('coffee', '?closure'),
    array('output' => 'js/all.js')
);
$am = new LazyAssetManager($factory);
$am->setFormula('all_js', $formula);

header('Content-Type: text/javascript');
echo $am->get('all_js')->dump();
A Thought
Assets are a part of the view layer
  and should be defined there.
<!-- header.php -->

<?php foreach (assetic_javascripts(
    array('js/core.js', 'js/more.js'),
    array('?yui_js')) as $url): ?>

<script src="<?php echo $url ?>"></script>

<?php endforeach; ?>
An Issue
Assets defined in the view layer
must actually exist somewhere
Option Number Bad
Lazily dump assets to the
      web directory
Option Number Good
Eagerly dump assets to the
      web directory
A template is a configuration file
Formula Loaders
extract asset formulae from templates
$loader = new FunctionCallsFormulaLoader();
$resource = new DirectoryResource(
    '/path/to/templates',
    '/.php$/'
);

$formulae = $loader->load($resource);
$am = new LazyAssetManager($factory);
$am->setLoader('php', $loader);
$am->addResource($resource, 'php');

$writer = new AssetWriter('/path/to/web');
$writer->writeManagerAssets($am);
$am = new LazyAssetManager($factory);
$am->setLoader('php', $loader);
$am->addResource($resource, 'php');
               Expensive every time
$writer = new AssetWriter('/path/to/web');
$writer->writeManagerAssets($am);
$cache = new ConfigCache('/path/to/cache');

$loader = new CachedFormulaLoader(
    $loader,
    $cache,
    $debug
);
$cache = new ConfigCache('/path/to/cache');

$loader = new CachedFormulaLoader(
    $loader,
    $cache,
    $debug
);
    Whether to stat each file for changes
Twig Integration
{% javascripts 'js/*.coffee' filter='coffee' %}
<script src="{{ asset_url }}"></script>
{% endjavascripts %}
<script src="js/92429d8.js"></script>
{% javascripts 'js/*.coffee' filter='coffee' %}
<script src="{{ asset_url }}"></script>
{% endjavascripts %}
{% javascripts 'js/*.coffee' filter='coffee'
   output='js/all.js' %}
<script src="{{ asset_url }}"></script>
{% endjavascripts %}
<script src="js/all.js"></script>
{% javascripts 'js/*.coffee' filter='coffee'
   output='js/all.js' %}
<script src="{{ asset_url }}"></script>
{% endjavascripts %}
{% javascripts 'js/*.coffee' filter='coffee,?closure' %}
<script src="{{ asset_url }}"></script>
{% endjavascripts %}
{% javascripts 'js/*.coffee' filter='coffee,?closure'
   debug=true %}
<script src="{{ asset_url }}"></script>
{% endjavascripts %}
{% javascripts 'js/*.coffee' filter='coffee,?closure'
   combine=false %}
<script src="{{ asset_url }}"></script>
{% endjavascripts %}
<script src="js/92429d8_1.js"></script>
<script src="js/92429d8_2.js"></script>
<script src="js/92429d8_3.js"></script>
Each “leaf” asset is referenced individually

<script src="js/92429d8_1.js"></script>
<script src="js/92429d8_2.js"></script>
<script src="js/92429d8_3.js"></script>
AsseticBundle
  Symfony2 integration
Configuration
# config.yml

assetic:
    debug: %kernel.debug%
    use_controller: false
    filters:
        coffee: ~
        yui_js:
             jar: /path/to/yuicompressor.jar
{# when use_controller=true (config_dev.yml) #}

<script src="{{ path('assetic_foo') }}"...
# routing_dev.yml
_assetic:
    resource: .
    type:     assetic
{# when use_controller=false (config_prod.yml) #}

<script src="{{ asset('js/core.js') }}"></script>
{# when use_controller=false (config_prod.yml) #}

<script src="{{ asset('js/core.js') }}"></script>

                 Lots for free
The Symfony2 Assets Helper


•   Multiple asset domains

•   Cache buster
framework:
    templating:
        assets_version: 1.2.3
        assets_base_urls:
            - http://assets1.domain.com
            - http://assets2.domain.com
            - http://assets3.domain.com
            - http://assets4.domain.com
{% stylesheets filter='scss,?yui_css' output='css/all.css'
   'css/src/main.scss' 'css/src/more.scss' %}
<link href="{{ asset_url }}" rel="stylesheet">
{% endstylesheets %}
<link href="http://assets3.domain.com/css/all.css?1.2.3" ...
assetic:dump
$ php app/console assetic:dump web/
$ php app/console assetic:dump s3://my-bucket
assetic:dump --watch
  Dump static assets in the background as you develop
How can you help?
How can you help?


•   Join the team!
How can you help?


•   Join the team!

•   Documentation
How can you help?


•   Join the team!

•   Documentation

•   Assetic needs a website
Questions?
http://github.com/kriswallsmith/assetic

More Related Content

What's hot

Moving from Django Apps to Services
Moving from Django Apps to ServicesMoving from Django Apps to Services
Moving from Django Apps to ServicesCraig Kerstiens
 
Let's write secure drupal code! - Drupal Camp Pannonia 2019
Let's write secure drupal code! - Drupal Camp Pannonia 2019Let's write secure drupal code! - Drupal Camp Pannonia 2019
Let's write secure drupal code! - Drupal Camp Pannonia 2019Balázs Tatár
 
[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVC[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVCAlive Kuo
 
The Way to Theme Enlightenment 2017
The Way to Theme Enlightenment 2017The Way to Theme Enlightenment 2017
The Way to Theme Enlightenment 2017Amanda Giles
 
eZ Publish Cluster Unleashed
eZ Publish Cluster UnleashedeZ Publish Cluster Unleashed
eZ Publish Cluster UnleashedBertrand Dunogier
 
BP-6 Repository Customization Best Practices
BP-6 Repository Customization Best PracticesBP-6 Repository Customization Best Practices
BP-6 Repository Customization Best PracticesAlfresco Software
 
Angular.js Fundamentals
Angular.js FundamentalsAngular.js Fundamentals
Angular.js FundamentalsMark
 
Render API - Pavel Makhrinsky
Render API - Pavel MakhrinskyRender API - Pavel Makhrinsky
Render API - Pavel MakhrinskyDrupalCampDN
 
Reusable bootstrap resources zend con 2010
Reusable bootstrap resources   zend con 2010Reusable bootstrap resources   zend con 2010
Reusable bootstrap resources zend con 2010Hector Virgen
 
Getting up & running with zend framework
Getting up & running with zend frameworkGetting up & running with zend framework
Getting up & running with zend frameworkSaidur Rahman
 
[WLDN] Supercharging word press development in 2018
[WLDN] Supercharging word press development in 2018[WLDN] Supercharging word press development in 2018
[WLDN] Supercharging word press development in 2018Adam Tomat
 
Getting to The Loop - London Wordpress Meetup July 28th
Getting to The Loop - London Wordpress Meetup  July 28thGetting to The Loop - London Wordpress Meetup  July 28th
Getting to The Loop - London Wordpress Meetup July 28thChris Adams
 
Drupal Javascript for developers
Drupal Javascript for developersDrupal Javascript for developers
Drupal Javascript for developersDream Production AG
 
Resource Routing in ExpressionEngine
Resource Routing in ExpressionEngineResource Routing in ExpressionEngine
Resource Routing in ExpressionEngineMichaelRog
 
Drupal Best Practices
Drupal Best PracticesDrupal Best Practices
Drupal Best Practicesmanugoel2003
 
Phase2 OpenPublish Presentation SF SemWeb Meetup, April 28, 2009
Phase2 OpenPublish Presentation SF SemWeb Meetup, April 28, 2009Phase2 OpenPublish Presentation SF SemWeb Meetup, April 28, 2009
Phase2 OpenPublish Presentation SF SemWeb Meetup, April 28, 2009Krista Thomas
 

What's hot (20)

Moving from Django Apps to Services
Moving from Django Apps to ServicesMoving from Django Apps to Services
Moving from Django Apps to Services
 
PHP API
PHP APIPHP API
PHP API
 
Let's write secure drupal code! - Drupal Camp Pannonia 2019
Let's write secure drupal code! - Drupal Camp Pannonia 2019Let's write secure drupal code! - Drupal Camp Pannonia 2019
Let's write secure drupal code! - Drupal Camp Pannonia 2019
 
Tax management-system
Tax management-systemTax management-system
Tax management-system
 
[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVC[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVC
 
The Way to Theme Enlightenment 2017
The Way to Theme Enlightenment 2017The Way to Theme Enlightenment 2017
The Way to Theme Enlightenment 2017
 
eZ Publish Cluster Unleashed
eZ Publish Cluster UnleashedeZ Publish Cluster Unleashed
eZ Publish Cluster Unleashed
 
BP-6 Repository Customization Best Practices
BP-6 Repository Customization Best PracticesBP-6 Repository Customization Best Practices
BP-6 Repository Customization Best Practices
 
Angular.js Fundamentals
Angular.js FundamentalsAngular.js Fundamentals
Angular.js Fundamentals
 
Render API - Pavel Makhrinsky
Render API - Pavel MakhrinskyRender API - Pavel Makhrinsky
Render API - Pavel Makhrinsky
 
Reusable bootstrap resources zend con 2010
Reusable bootstrap resources   zend con 2010Reusable bootstrap resources   zend con 2010
Reusable bootstrap resources zend con 2010
 
Getting up and running with Zend Framework
Getting up and running with Zend FrameworkGetting up and running with Zend Framework
Getting up and running with Zend Framework
 
Getting up & running with zend framework
Getting up & running with zend frameworkGetting up & running with zend framework
Getting up & running with zend framework
 
[WLDN] Supercharging word press development in 2018
[WLDN] Supercharging word press development in 2018[WLDN] Supercharging word press development in 2018
[WLDN] Supercharging word press development in 2018
 
Getting to The Loop - London Wordpress Meetup July 28th
Getting to The Loop - London Wordpress Meetup  July 28thGetting to The Loop - London Wordpress Meetup  July 28th
Getting to The Loop - London Wordpress Meetup July 28th
 
Drupal Javascript for developers
Drupal Javascript for developersDrupal Javascript for developers
Drupal Javascript for developers
 
Resource Routing in ExpressionEngine
Resource Routing in ExpressionEngineResource Routing in ExpressionEngine
Resource Routing in ExpressionEngine
 
Drupal Best Practices
Drupal Best PracticesDrupal Best Practices
Drupal Best Practices
 
Intro to Drush
Intro to DrushIntro to Drush
Intro to Drush
 
Phase2 OpenPublish Presentation SF SemWeb Meetup, April 28, 2009
Phase2 OpenPublish Presentation SF SemWeb Meetup, April 28, 2009Phase2 OpenPublish Presentation SF SemWeb Meetup, April 28, 2009
Phase2 OpenPublish Presentation SF SemWeb Meetup, April 28, 2009
 

Similar to Assetic (OSCON)

Introducing Assetic (NYPHP)
Introducing Assetic (NYPHP)Introducing Assetic (NYPHP)
Introducing Assetic (NYPHP)Kris Wallsmith
 
jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)
jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)
jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)Doris Chen
 
Styling components with JavaScript
Styling components with JavaScriptStyling components with JavaScript
Styling components with JavaScriptbensmithett
 
Understanding backbonejs
Understanding backbonejsUnderstanding backbonejs
Understanding backbonejsNick Lee
 
The Way to Theme Enlightenment
The Way to Theme EnlightenmentThe Way to Theme Enlightenment
The Way to Theme EnlightenmentAmanda Giles
 
Build Your Own CMS with Apache Sling
Build Your Own CMS with Apache SlingBuild Your Own CMS with Apache Sling
Build Your Own CMS with Apache SlingBob Paulin
 
Intro to php
Intro to phpIntro to php
Intro to phpSp Singh
 
Bcblackpool jquery tips
Bcblackpool jquery tipsBcblackpool jquery tips
Bcblackpool jquery tipsJack Franklin
 
WordPress Café: Using WordPress as a Framework
WordPress Café: Using WordPress as a FrameworkWordPress Café: Using WordPress as a Framework
WordPress Café: Using WordPress as a FrameworkExove
 
Railsbridge javascript
Railsbridge   javascriptRailsbridge   javascript
Railsbridge javascriptp4geoff
 
Express Presentation
Express PresentationExpress Presentation
Express Presentationaaronheckmann
 
以Vue開發電子商務網站
架構與眉角
以Vue開發電子商務網站
架構與眉角以Vue開發電子商務網站
架構與眉角
以Vue開發電子商務網站
架構與眉角Mei-yu Chen
 
Childthemes ottawa-word camp-1919
Childthemes ottawa-word camp-1919Childthemes ottawa-word camp-1919
Childthemes ottawa-word camp-1919Paul Bearne
 
Creating Operational Redundancy for Effective Web Data Mining
Creating Operational Redundancy for Effective Web Data MiningCreating Operational Redundancy for Effective Web Data Mining
Creating Operational Redundancy for Effective Web Data MiningJonathan LeBlanc
 
How to make a WordPress theme
How to make a WordPress themeHow to make a WordPress theme
How to make a WordPress themeHardeep Asrani
 
WordPress for developers - phpday 2011
WordPress for developers -  phpday 2011WordPress for developers -  phpday 2011
WordPress for developers - phpday 2011Maurizio Pelizzone
 
Amp and higher computing science
Amp and higher computing scienceAmp and higher computing science
Amp and higher computing scienceCharlie Love
 

Similar to Assetic (OSCON) (20)

Introducing Assetic (NYPHP)
Introducing Assetic (NYPHP)Introducing Assetic (NYPHP)
Introducing Assetic (NYPHP)
 
jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)
jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)
jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)
 
Styling components with JavaScript
Styling components with JavaScriptStyling components with JavaScript
Styling components with JavaScript
 
Understanding backbonejs
Understanding backbonejsUnderstanding backbonejs
Understanding backbonejs
 
The Way to Theme Enlightenment
The Way to Theme EnlightenmentThe Way to Theme Enlightenment
The Way to Theme Enlightenment
 
Build Your Own CMS with Apache Sling
Build Your Own CMS with Apache SlingBuild Your Own CMS with Apache Sling
Build Your Own CMS with Apache Sling
 
Intro to php
Intro to phpIntro to php
Intro to php
 
Drupal, meet Assetic
Drupal, meet AsseticDrupal, meet Assetic
Drupal, meet Assetic
 
Bcblackpool jquery tips
Bcblackpool jquery tipsBcblackpool jquery tips
Bcblackpool jquery tips
 
WordPress Café: Using WordPress as a Framework
WordPress Café: Using WordPress as a FrameworkWordPress Café: Using WordPress as a Framework
WordPress Café: Using WordPress as a Framework
 
Hppg
HppgHppg
Hppg
 
Railsbridge javascript
Railsbridge   javascriptRailsbridge   javascript
Railsbridge javascript
 
Express Presentation
Express PresentationExpress Presentation
Express Presentation
 
Php frameworks
Php frameworksPhp frameworks
Php frameworks
 
以Vue開發電子商務網站
架構與眉角
以Vue開發電子商務網站
架構與眉角以Vue開發電子商務網站
架構與眉角
以Vue開發電子商務網站
架構與眉角
 
Childthemes ottawa-word camp-1919
Childthemes ottawa-word camp-1919Childthemes ottawa-word camp-1919
Childthemes ottawa-word camp-1919
 
Creating Operational Redundancy for Effective Web Data Mining
Creating Operational Redundancy for Effective Web Data MiningCreating Operational Redundancy for Effective Web Data Mining
Creating Operational Redundancy for Effective Web Data Mining
 
How to make a WordPress theme
How to make a WordPress themeHow to make a WordPress theme
How to make a WordPress theme
 
WordPress for developers - phpday 2011
WordPress for developers -  phpday 2011WordPress for developers -  phpday 2011
WordPress for developers - phpday 2011
 
Amp and higher computing science
Amp and higher computing scienceAmp and higher computing science
Amp and higher computing science
 

More from Kris Wallsmith

How kris-writes-symfony-apps-london
How kris-writes-symfony-apps-londonHow kris-writes-symfony-apps-london
How kris-writes-symfony-apps-londonKris Wallsmith
 
How Kris Writes Symfony Apps
How Kris Writes Symfony AppsHow Kris Writes Symfony Apps
How Kris Writes Symfony AppsKris Wallsmith
 
Love and Loss: A Symfony Security Play
Love and Loss: A Symfony Security PlayLove and Loss: A Symfony Security Play
Love and Loss: A Symfony Security PlayKris Wallsmith
 
How Kris Writes Symfony Apps
How Kris Writes Symfony AppsHow Kris Writes Symfony Apps
How Kris Writes Symfony AppsKris Wallsmith
 
Doctrine MongoDB ODM (PDXPHP)
Doctrine MongoDB ODM (PDXPHP)Doctrine MongoDB ODM (PDXPHP)
Doctrine MongoDB ODM (PDXPHP)Kris Wallsmith
 
Advanced symfony Techniques
Advanced symfony TechniquesAdvanced symfony Techniques
Advanced symfony TechniquesKris Wallsmith
 
A Practical Introduction to Symfony2
A Practical Introduction to Symfony2A Practical Introduction to Symfony2
A Practical Introduction to Symfony2Kris Wallsmith
 

More from Kris Wallsmith (11)

Matters of State
Matters of StateMatters of State
Matters of State
 
The View From Inside
The View From InsideThe View From Inside
The View From Inside
 
How kris-writes-symfony-apps-london
How kris-writes-symfony-apps-londonHow kris-writes-symfony-apps-london
How kris-writes-symfony-apps-london
 
How Kris Writes Symfony Apps
How Kris Writes Symfony AppsHow Kris Writes Symfony Apps
How Kris Writes Symfony Apps
 
Love and Loss: A Symfony Security Play
Love and Loss: A Symfony Security PlayLove and Loss: A Symfony Security Play
Love and Loss: A Symfony Security Play
 
How Kris Writes Symfony Apps
How Kris Writes Symfony AppsHow Kris Writes Symfony Apps
How Kris Writes Symfony Apps
 
Doctrine MongoDB ODM (PDXPHP)
Doctrine MongoDB ODM (PDXPHP)Doctrine MongoDB ODM (PDXPHP)
Doctrine MongoDB ODM (PDXPHP)
 
Advanced symfony Techniques
Advanced symfony TechniquesAdvanced symfony Techniques
Advanced symfony Techniques
 
A Practical Introduction to Symfony2
A Practical Introduction to Symfony2A Practical Introduction to Symfony2
A Practical Introduction to Symfony2
 
Symfony 2
Symfony 2Symfony 2
Symfony 2
 
Symfony in the Cloud
Symfony in the CloudSymfony in the Cloud
Symfony in the Cloud
 

Recently uploaded

Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)wesley chun
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?Antenna Manufacturer Coco
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfsudhanshuwaghmare1
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
Tech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdfTech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdfhans926745
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
HTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesHTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesBoston Institute of Analytics
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CVKhem
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Enterprise Knowledge
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessPixlogix Infotech
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoffsammart93
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 

Recently uploaded (20)

Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
Tech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdfTech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdf
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
HTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesHTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation Strategies
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your Business
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 

Assetic (OSCON)