4 关注者

资源

Yii 中的资源是指可能在网页中被引用的文件。它可以是 CSS 文件、JavaScript 文件、图像或视频文件等。资源位于 Web 可访问的目录中,并由 Web 服务器直接提供服务。

通常情况下,最好以编程方式管理资源。例如,当您在页面中使用 yii\jui\DatePicker 部件时,它会自动包含所需的 CSS 和 JavaScript 文件,而不是要求您手动查找这些文件并包含它们。当您将部件升级到新版本时,它会自动使用新版本的资源文件。在本教程中,我们将介绍 Yii 提供的强大的资源管理功能。

资源包

Yii 以资源包为单位管理资源。资源包仅仅是位于某个目录中的资源集合。当您在 视图 中注册一个资源包时,它将在渲染的网页中包含该包中的 CSS 和 JavaScript 文件。

定义资源包

资源包被指定为扩展自 yii\web\AssetBundle 的 PHP 类。包的名称就是其对应的完全限定的 PHP 类名(不带开头的反斜杠)。资源包类应该是 可自动加载 的。它通常指定资源位于何处、该包包含哪些 CSS 和 JavaScript 文件,以及该包如何依赖于其他包。

以下代码定义了 基本项目模板 使用的主要资源包

<?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 目录下,该目录对应于 URL @web;该 bundle 包含一个 CSS 文件 css/site.css,不包含 JavaScript 文件;该 bundle 依赖于另外两个 bundle:yii\web\YiiAssetyii\bootstrap\BootstrapAsset。关于 yii\web\AssetBundle 属性的更详细解释,请参见以下内容。

  • sourcePath:指定包含此 bundle 中资源文件的根目录。如果根目录无法通过 Web 访问,则应设置此属性。否则,您应该设置 basePath 属性和 baseUrl 属性。这里可以使用 路径别名
  • basePath:指定包含此 bundle 中资源文件的可 Web 访问目录。当您指定 sourcePath 属性时,资源管理器 会将此 bundle 中的资源发布到可 Web 访问的目录中,并相应地覆盖此属性。如果您的资源文件已位于可 Web 访问的目录中并且不需要资源发布,则应设置此属性。这里可以使用 路径别名
  • baseUrl:指定对应于目录 basePath 的 URL。与 basePath 一样,如果您指定了 sourcePath 属性,则 资源管理器 会发布资源并相应地覆盖此属性。这里可以使用 路径别名
  • css:一个数组,列出此 bundle 中包含的 CSS 文件。请注意,只能使用正斜杠“/”作为目录分隔符。每个文件可以单独指定为字符串,也可以与属性标签及其值一起指定在数组中。
  • js:一个数组,列出此 bundle 中包含的 JavaScript 文件。此数组的格式与 css 的格式相同。每个 JavaScript 文件可以以下两种格式之一指定
    • 表示本地 JavaScript 文件的相对路径(例如 js/main.js)。可以通过将 yii\web\AssetManager::$basePath 添加到相对路径的前面来确定文件的实际路径,可以通过将 yii\web\AssetManager::$baseUrl 添加到相对路径的前面来确定文件的实际 URL。
    • 表示外部 JavaScript 文件的绝对 URL。例如,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:一个数组,列出此 bundle 依赖的资源 bundle 的名称(稍后将解释)。
  • jsOptions:指定在调用 yii\web\View::registerJsFile() 方法注册此 bundle 中的每个 JavaScript 文件时将传递给该方法的选项。
  • cssOptions:指定在调用 yii\web\View::registerCssFile() 方法注册此 bundle 中的每个 CSS 文件时将传递给该方法的选项。
  • publishOptions:指定在调用 yii\web\AssetManager::publish() 方法将源资源文件发布到 Web 目录时将传递给该方法的选项。仅当您指定了 sourcePath 属性时才使用此选项。

资源位置

根据其位置,资源可以分为以下几类:

  • 源资源:资源文件与 PHP 源代码一起位于无法通过 Web 直接访问的位置。为了在页面中使用源资源,应将其复制到 Web 目录并转换为所谓的已发布资源。此过程称为资源发布,稍后将详细介绍。
  • 已发布资源:资源文件位于 Web 目录中,因此可以通过 Web 直接访问。
  • 外部资源:资源文件位于与托管您的 Web 应用程序的服务器不同的 Web 服务器上。

