答案:在Yii3.0中需创建继承yii\web\AssetBundle的AppAsset类,设置$sourcePath指向真实物理路径,通过register()注册后调用head()和endBody()输出;配置assetManager启用hashCallback生成哈希文件名实现版本控制,并通过baseUrl动态切换CDN路径。

在Yii3.0中为前端资源(CSS、JS、图片等)建立可复用、可版本化、支持自动发布与CDN分发的资产包,是避免手动维护/<script>标签、解决资源路径混乱和缓存失效问题的关键步骤。</script>
创建基础资产包类
在项目根目录下新建 src/Assets/AppAsset.php 文件,内容如下:
```php
namespace App\Assets;
use yii\web\AssetBundle;
class AppAsset extends AssetBundle
{
public $sourcePath = '@app/web/assets';
public $css = [
'css/site.css',
];
public $js = [
'js/main.js',
];
public $depends = [
\yii\web\YiiAsset::class,
];
}
注意:Yii3.0已废弃 Yii2 的 assets/ 目录约定,【$sourcePath 必须指向实际存在的物理路径,且不能是 @webroot 下未映射的子目录】;否则注册后资源无法加载。
在布局中注册并输出资产
打开 views/layouts/main.php,在 <head> 区域顶部添加:
<?php App\Assets\AppAsset::register($this); ?>
紧接着在 <head> 末尾插入:= $this->head() ?>;在 </body> 前插入:= $this->endBody() ?>。
这一步必须严格按顺序执行:先 register → 再 head() → 最后 endBody()。漏掉 $this->endBody() 会导致依赖该钩子的 JS(如 jQuery 初始化代码)完全不执行。
启用自动资源压缩与哈希版本控制
修改 config/web.php 中的 assetManager 组件配置:
```php
'assetManager' => [
'appendTimestamp' => false,
'forceCopy' => YII_DEBUG,
'bundles' => [
'yii\web\YiiAsset' => [
'js' => ['js/yii.min.js'],
],
],
'converter' => [
'__class' => yii\web\AssetConverter::class,
'commands' => [
'css' => ['cssmin' => ['./node_modules/.bin/clean-css', '-o', 'css/{to}', 'css/{from}']],
'js' => ['uglifyjs' => ['./node_modules/.bin/uglifyjs', '--output', 'js/{to}', 'js/{from}']],
],
],
'hashCallback' => function ($path) {
return substr(md5_file($path), 0, 8);
},
],
其中 hashCallback 是关键:它让每个资源文件名自动附加8位MD5哈希,例如 main.a1b2c3d4.js。这样部署新版本时浏览器无需清缓存即可加载最新脚本。
注意:【启用 converter 前必须全局安装 clean-css 和 uglifyjs,且确保 node_modules/.bin 在系统 PATH 中或使用绝对路径】,否则 asset publish 会静默失败,页面无报错但资源不压缩。
配置CDN分发路径
方法一:通过环境变量动态切换
在 .env 中添加:ASSET_BASE_URL=https://cdn.example.com/assets;然后在 config/web.php 中:
'baseUrl' => $_ENV['ASSET_BASE_URL'] ?? '@web/assets'
方法二:按环境条件判断(推荐用于多环境部署)
```php
'baseUrl' => YII_ENV_PROD ? 'https://cdn.example.com/assets' : '@web/assets'
```
方法三:在 AssetBundle 类中覆盖 baseUrl 属性(适用于特定包单独托管)
```php
class AppAsset extends AssetBundle
{
public $baseUrl = 'https://cdn.example.com/app';
// ...
}
只要 baseUrl 不以 @ 开头,Yii 就会跳过别名解析,直接作为绝对URL使用。这是唯一能绕过 assetManager 全局 baseUrl 设置的方式。


















