如何使用自定义的Assets版本策略

3.4 版本
维护中的版本

3.1 对自定义版本策略的支持从Symfony 3.1起被引入。

Asset versioning(资源版本)是一种技巧,它通过对静态资源(CSS, JavaScript和图片等)的URL添加版本识别符(version identifier),提升了web程序性能。当资源内容发生改变时,其识别符也跟着改变并强制浏览器来重新下载,而不是复用缓存中的资源。

Symfony支持asset versioning(资源版本),靠的是 versionversion_format 配置选项。如果你的程序需要更多的高级版本(处理),比如基于一些外部信息来动态生成版本,你可以创建自己的版本策略。

创建你自己的资源版本微策略 

下面的例子展示了如何创建兼容 gulp-buster 的版本策略(version strategy)。这个工具定义的配置文件被称为 busters.json,将每一个资源文件映射到相应内容的hash值上:

1
2
3
4
{
    "js/script.js": "f9c7afd05729f10f55b689f36bb20172",
    "css/style.css": "91cd067f79a5839536b46c494c4272d8"
}

实现VersionStrategyInterface接口 

资源(assets)的版本策略,是实现了 VersionStrategyInterface 接口的PHP类。本例中,类的构造器把由 gulp-buster 生成的清单文件(manifest file),以及所生成的版本字符串格式,作为构造参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
// 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)
    {
        return json_decode(file_get_contents($this->manifestPath), true);
    }
}

注册Strategy服务 

在创建了PHP的策略文件之后,把它注册成Symfony服务:

1
2
3
4
5
6
7
8
# 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!-- 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>
1
2
3
4
5
6
7
8
9
10
11
12
13
// 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);

最后,对程序中的所有资源,或一部分 asset package 来开启这个全新的资源版本,这得益于 version_strategy 选项:

1
2
3
4
5
# app/config/config.yml
framework:
    # ...
    assets:
        version_strategy: 'app.assets.versioning.gulp_buster'
1
2
3
4
5
6
7
8
9
10
11
12
<!-- 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" />
    </framework:config>
</container>
1
2
3
4
5
6
7
// app/config/config.php
$container->loadFromExtension('framework', array(
    // ...
    'assets' => array(
        'version_strategy' => 'app.assets.versioning.gulp_buster',
    ),
));

本文,包括例程代码在内,采用的是 Creative Commons BY-SA 3.0 创作共用授权。

登录symfonychina 发表评论或留下问题(我们会尽量回复)