在定义资源 bundle 类时,如果指定了 sourcePath 属性,则表示使用相对路径列出的任何资源都将被视为源资源。如果您未指定此属性,则表示这些资源是已发布资源(因此您应该指定 basePathbaseUrl 以让 Yii 知道它们位于何处)。

建议您将属于应用程序的资源放在 Web 目录中,以避免不必要的资源发布过程。这就是为什么前面的示例中的 AppAsset 指定 basePath 而不是 sourcePath

对于 扩展,由于它们的资源与源代码一起位于不可 Web 访问的目录中,因此在为其定义资源 bundle 类时,必须指定 sourcePath 属性。

注意:不要使用 @webroot/assets 作为 源路径。此目录默认情况下由 资源管理器 用于保存从其源位置发布的资源文件。此目录中的任何内容都被视为临时内容,可能会被删除。

资源依赖项

当您在 Web 页面中包含多个 CSS 或 JavaScript 文件时,为了避免覆盖问题,它们必须遵循一定的顺序。例如,如果您在 Web 页面中使用 jQuery UI 小部件,则必须确保在包含 jQuery UI JavaScript 文件之前包含 jQuery JavaScript 文件。我们将此类排序称为资源之间的依赖关系。

资源依赖关系主要通过 yii\web\AssetBundle::$depends 属性指定。在 AppAsset 示例中,该资源 bundle 依赖于另外两个资源 bundle:yii\web\YiiAssetyii\bootstrap\BootstrapAsset,这意味着 AppAsset 中的 CSS 和 JavaScript 文件将在这两个依赖 bundle 中的文件之后包含。

资源依赖关系是可传递的。这意味着如果 bundle A 依赖于 B,而 B 依赖于 C,则 A 也将依赖于 C。

资源选项

您可以指定 cssOptionsjsOptions 属性来自定义在页面中包含 CSS 和 JavaScript 文件的方式。当 视图 调用 yii\web\View::registerCssFile()yii\web\View::registerJsFile() 方法包含 CSS 和 JavaScript 文件时,这些属性的值将分别传递给这两个方法。

注意:您在 bundle 类中设置的选项适用于 bundle 中的每个 CSS/JavaScript 文件。如果您想对不同的文件使用不同的选项,则应使用 上面 提到的格式或创建单独的资源 bundle,并在每个 bundle 中使用一组选项。

例如,要为 IE9 或以下版本的浏览器有条件地包含 CSS 文件,可以使用以下选项

public $cssOptions = ['condition' => 'lte IE9'];

这将导致 bundle 中的 CSS 文件使用以下 HTML 标签包含:

<!--[if lte IE9]>
<link rel="stylesheet" href="path/to/foo.css">
<![endif]-->

要将生成的 CSS 链接标签包装在 <noscript> 中,可以如下配置 cssOptions

public $cssOptions = ['noscript' => true];

要在页面的头部部分包含 JavaScript 文件(默认情况下,JavaScript 文件包含在主体部分的末尾),请使用以下选项

public $jsOptions = ['position' => \yii\web\View::POS_HEAD];

默认情况下,当发布资源 bundle 时,将发布 yii\web\AssetBundle::$sourcePath 指定的目录中的所有内容。您可以通过配置 publishOptions 属性来自定义此行为。例如,要仅发布 yii\web\AssetBundle::$sourcePath 的一个或几个子目录,可以在资源 bundle 类中执行以下操作

<?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" 包 的资源 bundle。通过指定 only 发布选项,将仅发布 fontscss 子目录。

Bower 和 NPM 资源安装

大多数 JavaScript/CSS 包由 Bower 和/或 NPM 包管理器管理。在 PHP 世界中,我们有 Composer 来管理 PHP 依赖项,但也可以像 PHP 包一样使用 composer.json 加载 Bower 和 NPM 包。

为此,我们应该稍微配置一下我们的 composer。有两种方法可以做到这一点


使用 asset-packagist 仓库

这种方法可以满足大多数需要 NPM 或 Bower 包的项目的需要。

