Gutenberg区块:如何利用`create-block`工具创建高性能的区块?

Gutenberg 区块开发:利用 create-block 构建高性能区块

大家好!今天我们来深入探讨如何利用 WordPress 官方提供的 create-block 工具,高效且高质量地构建 Gutenberg 区块。我们将重点关注如何构建高性能区块,避免常见的性能陷阱,并深入了解 create-block 生成的代码结构,以及如何根据实际需求进行定制。

create-block 工具介绍

create-block 是一个 CLI (Command Line Interface) 工具,它极大地简化了 Gutenberg 区块的开发流程。它能够自动生成区块所需的基本文件和代码结构,包括:

  • block.json: 区块的元数据文件,定义了区块的名称、标题、描述、属性、类别等信息。
  • index.js: 区块的入口文件,注册区块并导入编辑和保存组件。
  • edit.js: 定义区块在编辑器中的呈现和交互逻辑。
  • save.js: 定义区块在前端的呈现方式。
  • style.scss: 定义区块在编辑器和前端的通用样式。
  • editor.scss: 定义区块在编辑器中的特定样式。
  • style.js: 导入样式表,将样式应用于编辑器和前端。
  • index.php: 用于注册区块的 PHP 文件,通常包含 register_block_type 函数。

使用 create-block 的优点:

  • 快速启动: 避免了从零开始搭建区块结构,节省大量时间。
  • 规范化: 遵循 WordPress 官方推荐的开发规范,代码结构清晰易懂。
  • 可定制: 生成的代码可以根据需求进行灵活的修改和扩展。
  • 最佳实践: 包含一些最佳实践,例如自动处理样式加载。

使用 create-block 创建区块

首先,确保你已经安装了 Node.js 和 npm (或 yarn)。 然后,可以使用以下命令全局安装 create-block

npm install -g @wordpress/create-block

安装完成后,可以使用以下命令创建一个新的区块:

npx @wordpress/create-block my-block

my-block 替换为你想要的区块名称。 你也可以添加一些选项来自定义区块创建过程,例如:

  • --template: 指定要使用的模板 (例如:esnext, typescript),默认是 esnext
  • --namespace: 指定区块的命名空间,默认是主题或插件的名称。
  • --no-plugin: 不创建插件目录,将区块文件放在主题目录下。

例如,创建一个使用 Typescript 模板,命名空间为 "my-theme" 的区块:

npx @wordpress/create-block my-block --template typescript --namespace my-theme

create-block 会在当前目录下创建一个名为 my-block 的文件夹,其中包含了所有必要的区块文件。

create-block 生成的代码结构详解

接下来,我们深入了解 create-block 生成的代码结构,以便更好地理解和定制区块。

block.json

block.json 文件是区块的核心配置文件,它定义了区块的所有元数据。 以下是一个示例 block.json 文件:

{
    "name": "my-theme/my-block",
    "title": "My Block",
    "description": "A simple Gutenberg block.",
    "category": "common",
    "icon": "smiley",
    "keywords": [ "example", "test" ],
    "attributes": {
        "content": {
            "type": "string",
            "source": "html",
            "selector": "p"
        },
        "alignment": {
            "type": "string",
            "default": "left"
        }
    },
    "supports": {
        "align": true,
        "html": false
    },
    "textdomain": "my-theme",
    "editorScript": "file:./build/index.js",
    "editorStyle": "file:./build/index.css",
    "style": "file:./build/style-index.css"
}
  • name: 区块的唯一名称,格式为 namespace/block-name
  • title: 区块在编辑器中显示的标题。
  • description: 区块的描述信息。
  • category: 区块在区块插入器中所属的类别 (例如:common, formatting, layout)。
  • icon: 区块在区块插入器中显示的图标,可以是 Dashicon 的名称或 SVG 代码。
  • keywords: 用于搜索区块的关键词。
  • attributes: 定义区块的属性,每个属性都有 type (例如:string, number, boolean, object, array),source (指定属性的值从哪里获取,例如:html, attribute, meta) 和 selector (指定要获取值的 HTML 元素)。
  • supports: 定义区块支持的功能 (例如:align, html, className, customClassName)。
  • textdomain: 用于翻译区块的文本域。
  • editorScript: 编辑器脚本的路径。
  • editorStyle: 编辑器样式的路径。
  • style: 前端样式的路径。

index.js

index.js 文件是区块的入口文件,它负责注册区块并导入编辑和保存组件。

import { registerBlockType } from '@wordpress/blocks';
import './style.scss';

import Edit from './edit';
import save from './save';

