Skip to content

Added "How to Use a Custom Version Strategy for Assets" #7141

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Dec 12, 2016
202 changes: 202 additions & 0 deletions frontend/custom_version_strategy.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
.. index::
single: Asset; Custom Version Strategy

How to Use a Custom Version Strategy for Assets
===============================================

.. versionadded:: 2.7
The Asset component was introduced in Symfony 2.7.

Asset versioning is a technique that improves the performance of web
applications by adding a version identifier to the URL of your static assets
(CSS, JavaScript, images, etc.) When the content of the asset changes, the
identifier changes and the browser is forced to download it again instead of
using the cached version.

Symfony supports the basic asset versioning thanks to the
:ref:`version <reference-framework-assets-version>` and
:ref:`version_format <reference-framework-assets-version-format>` configuration
options. If your application requires a more advanced versioning, you can create
your own version strategy.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we add an example here, what "requires a more advanced versioning" means?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've reworded this part a bit. Thanks.


Creating your Own Asset Version Strategy
----------------------------------------

The following example shows how to create a version strategy compatible with
`gulp-buster`_. This tool defines a configuration file called ``busters.json``
which maps each asset file to its content hash:

.. code-block:: json

{
"js/script.js": "f9c7afd05729f10f55b689f36bb20172",
"css/style.css": "91cd067f79a5839536b46c494c4272d8"
}

Implement VersionStrategyInterface
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Asset version strategies are PHP classes that implement the
:class:`Symfony\\Component\\Asset\\VersionStrategy\\VersionStrategyInterface`.
In this example, the constructor of the class takes as arguments the path to
the manifest file generated by gulp-buster and the format of the generated
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gulp buster should be a link here, too

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

version string::

// src/AppBundle/Asset/VersionStrategy/GulpBusterVersionStrategy.php
namespace AppBundle\Asset\VersionStrategy;

use Symfony\Component\Asset\VersionStrategy\VersionStrategyInterface;

class GulpBusterVersionStrategy implements VersionStrategyInterface
{
/**
* @var string
*/
private $manifestPath;

/**
* @var string
*/
private $format;

/**
* @var string[]
*/
private $hashes;

/**
* @param string $manifestPath
* @param string|null $format
*/
public function __construct($manifestPath, $format = null)
{
$this->manifestPath = $manifestPath;
$this->format = $format ?: '%s?%s';
}

public function getVersion($path)
{
if (!is_array($this->hashes)) {
$this->hashes = $this->loadManifest();
}

return isset($this->hashes[$path]) ? $this->hashes[$path] : '';
}

public function applyVersion($path)
{
$version = $this->getVersion($path);

if ('' === $version) {
return $path;
}

$versionized = sprintf($this->format, ltrim($path, '/'), $version);

if ($path && '/' === $path[0]) {
return '/'.$versionized;
}

return $versionized;
}

private function loadManifest(array $options)
{
$hashes = json_decode(file_get_contents($this->manifestPath), true);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable is not needed.


return $hashes;
}
}

Register the Strategy Service
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

After creating the strategy PHP class, register it as a Symfony service
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing colon at the end of the sentence.


.. configuration-block::

.. code-block:: yaml

# app/config/services.yml
services:
app.assets.versioning.gulp_buster:
class: AppBundle\Asset\VersionStrategy\GulpBusterVersionStrategy
arguments:
- "%kernel.root_dir%/../busters.json"
- "%%s?version=%%s"
public: false

.. code-block:: xml

<!-- app/config/services.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services
http://symfony.com/schema/dic/services/services-1.0.xsd"
>
<services>
<service id="app.assets.versioning.gulp_buster"
class="AppBundle\Asset\VersionStrategy\GulpBusterVersionStrategy" public="false">
<argument>%kernel.root_dir%/../busters.json</argument>
<argument>%%s?version=%%s</argument>
</service>
</services>
</container>

.. code-block:: php

// app/config/services.php
use Symfony\Component\DependencyInjection\Definition;

$definition = new Definition(
'AppBundle\Asset\VersionStrategy\GulpBusterVersionStrategy',
array(
'%kernel.root_dir%/../busters.json',
'%%s?version=%%s',
)
);
$definition->setPublic(false);

$container->setDefinition('app.assets.versioning.gulp_buster', $definition);

Finally, enable the new asset versioning for all the application assets or just
for some :ref:`asset package <reference-framework-assets-packages>` thanks to
the :ref:`version_strategy <reference-framework-assets-version_strategy>` option:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like you have to add a label for this.


.. configuration-block::

.. code-block:: yaml

# app/config/config.yml
framework:
# ...
assets:
version_strategy: 'app.assets.versioning.gulp_buster'

.. code-block:: xml

<!-- app/config/config.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:framework="http://symfony.com/schema/dic/symfony"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd
http://symfony.com/schema/dic/symfony http://symfony.com/schema/dic/symfony/symfony-1.0.xsd">

<framework:config>
<framework:assets version_strategy="app.assets.versioning.gulp_buster" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In XML, the attribute should be version-strategy.

</framework:config>
</container>

.. code-block:: php

// app/config/config.php
$container->loadFromExtension('framework', array(
// ...
'assets' => array(
'version_strategy' => 'app.assets.versioning.gulp_buster',
),
));

.. _`gulp-buster`: https://www.npmjs.com/package/gulp-buster
1 change: 1 addition & 0 deletions reference/configuration/framework.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1090,6 +1090,7 @@ option.
``version``. This makes it easier to increment the cache on each
deployment.

.. _reference-framework-assets-version-format:
.. _reference-templating-version-format:
.. _reference-assets-version-format:

Expand Down
2 changes: 2 additions & 0 deletions reference/twig_reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ Returns an instance of ``ControllerReference`` to be used with functions
like :ref:`render() <reference-twig-function-render>` and
:ref:`render_esi() <reference-twig-function-render-esi>`.

.. _reference-twig-function-asset:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why did you add this here @javiereguiluz ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. It was in the original PR. I've just removed it.


asset
~~~~~

Expand Down