brain/assets

WordPress 资产助手。

0.3.0 2024-03-01 18:23 UTC

This package is auto-updated.

Last update: 2024-08-30 19:39:32 UTC


README

license packagist PHP version requirement Quality Assurance

Assets

这是一个 Composer 包,可用于在 WordPress 插件、主题和库中处理资产 URL,以及样式/脚本排队。

包 API 入口点是类 Brain\Assets\Assets,因此首先要做的是获取其实例。

这可以通过一个静态构造函数来完成,根据库的使用位置选择几个可用的选项:在插件中、在主题中或库中。

use Brain\Assets\Assets;

// For plugins.
// First param is main plugin file,second optional param
// is the subfolder in which assets files are saved.
Assets::forPlugin(__FILE__, '/dist');

// For themes.
// First param is the subfolder in which assets files are saved.
Assets::forTheme('/dist');

// For child themes.
// First param is the subfolder in which assets files are saved.
Assets::forChildTheme('/dist');

// For libraries.
// First param is the name of the library.
// Second param is absolute path in which assets files are saved.
// Third param is the absolute URL that points to the base path.
Assets::forLibrary('my-lib', __DIR__ . '/dist', content_url('/vendor/acme/my-lib/dist'));

获取 Assets 实例后,可以调用两组方法

  • 排队脚本和样式 的方法
  • 获取资产 URL 的方法

排队资产

Assets 类的第一组方法可以用来排队样式和脚本,并作用于排队输出。例如

$assets = Assets::forPlugin(__FILE__, '/dist');

$assets->enqueueScript('my-script', strategy: 'async')
  ->useAsync()
  ->useAttribute('crossorigin', 'anonymous')
  ->localize('MyScriptData', ['foo' => 'bar'])
  ->prependInline("window.foo = 'Foo';");

$assets->enqueueStyle('my-alt-style')
  ->asAlternate()
  ->useAttribute("disabled", null)
  ->useAttribute("data-something", "Something")
  ->withTitle('my style')
  ->withCondition('lte IE 10')
  ->appendInline(".custom-color: #{$customColor}");

正确钩子

WordPress 要求使用正确的钩子(例如 wp_enqueue_scriptsadmin_enqueue_scripts)来排队资产,并且调用 Assets::enqueueStyle()Assets::enqueueScript() 方法时也是如此。

Assets 的实例可以提前创建而不会出现任何问题,但实际的排队必须通过正确的钩子来完成。

WordPress 的依赖提取 Webpack 插件支持

WordPress 的 依赖提取 Webpack 插件(在使用 wp-scripts 时包含)生成一个名为 <asset name>.asset.php 的 PHP 文件,其中包含有关脚本依赖和版本的信息。要使用此文件,请使用 Assets::useDependencyExtractionData() 方法。

例如,使用以下代码

$assets = Assets::forTheme('/dist')->useDependencyExtractionData();
$assets->enqueueScript('main', strategy: 'async');
$assets->enqueueScript('secondary', strategy: Strategy::newDeferInFooter());
$assets->enqueueScript('head', strategy: Strategy::newInHead());

然后库将调用

