学习 Gutenberg:设置自定义 webpack 配置

Avatar of Andy Bell
Andy Bell 发布

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 $200 免费额度!

Gutenberg 将现代 JavaScript 技术栈引入 WordPress 生态系统,这意味着需要学习一些新的工具。虽然像 create-guten-block 这样的工具非常有用,但了解其内部工作原理也很方便。

文章系列

  1. 系列介绍
  2. 什么是 Gutenberg?
  3. 使用 create-guten-block 入门
  4. 现代 JavaScript 语法
  5. React 101
  6. 设置自定义 webpack (本文)
  7. 自定义“卡片”块
我们将在本文中配置的文件应该与我们在 第 2 部分使用 create-guten-block 入门 中介绍的内容一致。如果您像我一样(在阅读 Andy 的教程之前!),不想立即深入配置部分,则由 create-guten-block 创建的脚手架与我们即将在此处创建的内容相匹配,因此您当然也可以使用它。

让我们开始吧!

入门

Webpack 将前端代码库中的小型模块化部分压缩成一个高效的文件。它具有很强的扩展性和可配置性,并且是网络上一些最受欢迎的产品和项目的核心。它是一个非常棒的 JavaScript 工具,尽管它可以用于几乎任何你想要的事情。在本教程中,它唯一的关注点是 JavaScript。

我们将让 Webpack 做的事情是监视我们对一些自定义块文件所做的更改,并使用 Babel 编译它们以生成大多数浏览器可以读取的 JavaScript 文件。它还会合并我们导入的任何依赖项。

但首先,我们需要一个地方来存储我们实际的 Webpack 设置和前端文件。在 第 2 部分 中,当我们浏览由 create-guten-block 生成的文件时,我们发现它创建了一个 WordPress 插件的基础架构,该插件以 WordPress 的方式加载我们的前端文件,并使我们能够通过 WordPress 激活该插件。我将利用下一部分来引导我们设置自定义块的 WordPress 插件的基础架构。

设置插件

希望您仍然有一个从第 2 部分的入门指南中运行的本地 WordPress 实例,但如果没有,您需要安装一个才能继续执行我们即将执行的操作。在该安装中,导航到 wp-content/plugins 并创建一个名为 card-block 的新目录(剧透警告:我们将创建一个卡片块……谁不喜欢卡片?)。

然后,在 card-block 内部,创建一个名为 card-block.php 的文件。这将等同于 create-guten-block 中的 plugin.php。接下来,插入这段注释,告诉 WordPress 将此目录识别为插件并在仪表盘的“插件”页面中显示它。

<?php
   /*
   Plugin Name: Card Block
   */

不要忘记打开 PHP 标签,但您可以省略关闭标签,因为我们很快就会向此文件添加更多内容。

WordPress 通过查找这些注释来注册插件,就像它在主题的 style.css 顶部查找注释一样。这是您在其他插件的主文件中顶部找到的内容的简化版本。如果您计划将其发布在 WordPress 插件存储库中,您还需要添加描述和版本号以及许可证和作者信息。

通过 WordPress 仪表盘激活该插件,我将重新接手控制权,引导您完成设置 Webpack 配置!

Webpack 入门

我们要做的第一件事是初始化 npm。在插件文件夹的**根目录**(wp-content/plugins/card-block)中运行以下命令:

npm init

这将询问您一些关于项目的问题,并最终生成一个 package.json 文件,该文件列出依赖项并存储项目核心信息。

接下来,让我们安装 Webpack:

npm install webpack --save-dev

您可能已经注意到,我们正在将 Webpack 本地安装到我们的项目中。对于容易发生重大更改的关键软件包,这是一个很好的实践。这也意味着您和您的团队都在使用相同的版本。

然后运行此命令:

npm install extract-text-webpack-plugin@next --save-dev

然后安装这些 Sass 和 CSS 依赖项:

npm install node-sass sass-loader css-loader --save-dev

# J Parenti wrote in to say that in Babel 7, it's different. You may need to:
npm uninstall --save-dev sass-loader
npm install --save-dev [email protected]

现在,使用 NPX 允许我们使用本地依赖项而不是任何全局依赖项:

npm install npx -g

最后,运行此命令:

npm install webpack-cli --save-dev

这将为您安装 Webpack CLI

现在我们已经安装了它,我们应该创建我们的配置文件。仍在插件的根目录中,创建一个名为 webpack.config.js 的文件并打开它,以便我们可以开始编码。

