Gutenbergブロックエディターのカスタムブロックを自作したい。しかもSassではなくStylusで。という、Stylus大好きスタイラサーのための環境構築編です。@wordpress/scripts
をベースとなります。
ベーシックな部分はこちらを参考にさせていただきました。加えてSassに関連する部分をStylus版に変更した感じです。
【WordPress】カスタムブロックの作り方を書いてみた - Qiita -
ディレクトリ構成図
my-block-plugin
├ node_modules
├ public (公開フォルダ)
│ ├ assets (buildフォルダ)
│ └ my-block-plugin.php (プラグインのメインファイル)
├ src
│ ├ editor.js (エディター用JS)
│ ├ editor.styl (エディター用CSS)
│ ├ script.js (エディター・フロント両用JS)
│ └ style.styl (エディター・フロント両用CSS)
├ package.json
├ webpack.config.js
└ (yarn.lock)
package.json
package.json (クリックで全体を表示)
{
"name": "my-block-plugin",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "wp-scripts build --mode=development --config webpack.config.js --watch",
"build": "wp-scripts build --mode=production --config webpack.config.js"
},
"author": "Watashi",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.10.4",
"@babel/preset-env": "^7.10.4",
"@babel/preset-react": "^7.10.4",
"@lipemat/css-mqpacker": "^8.0.1",
"@wordpress/block-editor": "^4.3.1",
"@wordpress/blocks": "^6.20.1",
"@wordpress/browserslist-config": "^2.7.0",
"@wordpress/components": "^10.0.1",
"@wordpress/dependency-extraction-webpack-plugin": "^2.8.0",
"@wordpress/editor": "^9.20.1",
"@wordpress/element": "^2.16.0",
"@wordpress/scripts": "^12.1.1",
"autoprefixer": "^9.8.5",
"babel-loader": "^8.1.0",
"clean-webpack-plugin": "^3.0.0",
"css-declaration-sorter": "^5.1.2",
"css-loader": "^3.6.0",
"mini-css-extract-plugin": "^0.9.0",
"optimize-css-assets-webpack-plugin": "^5.0.3",
"path": "^0.12.7",
"postcss-combine-duplicated-selectors": "^9.0.0",
"postcss-loader": "^3.0.0",
"sort-css-media-queries": "^1.5.0",
"stylus": "^0.54.7",
"stylus-loader": "^3.0.2",
"terser-webpack-plugin": "^3.0.6",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.12",
"webpack-fix-style-only-entries": "^0.5.1",
"webpack-merge": "^5.0.9"
},
"browserslist": [
"extends @wordpress/browserslist-config"
]
}
モジュールをざっくり分類するとこんな感じです。
モジュールをざっくり分類 (クリックで全体を表示)
WordPress公式
@wordpress/block-editor
@wordpress/blocks
@wordpress/browserslist-config
@wordpress/components
@wordpress/dependency-extraction-webpack-plugin
@wordpress/editor
@wordpress/element
@wordpress/scripts
JS/BABEL関連
@babel/core
@babel/preset-env
@babel/preset-react
babel-loader
terser-webpack-plugin
Stylus/CSS関連
@lipemat/css-mqpacker
autoprefixer
css-declaration-sorter
css-loader
mini-css-extract-plugin
optimize-css-assets-webpack-plugin
postcss-combine-duplicated-selectors
postcss-loader
sort-css-media-queries
stylus
stylus-loader
webpack-fix-style-only-entries
その他
clean-webpack-plugin
path
webpack
webpack-cli
モジュールごとの役割は webpack.config.js
のコメントにも書いてあります。
今回は使用していませんが、 img-loader
, file-loader
, url-loader
, resolve-url-loader
なども、もちろんSass同様に使えます。
webpack.config.js
webpack.config.js (クリックして全体を表示)
const DependencyExtractionWebpackPlugin = require('@wordpress/dependency-extraction-webpack-plugin')
const FixStyleOnlyEntriesPlugin = require('webpack-fix-style-only-entries')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const OptimizeCSSAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
const TerserWebpackPlugin = require('terser-webpack-plugin')
const autoprefixer = require('autoprefixer')
const path = require('path')
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
// For PostCSS
const cssDeclarationSorter = require('css-declaration-sorter')
const cssMqpacker = require('@lipemat/css-mqpacker')
const postCssCombineDuplicatedSelectors = require('postcss-combine-duplicated-selectors')
const sortCssMediaQueries = require('sort-css-media-queries')
module.exports = (env, argv) => {
// モードが development なら trueを返す
function isDevelopment () {
return argv.mode === 'development'
}
var config = {
entry: {
editor: path.resolve(__dirname, 'src', 'editor.js'),
script: path.resolve(__dirname, 'src', 'script.js'),
style: path.resolve(__dirname, 'src', 'style.styl')
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'public', 'assets')
},
optimization: {
minimizer: [
// JavaScriptを圧縮する
new TerserWebpackPlugin({
// sourceMapをmodeによって削除する
sourceMap: isDevelopment()
}),
// CSSを圧縮する
new OptimizeCSSAssetsWebpackPlugin(
{
cssProcessorOptions: {
map: {
inline: false,
annotation: true
}
}
}
)
]
},
plugins: [
// ビルドの度にビルドフォルダーを削除する
new CleanWebpackPlugin(),
// assets.phpファイルを出力する
new DependencyExtractionWebpackPlugin(),
// CSSをentryに指定したとき同名の不要なjsが出力されないようにする
new FixStyleOnlyEntriesPlugin({
extensions: ['styl', 'css']
}),
// CSSファイルを別ファイルで出力する
new MiniCssExtractPlugin({
filename: '[name].css'
})
],
devtool: 'source-map',
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [
'@babel/preset-env',
[
'@babel/preset-react',
{
// 通常は'React.createElement.xxxx'を記述しますが、WordPressのブロックエディターはWordPress用のReactを使用するため、以下のように記述します
'pragma': 'wp.element.createElement',
'pragmaFrag': 'wp.element.Fragment',
'development': isDevelopment()
}
]
]
}
}
},
{
test: /\.(styl|css)$/,
use: [
{
loader: MiniCssExtractPlugin.loader
},
{
loader: 'css-loader'
},
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [
// 重複するセレクタをまとめる
postCssCombineDuplicatedSelectors({
removeDuplicatedProperties: true
}),
// 重複するメディアクエリをまとめる
cssMqpacker({
// メディアクエリをソート
sort: sortCssMediaQueries
}),
// CSSの属性をソート
cssDeclarationSorter({
order: 'smacss'
}),
// ベンダープレフィックスを付与
autoprefixer({
// CSSグリッドを使う
grid: true
})
]
}
},
{
loader: 'stylus-loader'
}
]
}
]
}
}
return config
}
my-block-plugin.php
プラグインのメインファイル。
my-block-plugin.php (クリックして全体を表示)
<?php
/**
* Plugin Name: 僕のStylusブロック
*/
if ( !defined( 'ABSPATH' ) ) {
exit;
}
add_action( 'init', 'my_block_plugin_register' );
function my_block_plugin_register() {
$editor_asset = include( plugin_dir_path( __FILE__ ) . 'assets/editor.asset.php' );
$script_asset = include( plugin_dir_path( __FILE__ ) . 'assets/script.asset.php' );
// エディター用JSを登録
wp_register_script(
'my-block-plugin-editor-script',
plugins_url( 'assets/editor.js', __FILE__ ),
$editor_asset['dependencies'],
$editor_asset['version']
);
// エディター・フロント両用JSを登録
wp_register_script(
'my-block-plugin-script',
plugins_url( 'assets/script.js', __FILE__ ),
$script_asset['dependencies'],
$script_asset['version']
);
// エディター用CSSを登録
wp_register_style(
'my-block-plugin-editor-style',
plugins_url( 'assets/editor.css', __FILE__ ),
array( 'wp-edit-blocks' ),
filemtime( plugin_dir_path( __FILE__ ) . 'assets/editor.css' )
);
// エディター・フロント両用CSSを登録
wp_register_style(
'my-block-plugin-style',
plugins_url( 'assets/style.css', __FILE__ ),
array(),
filemtime( plugin_dir_path( __FILE__ ) . 'assets/style.css' )
);
// カスタムブロックの登録
register_block_type(
'my-block-plugin/my-block',
[
'editor_script' => 'my-block-plugin-editor-script', // エディター用JSを読み込む
// 'script' => 'my-block-plugin-script', // エディター・フロント両用JSを読み込む
// 'editor_style' => 'my-block-plugin-editor-style', // エディター用CSSを読み込む
'style' => 'my-block-plugin-style' // エディター・フロント両用CSSを読み込む
]
);
}
my_block_plugin
, my-block-plugin
の文字列はご自分のプラグイン名に合わせて変更してください。
register_block_type
の部分では必要ないJS, CSSは必要に応じてコメントアウトしてください。今回のサンプルでは editor_script
と style
のみ使うので他はコメント化しています。
wp_register_style
の第4引数 filetime
は、ビルドするごとにブラウザキャッシュを消すための小技です。ただし、Stylus側が空でCSSが出力されていない場合にはエラーが出るのでご注意ください。
editor.js
editor.js (クリックして全体を表示)
import { RichText } from '@wordpress/editor'
import { registerBlockType } from '@wordpress/blocks'
registerBlockType( 'my-block-plugin/my-block', {
title: '僕のサンプル 青いブロック',
category: 'common',
icon: 'wordpress-alt',
attributes: {
text: {
type: 'string',
source: 'html',
selector: 'p',
},
},
edit: ( props ) => {
const onChangeText = ( newText ) => {
props.setAttributes( { text: newText } );
};
return (
<div>
<RichText
className={ props.className }
tagName="p"
value={ props.attributes.text }
onChange={ onChangeText }
/>
</div>
);
},
save: ( props ) => {
return (
<div>
<p>{ props.attributes.text }</p>
</div>
);
},
});
エディター画面のみで読み込まれるJS。実際にブロックを設計するファイルです。ここをReactで書いていきます。
内容は、動作確認用として、テキストを入力して表示するブロックのサンプルとなります。今回は環境構築が目的ということで、具体的な中身の解説は今回は割愛します。
style.styl
同じく動作確認用です。エディター、フロント両方で読み込まれるCSSです。
style.styl (クリックして全体を表示)
.wp-block-my-block-plugin-my-block
background-color: #5cb1e3
border-radius: 4px
color: rgba(255,255,255,0.95)
margin-top: 24px
margin-bottom: 24px
padding: 24px
動作確認
ターミナルでプラグインディレクトリへ移動して、ビルドしましょう。
npm run build
プラグインの public
フォルダをまるごとWordPressの plugins
フォルダ直下に入れます。僕は、テスト環境では public
フォルダのシンボリックリンクを作って plugins
フォルダ直下に入れています…が、もっといい方法があったら教えてください。
WordPressプラグイン画面で「僕のStylusブロック」を有効化します。
投稿編集画面へ行き、自作ブロックが「一般ブロック」の中に登録されているか確認し、あったら使ってみましょう。青い背景のブロックができます。
文字を書いて保存します。
フロント側をプレビューして文字が表示されていればOKです。
以上 @wordpress/scripts
と Stylusを使った環境構築の一例でした。
参考文献
【WordPress】カスタムブロックの作り方を書いてみた - Qiita -
registerBlockTypeで指定する内容について - Qiita -