83. 资源css与js优化处理
为了提高页面加载性能,drupal可以开启资源优化处理,这将在不影响加载顺序及加载条件的情况下,将可聚合的资源文件合并在一起,多个文件变成一个文件,这样就减少了浏览器下载次数,同时还对资源进行缩小化处理,去掉注释、空行、空格、BOM,以及纠正资源编码等,优化器的调用入口是在资源解析器(服务名:asset.resolver
)中进行的,本主题讲解资源如何优化。
Css集优化器:
对页面css文件集进行优化处理
服务名:asset.css.collection_optimizer
类:Drupal\Core\Asset\CssCollectionOptimizer
该服务需要css集分组器、优化器、导出器三个服务协助,见下文。
调用方式:
\Drupal::service('asset.css.collection_optimizer')->optimize($css);
参数$css是一个数组,键名为资源路径,键值为选项数组,该数组须已排序,后面的后加载。
该方法返回一个数组,键名是从0开始递增的数字,代表加载顺序,越靠后越后加载,键值是一个选项数组。
在返回的数组中每个元素代表着一个css资源文件,可能是一个外部css,或内部不可聚合的css文件,或是一个可聚合资源组经过聚合的css文件,聚合是指按加载顺序将相邻可合并的css文件划分到一个组,将组内多个css文件缩小并合并到一个文件中,在页面打开时只进行一次下载即可,提高性能,如果是经过聚合的资源,那么元素数组中会存在preprocessed键,其值为true。
聚合结果被资源导出器保存到文件系统中,系统在以下位置保存着被聚合css文件集到聚合结果文件的映射:
\Drupal::state()->get('drupal_css_cache_files')
是一个数组,键名为哈希值,由可聚合资源组内源css文件地址构成数组经过sha256运算得到,键值为被聚合得到的文件的uri地址,该地址由资源导出器返回,以“public://”开头,见资源导出器。
外部文件不会被聚合,内部文件须可聚合且开启聚合配置时才聚合,是否可聚合与库定义中css文件选项preprocess、路径是否带参数等有关,开启聚合配置的后台地址是:
/admin/config/development/performance
程序方式为:
\Drupal::config ('system.performance')->get('css.preprocess');
在css聚合前需要先分组,只有同一个组内的css才能聚合,分组工作由css分组器进行,见下。
在W3C的css规范中指定了@import的使用规则,她必须在本表单的任何规则之前,因此该服务在聚合后做了相应处理,见:
https://www.w3.org/TR/REC-CSS2/cascade.html#at-import
Css集分组器grouper:
服务id:asset.css.collection_grouper
类:Drupal\Core\Asset\CssCollectionGrouper
在保证css集内加载顺序不变的情况下,将css集内css划分成多个逻辑组,调用方式:
\Drupal::service('asset.css.collection_grouper')->group($css_assets);
参数$css_assets是一个数组,键名为css路径,键值为选项数组,返回一个数组,键名是从0开始递增的数字,这代表逻辑组的编号(这里讲的组是指可聚合资源组,和库定义选项里面的group是不同的概念),同一个组内的css一定是传入数组中相邻的css,且保持顺序不变,每个组至少一个css成员,且组内css成员的以下信息是完全相同的:
preprocess、type、group、media、browsers
只有这些信息相同才能被聚合,如果选项值preprocess为false或者type为external,那么该css将自成一组,且组内只有她一个成员
返回的组数组($groups[$i])中,有如下键名:
Items:值为一个数组,保存成员的选项数组
media
browsers
preprocess
type
group
后五个键名的值来自选项数组,相同组内的css资源她们的这些信息是相同的,
在代码中你会看到'basename'选项,这在单元测试中用到,不必理会
在该服务中可以看出目前的实现(drupal8.5)中没有支持css压缩选项minified。如果支持那么不应该放入组信息里
css优化器optimizer:
用于压缩优化单个css文件,删除注释、空格、换行,BOM,替换@import,以utf8输出内容
服务:asset.css.optimizer
类:Drupal\Core\Asset\CssOptimizer
调用如下:
\Drupal::service('asset.css.optimizer')->optimize($css_asset);
参数$css_asset是经过内部处理的选项数组,其中data键保存了文件路径(可以是流路径,也可以是相对于系统根目录的路径,此时无前缀“/”),可在控制器中执行以下代码测试该服务的输出:
$css_asset = ['type' => 'file',
'preprocess' => true,
'data' => 'core/themes/bartik/css/components/form.css'
];
$data = \Drupal::service('asset.css.optimizer')->optimize($css_asset);
print_r($data);
die;
资源导出器dumper:
用于将一个组内聚合优化后的css或js资源保存到一个文件中,并返回文件uri。
服务:asset.css.dumper
类:Drupal\Core\Asset\AssetDumper
调用方式:
$uri = \Drupal::service('asset.css.dumper')->dump($data, $file_extension);
参数$data是要保存的资源数据,$file_extension是要保存的资源类型,css或者js,内部使用她做子目录和文件扩展名
该服务采用流包装器“public://”,关于流包装器请见本系列《云客Drupal8源码分析之php流Streams、公共文件、私有文件》主题,“public://”的默认位置为:sites/default/files/
文件名采用sha256及Base64编码,如下所示:
$filename = $file_extension . '_' . Crypt::hashBase64($data) . '.' . $file_extension;
如果php存在zlib扩展,且以下配置为true:
\Drupal::config('system.performance')->get($file_extension . '.gzip')
那么还会产生压缩文件,在浏览器支持时进一步提高传输性能,你可以使用配置系统或配置文件关闭该行为。
文件操作请见本系列文件系统相关主题。
该服务返回文件的uri,类似如下:
public://css/ css_mMHZVBWrcsPaqRLbvud1u1JSon5n08FZbS-IBt37v0Q.css
在最终页面上这种采用流协议的uri将被替换为服务器绝对路径,如:
/sites/default/files/css/ css_mMHZVBWrcsPaqRLbvud1u1JSon5n08FZbS-IBt37v0Q.css
js集优化器:
用于对页面加载的多个js文件进行优化
服务名:asset.js.collection_optimizer
类:Drupal\Core\Asset\JsCollectionOptimizer
和css集优化器大同小异,不再多讲,相关数据被缓存在如下位置:
\Drupal::state()->get('system.js_cache_files');
js集分组器:
服务名:asset.js.collection_grouper
类:Drupal\Core\Asset\JsCollectionGrouper
与css的分组器几乎相同,都是在保证集内资源加载顺序不变的情况下,将资源划分成多个逻辑组,调用如下:
\Drupal::service(' asset.js.collection_grouper ')->group($js_assets);
唯一区别仅是不考虑媒体查询参数
js优化器:
服务名:asset.js.optimizer
类:Drupal\Core\Asset\JsOptimizer
优化单个js文件,和css的优化器相比,它简单许多,只是进行简单的编码转换、移除bom等
js导出器:
服务id:asset.js.dumper
类:Drupal\Core\Asset\AssetDumper
与css完全相同,共享同一个类文件
补充:
在drupal中没有对css文件的编码做任何限制,有无bom均可,最终被聚合的css将采用没有bom的utf8编码