使用此 Webpack 文件,我们将使用传统的 ES5 代码以获得最大的兼容性,因为它与 Node JS 运行。您可以使用 ES6 和 Babel,但为了本教程的目的,我们将尽量保持简单。

好的,让我们添加一些常量和导入。将以下内容添加到 webpack.config.js 文件的顶部:

var ExtractText = require('extract-text-webpack-plugin');
var debug = process.env.NODE_ENV !== 'production';
var webpack = require('webpack');

debug 变量声明我们是否处于 debug 模式。这是我们的默认模式,但可以通过在 Webpack 命令前加上 NODE_ENV=production 来覆盖。debug 布尔标志将确定 Webpack 是否生成源映射并压缩代码。

如您所见,我们正在引入一些依赖项。我们知道需要 Webpack,所以我们跳过它。相反,让我们将注意力集中在 ExtractText 上。从本质上讲,ExtractText 使我们能够将 JavaScript 以外的文件包含进来。我们将需要它用于我们的 Sass 文件。默认情况下,Webpack 假设所有内容都是 JavaScript,因此 ExtractText 就像 *转换* 其他类型的文件一样。

现在让我们添加一些配置。在 webpack 定义之后添加以下内容:

var extractEditorSCSS = new ExtractText({
  filename: './blocks.editor.build.css'
});

var extractBlockSCSS = new ExtractText({
  filename: './blocks.style.build.css'
});

我们在那里所做的是通过传递一个配置对象来实例化两个 ExtractText 实例。我们设置的只是两个块样式表的输出。我们将在接下来的系列文章中介绍这些内容,但现在您只需要知道这是开始编译 Sass 的第一步。

好的,在最后一段代码之后,添加以下内容:

var plugins = [ extractEditorSCSS, extractBlockSCSS ];

在这里,我们有两个插件数组。我们的 ExtractText 实例位于核心插件集中,我们还有一些优化插件,只有在非 debug 模式下才会将其合并到核心插件集中。我们正在最后运行该逻辑。

接下来,添加此 SCSS 配置对象:

var scssConfig = {
  use: [
    {
      loader: 'css-loader'
    },
    {
      loader: 'sass-loader',
      options: {
        outputStyle: 'compressed'
      }
    }
  ]
};

此对象将告诉我们的 Webpack 实例在遇到 scss 文件时如何表现。我们将其放在一个配置对象中,以尽可能保持 DRY 原则。

最后,配置的核心部分:

module.exports = {
  context: __dirname,
  devtool: debug ? 'inline-sourcemap' : null,
  mode: debug ? 'development' : 'production',
  entry: './blocks/src/blocks.js',
  output: {
    path: __dirname + '/blocks/dist/',
    filename: 'blocks.build.js'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: [
          {
            loader: 'babel-loader'
          }
        ]
      },
      {
        test: /editor\.scss$/,
        exclude: /node_modules/,
        use: extractEditorSCSS.extract(scssConfig)
      },
      {
        test: /style\.scss$/,
        exclude: /node_modules/,
        use: extractBlockSCSS.extract(scssConfig)
      }
    ]
  },
  plugins: plugins
};

这就是我们的整个配置,让我们来分解一下。

脚本以 module.exports 开头,这基本上是在说,“当您导入或引入我时,这就是您得到的内容。”我们可以确定我们向导入我们代码的任何内容公开什么,这意味着我们可以运行 module.exports 上面的代码来执行一些繁重的计算,例如。

接下来,让我们看看以下一些属性:

  • context 是我们的基准,路径将从此处解析。我们传递了 __dirname,它是当前工作目录。
  • devtool 是我们 定义我们可能想要或不想要的源映射类型 的地方。如果我们不在 debug 模式下,则使用三元运算符传递 null
  • entry 是我们告诉 Webpack 开始其打包过程的地方。在我们的例子中,这是我们 blocks.js 文件的路径。
  • output 正如其名称所示。我们传递一个对象,该对象定义了输出路径和我们想要调用的文件名。

接下来是 module,我们将对其进行更详细的介绍。module 部分可以包含多个规则。在我们的例子中,我们唯一的 rule 是查找 JavaScript 和 SCSS 文件。它通过使用由 test 属性定义的正则表达式进行搜索来实现这一点。规则的最终目标是找到正确类型的文件并将它们传递给加载器,在本例中为 babel-loader。正如我们在本系列之前的教程中学到的那样,Babel 将我们的现代 ES6 代码转换为更受支持的 ES5 代码。