wp_enqueue_script(
    'my-theme-main',
    'https://example.com/wp-content/themes/my-theme/dist/main.js?v=a29c9d677e174811e603',
    ['react', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data'],
    null,
    ['in_footer' => false, 'strategy' => 'async']
);

wp_enqueue_script(
    'my-theme-secondary',
    'https://example.com/wp-content/themes/my-theme/dist/secondary.js?v=d1e2af1f57008411b820',
    ['wp-api-fetch', 'lodash'],
    null,
    ['in_footer' => true, 'strategy' => 'defer']
);

wp_enqueue_script(
    'my-theme-head',
    'https://example.com/wp-content/themes/my-theme/dist/head.js?v=2933858c47af52e33b8a',
    [],
    null,
    ['in_footer' => false]
);

注册

除了 Assets::enqueueScript()Assets::enqueueStyle() 之外,Assets 类还有 Assets::registerScript()Assets::registerStyle(),它们返回由“排队”方法返回的相同的 Enqueue 实例。该对象有一个 Enqueue::enqueue() 方法,可以用来在已注册的资产上调用 wp_enqueue_script()/wp_enqueue_style()

值得注意的是,Enqueue 实例还有一个 Enqueue::dequeue() 方法,它只有在资产被排队时(无论是通过 Assets::enqueueStyle() /Assets::enqueueSscript() 还是通过注册方法 + Enqueue::enqueue())才有效,就像 Enqueue::enqueue() 只在资产尚未排队时才有效。

优点

库的优点是显而易见的。只需通过从库传递一个脚本文件名,我们就可以获得

  • 一个唯一的脚本 "handle",通过在主题名称前缀(对于插件将是相同的)
  • 一个完整的 URL,包括缓存破坏查询变量,该 URL 使用由依赖提取 Webpack 插件确定的版本
  • 依赖项,由依赖提取 Webpack 插件确定
  • 排队 "策略"

这已经大大提高了开发体验,并减少了需要编写的代码量。

此外,它还允许我们

  • 更改打印的 <link><script> 标签的 HTML 属性(包括自定义属性);
  • 为脚本和样式表添加条件入队功能;
  • 将本地化数据传递给脚本;
  • 将内联代码前置或后置到标签中(对于CSS,仅支持"append");

清单文件

如果我们使用Webpack,并且使用了Webpack Manifest Plugin,我们将有一个包含未处理资产文件名称到已处理文件映射的manifest.json文件。

当使用任何forPluginforThemeforChildThemeforLibrary方法实例化Assets类时,库会自动识别“base”文件夹中的manifest.json文件,如果找到,则用于解析完整URL。

清单+依赖提取Webpack插件

同时使用wp-scripts(或仅使用"Dependency Extraction"插件)和Webpack清单,可以实现非常强大且简洁的工作流程。

Assets类提供了一个Assets::registerAllFromManifest()方法,正如其名称所暗示的,注册所有在manifest.json中存在的CSS/JS资产。结合"Dependency Extraction"插件,它可以自动提供每个资产的依赖项和版本,我们可以通过一行代码自动注册所有资产。

Assets::registerAllFromManifest()返回一个包含所有注册资产的Enqueue实例的Collection类,提供过滤它们和通过名称或句柄获取特定实例的方法。

对用于文件的名字有一些约定(例如,使用"-admin"后缀为后端资产,"-view"后缀为前端资产,"-block"后缀为与块相关的资产),可以编写如下代码:

$myAssets = Assets::forTheme('/dist')->useDependencyExtractionData()->registerAllFromManifest();

add_action('admin_enqueue_scripts'), fn () => $myAssets->keep('*-admin')->enqueue());
add_action('wp_enqueue_scripts'), fn () => $myAssets->keep('*-view')->enqueue());

这三行代码就足够注册可能很多资产,并正确地按URL、正确依赖和正确版本入队。.

带有"-block"后缀的资产在片段中未入队,因为我们可能希望在block.json中使用它们的句柄,让WordPress在需要时入队它们。

关于Collection对象更多

Collection类提供了许多不同的方式来过滤资产。上述显示的Collection::keep()方法不仅支持glob模式,还接受正则表达式,如$myAssets->keep('#foo-[a-z]+bar#')或简单字符串,如$myAssets->keep('admin'),在这种情况下,它使用str_contains()进行过滤。

除了Collection::keep()外,集合还提供Collection::discard()(具有相似特性但范围相反)、Collection::filter()(使用自定义回调进行过滤)以及基于类型进行过滤的方法,如Collection::cssOnly()Collection::jsOnly()

此外,该类提供通过句柄或文件名检索单个实例的方法,这对于精确注册特定资产非常有用。例如