注意:从 2.0.13 开始,基本和高级应用程序模板都预先配置为默认使用 asset-packagist,因此您可以跳过此部分。

在项目的 composer.json 中,添加以下行

"repositories": [
    {
        "type": "composer",
        "url": "https://asset-packagist.org"
    }
]

在您的 应用程序配置 中调整 @npm@bower 别名

$config = [
    ...
    'aliases' => [
        '@bower' => '@vendor/bower-asset',
        '@npm'   => '@vendor/npm-asset',
    ],
    ...
];

访问 asset-packagist.org 以了解其工作原理。

使用 fxp/composer-asset-plugin

与 asset-packagist 相比,composer-asset-plugin 不需要对应用程序配置进行任何更改。相反,它需要通过运行以下命令全局安装特殊的 Composer 插件

composer global require "fxp/composer-asset-plugin:^1.4.1"

此命令全局安装 composer 资源插件,允许通过 Composer 管理 Bower 和 NPM 包依赖项。插件安装后,计算机上的每个项目都将通过 composer.json 支持 Bower 和 NPM 包。

将以下行添加到项目的 composer.json 中,以调整安装的包将放置的目录(如果要使用 Yii 发布它们)

"config": {
    "fxp-asset": {
        "installer-paths": {
            "npm-asset-library": "vendor/npm",
            "bower-asset-library": "vendor/bower"
        }
    }
}

注意:与 asset-packagist 相比,fxp/composer-asset-plugin 会显着降低 composer update 命令的速度。


配置 Composer 以支持 Bower 和 NPM 后

  1. 修改应用程序或扩展的 composer.json 文件,并在 require 条目中列出包。您应该使用 bower-asset/PackageName(对于 Bower 包)或 npm-asset/PackageName(对于 NPM 包)来引用库。
  2. 运行 composer update
  3. 创建资源 bundle 类并列出计划在应用程序或扩展中使用的 JavaScript/CSS 文件。您应该将 sourcePath 属性指定为 @bower/PackageName@npm/PackageName。这是因为 Composer 将在对应于此别名的目录中安装 Bower 或 NPM 包。

注意:某些包可能会将其所有分发文件放在子目录中。如果是这种情况,您应该将子目录指定为 sourcePath 的值。例如,yii\web\JqueryAsset 使用 @bower/jquery/dist 而不是 @bower/jquery

使用资源 bundle

要使用资产包,请通过调用 视图 中的 yii\web\AssetBundle::register() 方法将其注册。例如,在视图模板中,您可以像下面这样注册一个资产包

use app\assets\AppAsset;
AppAsset::register($this);  // $this represents the view object

信息: yii\web\AssetBundle::register() 方法返回一个资产包对象,其中包含已发布资产的信息,例如 basePathbaseUrl

如果您在其他地方注册资产包,则应提供所需的视图对象。例如,要在 小部件 类中注册资产包,可以通过 $this->view 获取视图对象。

当资产包与视图注册时,Yii 会在后台注册其所有依赖的资产包。如果资产包位于 Web 无法访问的目录中,它将被发布到 Web 目录。稍后,当视图呈现页面时,它将为注册的包中列出的 CSS 和 JavaScript 文件生成 <link><script> 标签。这些标签的顺序由注册包之间的依赖关系以及 yii\web\AssetBundle::$cssyii\web\AssetBundle::$js 属性中列出的资产的顺序决定。

动态资产包

作为常规的 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' // file, which is always used
    ];

    public function init()
    {
        parent::init();
        $this->js[] = 'i18n/' . Yii::$app->language . '.js'; // dynamic file added
    }
}

特定的资产包也可以通过 yii\web\AssetBundle::register() 返回的实例进行调整。例如

use app\assets\SophisticatedAssetBundle;
use Yii;

$bundle = SophisticatedAssetBundle::register(Yii::$app->view);
$bundle->js[] = 'i18n/' . Yii::$app->language . '.js'; // dynamic file added

注意:尽管支持动态调整资产包,但这是一种不好的实践,可能会导致意外的副作用,应尽量避免。

自定义资产包