最后是我们的插件部分。在这里,我们传递我们的插件实例数组。在我们的项目中,我们有压缩代码、删除重复代码以及减少常用 ID 长度的插件。所有这些都是为了确保我们的生产代码得到优化。

作为参考,这是您的完整配置文件应有的样子

var ExtractText = require('extract-text-webpack-plugin');
var debug = process.env.NODE_ENV !== 'production';
var webpack = require('webpack');

var extractEditorSCSS = new ExtractText({
  filename: './blocks.editor.build.css'
});

var extractBlockSCSS = new ExtractText({
  filename: './blocks.style.build.css'
});

var plugins = [extractEditorSCSS, extractBlockSCSS];

var scssConfig = {
  use: [
    {
      loader: 'css-loader'
    },
    {
      loader: 'sass-loader',
      options: {
        outputStyle: 'compressed'
      }
    }
  ]
};

module.exports = {
  context: __dirname,
  devtool: debug ? 'inline-sourcemap' : null,
  mode: debug ? 'development' : 'production',
  entry: './blocks/src/blocks.js',
  output: {
    path: __dirname + '/blocks/dist/',
    filename: 'blocks.build.js'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: [
          {
            loader: 'babel-loader'
          }
        ]
      },
      {
        test: /editor\.scss$/,
        exclude: /node_modules/,
        use: extractEditorSCSS.extract(scssConfig)
      },
      {
        test: /style\.scss$/,
        exclude: /node_modules/,
        use: extractBlockSCSS.extract(scssConfig)
      }
    ]
  },
  plugins: plugins
};
Webpack 配置完成。我将把话筒交还,向大家展示如何正式向 WordPress 注册我们的区块。对于习惯于在 WordPress 中处理操作和过滤器的人来说,这应该会感觉很熟悉。

注册我们的区块

回到 card-block.php 中,我们现在的主要任务是将我们将使用 webpack 构建的 JavaScript 和 CSS 文件加入队列。在主题中,我们会使用 wp_enqueue_scriptwp_enqueue_style 在添加到 wp_enqueue_scripts 的操作中调用这些函数。在这里,我们基本上做了同样的事情,只是我们使用特定于区块的函数将脚本和样式加入队列。

将这段代码放在 card-block.php 中起始注释下方

function my_register_gutenberg_card_block() {

  // Register our block script with WordPress
  wp_register_script(
    'gutenberg-card-block',
    plugins_url('/blocks/dist/blocks.build.js', __FILE__),
    array('wp-blocks', 'wp-element', 'wp-editor')
  );

  // Register our block's base CSS  
  wp_register_style(
    'gutenberg-card-block-style',
    plugins_url( '/blocks/dist/blocks.style.build.css', __FILE__ ),
    array( 'wp-blocks' )
  );
  
  // Register our block's editor-specific CSS
  if( is_admin() ) :
     wp_register_style(
      'gutenberg-card-block-edit-style',
      plugins_url('/blocks/dist/blocks.editor.build.css', __FILE__),
      array( 'wp-edit-blocks' )
    );
  endif;
  
  // Enqueue the script in the editor
  register_block_type('card-block/main', array(
    'editor_script' => 'gutenberg-card-block',
    'editor_style' => 'gutenberg-card-block-edit-style',
    'style' => 'gutenberg-card-block-edit-style'
  ));
}

add_action('init', 'my_register_gutenberg_card_block');

如上述注释所示,我们首先使用句柄 gutenberg-card-block 和两个依赖项:wp-blockswp-elements 向 WordPress 注册我们的脚本。此函数仅 *注册* 脚本,不会将其加入队列。对于我们的编辑和主样式表,我们也做了类似的事情。

我们的最终函数 register_block_type 为我们执行了加入队列的操作。它还为区块指定了一个名称,card-block/main,它将此区块识别为命名空间 card-block 中的 main 区块,然后将我们刚刚注册的脚本和样式识别为区块的主要编辑器脚本、编辑器样式表和主要样式表。

如果您熟悉主题开发,您可能已经使用 get_template_directory() 在像上面这样的钩子中处理文件路径。对于插件开发,我们使用函数 plugins_url(),它执行的操作与之几乎相同,只是它不以这种方式连接路径:get_template_directory() . '/script.js'plugins_url() 接受一个字符串路径作为参数,并为我们执行连接操作。第二个参数 _ FILE _ 是 PHP 的 魔术常量 之一,它等效于当前文件的完整文件路径。

