分析 WordPress `gutenberg_get_assets()` 函数源码:编辑器脚本与样式的依赖加载机制。

WordPress Gutenberg 的资产加载机制:gutenberg_get_assets() 函数解剖

大家好,欢迎来到本次 Gutenberg 资产加载机制的剖析讲座。今天我们要深入研究 WordPress Gutenberg 编辑器幕后的英雄之一:gutenberg_get_assets() 函数。

这函数就像一个尽职尽责的管家,负责确保 Gutenberg 编辑器正常运行所需的所有 JavaScript 脚本和 CSS 样式都已正确加载。别看它名字平平无奇,实际上它掌管着整个 Gutenberg 编辑器的前端命脉。

准备好一起解开它的神秘面纱了吗?让我们开始吧!

1. 资产的概念:脚本与样式

在深入研究代码之前,我们首先需要理解什么是“资产”。 在 Web 开发中,资产通常指的是构建 Web 页面所需的文件,比如:

  • JavaScript 脚本 (.js 文件):负责处理页面的动态行为和交互。
  • CSS 样式表 (.css 文件):负责控制页面的外观和布局。

对于 Gutenberg 来说,它需要大量的 JavaScript 和 CSS 才能实现其丰富的功能。 gutenberg_get_assets() 函数的任务就是管理这些资产,并确保它们以正确的顺序和方式加载到页面中。

2. gutenberg_get_assets() 函数的核心职责

gutenberg_get_assets() 函数的主要职责可以概括为以下几点:

  • 注册资产:将 Gutenberg 编辑器所需的所有 JavaScript 和 CSS 资产注册到 WordPress 的资源队列中。
  • 定义依赖关系:明确各个资产之间的依赖关系,确保它们以正确的顺序加载。比如,A 脚本依赖 B 脚本,那么 B 必须在 A 之前加载。
  • 确定版本号:为每个资产指定版本号,以便在更新时可以强制浏览器重新加载新的资产文件。
  • 本地化脚本:将 PHP 中的数据传递给 JavaScript 脚本,实现服务器端和客户端之间的通信。

3. 源码剖析:一步一步追踪

现在,让我们深入研究 gutenberg_get_assets() 函数的源码。 这个函数通常位于 Gutenberg 插件的核心文件中,比如 plugins/gutenberg/lib/client-assets.php

<?php

/**
 * Retrieves all the registered scripts and styles for the editor
 *
 * @return array {
 *     @type string[] $scripts List of script handles
 *     @type string[] $styles List of style handles
 * }
 */
function gutenberg_get_assets() {
    $dependencies = array( 'wp-polyfill' );

    if ( gutenberg_is_amp_context() ) {
        $dependencies[] = 'wp-polyfill-inert';
        $dependencies[] = 'wp-polyfill-url';
    }

    $editor_scripts = array(
        'wp-format-library',
        'wp-block-library',
        'wp-block-directory',
        'wp-blocks',
        'wp-components',
        'wp-compose',
        'wp-data',
        'wp-date',
        'wp-edit-blocks',
        'wp-editor',
        'wp-element',
        'wp-i18n',
        'wp-keycodes',
        'wp-media-utils',
        'wp-plugins',
        'wp-rich-text',
        'wp-token-list',
        'lodash',
        'react',
        'react-dom',
    );

    $editor_scripts = array_merge(
        $editor_scripts,
        array(
            'wp-editor-script',
            'wp-nux',
            'wp-block-editor',
        )
    );

    $editor_styles = array(
        'wp-components',
        'wp-block-library',
        'wp-block-editor',
        'wp-editor',
        'wp-format-library',
    );

    if ( is_rtl() ) {
        $editor_styles[] = 'wp-editor-rtl';
    }

    return array(
        'scripts' => $editor_scripts,
        'styles'  => $editor_styles,
    );
}

步骤 1:基础依赖项

$dependencies = array( 'wp-polyfill' );