registerBlockType( 'my-theme/my-block', {
    edit: Edit,
    save,
} );
  • registerBlockType: WordPress 提供的函数,用于注册区块。它接受两个参数:区块的名称和配置对象。
  • edit: 编辑器组件,定义区块在编辑器中的呈现和交互逻辑。
  • save: 保存组件,定义区块在前端的呈现方式。

edit.js

edit.js 文件定义区块在编辑器中的呈现和交互逻辑。

import { __ } from '@wordpress/i18n';
import { useBlockProps, RichText } from '@wordpress/block-editor';

import './editor.scss';

export default function Edit( { attributes, setAttributes } ) {
    const { content } = attributes;

    return (
        <p { ...useBlockProps() }>
            <RichText
                tagName="span"
                className="my-block-content"
                value={ content }
                onChange={ ( newContent ) => setAttributes( { content: newContent } ) }
                placeholder={ __( 'Write something...', 'my-theme' ) }
            />
        </p>
    );
}
  • useBlockProps: 一个 Hook,用于获取区块的属性,例如 classNamestyle,并将其应用到根元素。
  • RichText: 一个组件,用于创建可编辑的文本区域。
  • attributes: 区块的属性对象。
  • setAttributes: 一个函数,用于更新区块的属性。

save.js

save.js 文件定义区块在前端的呈现方式。

import { useBlockProps, RichText } from '@wordpress/block-editor';

export default function save( { attributes } ) {
    const { content } = attributes;

    return (
        <p { ...useBlockProps.save() }>
            <RichText.Content tagName="span" className="my-block-content" value={ content } />
        </p>
    );
}
  • useBlockProps.save(): 类似于 useBlockProps(),但它返回的是用于保存组件的属性。
  • RichText.Content: 一个组件,用于在前端呈现 RichText 组件的内容。

style.scsseditor.scss

style.scss 文件定义区块在编辑器和前端的通用样式,editor.scss 文件定义区块在编辑器中的特定样式。

// style.scss
.wp-block-my-theme-my-block {
  border: 1px solid #ccc;
  padding: 10px;
}

.my-block-content {
  font-style: italic;
}

// editor.scss
.wp-block-my-theme-my-block {
  background-color: #f0f0f0;
}

index.php

index.php 文件用于注册区块的 PHP 文件,通常包含 register_block_type 函数。

<?php
/**
 * Registers the block using the metadata loaded from the `block.json` file.
 * Behind the scenes, it registers also all assets so they can be enqueued
 * through the block editor in the corresponding context.
 *
 * @see https://developer.wordpress.org/reference/functions/register_block_type/
 */
function my_theme_my_block_block_init() {
    register_block_type( __DIR__ . '/build' );
}
add_action( 'init', 'my_theme_my_block_block_init' );
  • register_block_type: WordPress 提供的函数,用于在 PHP 中注册区块。它接受一个参数:包含区块元数据的 block.json 文件的路径。
  • add_action( 'init', 'my_theme_my_block_block_init' ): 将 my_theme_my_block_block_init 函数挂载到 init 钩子上,以便在 WordPress 初始化时注册区块。

构建高性能区块的策略

创建高性能的 Gutenberg 区块需要考虑多个方面,包括:

  1. 最小化依赖: 避免引入不必要的第三方库,减少代码体积和加载时间。
  2. 优化属性: 只定义必要的属性,避免存储冗余数据。
  3. 选择合适的 source 根据属性的来源选择合适的 source (例如:html, attribute, meta),避免不必要的 DOM 操作。
  4. 避免重复渲染: 使用 useMemouseCallback 等 Hook 来避免不必要的组件重新渲染。
  5. 代码分割: 将区块代码分割成多个模块,按需加载,减少初始加载时间。
  6. 图片优化: 对区块中使用的图片进行优化,例如压缩图片大小、使用 WebP 格式、使用懒加载。
  7. 服务器端渲染 (SSR): 对于复杂的区块,可以考虑使用服务器端渲染,提高首屏加载速度。
  8. 缓存: 使用缓存机制,例如对象缓存或瞬态缓存,减少数据库查询。

下面我们详细讨论其中几个重要的策略,并提供示例代码。

1. 优化属性和选择合适的 source

区块属性定义了区块的数据结构,不合理的属性设计会影响性能。

示例:避免存储冗余数据

假设我们有一个显示文章标题的区块,如果直接将完整的文章对象存储在区块属性中,会导致存储大量冗余数据,影响性能。

// 不推荐的做法
attributes: {
  post: {
    type: 'object',
  }
}

更合理的做法是只存储文章的 ID,然后通过 ID 获取文章标题。