$myAssets = Assets::forTheme('/dist')->useDependencyExtractionData()->registerAllFromManifest();
$myAssets->byName('main', 'js')->localize('MyData', $mainScriptData);

add_action('wp_enqueue_scripts'), fn () => $myAssets->discard('*-admin')->enqueue());

请查阅Collection源代码以了解该类提供的所有有用API。

检索注册/入队资产的集合

Assets类提供了一个Assets::collection()方法,该方法返回一个包含所有已入队/注册资产的Collection实例。该集合允许我们对单个资产(通过Collection::oneByName()Collection::oneByHandle()检索)或对全部或部分资产进行集体操作(使用Collection提供的许多方法之一进行过滤,见上文)。

以下是一个示例,说明如何通过几行代码获取所有资产的"自动批量注册",这些代码在资产目录中循环文件

$assets = Assets::forTheme('/dist')->useDependencyExtractionData();

foreach (glob($assets->context()->basePath() . '*.{css,js}', GLOB_BRACE) as $file) {
    str_ends_with($file, '.css')
        ? $assets->registerStyle(basename($file, '.css'))
        : $assets->registerScript(basename($file, '.js'));  
}

add_action('admin_enqueue_scripts'), fn () => $assets->collection()->keep('*-admin')->enqueue());
add_action('wp_enqueue_scripts'), fn () => $assets->collection()->keep('*-view')->enqueue());

请注意:由于Collection具有不可变设计,不要存储Assets::collection()的结果,而始终调用该方法以检索最新的集合。

调试

库有一个用于两种情况的"调试"状态标志

  • 当为真时,确保在每个请求上使用新的"版本"参数为资产URL。
  • 当启用最小化查找时(见下文),决定是否寻找资产的最小化版本(扩展名前有 .min 的版本)。

"调试"状态取决于 SCRIPT_DEBUG 常量的值,但可以通过以下方法设置:Assets::forceDebug()Assets::forceNoDebug()

最小化文件解析

一些用于编译资产的方法定义了两个版本的文件,一个用于调试目的,另一个是带有 .min 后缀的"最小化"版本。例如,我们可能同时拥有 my-style.cssmy-style.min.css

在这种情况下,可以指示库在"调试"为 false 时查找最小化文件。这是通过 Assets::tryMinUrls() 方法完成的。

例如

Assets::forPlugin(__FILE__, '/dist')
    ->tryMinUrls()
    ->enqueueStyle('my-style.css');

当"调试"为 false 时,上面的代码片段将搜索 my-style.min.css,如果找到,则将其排队,如果未找到最小化文件,则回退到 my-style.css

如果最小化文件是资产构建管道创建的 唯一 文件,则可以像往常一样排队,将 .min 部分作为文件名的一部分。

Assets::forPlugin(__FILE__, '/dist')->enqueueStyle('my-style.min');

HTTP方案解析

当"Context" "secure" 状态启用时,此库强制使用 https 方案。这默认基于 WordPress 函数 is_ssl() 的结果。

可以使用 Assets::forceSecureUrls()Assets::dontForceSecureUrls() 来禁用此功能。

禁用后,基础 URL 将按原样使用,这可能在 HTTPs 上下文中包含 https,因为通过 forPlugin()forTheme() 构造函数创建的 Assets 实例;然而,当使用 Assets::forLibrary() 然后在获取的实例上调用 dontForceSecureUrls() 时,所有资产使用的 HTTP 方案将由开发人员决定,并且仅取决于 $baseUrl 参数。

排队外部资产

使用 Assets::enqueueStyle()Assets::enqueueScript() 时,需要传递要排队的资产文件名,库将解析完整 URL。

有时希望只是排队给定的完整 URL,例如位于 CDN(或任何非本地)的文件,这可以通过简单地调用 wp_enqueue_scriptwp_enqueue_style 来轻松完成。