Yii 通过一个名为 assetManager 的应用程序组件管理资产包,该组件由 yii\web\AssetManager 实现。通过配置 yii\web\AssetManager::$bundles 属性,可以自定义资产包的行为。例如,默认的 yii\web\JqueryAsset 资产包使用安装的 jQuery Bower 包中的 jquery.js 文件。为了提高可用性和性能,您可能希望使用 Google 托管的版本。这可以通过在应用程序配置中配置 assetManager 来实现,如下所示

return [
    // ...
    'components' => [
        'assetManager' => [
            'bundles' => [
                'yii\web\JqueryAsset' => [
                    'sourcePath' => null,   // do not publish the bundle
                    'js' => [
                        '//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js',
                    ]
                ],
            ],
        ],
    ],
];

您可以通过 yii\web\AssetManager::$bundles 以类似的方式配置多个资产包。数组键应为资产包的类名(不带开头的反斜杠),数组值应为相应的 配置数组

提示:您可以有条件地选择在资产包中使用哪些资产。以下示例演示了如何在开发环境中使用 jquery.js,而在其他情况下使用 jquery.min.js

'yii\web\JqueryAsset' => [
    'js' => [
        YII_ENV_DEV ? 'jquery.js' : 'jquery.min.js'
    ]
],

您可以通过将要禁用的资产包的名称与 false 关联来禁用一个或多个资产包。当您将禁用的资产包与视图注册时,其任何依赖包都不会被注册,并且视图也不会在它渲染的页面中包含包中的任何资产。例如,要禁用 yii\web\JqueryAsset,您可以使用以下配置

return [
    // ...
    'components' => [
        'assetManager' => [
            'bundles' => [
                'yii\web\JqueryAsset' => false,
            ],
        ],
    ],
];

您还可以通过将 yii\web\AssetManager::$bundles 设置为 false 来禁用所有资产包。

请记住,通过 yii\web\AssetManager::$bundles 进行的自定义是在创建资产包时应用的,例如在对象构造函数阶段。因此,之后对包对象进行的任何调整都将覆盖在 yii\web\AssetManager::$bundles 级别设置的映射。特别是:在 yii\web\AssetBundle::init() 方法内部或已注册的包对象上进行的调整将优先于 AssetManager 配置。以下是一些示例,其中通过 yii\web\AssetManager::$bundles 设置的映射无效

// Program source code:

namespace app\assets;

use yii\web\AssetBundle;
use Yii;

class LanguageAssetBundle extends AssetBundle
{
    // ...

    public function init()
    {
        parent::init();
        $this->baseUrl = '@web/i18n/' . Yii::$app->language; // can NOT be handled by `AssetManager`!
    }
}
// ...

$bundle = \app\assets\LargeFileAssetBundle::register(Yii::$app->view);
$bundle->baseUrl = YII_DEBUG ? '@web/large-files': '@web/large-files/minified'; // can NOT be handled by `AssetManager`!


// Application config :

return [
    // ...
    'components' => [
        'assetManager' => [
            'bundles' => [
                'app\assets\LanguageAssetBundle' => [
                    'baseUrl' => 'https://some.cdn.com/files/i18n/en' // makes NO effect!
                ],
                'app\assets\LargeFileAssetBundle' => [
                    'baseUrl' => 'https://some.cdn.com/files/large-files' // makes NO effect!
                ],
            ],
        ],
    ],
];

资产映射

有时您可能希望“修复”多个资产包中使用的错误/不兼容的资产文件路径。例如,包 A 使用 jquery.min.js 版本 1.11.1,包 B 使用 jquery.js 版本 2.1.1。虽然您可以通过自定义每个包来解决此问题,但更简单的方法是使用资产映射功能将错误的资产映射到所需的资产。为此,请配置 yii\web\AssetManager::$assetMap 属性,如下所示

return [
    // ...
    'components' => [
        'assetManager' => [
            'assetMap' => [
                'jquery.js' => '//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js',
            ],
        ],
    ],
];

assetMap 的键是要修复的资产名称,值是所需的资产路径。当您将资产包与视图注册时,其 cssjs 数组中的每个相对资产文件都将针对此映射进行检查。如果发现任何键是资产文件的最后一部分(如果可用,则以 yii\web\AssetBundle::$sourcePath 为前缀),则相应的将值替换资产并与视图注册。例如,资产文件 my/path/to/jquery.js 与键 jquery.js 匹配。

