ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Yii2 资源管理实战:从资源包定义、发布到组合压缩的完整指南

Yii2 资源管理实战:从资源包定义、发布到组合压缩的完整指南 Yii2 资源管理实战从资源包定义、发布到组合压缩的完整指南【免费下载链接】yii2Yii 2: The Fast, Secure and Professional PHP Framework项目地址: https://gitcode.com/gh_mirrors/yi/yii2导读本文以 Yii2 官方指南的「资源Assets」章节为骨架系统讲解 Yii2 如何以**资源包Asset Bundle**为单位管理 CSS、JavaScript、图片与视频等静态资源如何定义资源包、如何发布不可 Web 访问的源码资源、如何处理资源依赖与排序、如何接入 Bower/NPM 前端包、如何做资源映射、缓存破除、LESS/SCSS/TypeScript 等扩展语法的自动转换以及最终如何通过asset控制台命令将资源组合压缩以提升生产环境性能。读完本文你将能够在自己的 Yii2 应用或扩展中熟练定义、注册、自定义与优化资源包并理解其底层实现原理。一、什么是资源Asset在 Yii2 中资源是指可以在 Web 页面中被引用的文件CSS 文件、JavaScript 文件、图片、视频文件等。资源位于 Web 可访问的目录中由 Web 服务器直接提供。理想的做法是以编程方式管理资源。例如当页面中使用yii\jui\DatePicker图形控件时它会在页面中自动引入所需的 CSS 和 JavaScript 文件而不需要你手工查找并引入这些文件当你升级该控件到新版本时它也会自动使用新版本的资源文件。这正是 Yii2 强大的资源管理能力所实现的参见视图与资源的使用。二、资源包Asset Bundle与定义方式Yii2 以资源包为单位管理资源。一个资源包就是位于某个目录下的一组资源的集合。当你在视图中注册一个资源包时该包内的 CSS 与 JavaScript 文件会被自动包含进渲染出的 Web 页面。资源包以继承yii\web\AssetBundle的 PHP 类来表示。资源包的名称就是其对应的 PHP 类全限定名不含开头的反斜杠。资源包类必须可被自动加载。通常它指定资源位于何处、包含哪些 CSS/JavaScript 文件、以及依赖哪些其他资源包。以下代码定义了 Basic 项目模板所使用的核心资源包?php namespace app\assets; use yii\web\AssetBundle; class AppAsset extends AssetBundle { public $basePath webroot; public $baseUrl web; public $css [ css/site.css, [css/print.css, media print], ]; public $js [ ]; public $depends [ yii\web\YiiAsset, yii\bootstrap\BootstrapAsset, ]; }上面的AppAsset类表明资源文件位于webroot目录对应 URLweb包内包含一个 CSS 文件css/site.css且没有 JavaScript 文件该包依赖另外两个包yii\web\YiiAsset与yii\bootstrap\BootstrapAsset。AssetBundle 核心属性详解对照框架源码 framework/web/AssetBundle.php 中的属性声明各属性的含义与约束如下sourcePath源路径指定包含该资源包源文件的根目录。当根目录不可被 Web 访问时必须设置此属性否则应改设basePath与baseUrl。支持使用路径别名。从源码看init()方法会通过Yii::getAlias()解析该路径并去除末尾斜杠见 AssetBundle.php。basePath基础路径指定一个可被 Web 访问、包含资源包文件的目录。当你设置了sourcePath时资源管理器会在发布资源时自动改写此属性。如果你的资源文件已经在 Web 可访问目录中、无需发布则必须设置此属性。同样支持路径别名。baseUrl基础 URL与basePath对应的 URL。若设置了sourcePath资源管理器发布资源后同样会自动改写此属性。支持路径别名。css列出资源包内 CSS 文件的数组。注意目录分隔符只能使用正斜杠/。每个文件既可以直接写成字符串也可以写成「数组 HTML 属性键值对」的形式如示例中的[css/print.css, media print]。源码中registerAssetFiles()会对数组形式的条目做ArrayHelper::merge合并cssOptions与条目自身的选项后调用registerCssFile()见 AssetBundle.php。js列出资源包内 JavaScript 文件的数组格式与css相同。每个 JS 文件可以用以下两种形式之一指定相对路径表示本地 JavaScript 文件如js/main.js。文件实际路径 basePath前缀 相对路径实际 URL baseUrl前缀 相对路径源码见 AssetManager::getAssetUrl()。绝对 URL表示外部 JavaScript 文件例如https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js或//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js协议相对。depends依赖列出本资源包所依赖的其它资源包名称的数组。jsOptions传给yii\web\View::registerJsFile()的选项应用于本包内每一个JavaScript 文件。cssOptions传给yii\web\View::registerCssFile()的选项应用于本包内每一个CSS 文件。publishOptions传给yii\web\AssetManager::publish()的选项仅当设置了sourcePath时才生效。补充说明js/css中数组形式的条目首个元素为文件路径、其余为键值对可以按文件单独覆盖jsOptions/cssOptions该能力自 2.0.7 起可用见 AssetBundle.php 的注释说明。资源位置分类根据资源所处的位置可将其分为三类源资源source assets与 PHP 源码放在一起、无法被 Web 直接访问的资源文件。要在页面中使用它们必须先复制到 Web 目录并转换为「已发布资源」。这一过程称为资源发布asset publishing。已发布资源published assets位于 Web 目录、可被 Web 直接访问的资源文件。外部资源external assets位于与当前 Web 应用不同服务器上的资源文件。定义资源包类时如果设置了sourcePath则相对路径列出的资源被视为源资源如果没有设置sourcePath则这些资源被视为已发布资源此时必须设置basePath与baseUrl让 Yii 知道它们在哪里。推荐实践属于应用自身的资源应放在 Web 可访问目录中以省去不必要的发布过程——这就是前面AppAsset使用basePath而非sourcePath的原因。而对于扩展由于其资源与源码一同位于不可 Web 访问的目录定义资源包类时必须设置sourcePath。注意不要将webroot/assets用作sourcePath。该目录是资源管理器默认用于存放发布资源的目录其中任何内容都被视为临时内容、可能被清理删除。资源依赖Asset Dependencies当页面中包含多个 CSS/JavaScript 文件时它们必须遵循一定的先后顺序以避免相互覆盖问题。例如使用 jQuery UI 控件时必须保证 jQuery 的 JS 文件先于 jQuery UI 的 JS 文件引入。这种顺序约束就是「资源依赖」。资源依赖主要通过depends属性声明。在AppAsset示例中资源包依赖yii\web\YiiAsset与yii\bootstrap\BootstrapAsset意味着AppAsset中的 CSS/JS 文件会排在被依赖包的文件之后引入。资源依赖具有传递性若包 A 依赖包 B、B 依赖包 C则 A 也依赖 C。这一机制在 View::registerAssetFiles() 中实现注册某个包时会先递归注册其全部depends依赖再注册包自身的文件View::registerAssetBundle()还会检测循环依赖并抛出InvalidConfigException见 View.php。资源选项Asset Options通过cssOptions与jsOptions可以定制 CSS/JS 文件在页面中的引入方式。这些属性值会被传给View::registerCssFile()/View::registerJsFile()。注意在资源包类中设置的选项作用于包内每一个CSS/JS 文件。如果希望不同文件使用不同选项应使用上文css/js的数组条目格式或拆分多个资源包、每个包各用一组选项。典型用法示例按浏览器条件引入 CSS针对 IE9 及以下浏览器public $cssOptions [condition lte IE9];该设置会让包内的 CSS 文件以如下 HTML 形式引入!--[if lte IE9] link relstylesheet hrefpath/to/foo.css ![endif]--用noscript包裹生成的 CSS 链接public $cssOptions [noscript true];将 JS 文件引入页面head区域默认 JS 位于/body之前public $jsOptions [position \yii\web\View::POS_HEAD];只发布sourcePath的部分子目录默认情况下资源包发布时会发布sourcePath目录下的全部内容。通过publishOptions的only选项可以只发布部分子目录例如为 FontAwesome 字体库定义资源包?php namespace app\assets; use yii\web\AssetBundle; class FontAwesomeAsset extends AssetBundle { public $sourcePath bower/font-awesome; public $css [ css/font-awesome.min.css, ]; public $publishOptions [ only [ fonts/, css/, ] ]; }上述示例为 fontawesome 的文档注释这些选项最终会透传给FileHelper::copyDirectory()。三、Bower 与 NPM 资源的接入大多数 JavaScript/CSS 包由 Bower 和/或 NPM 包管理器管理。在 PHP 世界中有 Composer 管理 PHP 依赖但也可以让 Composer 像加载 PHP 包一样加载 Bower 与 NPM 包。为此需要稍微配置 Composer有两种方案方式一使用 asset-packagist 仓库这种方式能满足大多数需要 NPM/Bower 包的项目需求。注意自 2.0.13 起Basic 与 Advanced 项目模板均已默认配置为使用 asset-packagist因此如果你使用新模板可以跳过本节。在项目的composer.json中添加以下内容repositories: [ { type: composer, url: https://asset-packagist.org } ]并在应用配置中调整npm与bower两个别名$config [ ... aliases [ bower vendor/bower-asset, npm vendor/npm-asset, ], ... ];方式二使用 fxp/composer-asset-plugin与 asset-packagist 相比composer-asset-plugin不需要修改应用配置但需要全局安装一个特殊的 Composer 插件composer global require fxp/composer-asset-plugin:^1.4.1该命令全局安装 composer asset plugin从而可以通过 Composer 管理 Bower 与 NPM 包依赖。插件安装后你计算机上的任何项目都能通过composer.json支持 Bower/NPM 包。若希望用 Yii 发布这些包可在项目的composer.json中指定安装目录config: { asset-installer-paths: { npm-asset-library: vendor/npm, bower-asset-library: vendor/bower } }注意与 asset-packagist 相比fxp/composer-asset-plugin会显著拖慢composer update命令。配置完成后的三步使用流程修改应用或扩展的composer.json在require中列出包名Bower 包用bower-asset/PackageNameNPM 包用npm-asset/PackageName执行composer update创建资源包类列出要使用的 JavaScript/CSS 文件并将sourcePath设为bower/PackageName或npm/PackageName——因为 Composer 会将对应包安装到这些别名指向的目录中。注意有些包会把发行文件放在子目录中此时应将子目录作为sourcePath的值。例如yii\web\JqueryAsset使用bower/jquery/dist而非bower/jquery。从框架源码可见这一实践JqueryAsset.php 正是将sourcePath设为bower/jquery/dist、js设为[jquery.js]。四、在视图中使用资源包在视图中调用yii\web\AssetBundle::register()即可注册资源包。例如在视图模板中use app\assets\AppAsset; AppAsset::register($this); // $this 代表视图对象view提示register()方法返回一个资源包对象其中包含已发布资源的信息例如basePath与baseUrl见 AssetBundle::register()其内部委托给View::registerAssetBundle()。如果在其它位置注册资源包则需要自行提供视图对象。例如在图形控件widget类中注册资源包可通过$this-view取得视图对象。当资源包在视图中注册后Yii 在后台会自动注册其所有依赖的资源包如果某个资源包位于 Web 不可访问的目录它会被发布到 Web 目录。之后视图渲染页面时会为已注册资源包css/js列表中的文件生成link与script标签。标签的顺序由已注册包之间的依赖关系以及各包css/js数组内的文件顺序共同决定。在源码层面View::endBody()中会对所有已注册资源包依次调用registerAssetFiles()见 View.php。动态资源包资源包本身就是普通 PHP 类可以携带额外逻辑并在运行时动态调整内部参数。例如某个复杂的 JavaScript 库将国际化资源按语言拆分为独立文件你需要根据当前语言向页面追加特定的.js文件。可以通过覆写yii\web\AssetBundle::init()实现namespace app\assets; use yii\web\AssetBundle; use Yii; class SophisticatedAssetBundle extends AssetBundle { public $sourcePath /path/to/sophisticated/src; public $js [ sophisticated.js // 始终使用的文件 ]; public function init() { parent::init(); $this-js[] i18n/ . Yii::$app-language . .js; // 动态追加的文件 } }也可以通过register()返回的实例来调整特定资源包use app\assets\SophisticatedAssetBundle; use Yii; $bundle SophisticatedAssetBundle::register(Yii::$app-view); $bundle-js[] i18n/ . Yii::$app-language . .js; // 动态追加的文件注意虽然 Yii 支持动态调整资源包但这属于不良实践可能引发意想不到的副作用应尽可能避免。通过 assetManager 自定义资源包Yii 通过名为assetManager的应用组件管理资源包该组件由yii\web\AssetManager实现。通过配置其bundles属性即可自定义某个资源包的行为。例如默认的yii\web\JqueryAsset使用本地安装的 Bower jQuery 包中的jquery.js为了提高可用性与性能你可能希望改用 Google 托管的版本可在应用配置中这样设置assetManagerreturn [ // ... components [ assetManager [ bundles [ yii\web\JqueryAsset [ sourcePath null, // 不发布该包 js [ //ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js, ] ], ], ], ], ];可以通过bundles以类似方式配置多个资源包数组键为资源包类名不含前导反斜杠数组值为对应的配置数组。从源码看AssetManager::getBundle()在创建资源包实例时会合并应用这份配置见 AssetManager.php。技巧可以按条件选择包内使用哪些资源。例如开发环境使用jquery.js其它环境使用压缩版jquery.min.jsyii\web\JqueryAsset [ js [ YII_ENV_DEV ? jquery.js : jquery.min.js ] ],也可以禁用一个或多个资源包将资源包名映射为false。当某个被禁用的资源包在视图中注册时其依赖包也不会注册视图不会在页面中包含该包的任何资源。例如禁用yii\web\JqueryAssetreturn [ // ... components [ assetManager [ bundles [ yii\web\JqueryAsset false, ], ], ], ];还可以将bundles整体设为false来禁用所有资源包。测试代码tests/framework/web/AssetManagerTest.php中的testGetBundleReturnsDummyWhenBundlesDisabled验证了这一行为当bundles false时getBundle()返回一个「哑包」dummy bundle其js/css均被清空。资源映射Asset Mapping有时你想「修正」多个资源包中错误或不兼容的资源文件路径。例如包 A 使用jquery.min.js1.11.1包 B 使用jquery.js2.1.1。除了逐个自定义资源包外更简单的做法是使用资源映射特性将错误的资源映射到期望的资源。配置assetManager的assetMap属性即可return [ // ... components [ assetManager [ assetMap [ jquery.js //ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js, ], ], ], ];assetMap的键是想要修正的资源名值是期望的资源路径。注册资源包时其css与js数组中的每个相对资源文件都会与此映射比对如果某个键是资源文件路径的最后一段若存在sourcePath则以其为前缀对应值就会替换该资源并注册到视图。例如资源文件my/path/to/jquery.js会命中键jquery.js。其匹配逻辑在 AssetManager::resolveAsset() 中实现使用的是后缀比较substr_compare。注意只有使用相对路径指定的资源才受资源映射影响。映射目标路径必须是绝对 URL或者是相对于basePath的路径。五、资源发布Asset Publishing与缓存破除如前所述如果资源包位于不可 Web 访问的目录那么当它在视图中注册时其资源会被复制到 Web 目录。这个过程称为资源发布由yii\web\AssetManager自动完成。默认情况下资源发布到目录webroot/assets对应 URLweb/assets。可以通过配置basePath与baseUrl属性自定义发布位置。发布目录的子目录名由源路径的 CRC32 哈希结合文件修改时间、框架版本与linkAssets状态生成见 AssetManager::hash()——这就是为什么发布后的 URL 形如/assets/5515a87c/yii.js。使用符号链接发布linkAssets如果操作系统与 Web 服务器允许可以改用符号链接而不是复制文件来发布资源。将linkAssets设为true即可启用return [ // ... components [ assetManager [ linkAssets true, ], ], ];采用上述配置后资源管理器在发布时会为资源包的源路径创建符号链接。这比复制文件更快而且能保证已发布资源始终与源码一致。源码中publishFile()与publishDirectory()均对linkAssets分支做了处理见 AssetManager.php 与 AssetManager.php。测试用例testPublishFileWithLinkAssets、testPublishDirectoryWithLinkAssets也验证了该行为。注意符号链接要求 Linux/Unix 或 Windows Vista/2008 及以上的环境部分 Web 服务器需要额外配置才能访问链接资源例如 Apache 需要为 Web 目录开启Options FollowSymLinks。缓存破除Cache BustingappendTimestamp生产环境通常会对静态资源启用 HTTP 缓存但副作用是当你修改并重新部署资源后浏览器可能仍因 HTTP 缓存使用旧版本。为此Yii2 自2.0.3起引入了缓存破除功能配置assetManager即可启用return [ // ... components [ assetManager [ appendTimestamp true, ], ], ];启用后每个已发布资源的 URL 末尾都会附加其最后修改时间戳。例如yii.js的 URL 会变成/assets/5515a87c/yii.js?v1423448645其中v参数即yii.js文件的最后修改时间戳。此后只要修改资源其 URL 也会随之变化从而强制浏览器获取最新版本。该逻辑实现在 AssetManager::getAssetUrl() 中通过filemtime($assetPath)取文件修改时间并拼接到 URL。六、框架内置的常用资源包Yii2 核心代码定义了多个资源包以下是应用或扩展代码中常用的几个yii\web\YiiAsset主要包含yii.js文件实现 JavaScript 代码模块化组织机制并为data-method、data-confirm等属性提供特殊支持更多信息见客户端脚本。从源码看它依赖yii\web\JqueryAssetsourcePath为yii/assets见 YiiAsset.php对应仓库中的 framework/assets/yii.js。yii\web\JqueryAsset包含 jQuery Bower 包中的jquery.js文件见 JqueryAsset.php。yii\bootstrap\BootstrapAsset包含 Twitter Bootstrap 框架的 CSS 文件。yii\bootstrap\BootstrapPluginAsset包含 Twitter Bootstrap 框架的 JavaScript 文件用于支持 Bootstrap 的 JavaScript 插件。yii\jui\JuiAsset包含 jQuery UI 库的 CSS 与 JavaScript 文件。如果你的代码依赖 jQuery、jQuery UI 或 Bootstrap应优先使用这些预定义资源包而不是自行创建版本。若这些包的默认设置不满足需求可按照上文「自定义资源包」小节的方式调整。七、资源转换Asset ConversionLESS、SCSS、TypeScript 等开发者往往不直接编写 CSS/JavaScript而是使用扩展语法再借助工具转换为 CSS/JavaScript。例如 CSS 侧可使用 LESS 或 SCSSJavaScript 侧可使用 TypeScript。你可以在资源包的css与js属性中直接列出扩展语法文件例如class AppAsset extends AssetBundle { public $basePath webroot; public $baseUrl web; public $css [ css/site.less, ]; public $js [ js/site.ts, ]; public $depends [ yii\web\YiiAsset, yii\bootstrap\BootstrapAsset, ]; }在视图中注册这样的资源包时资源管理器会自动运行预处理工具将可识别的扩展语法资源转换为 CSS/JavaScript页面最终引入的是转换后的文件而非扩展语法原文。Yii 依据文件扩展名识别资源所用语法。默认支持的语法与扩展名如下见 AssetConverter.php 中$commands默认值LESS.lessSCSS.scssStylus.stylCoffeeScript.coffeeTypeScript.tsYii 依赖机器上安装的预处理工具完成转换。例如使用 LESS 需要安装lessc预处理命令。AssetConverter::convert()会检查目标文件与源文件的修改时间仅在目标缺失或过旧时重新执行转换命令见 AssetConverter.php命令行通过proc_open执行{from}/{to}占位符会被替换为转义后的源/目标文件路径见 AssetConverter.php。你可以通过配置assetManager的converter属性来定制预处理命令与支持的扩展语法return [ components [ assetManager [ converter [ class yii\web\AssetConverter, commands [ less [css, lessc {from} {to} --no-color], ts [js, tsc --out {to} {from}], ], ], ], ], ];上述配置通过yii\web\AssetConverter::commands指定支持的扩展语法数组键是文件扩展名不含前导点值是转换结果的扩展名以及执行转换的命令命令中的{from}与{to}会被替换为源资源文件路径与目标资源文件路径。需要注意的是仓库当前默认的 LESS 命令为lessc {from} {to} --no-color --source-mapSCSS 命令为sass --stylecompressed {from} {to}覆盖配置时可按需保留或修改。提示除上述方式外还可以使用 grunt 等构建工具监听并自动转换扩展语法资源。这种情况下应把转换后的 CSS/JavaScript 文件列入资源包而不是原始文件。八、组合与压缩资源一个 Web 页面可能包含大量 CSS 和/或 JavaScript 文件。为减少 HTTP 请求数量与总体下载体积常见做法是把多个 CSS/JS 文件组合并压缩成一个或极少数文件然后在页面中引入这些压缩文件。提示组合与压缩通常在生产模式下需要。开发模式下使用原始 CSS/JS 文件往往更便于调试。下面介绍一种无需修改现有应用代码即可组合压缩资源的思路找出应用中计划组合压缩的所有资源包将这些包划分为一个或几个组注意每个包只能属于一个组将每组内的 CSS 文件组合/压缩为单个文件JS 文件同理为每个组定义一个新的资源包将css与js属性设为组合后的 CSS/JS 文件将该组内原资源包的css/js置为空数组并把其depends设为该组对应的新资源包。采用这种方法后在视图中注册某个资源包时会自动触发其所属组的新资源包注册页面最终引入的是组合/压缩后的文件而非原始文件。手动示例假设应用有页面 X 和 Y页面 X 使用资源包 A、B、C页面 Y 使用资源包 B、C、D。划分资源包有两种思路一是把所有资源包放进单个组二是把 A 放入组 X、D 放入组 Y、(B, C) 放入组 S。哪种更好取决于场景。第一种方式的优点是两个页面共享同一份组合后的 CSS/JS 文件HTTP 缓存效率更高缺点是由于单组包含所有包组合文件的体积更大会增加初始传输时间。为简化示例这里采用第一种方式单组包含所有包。提示将资源包分组并非易事通常需要分析不同页面上各类资源的真实流量数据。初期可以从单组开始以简化操作。使用现有工具例如 Closure Compiler、YUI Compressor组合并压缩所有包中的 CSS/JS 文件。注意文件必须按满足包间依赖的顺序组合——例如包 A 依赖 BB 又依赖 C 与 D则应按照 C、D → B → A 的顺序排列文件。组合压缩后得到一个 CSS 文件与一个 JS 文件。假设命名为all-xyz.css与all-xyz.js其中xyz是时间戳或哈希值用于保证文件名唯一、避免 HTTP 缓存问题。最后一步在应用配置中如下配置assetManagerreturn [ components [ assetManager [ bundles [ all [ class yii\web\AssetBundle, basePath webroot/assets, baseUrl web/assets, css [all-xyz.css], js [all-xyz.js], ], A [css [], js [], depends [all]], B [css [], js [], depends [all]], C [css [], js [], depends [all]], D [css [], js [], depends [all]], ], ], ], ];如「自定义资源包」小节所述上述配置改变了每个包的默认行为A、B、C、D 不再包含任何资源文件全部依赖包含组合文件all-xyz.css与all-xyz.js的all包。因此页面 X 不再引入 A、B、C 的原始文件而只引入这两个组合文件页面 Y 同理。还有一个让上述方案更顺滑的技巧与其直接修改应用配置文件不如把资源包定制数组放在独立文件中再按条件包含进应用配置。例如return [ components [ assetManager [ bundles require __DIR__ . / . (YII_ENV_PROD ? assets-prod.php : assets-dev.php), ], ], ];也就是说资源包配置数组在生产模式存放在assets-prod.php非生产模式存放在assets-dev.php。注意此组合机制依赖AssetManager::bundles对已注册资源包属性的覆盖能力。但如前所述该能力不覆盖在AssetBundle::init()方法内或注册之后进行的动态调整因此组合压缩时应避免使用这类动态资源包。使用 asset 控制台命令Yii 提供了名为asset的控制台命令来自动化上述过程实现位于 framework/console/controllers/AssetController.php。使用该命令前需要先创建一个配置文件描述哪些资源包将被组合、如何分组。可以先通过子命令asset/template生成模板再按需修改yii asset/template assets.php该命令会在当前目录生成assets.php文件内容大致如下?php /** * 用于 yii asset 控制台命令的配置文件。 * 注意在控制台环境中一些路径别名如 webroot 与 web 可能不存在 * 请记得定义这些缺失的路径别名。 */ return [ // 调整 JavaScript 文件压缩的命令/回调 jsCompressor java -jar compiler.jar --js {from} --js_output_file {to}, // 调整 CSS 文件压缩的命令/回调 cssCompressor java -jar yuicompressor.jar --type css {from} -o {to}, // 压缩后是否删除资源源文件自 2.0.10 起支持默认 false deleteSource false, // 要压缩的资源包列表 bundles [ // yii\web\YiiAsset, // yii\web\JqueryAsset, ], // 压缩输出的资源包 targets [ all [ class yii\web\AssetBundle, basePath webroot/assets, baseUrl web/assets, js js/all-{hash}.js, css css/all-{hash}.css, ], ], // 资源管理器配置 assetManager [ ], ];需要修改此文件在bundles选项中指定计划组合的包在targets选项中指定包如何划分为组可以指定一个或多个组。JavaScript 文件将被组合、压缩并写入js/all-{hash}.js其中{hash}会被替换为结果文件的哈希值源码见 AssetController.php 中targets属性的说明。注意由于webroot与web别名在控制台应用中不可用需要在配置中显式定义它们。jsCompressor与cssCompressor选项指定执行 JS/CSS 组合压缩的控制台命令或 PHP 回调。默认情况下Yii 使用 Closure Compiler 组合 JavaScript 文件、使用 YUI Compressor 组合 CSS 文件见 AssetController.php。需要自行安装这些工具或调整选项改用你偏好的工具。注意如果你通过AssetManager::bundles或AssetManager::assetMap自定义了资源包并希望这些自定义也作用于压缩源文件应把相应选项放入 asset 命令配置文件内的assetManager段中。注意指定压缩源时应避免使用参数会动态调整的资源包例如在init()中或注册后调整的包因为它们压缩后可能工作异常。有了配置文件即可运行asset命令组合压缩资源文件并生成新的资源包配置文件assets-prod.phpyii asset assets.php config/assets-prod.php生成的配置文件可以像上一小节描述的那样包含进应用配置。另外AssetController的默认动作是compress见 AssetController.php因此yii asset等价于执行压缩动作。提示asset命令并不是自动化组合压缩的唯一选择也可以使用 grunt 任务运行器达到相同效果。资源包分组Grouping Asset Bundles上一小节介绍了将所有资源包合并为单包以最小化 HTTP 请求的做法但这并不总是可取的。例如应用同时拥有「前端frontend」与「后台backend」二者使用不同的 CSS/JS 文件集合。此时把两个端的资源包合并为一个意义不大前端资源包不会被后台使用请求前端页面时还要传输后台资源纯属浪费带宽。解决方法是把资源包划分成组、按组各自组合压缩。下面的配置演示了如何分组return [ ... // 按组指定输出资源包 targets [ allShared [ js js/all-shared-{hash}.js, css css/all-shared-{hash}.css, depends [ // 包含 backend 与 frontend 共享的所有资源 yii\web\YiiAsset, app\assets\SharedAsset, ], ], allBackEnd [ js js/all-{hash}.js, css css/all-{hash}.css, depends [ // 仅包含 backend 资源 app\assets\AdminAsset ], ], allFrontEnd [ js js/all-{hash}.js, css css/all-{hash}.css, depends [], // 包含所有其余资源 ], ], ... ];可以看到资源包被划分为三个组allShared、allBackEnd与allFrontEnd各自依赖一组合适的资源包。例如allBackEnd依赖app\assets\AdminAsset。用该配置运行asset命令时资源包会按上述规则组合。提示可以让某个目标包的depends配置为空。这样该资源包将依赖所有「没有被其它目标包依赖」的剩余资源包。九、资源管理器AssetManager与资源发布总结一下资源管理器的核心职责由yii\web\AssetManager承担见 framework/web/AssetManager.php它作为应用组件通过Yii::$app-assetManager访问主要功能包括getBundle()按名称加载资源包应用bundles配置、按需发布publish true并缓存实例bundles false时返回空的哑包见 AssetManager.phppublish()将文件或目录发布到basePath返回[目标路径, 目标URL]文件按修改时间增量复制目录发布支持only/except/beforeCopy/afterCopy/forceCopy等选项见 AssetManager.phpgetAssetUrl()/getAssetPath()结合assetMap与appendTimestamp计算资源的最终 URL 与路径见 AssetManager.phpgetConverter()惰性创建yii\web\AssetConverter实例用于扩展语法资源转换见 AssetManager.php。发布目录的子目录名通过hash()生成CRC32 文件修改时间 框架版本 linkAssets 状态因此同一份源码在不同部署中会得到一致的目录名webroot/assets下的已发布内容被视为临时数据可安全清理后由下次请求重新生成。十、总结Yii2 的资源管理以「资源包」为核心抽象贯穿从开发到生产的完整链路定义继承yii\web\AssetBundle声明sourcePath/basePath/baseUrl/css/js/depends等属性接入前端生态通过 asset-packagist 或 fxp/composer-asset-plugin 让 Composer 管理 Bower/NPM 包配合bower/npm别名使用注册在视图或控件中调用AssetBundle::register()依赖、发布、标签顺序由 Yii 自动处理定制通过assetManager的bundles、assetMap、linkAssets、appendTimestamp等配置实现 CDN 替换、路径修正、符号链接发布与缓存破除转换借助AssetConverter自动将 LESS/SCSS/Stylus/CoffeeScript/TypeScript 编译为 CSS/JS优化使用asset控制台命令asset/template生成配置、asset执行压缩按组组合压缩资源减少 HTTP 请求与传输体积。掌握这套体系后无论是应用开发、扩展开发还是生产性能调优你都能以统一、可维护的方式管理前端资源。相关实现与测试可进一步阅读仓库源码AssetBundle.php、AssetManager.php、AssetConverter.php、AssetController.php、View.php 以及 AssetManagerTest.php。【免费下载链接】yii2Yii 2: The Fast, Secure and Professional PHP Framework项目地址: https://gitcode.com/gh_mirrors/yi/yii2创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表