Gutenberg 将现代 JavaScript 技术栈引入 WordPress 生态系统,这意味着需要学习一些新的工具。虽然像 create-guten-block 这样的工具非常有用,但了解其内部工作原理也很方便。
文章系列
- 系列介绍
- 什么是 Gutenberg?
- 使用 create-guten-block 入门
- 现代 JavaScript 语法
- React 101
- 设置自定义 webpack (本文)
- 自定义“卡片”块
让我们开始吧!
入门
Webpack 将前端代码库中的小型模块化部分压缩成一个高效的文件。它具有很强的扩展性和可配置性,并且是网络上一些最受欢迎的产品和项目的核心。它是一个非常棒的 JavaScript 工具,尽管它可以用于几乎任何你想要的事情。在本教程中,它唯一的关注点是 JavaScript。
我们将让 Webpack 做的事情是监视我们对一些自定义块文件所做的更改,并使用 Babel 编译它们以生成大多数浏览器可以读取的 JavaScript 文件。它还会合并我们导入的任何依赖项。
设置插件
希望您仍然有一个从第 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 插件存储库中,您还需要添加描述和版本号以及许可证和作者信息。
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
};
注册我们的区块
回到 card-block.php
中,我们现在的主要任务是将我们将使用 webpack 构建的 JavaScript 和 CSS 文件加入队列。在主题中,我们会使用 wp_enqueue_script
和 wp_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-blocks
和 wp-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 的 魔术常量 之一,它等效于当前文件的完整文件路径。
启动 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 感到更加舒适,并感觉自己可以深入研究并进行自定义以适应您的项目。
文章系列
- 系列介绍
- 什么是 Gutenberg?
- 使用 create-guten-block 入门
- 现代 JavaScript 语法
- React 101
- 设置自定义 webpack (本文)
- 自定义“卡片”块
我在让 WebPack 正确生成 dist 文件夹中的文件时遇到了一些麻烦。经过一番挖掘,我发现 webpack 配置文件的入口点是 blocks/blocks.js,但此文件为空。我在该文件中添加了
import './block/block.js';
以引入您上面概述的代码,现在一切正常了。不确定我是否错过了什么,或者教程 5 或 6 是否应该提到在 block/blocks.js 文件中添加一些内容。Justin 观察得很仔细。谢谢。
我已更新这些内容 :)
大家好。我有点困惑……请参见 此处。
我真的很困惑。webpack.config.js 中的入口点设置为
/blocks/src/block.js
,但您的教程中指定在“src”文件夹中创建一个名为“blocks.js”的文件,而不是“block.js”。也许我只是没有正确理解?嗨,Josiah,抱歉让你困惑了。那是我的错误。我把自己也弄糊涂了。
绝对是
blocks.js
,因为该文件会引入所有区块文件(如果需要)。酷!看来我没有疯,哈哈。