注意:只有使用相对路径指定的资产才受资产映射的影响。目标资产路径应为绝对 URL 或相对于 yii\web\AssetManager::$basePath 的路径。

资产发布

如前所述,如果资产包位于 Web 无法访问的目录中,则在将包与视图注册时,其资产将被复制到 Web 目录。此过程称为资产发布,由 资产管理器 自动完成。

默认情况下,资产发布到 @webroot/assets 目录,该目录对应于 URL @web/assets。您可以通过配置 basePathbaseUrl 属性来自定义此位置。

如果您的操作系统和 Web 服务器允许,您可以考虑使用符号链接而不是通过文件复制发布资产。此功能可以通过将 linkAssets 设置为 true 来启用。

return [
    // ...
    'components' => [
        'assetManager' => [
            'linkAssets' => true,
        ],
    ],
];

使用上述配置,资产管理器将在发布资产包时创建指向资产包源路径的符号链接。这比文件复制更快,还可以确保发布的资产始终是最新的。

缓存清除

对于在生产模式下运行的 Web 应用程序,启用资产和其他静态资源的 HTTP 缓存是一种常见的做法。这种做法的一个缺点是,每当您修改资产并将其部署到生产环境时,用户客户端可能仍然由于 HTTP 缓存而使用旧版本。为了克服这个缺点,您可以使用在 2.0.3 版本中引入的缓存清除功能,方法是配置 yii\web\AssetManager,如下所示

return [
    // ...
    'components' => [
        'assetManager' => [
            'appendTimestamp' => true,
        ],
    ],
];

这样做,每个已发布资产的 URL 将附加其最后修改时间戳。例如,yii.js 的 URL 可能如下所示:/assets/5515a87c/yii.js?v=1423448645",其中参数 v 表示 yii.js 文件的最后修改时间戳。现在,如果您修改了资产,其 URL 也会发生变化,这会导致客户端获取资产的最新版本。

常用资产包

Yii 核心代码定义了许多资产包。其中,以下包经常使用,并且可能在您的应用程序或扩展代码中被引用。

  • yii\web\YiiAsset:它主要包含 yii.js 文件,该文件实现了在模块中组织 JavaScript 代码的机制。它还为 data-methoddata-confirm 属性和其他有用功能提供特殊支持。有关 yii.js 的更多信息,请参见 客户端脚本部分
  • yii\web\JqueryAsset:它包含 jQuery Bower 包中的 jquery.js 文件。
  • 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,则应使用这些预定义的资产包,而不是创建您自己的版本。如果这些包的默认设置不能满足您的需求,您可以根据 自定义资产包 小节中的描述对其进行自定义。

资产转换

开发人员通常不会直接编写 CSS 和/或 JavaScript 代码,而是使用一些扩展语法编写它们,并使用特殊的工具将其转换为 CSS/JavaScript。例如,对于 CSS 代码,您可以使用 LESSSCSS;对于 JavaScript,您可以使用 TypeScript

您可以在资产包的 cssjs 属性中列出扩展语法中的资产文件。例如,

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。当视图最终呈现页面时,它将在页面中包含 CSS/JavaScript 文件,而不是扩展语法中的原始资产。

Yii 使用文件名扩展名来识别资产属于哪种扩展语法。默认情况下,它识别以下语法和文件名扩展名

Yii 依赖于已安装的预处理器工具来转换资产。例如,要使用 LESS,您应该安装 lessc 预处理器命令。

您可以通过配置 yii\web\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} 标记将分别替换为源资源文件路径和目标资源文件路径。

信息:除了上面描述的方法之外,还有其他方法可以处理扩展语法中的资源。例如,您可以使用 grunt 等构建工具来监视和自动转换扩展语法中的资源。在这种情况下,您应该在资源包中列出生成的 CSS/JavaScript 文件,而不是原始文件。

组合和压缩资源