// 推荐的做法
attributes: {
  postId: {
    type: 'number',
  },
  postTitle: {
    type: 'string',
  }
}

选择合适的 source

source 属性指定了属性的值从哪里获取。常用的 source 包括:

  • html: 从 HTML 元素的内容中获取。
  • attribute: 从 HTML 元素的属性中获取。
  • meta: 从文章的元数据中获取。

选择合适的 source 可以避免不必要的 DOM 操作。

示例:使用 attribute 而不是 html

假设我们有一个显示链接地址的区块,如果使用 html 来获取链接地址,会导致每次渲染时都需要解析 HTML 元素。

// 不推荐的做法
attributes: {
  url: {
    type: 'string',
    source: 'html',
    selector: 'a',
  }
}

更合理的做法是使用 attribute,直接从 <a> 标签的 href 属性中获取链接地址。

// 推荐的做法
attributes: {
  url: {
    type: 'string',
    source: 'attribute',
    selector: 'a',
    attribute: 'href',
  }
}

2. 避免重复渲染

React 组件的渲染是一个昂贵的操作,不必要的重新渲染会降低性能。可以使用 useMemouseCallback 等 Hook 来避免不必要的组件重新渲染。

useMemo

useMemo 用于缓存计算结果,只有当依赖项发生变化时,才会重新计算。

示例:缓存计算结果

假设我们有一个需要计算复杂值的区块,可以使用 useMemo 来缓存计算结果。

import { useMemo } from '@wordpress/element';

function MyBlock( { attributes } ) {
  const { value } = attributes;

  const expensiveValue = useMemo( () => {
    // 进行复杂的计算
    console.log('Calculating expensive value...');
    return value * 2;
  }, [ value ] ); // 只有当 value 发生变化时,才会重新计算

  return (
    <div>
      Value: {value}
      Expensive Value: {expensiveValue}
    </div>
  );
}

useCallback

useCallback 用于缓存函数,只有当依赖项发生变化时,才会重新创建函数。

示例:缓存事件处理函数

假设我们有一个按钮,点击时需要执行一个函数,可以使用 useCallback 来缓存函数。

import { useCallback } from '@wordpress/element';

function MyBlock( { setAttributes } ) {
  const handleClick = useCallback( () => {
    setAttributes( { clicked: true } );
  }, [ setAttributes ] ); // 只有当 setAttributes 发生变化时,才会重新创建函数

  return (
    <button onClick={handleClick}>Click Me</button>
  );
}

3. 代码分割

代码分割是将区块代码分割成多个模块,按需加载,减少初始加载时间。可以使用 import() 语法来实现代码分割。

示例:延迟加载组件

假设我们有一个包含大量代码的组件,可以使用 import() 语法来延迟加载该组件。

import { useState, useEffect } from '@wordpress/element';

function MyBlock() {
  const [ MyComponent, setMyComponent ] = useState( null );

  useEffect( () => {
    import( './my-component' )
      .then( ( module ) => {
        setMyComponent( module.default );
      } );
  }, [] );

  if ( ! MyComponent ) {
    return <p>Loading...</p>;
  }

  return <MyComponent />;
}

4. 使用服务器端渲染 (SSR)

对于复杂的区块,可以使用服务器端渲染,提高首屏加载速度。服务器端渲染是指在服务器端生成 HTML 代码,然后将 HTML 代码发送给客户端。 客户端只需要渲染 HTML 代码,而不需要执行 JavaScript 代码,从而提高了首屏加载速度。

实现服务器端渲染需要进行额外的配置,例如使用 Next.js 或 Gatsby 等框架。

性能测试和优化

在开发过程中,需要对区块进行性能测试,找出性能瓶颈,并进行优化。可以使用 Chrome DevTools 等工具进行性能测试。

Chrome DevTools

Chrome DevTools 提供了强大的性能分析工具,可以帮助我们找出性能瓶颈。

  • Performance 面板: 用于录制和分析页面性能。
  • Memory 面板: 用于分析内存使用情况。
  • Coverage 面板: 用于分析代码覆盖率,找出未使用的代码。

总结

通过 create-block 工具,我们能快速搭建 Gutenberg 区块的基础结构。 高性能区块的关键在于优化属性设计、避免不必要的渲染、合理分割代码、以及在适当情况下使用服务器端渲染。 持续的性能测试和优化是保证区块性能的关键。

持续学习和实践

Gutenberg 区块开发是一个不断发展的领域,需要不断学习和实践。 关注 WordPress 官方文档和社区,了解最新的技术和最佳实践。 通过实际项目,积累经验,提高开发水平。

发表回复

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