使用 Symfony Asset 组件管理你的 CSS Javascript 和图片文件

使用 Symfony Asset 组件管理你的 CSS Javascript 和图片文件

Chris Yue No Comment
Posts

之所以想介绍 Symfony Asset 组件,是因为我估计这个组件是 Symfony 组件包里可能最容易被轻视的组件之一了。我之前就从来没有正眼看过相关的文档,也从来没用过相关功能,直到最近公司网站要做 CDN 加速的时候,才想起来有这么一个东西。

可能很多学习 Symfony 的同学或多或少都在 Symfony 官方最佳实践教程里看到过 asset 这个 twig 函数,但文档并没有解释 asset 是做什么的,能带来什么样的好处。我最近仔细阅读了 Asset 组件的文档,并做了相关实践,把一些有用的信息分享一下。

Asset 是什么东东?

其实就是 css / javascript / 图片 这类静态文件的统称啦。

Asset 管理维护会遇到的常见问题

过去静态文件的路径都是写死在模板文件里的,比如官网提供的例子:

<link rel="stylesheet" type="text/css" href="/css/main.css">

<!-- ... -->

<a href="/"><img src="/images/logo.png"></a>

除非真的是一个相当相当简单的项目你可以这么写,你最好不要把这些路径写死,因为你会给你自己挖以下几个坑儿:

  1. 你要不断得在每一个引用静态文件的地方写全路径。
  2. 版本管理麻烦。你可能想要缓存你的静态文件,而缓存静态文件需要通过在 URL 地址后面添加版本号(一般来说类似于 /main.css?v=1 的方式)来控制缓存是否要更新,但如果你的路径都是在各个文件里写死的……那你就一个一个慢慢改吧,还容易漏。
  3. 项目刚开始静态文件路径写死一时爽,万一静态文件目录的路径变了你就傻叉了,又一个一个慢慢改吧。
  4. 有一种技术叫做多 CDN,用来减轻单 CDN 的压力。假如文件 main.css 做了两个 CDN http://cdn1.com/main.csshttp://cdn2.com/main.css,如果路径是写死的,你如何做到让页面随机返回这两个 CDN 地址中的其中一个?

那 Symfony Asset 组件能干啥?

正好对应于上面的几个问题:

  1. 有了它,你不用再把路径写全了,而是可以把公用的目录部分省略掉
  2. 有了它,指定静态文件版本方便了,就一个配置的事儿!
  3. 有了它,移动静态文件的位置方便了,换目录换域名换 CDN,随便换!
  4. 有了它,实现多 CDN 不是梦!

Symfony Asset 组件这么棒,怎么用呢?

Symfony Asset Component 官方文档里其实已经有了非常想尽的描述,其实不用看内容,直接看代码也应该立马能明白大概的用法。这里我只提一些可能比较难看懂的地方。

Request Context Aware Assets

首先我们要明确这个例子是要告诉我们要实现什么样的目的。我们有的项目,可能是放在某个域名中的其中一个分类下面的。比如 www.chrisyue.com/blog/。那么这个项目的所有静态文件,按理也应该都放在项目根目录下的 /blog 目录里。如果正好你的项目使用了 Symfony HttpFoundation 组件,那么恭喜你,通过以下方式你就可以让静态文件的目录随着项目目录的变化而变化:

use Symfony\Component\Asset\PathPackage;
use Symfony\Component\Asset\Context\RequestStackContext;
// ...

$package = new PathPackage(
    '/static/images',
    new StaticVersionStrategy('v1'),
    new RequestStackContext($requestStack) // 比如项目根目录是 /blog/,此信息包含在 request stack 里
);

echo $package->getUrl('/logo.png');
// result: /blog/static/images/logo.png?v1

我用的是 Symfony 框架,那在框架里该如何使用 Symfony Asset 组件呢?

这点似乎在官网上没有特别详细的介绍,不过从我使用的经验来说,也很容易。首先 Symfony 框架自带 assets.packages 服务,这个服务就是 $package 对象:

$container->get('assets.packages')->getUrl('/logo.png');

另外,在 Symfomy 框架的配置文件里 config.yml 里,asset 也提供了一些功能:

    # assets configuration
    assets:
        enabled:              false
        version_strategy:     null
        version:              null
        version_format:       '%%s?%%s'
        base_path:            ''
        base_urls:            []

        # 你也可以设置单独的 package 配置,使用 asset 函数时指定 package 名称就好
        packages:
            cdn:
                version_strategy:     null
                version:              ~
                version_format:       null
                base_path:            '/upload'
                base_urls:
                    - 'http://cdn.example.com'
                    - 'http://cdn2.example.com'

可以看到所有的选项其实就对应 assets package 的功能。

注意 assets 里可以定义 packages,在 twig 模板中,你就可以使用 asset 函数的第二个参数来指定你要使用的 package:

<img src="{{ asset('/path/to/img', 'cdn') }}">

弱弱的多问一句:Symfony Assetic 组件又是什么鬼,跟 Asset 组件有什么关系吗?

答案是没有任何关系。asset 是用来管理静态文件的链接地址的;而 assetic 是用来管理 css、js 文件的部署的。如果你熟悉一些前端工具,比如 grunt,或者 gulp,你就可以这么理解:assetic 就是 Symfony 内置的 grunt 或者 gulp 工具。正是因为 assetic 做了目前 grunt 和 gulp 已经做得很好的功能,对于处女座一样的 Symfony 小组来说怎么能忍受又重复发明轮子呢所以在 Symfony 3.0 里把 Assetic 组件从 Symfony 框架默认组件里去掉了……

使用 Symfony Asset 组件管理你的 CSS Javascript 和图片文件 by Chris Yue is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.

微信赞赏码

写作累,服务器还越来越贵
求分担,祝愿好人一生平安
天使打赏人

发表评论

42 − = 38