if ( gutenberg_is_amp_context() ) {
    $dependencies[] = 'wp-polyfill-inert';
    $dependencies[] = 'wp-polyfill-url';
}

这段代码首先定义了一个 $dependencies 数组,其中包含了一些基础的依赖项。

  • 'wp-polyfill':这是一个 JavaScript polyfill 库,用于提供对旧版浏览器不支持的新 JavaScript 功能的兼容性支持。
  • gutenberg_is_amp_context():如果当前是 AMP (Accelerated Mobile Pages) 环境,则会添加额外的 polyfill,以确保 Gutenberg 编辑器在 AMP 页面上也能正常工作。

步骤 2:编辑器脚本

$editor_scripts = array(
    'wp-format-library',
    'wp-block-library',
    'wp-block-directory',
    'wp-blocks',
    'wp-components',
    'wp-compose',
    'wp-data',
    'wp-date',
    'wp-edit-blocks',
    'wp-editor',
    'wp-element',
    'wp-i18n',
    'wp-keycodes',
    'wp-media-utils',
    'wp-plugins',
    'wp-rich-text',
    'wp-token-list',
    'lodash',
    'react',
    'react-dom',
);

$editor_scripts = array_merge(
    $editor_scripts,
    array(
        'wp-editor-script',
        'wp-nux',
        'wp-block-editor',
    )
);

这里定义了一个 $editor_scripts 数组,其中包含了 Gutenberg 编辑器所需的所有 JavaScript 脚本的句柄 (handle)。 每个句柄都对应着一个已注册的 JavaScript 文件。

  • 'wp-format-library':包含格式化文本的工具和函数。
  • 'wp-block-library':包含 WordPress 内置的各种块的定义。
  • 'wp-block-directory':用于从块目录中搜索和安装块。
  • 'wp-blocks':包含用于创建和管理块的 API。
  • 'wp-components':包含各种 UI 组件,如按钮、输入框、下拉菜单等。
  • 'wp-compose':包含用于组合 React 组件的工具。
  • 'wp-data':包含用于管理应用程序状态的 Redux 风格的数据存储。
  • 'wp-date':包含用于处理日期和时间的函数。
  • 'wp-edit-blocks':包含用于编辑块的工具。
  • 'wp-editor':包含 Gutenberg 编辑器的核心功能。
  • 'wp-element':包含 React 的核心 API。
  • 'wp-i18n':包含用于国际化 (i18n) 的函数。
  • 'wp-keycodes':包含常用的键盘代码。
  • 'wp-media-utils':包含用于处理媒体文件的工具。
  • 'wp-plugins':包含用于管理插件的 API。
  • 'wp-rich-text':包含用于处理富文本的工具。
  • 'wp-token-list':包含用于管理 token 列表的工具。
  • 'lodash':一个流行的 JavaScript 实用工具库。
  • 'react':一个用于构建用户界面的 JavaScript 库。
  • 'react-dom':一个用于将 React 组件渲染到 DOM 的库。
  • 'wp-editor-script':The main editor script
  • 'wp-nux':New User Experience
  • 'wp-block-editor': Block Editor

步骤 3:编辑器样式

$editor_styles = array(
    'wp-components',
    'wp-block-library',
    'wp-block-editor',
    'wp-editor',
    'wp-format-library',
);

if ( is_rtl() ) {
    $editor_styles[] = 'wp-editor-rtl';
}

这里定义了一个 $editor_styles 数组,其中包含了 Gutenberg 编辑器所需的所有 CSS 样式的句柄。 同样,每个句柄都对应着一个已注册的 CSS 文件。

  • 'wp-components':包含各种 UI 组件的样式。
  • 'wp-block-library':包含 WordPress 内置的各种块的样式。
  • 'wp-block-editor':包含块编辑器的样式。
  • 'wp-editor':包含 Gutenberg 编辑器的核心样式。
  • 'wp-format-library':包含格式化文本的样式。