一个网页可以包含许多 CSS 和/或 JavaScript 文件。为了减少 HTTP 请求的数量和这些文件的总下载大小,一种常见的做法是将多个 CSS/JavaScript 文件组合并压缩成一个或很少几个文件,然后在网页中包含这些压缩文件而不是原始文件。

信息:组合和压缩资源通常在应用程序处于生产模式时需要。在开发模式下,使用原始的 CSS/JavaScript 文件通常更便于调试。

接下来,我们将介绍一种无需修改现有应用程序代码即可组合和压缩资源文件的方法。

  1. 找到应用程序中您计划组合和压缩的所有资源包。
  2. 将这些包分成一组或几组。请注意,每个包只能属于一个组。
  3. 将每个组中的 CSS 文件组合/压缩成一个文件。对 JavaScript 文件也执行类似的操作。
  4. 为每个组定义一个新的资源包。
    • cssjs 属性分别设置为组合后的 CSS 和 JavaScript 文件。
    • 通过将每个组中的资源包的 cssjs 属性设置为为空,并将它们的 depends 属性设置为为该组创建的新资源包来自定义资源包。

使用这种方法,当您在视图中注册一个资源包时,它会导致自动注册原始包所属组的新资源包。结果,组合/压缩后的资源文件包含在页面中,而不是原始文件。

一个例子

让我们用一个例子来进一步解释上述方法。

假设您的应用程序有两个页面,X 和 Y。页面 X 使用资源包 A、B 和 C,而页面 Y 使用资源包 B、C 和 D。

您有两种方法可以划分这些资源包。一种是使用单个组包含所有资源包,另一种是将 A 放入组 X,将 D 放入组 Y,并将 (B、C) 放入组 S。哪一个更好?这取决于具体情况。第一种方法的优点是两个页面共享相同的组合 CSS 和 JavaScript 文件,这使得 HTTP 缓存更有效。另一方面,由于单个组包含所有包,因此组合的 CSS 和 JavaScript 文件的大小会更大,从而增加初始文件传输时间。为简单起见,在本例中,我们将使用第一种方法,即使用单个组包含所有包。

信息:将资源包分成组并非一项简单的任务。它通常需要分析不同页面上各种资源的真实世界流量数据。在开始时,您可以先使用单个组,以简化操作。

使用现有的工具(例如 Closure CompilerYUI Compressor)来组合和压缩所有包中的 CSS 和 JavaScript 文件。请注意,应按照满足包之间依赖关系的顺序组合文件。例如,如果包 A 依赖于 B,而 B 依赖于 C 和 D,那么您应该从 C 和 D 开始列出资源文件,然后是 B,最后是 A。

组合和压缩后,我们将得到一个 CSS 文件和一个 JavaScript 文件。假设它们分别命名为 all-xyz.cssall-xyz.js,其中 xyz 代表一个时间戳或哈希值,用于使文件名唯一,以避免 HTTP 缓存问题。

现在我们到了最后一步。在应用程序配置中按如下方式配置 资源管理器