Assets 类提供了 enqueueExternalStyle()enqueueExternalScript(),可以用于几乎无处理的排队资产,然后可以使用库提供的"高级"方法。

例如

$assets->enqueueExternalScript('foo-js', 'https://cdn.example.com/foo.js?v=1.0')
  ->useDefer()
  ->useAttribute('data-id', 'foo-script')
  ->withCondition('lte IE 10')
  ->localize('MyScriptData', ['foo' => 'bar'])
  ->prependInline("window.foo = 'Foo';");
  ->appendInline("delete window.foo;");

请注意,当使用这些方法时,库将排队资产而不会尝试附加任何缓存破坏查询变量(并且也阻止 WordPress 添加其版本),因为非本地资产 URL 通常包含作为 URL 部分的缓存变量。

库在给定 URL 上尝试的唯一处理是 调整方案:默认情况下,以 http:// 开头的 URL 将转换为使用 https://,如果 is_ssl() 为真。此处理也可以通过 Assets::dontForceSecureUrls() 禁用。

值得注意的是,使用以 //(相对方案)开头的外部 URL 也会跳过任何方案处理。

获取 URL

除了排队资产外,库还提供了获取资产 URL 的方法,这些方法除了用于脚本和样式之外,对任何类型的资产都可能有用,如图像、视频、字体等。

以下是一个快速示例

$assets = Assets::forPlugin(__FILE__, '/dist');

$styleUrl  = $assets->assetUrl('css/my-style.css');
$scriptUrl = $assets->assetUrl('js/my-script.js');
$imageUrl = $assets->assetUrl('images/foo.jpg');
$fontUrl = $assets->assetUrl('fonts/bar.eot');
$videoUrl = $assets->assetUrl('videos/baz.mp4');

在上述代码片段中,假设不同类型的资产(图像、视频、字体、CSS、JS)保存在主要资产文件夹的子文件夹中,在这种情况下是插件文件夹内的 /dist

如果是这种情况,可以指示 Assets 对象关于这些子文件夹的存在,然后使用特定类型的获取 URL 的方法。

$assets = Assets::forPlugin(__FILE__, '/dist')
  ->withCssFolder('/css')
  ->withJsFolder('/js')
  ->withImagesFolder('/images')
  ->withVideosFolder('/videos')
  ->withFontsFolder('fonts');

$styleUrl  = $assets->cssUrl('my-style');
$scriptUrl = $assets->jsUrl('my-script');
$imageUrl = $assets->imgUrl('foo.jpg');
$fontUrl = $assets->fontUrl('bar.eot');
$videoUrl = $assets->videoUrl('baz.mp4');

这个最后的代码片段与前面的代码片段等效。但子文件夹在创建实例时设置一次,然后可以使用更简洁、更明确的获取 URL 的方法。

注意,对于JS和CSS文件,无需传递文件扩展名。

URL包含版本号

上述方法获取的所有URL都包含用于缓存破坏的查询变量。例如

print $assets->cssUrl('my-style');
// https://www.example.com/wp-content/themes/my-theme/dist/my-style.css?v=1708973312

要获取不带任何版本查询变量的URL,可以使用方法的“原始”版本

$assets->rawAssetUrl('my-style.css');
$assets->rawCssUrl('my-style');
$assets->rawJsUrl('my-script');
$assets->rawImgUrl('foo.jpg');
$assets->rawFontUrl('bar.eot');
$assets->rawVideoUrl('baz.mp4');

或者,可以通过调用Assets::dontAddVersion()将整个Asset实例配置为从不添加版本查询变量

print $assets->dontAddVersion()->cssUrl('my-style');
// https://www.example.com/wp-content/themes/my-theme/dist/my-style.css

需求

该库需要

  • PHP 8.0+
  • WordPress 6.3+.

在开发模式下安装时,需要以下包

许可证

Brain Monkey是开源的,并使用MIT许可证发布。有关更多信息,请参阅LICENSE文件。