is_rtl() 函数用于检查当前语言是否为从右到左 (RTL) 的语言。 如果是,则会添加 'wp-editor-rtl' 样式,以提供对 RTL 语言的支持。

步骤 4:返回结果

return array(
    'scripts' => $editor_scripts,
    'styles'  => $editor_styles,
);

最后,函数返回一个包含 $editor_scripts$editor_styles 数组的关联数组。 这个数组会被传递给 WordPress 的资源队列,以便正确加载 Gutenberg 编辑器所需的资产。

4. 如何使用 gutenberg_get_assets() 函数

虽然 gutenberg_get_assets() 函数通常在 Gutenberg 插件内部使用,但了解如何使用它可以帮助你更好地理解 Gutenberg 的资产加载机制。

<?php

function my_custom_gutenberg_assets() {
    $assets = gutenberg_get_assets();

    // 获取脚本列表
    $scripts = $assets['scripts'];

    // 获取样式列表
    $styles = $assets['styles'];

    // 在这里可以对脚本和样式列表进行修改
    // 例如,添加自定义的脚本或样式

    // 注册自定义脚本
    wp_register_script(
        'my-custom-script',
        plugins_url( 'my-custom-script.js', __FILE__ ),
        $scripts, // 依赖于 Gutenberg 的脚本
        '1.0.0',
        true // 在页脚加载
    );

    // 注册自定义样式
    wp_register_style(
        'my-custom-style',
        plugins_url( 'my-custom-style.css', __FILE__ ),
        $styles, // 依赖于 Gutenberg 的样式
        '1.0.0'
    );

    // 将自定义脚本和样式添加到编辑器
    wp_enqueue_script( 'my-custom-script' );
    wp_enqueue_style( 'my-custom-style' );
}

add_action( 'enqueue_block_editor_assets', 'my_custom_gutenberg_assets' );

在这个例子中,我们首先调用 gutenberg_get_assets() 函数来获取 Gutenberg 编辑器的脚本和样式列表。 然后,我们使用 wp_register_script()wp_register_style() 函数来注册我们自己的自定义脚本和样式。 最后,我们使用 wp_enqueue_script()wp_enqueue_style() 函数将自定义脚本和样式添加到编辑器中。

5. 依赖关系的管理:确保加载顺序

Gutenberg 编辑器依赖于大量的 JavaScript 脚本和 CSS 样式,它们之间存在着复杂的依赖关系。 正确管理这些依赖关系至关重要,因为如果某个脚本或样式在它所依赖的脚本或样式之前加载,就会导致错误。

gutenberg_get_assets() 函数通过以下方式来管理依赖关系:

  • 显式声明依赖项:在注册每个脚本和样式时,都会明确声明它所依赖的其他脚本和样式。 例如,wp_register_script( 'my-script', 'my-script.js', array( 'jquery' ) ) 表示 my-script.js 依赖于 jquery
  • 使用 WordPress 的资源队列:WordPress 的资源队列会自动处理脚本和样式的加载顺序,确保它们按照依赖关系正确加载。
wp_register_script(
    'my-script',
    plugins_url( 'my-script.js', __FILE__ ),
    array( 'jquery', 'wp-blocks' ), // 依赖于 jQuery 和 wp-blocks
    '1.0.0',
    true
);

在这个例子中,my-script.js 依赖于 jquerywp-blocks。 WordPress 的资源队列会自动确保 jquerywp-blocksmy-script.js 之前加载。

6. 版本控制:避免缓存问题

在 Web 开发中,浏览器缓存是一个非常重要的问题。 如果浏览器缓存了旧版本的 JavaScript 脚本或 CSS 样式,即使服务器端已经更新了这些文件,用户仍然会看到旧版本的内容。