return [
    '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.cssall-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 中。

注意:此资源组合机制基于 yii\web\AssetManager::$bundles 覆盖已注册资源包属性的能力。但是,如上所述,此功能不涵盖在 yii\web\AssetBundle::init() 方法中或注册包后执行的资源包调整。在资源组合期间,您应该避免使用此类动态包。

使用 asset 命令

Yii 提供了一个名为 asset 的控制台命令来自动化我们刚刚描述的方法。

要使用此命令,您应该首先创建一个配置文件来描述哪些资源包应该组合以及如何分组。您可以先使用 asset/template 子命令生成一个模板,然后修改它以适合您的需求。

yii asset/template assets.php

该命令在当前目录中生成一个名为 assets.php 的文件。此文件的内容如下所示

<?php
/**
 * Configuration file for the "yii asset" console command.
 * Note that in the console environment, some path aliases like '@webroot' and '@web' may not exist.
 * Please define these missing path aliases.
 */
return [
    // Adjust command/callback for JavaScript files compressing:
    'jsCompressor' => 'java -jar compiler.jar --js {from} --js_output_file {to}',
    // Adjust command/callback for CSS files compressing:
    'cssCompressor' => 'java -jar yuicompressor.jar --type css {from} -o {to}',
    // Whether to delete asset source after compression:
    'deleteSource' => false,
    // The list of asset bundles to compress:
    'bundles' => [
        // 'yii\web\YiiAsset',
        // 'yii\web\JqueryAsset',
    ],
    // Asset bundle for compression output:
    'targets' => [
        'all' => [
            'class' => 'yii\web\AssetBundle',
            'basePath' => '@webroot/assets',
            'baseUrl' => '@web/assets',
            'js' => 'js/all-{hash}.js',
            'css' => 'css/all-{hash}.css',
        ],
    ],
    // Asset manager configuration:
    'assetManager' => [
    ],
];

您应该修改此文件并在 bundles 选项中指定您计划组合的包。在 targets 选项中,您应该指定如何将包分成组。您可以指定一个或多个组,如前所述。

注意:由于别名 @webroot@web 在控制台应用程序中不可用,因此您应该在配置中显式定义它们。

JavaScript 文件被组合、压缩并写入 js/all-{hash}.js,其中 {hash} 被替换为结果文件的哈希值。

jsCompressorcssCompressor 选项指定执行 JavaScript 和 CSS 组合/压缩的控制台命令或 PHP 回调。默认情况下,Yii 使用 Closure Compiler 组合 JavaScript 文件,使用 YUI Compressor 组合 CSS 文件。您应该手动安装这些工具或调整这些选项以使用您喜欢的工具。

使用配置文件,您可以运行 asset 命令来组合和压缩资源文件,然后生成一个新的资源包配置文件 assets-prod.php

yii asset assets.php config/assets-prod.php

生成的配置文件可以包含在应用程序配置中,如上一小节所述。

注意:如果您通过 yii\web\AssetManager::$bundlesyii\web\AssetManager::$assetMap 自定义应用程序的资源包,并希望将此自定义应用于压缩源文件,则应将这些选项包含到资源命令配置文件内的 assetManager 部分。

注意:在指定压缩源时,应避免使用其参数可能动态调整(例如在 init() 方法中或注册后)的资源包,因为它们在压缩后可能无法正常工作。

信息:使用 asset 命令不是自动化资源组合和压缩过程的唯一选项。您可以使用出色的任务运行器工具 grunt 来实现相同的目标。

资源包分组

在上一小节中,我们解释了如何将所有资源包组合成一个,以最大程度地减少应用程序中引用的资源文件的 HTTP 请求。这在实践中并不总是理想的。例如,假设您的应用程序有一个“前端”和一个“后端”,每个都使用一组不同的 JavaScript 和 CSS 文件。在这种情况下,将来自两个端的所有资源包组合成一个是没有意义的,因为“前端”的资源包不被“后端”使用,并且在请求“前端”页面时发送“后端”资源会浪费网络带宽。

为了解决上述问题,您可以将资源包分成组,并组合每个组的资源包。以下配置显示了如何对资源包进行分组

return [
    ...
    // Specify output bundles with groups:
    'targets' => [
        'allShared' => [
            'js' => 'js/all-shared-{hash}.js',
            'css' => 'css/all-shared-{hash}.css',
            'depends' => [
                // Include all assets shared between 'backend' and 'frontend'
                'yii\web\YiiAsset',
                'app\assets\SharedAsset',
            ],
        ],
        'allBackEnd' => [
            'js' => 'js/all-{hash}.js',
            'css' => 'css/all-{hash}.css',
            'depends' => [
                // Include only 'backend' assets:
                'app\assets\AdminAsset'
            ],
        ],
        'allFrontEnd' => [
            'js' => 'js/all-{hash}.js',
            'css' => 'css/all-{hash}.css',
            'depends' => [], // Include all remaining assets
        ],
    ],
    ...
];

如您所见,资源包被分成三个组:allSharedallBackEndallFrontEnd。它们各自依赖于一组适当的资源包。例如,allBackEnd 依赖于 app\assets\AdminAsset。当使用此配置运行 asset 命令时,它将根据上述规范组合资源包。

信息:您可以将目标包的 depends 配置留空。这样做,该特定资源包将依赖于其他目标包不依赖的所有剩余资源包。

发现错别字或您认为此页面需要改进?
在 github 上编辑它 !