最后,如果您想向此插件添加更多区块,则需要为每个区块提供此函数的一个版本。您可以找出哪些是变量,并生成某种循环来使其保持简洁和 DRY,以便将来使用。现在,我将引导大家完成 Babel 的启动和运行。

启动 Babel

Babel 将我们的 ES6 代码转换为更受支持的 ES5 代码,因此我们需要安装一些依赖项。在插件的根目录(wp-content/plugins/card-block)中,运行以下命令

npm install babel-core babel-loader babel-plugin-add-module-exports babel-plugin-transform-react-jsx babel-preset-env --save-dev

2019 年 4 月更新:由于 Babel 从 6 升级到 7 的重大变化,我们在过去几个月对这部分内容进行了大量更新。感谢 Nina Regli、Rick Hughs 和 Bryan Chong。<.p>

Nina 使用以下命令成功安装:

npm install --save-dev @babel/core @babel/preset-env

Rick 使用以下命令成功安装:

npm install @babel/core babel-loader babel-plugin-add-module-exports babel-plugin-transform-react-jsx @babel/preset-env --save-dev

Bryan 使用以下命令成功安装:

npm install --save-dev @babel/preset-react babel-preset-minify @babel/core @babel/cli @babel/preset-en

Bryan 还将 .babelrc 重命名为 babel.config.js 并对其进行了如下配置

module.exports = function (api) {
  return {
    presets: [
      [
        "@babel/preset-react",
        {
          "pragma": "wp.element.createElement"
        }
      ],
      "minify",
      "@babel/env"
    ]
  };
}

这个庞大的 npm 安装命令添加了所有 Babel 依赖项。现在,我们可以添加我们的 .babelrc 文件,该文件存储了一些设置。它可以防止我们不得不一遍遍地在命令行中重复这些设置。

仍然在您的主题文件夹中,添加以下文件:.babelrc

现在打开它并粘贴以下内容

{
  "presets": ["env"],
  "plugins": [
    ["transform-react-jsx", {
      "pragma": "wp.element.createElement"
    }]
  ]
}

2019 年 4 月更新:使用 Babel 7,您可能需要 "presets": ["@babel/preset-env"],

因此,我们在这里有两个东西

"presets": ["env"] 基本上是魔法。它会自动确定要使用哪些 ES 功能来生成您的 ES5 代码。我们过去必须为所有不同的 ES 版本(例如 ES2015)添加不同的预设,但现在已经简化了。

在插件中,您会注意到有一个 React JSX 转换器。它正在整理我们的 JSX 并将其转换为正确的 JavaScript,但我们正在告诉它生成 WordPress 元素,而不是 React 元素,JSX 通常与后者相关联。

生成存根文件

我们要做的最后一件事是生成一些存根文件,并测试我们的 webpack 和 WordPress 设置是否都正常。

进入您的插件目录并创建一个名为 blocks 的文件夹,并在其中创建两个文件夹:一个名为 src,另一个名为 dist

src 文件夹中,创建以下文件。我们也添加了路径,因此您可以将它们放在正确的位置

  • blocks.js
  • common.scss
  • block/block.js
  • block/editor.scss
  • block/style.scss

创建这些文件后,打开 blocks.js 并添加此单行代码并保存

import './block/block';

好的,所以现在我们已经生成了最少数量的文件,让我们运行 webpack。打开您的终端并移动到当前插件文件夹中,然后我们可以运行以下命令,这将启动 webpack

npx webpack

非常简单,对吧?如果您继续查看您的 dist 文件夹,您应该会看到其中有一些编译后的内容!

总结

已经完成了大量的设置,但是我们所有的准备工作都已就绪。我们已经设置了 webpack、Babel 和 WordPress,使它们能够作为一个团队协同工作以构建或自定义 Gutenberg 区块(以及未来的区块)。希望现在您对使用 webpack 感到更加舒适,并感觉自己可以深入研究并进行自定义以适应您的项目。


文章系列

  1. 系列介绍
  2. 什么是 Gutenberg?
  3. 使用 create-guten-block 入门
  4. 现代 JavaScript 语法
  5. React 101
  6. 设置自定义 webpack (本文)
  7. 自定义“卡片”块