gutenberg_get_assets() 函数通过以下方式来解决缓存问题:

  • 为每个资产指定版本号:在注册每个脚本和样式时,都会指定一个版本号。 例如,wp_register_script( 'my-script', 'my-script.js', array(), '1.0.0' ) 表示 my-script.js 的版本号为 1.0.0
  • 在更新资产时更新版本号:当 JavaScript 脚本或 CSS 样式更新时,必须更新其版本号。 这样,浏览器就会认为这是一个新的文件,并强制重新加载它。
wp_register_script(
    'my-script',
    plugins_url( 'my-script.js', __FILE__ ),
    array(),
    '1.0.1', // 版本号已更新
    true
);

在这个例子中,my-script.js 的版本号从 1.0.0 更新为 1.0.1。 这样,浏览器就会强制重新加载 my-script.js 文件。

7. 本地化脚本:PHP 和 JavaScript 的桥梁

有时候,我们需要将 PHP 中的数据传递给 JavaScript 脚本,以便在客户端使用。 例如,我们可能需要将当前用户的 ID 或网站的 URL 传递给 JavaScript 脚本。

gutenberg_get_assets() 函数通常会结合 wp_localize_script() 函数来实现脚本的本地化。

<?php

function my_custom_gutenberg_assets() {
    // 注册脚本
    wp_register_script(
        'my-script',
        plugins_url( 'my-script.js', __FILE__ ),
        array( 'wp-blocks', 'wp-element', 'wp-editor' ),
        '1.0.0',
        true
    );

    // 本地化脚本
    wp_localize_script(
        'my-script',
        'myScriptData', // JavaScript 中使用的对象名称
        array(
            'ajax_url' => admin_url( 'admin-ajax.php' ),
            'nonce'    => wp_create_nonce( 'my_nonce' ),
        )
    );

    // 将脚本添加到编辑器
    wp_enqueue_script( 'my-script' );
}

add_action( 'enqueue_block_editor_assets', 'my_custom_gutenberg_assets' );

在这个例子中,我们使用 wp_localize_script() 函数将一个名为 myScriptData 的 JavaScript 对象传递给 my-script.jsmyScriptData 对象包含 ajax_urlnonce 两个属性,它们分别对应着 WordPress 的 AJAX URL 和一个用于安全验证的 nonce 值。

my-script.js 中,我们可以使用 myScriptData.ajax_urlmyScriptData.nonce 来访问这些值。

// my-script.js
jQuery(document).ready(function($) {
    console.log(myScriptData.ajax_url);
    console.log(myScriptData.nonce);
});

8. 总结与展望

gutenberg_get_assets() 函数是 Gutenberg 编辑器资产加载机制的核心。 通过注册资产、定义依赖关系、确定版本号和本地化脚本,它确保 Gutenberg 编辑器所需的所有 JavaScript 脚本和 CSS 样式都已正确加载,并以最佳的方式运行。

理解 gutenberg_get_assets() 函数的工作原理可以帮助你更好地理解 Gutenberg 编辑器的内部机制,并为自定义 Gutenberg 编辑器提供更多可能性。

重点回顾:

功能 描述
注册资产 将 Gutenberg 编辑器所需的 JavaScript 和 CSS 文件注册到 WordPress 的资源队列中。
定义依赖关系 明确各个资产之间的依赖关系,确保它们以正确的顺序加载。
确定版本号 为每个资产指定版本号,以便在更新时可以强制浏览器重新加载新的资产文件。
本地化脚本 将 PHP 中的数据传递给 JavaScript 脚本,实现服务器端和客户端之间的通信。
wp_register_script 用于注册 JavaScript 脚本,接受脚本句柄、URL、依赖项数组、版本号和是否在页脚加载等参数。
wp_register_style 用于注册 CSS 样式表,接受样式表句柄、URL、依赖项数组和版本号等参数。
wp_enqueue_script 用于将已注册的 JavaScript 脚本添加到页面中。
wp_enqueue_style 用于将已注册的 CSS 样式表添加到页面中。
wp_localize_script 用于将 PHP 中的数据传递给 JavaScript 脚本。

希望今天的讲座对你有所帮助。 感谢大家的参与!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注