{"id":30464,"date":"2020-03-17T11:35:52","date_gmt":"2020-03-17T11:35:52","guid":{"rendered":"https:\/\/www.designbombs.com\/?p=30464"},"modified":"2020-03-24T11:33:05","modified_gmt":"2020-03-24T11:33:05","slug":"creating-a-gutenberg-block-using-the-official-new-package","status":"publish","type":"post","link":"https:\/\/www.designbombs.com\/creating-a-gutenberg-block-using-the-official-new-package\/","title":{"rendered":"Creating a Gutenberg block using the official new package"},"content":{"rendered":"<p>I have finally started creating blocks for <a href=\"https:\/\/wordpress.org\/gutenberg\/\">Gutenberg<\/a>, the (not-so-new anymore) editor for WordPress. Since I have not coded with JavaScript in several years, and have not ventured into React yet, I had been wondering how easy it would be to create a new block.<\/p>\n<p>As luck would have it, a new tool to scaffold Gutenberg blocks <a href=\"https:\/\/make.wordpress.org\/core\/2020\/02\/28\/new-wordpress-create-block-package-for-block-scaffolding\/\">was released<\/a> just a few days before my work started: the <a href=\"https:\/\/developer.wordpress.org\/block-editor\/packages\/packages-create-block\/\">@wordpress\/block package<\/a> (also called @wordpress\/create-block), which allows to create a new WordPress plugin containing all the necessary JavaScript, CSS and PHP files to register a block, with zero configuration.<\/p>\n<p>It is not strictly needed to use a scaffolding project to create a new Gutenberg block. However, modern JavaScript-based projects depend on a great amount of tools to function adequately, and their set-up can be overwhelming: <a href=\"https:\/\/webpack.js.org\/\">webpack<\/a> to bundle the JavaScript files for distribution, <a href=\"https:\/\/babeljs.io\/\">Babel<\/a> to compile the latest JavaScript code into code that can run in older browsers, <a href=\"https:\/\/eslint.org\/\">ESLint<\/a> to find problems in JavaScript code, and others.<\/p>\n<p>Moreover, because these tools are being actively developed and new releases made available every few months, configuring them into our project is not a one-time task, but an ongoing problem. For this reason, a scaffolding tool which can set-up the initial configuration for the JavaScript project, and keep it always up-to-date using the latest improvements, is deeply needed (more for JavaScript newbies, like me). The @wordpress\/block package was launched to accomplish this goal.<\/p>\n<p>We also have other tools to create blocks, such as Ahmad Awais&#8217; <a href=\"https:\/\/github.com\/ahmadawais\/create-guten-block#getting-started\">create-guten-block<\/a> developer toolkit, and the <a href=\"https:\/\/developer.wordpress.org\/block-editor\/tutorials\/block-tutorial\/generate-blocks-with-wp-cli\/\">WP-CLI <code>scaffold block<\/code> command<\/a>. However, the @wordpress\/block package is an official tool by the WordPress project, so we can expect it to be supported in the long term, reflecting the needs of the Gutenberg project as steered by the team working on it.<\/p>\n<p>Hence I decided to create my block using this new package. Following is my experience using this tool, all the problems I came across, how I solved them, and how my set-up looks like for my own development needs.<\/p>\n<h2>Scaffolding a new project<\/h2>\n<p>To create a new project, open a terminal window, browse to the folder where to create the new project, and then execute this command:<\/p>\n<pre><code class=\"prettyprint language-bash\">$ npm init @wordpress\/block my-block\r\n<\/code><\/pre>\n<p>(You must have installed <a href=\"https:\/\/nodejs.org\/en\/\">Node.js<\/a> version 10.0.0 or above, and <a href=\"https:\/\/www.npmjs.com\/get-npm\">npm<\/a> version 6.9.0 or above.)<\/p>\n<p>Once installed, you can observe the changes done to your block&#8217;s JavaScript files and have them automatically compiled, by running this command:<\/p>\n<pre><code class=\"prettyprint language-bash\">$ cd my-block\r\n$ npm start\r\n<\/code><\/pre>\n<p>Depending on your internet connection speed, the process may take several minutes (during which all dependencies are downloaded and installed in the <code>node_modules<\/code> folder). In my case, it took around 4 minutes, hence the GIF below is so slow-moving (the <a href=\"https:\/\/developer.wordpress.org\/block-editor\/packages\/packages-create-block\/#quick-start\">official demo is much faster<\/a>):<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-30465\" src=\"https:\/\/www.designbombs.com\/wp-content\/uploads\/2020\/03\/create-block.gif\" alt=\"Creating a block using the @wordpress\/block package\" width=\"614\" height=\"328\" \/><\/p>\n<h2>Inspecting the created project<\/h2>\n<p>We have by now scaffolded a new project. Let&#8217;s take a look at what files it is composed of, and what content they include:<\/p>\n<pre><code class=\"prettyprint language-bash\">my-block\/\r\n\u251c\u2500\u2500build\/\r\n\u2502 \u251c\u2500\u2500 index.asset.php\r\n\u2502 \u2514\u2500\u2500 index.js\r\n\u251c\u2500\u2500 src\/\r\n\u2502 \u2514\u2500\u2500 index.js\r\n\u251c\u2500\u2500 .gitignore\r\n\u251c\u2500\u2500 .editorconfig\r\n\u251c\u2500\u2500 package.json\r\n\u251c\u2500\u2500 package-lock.json\r\n\u251c\u2500\u2500 editor.css\r\n\u251c\u2500\u2500 style.css\r\n\u2514\u2500\u2500 my-block.php\r\n<\/code><\/pre>\n<p>File <code>src\/index.js<\/code> registers and renders the block in JavaScript, and this file gets compiled and included in the website as <code>build\/index.js<\/code> (this process is done automatically when running <code>npm start<\/code>, or when running <code>npm run build<\/code> for building the code for production). Files <code>editor.css<\/code> and <code>style.css<\/code> contain the block styles, just for the editor in the first case, and for both editor and client-side in the second case. Finally, file <code>my-block.php<\/code> (which has the name we chose for the block when executing the <code>npm init @wordpress\/block<\/code> command) is the WordPress plugin file, which registers the block in the admin. All other files contain meta-data, and are not directly related to the block.<\/p>\n<p>The content of the WordPress plugin file <code>my-block.php<\/code> is the following:<\/p>\n<pre><code class\"prettyprint language-php\">\r\n\/**\r\n * Plugin Name:     My Block\r\n * Description:     Example block written with ESNext standard and JSX support \u2013 build step required.\r\n * Version:         0.1.0\r\n * Author:          The WordPress Contributors\r\n * License:         GPL-2.0-or-later\r\n * Text Domain:     create-block\r\n *\r\n * @package         create-block\r\n *\/\r\n\r\n\/**\r\n * Registers all block assets so that they can be enqueued through the block editor\r\n * in the corresponding context.\r\n *\r\n * @see https:\/\/developer.wordpress.org\/block-editor\/tutorials\/block-tutorial\/applying-styles-with-stylesheets\/\r\n *\/\r\nfunction create_block_my_block_block_init() {\r\n  $dir = dirname( __FILE__ );\r\n\r\n  $script_asset_path = \"$dir\/build\/index.asset.php\";\r\n  if ( ! file_exists( $script_asset_path ) ) {\r\n    throw new Error(\r\n      'You need to run `npm start` or `npm run build` for the \"create-block\/my-block\" block first.'\r\n    );\r\n  }\r\n  $index_js     = 'build\/index.js';\r\n  $script_asset = require( $script_asset_path );\r\n  wp_register_script(\r\n    'create-block-my-block-block-editor',\r\n    plugins_url( $index_js, __FILE__ ),\r\n    $script_asset['dependencies'],\r\n    $script_asset['version']\r\n  );\r\n\r\n  $editor_css = 'editor.css';\r\n  wp_register_style(\r\n    'create-block-my-block-block-editor',\r\n    plugins_url( $editor_css, __FILE__ ),\r\n    array(),\r\n    filemtime( \"$dir\/$editor_css\" )\r\n  );\r\n\r\n  $style_css = 'style.css';\r\n  wp_register_style(\r\n    'create-block-my-block-block',\r\n    plugins_url( $style_css, __FILE__ ),\r\n    array(),\r\n    filemtime( \"$dir\/$style_css\" )\r\n  );\r\n\r\n  register_block_type( 'create-block\/my-block', array(\r\n    'editor_script' =&gt; 'create-block-my-block-block-editor',\r\n    'editor_style'  =&gt; 'create-block-my-block-block-editor',\r\n    'style'         =&gt; 'create-block-my-block-block',\r\n  ) );\r\n}\r\nadd_action( 'init', 'create_block_my_block_block_init' );\r\n<\/code><\/pre>\n<p>There are a few observations we can make here:<\/p>\n<p><strong>We must execute a search\/replace to add our own namespace<\/strong><\/p>\n<p>To make it unique upon registration, every block is composed of two parts, a namespace and a block name, with shape <code>namespace\/block-name<\/code>. However, the <code>npm init @wordpress\/block<\/code> command only allows to specify the block name, but not the namespace! (Executing <code>npm init @wordpress\/block my-namespace\/my-block<\/code> doesn&#8217;t work, I tried). Instead, it creates the block using the <code>\"create-block\"<\/code> namespace, which is certainly not very helpful (I wonder if there is a plan to address this issue).<\/p>\n<p>Hence, we need to do a search and replace of all files in the project, from strings <code>\"create-block\"<\/code> and <code>\"create_block\"<\/code> to our own namespace.<\/p>\n<p><strong>We may need to update the plugin name<\/strong><\/p>\n<p>Similarly to the previous case, we can&#8217;t indicate the plugin&#8217;s title when scaffolding the new project. Instead, it is created by transforming the block name into title-case form. For instance, since my block was called <code>my-block<\/code>, the plugin title was called <code>My Block<\/code>. If we need to update it, we must also do a search\/replace in all files in the project (it appears in more than 1 file).<\/p>\n<p><strong>We must review the license<\/strong><\/p>\n<p>The default license is GPL-2.0-or-later, which may not apply for our plugin, so beware to change it before publishing the plugin in the directory.<\/p>\n<p><strong>It is a single-block plugin<\/strong><\/p>\n<p>The project is a plugin registering a single block. Let&#8217;s analyze this issue in detail in the section below.<\/p>\n<h2>Reconsidering the single-block plugin distribution model<\/h2>\n<p>The scaffolded new project has the shape of a single-block plugin, which is expected to become the <a href=\"https:\/\/make.wordpress.org\/meta\/2019\/03\/08\/the-block-directory-and-a-new-type-of-plugin\/\">default packaging for blocks for the upcoming block directory<\/a>. This approach has benefits and drawbacks: on the positive side, it enables users to only install the required blocks, avoiding the bloat from installing unneeded blocks contained in bundles; on the negative side, bundling blocks often makes sense, since they may reuse functionality\/code that can be shipped together in the same plugin, and having to enable many plugins (one per block) may be inconvenient.<\/p>\n<p>There is an approach we can use to have the best of both worlds, being able to decide if to ship our blocks through single-block plugins, or through a block-bundle plugin, on a project-by-project basis: decouple the block logic from its registration in the WordPress admin into 2 separate entities, and merge them together through the PHP dependency manager <a href=\"https:\/\/getcomposer.org\">Composer<\/a>. This strategy is supported by the <a href=\"https:\/\/make.wordpress.org\/meta\/2019\/03\/08\/the-block-directory-and-a-new-type-of-plugin\/#comment-8966\">philosophy of a block<\/a>: it must be an autonomous unit and context-agnostic, so it can be used, as much as possible, in a variety of different contexts.<\/p>\n<p>(If you haven&#8217;t used Composer yet, I strongly recommend you learn about this tool first, since it can greatly ease setting-up and managing any PHP project. I wrote a guide on how to use it with WordPress <a href=\"\/\/www.smashingmagazine.com\/2019\/03\/composer-wordpress\/)\">here<\/a>.)<\/p>\n<p>Let&#8217;s re-architect our project into 2 separate entities next.<\/p>\n<h2>Re-architecting the structure of the new project<\/h2>\n<p>We will split the project into two:<\/p>\n<ol>\n<li>The Gutenberg block, autonomous of any plugin<\/li>\n<li>The WordPress plugin, which includes the Gutenberg block through Composer<\/li>\n<\/ol>\n<p>Working demos for these 2 projects are located in these 2 repos (which I am currently developing): a <a href=\"https:\/\/github.com\/leoloso\/graphiql-wp-block\">GraphiQL block<\/a>, accessible through the <a href=\"https:\/\/github.com\/leoloso\/graphiql-block-wp-plugin\">GraphiQL plugin<\/a>.<\/p>\n<p>Having the WordPress plugin project include the Gutenberg block project is best achieved through <a href=\"https:\/\/getcomposer.org\/doc\/01-basic-usage.md#autoloading\">autoloading<\/a>, enabled by following the <a href=\"https:\/\/www.php-fig.org\/psr\/psr-4\/\">PSR-4<\/a> convention. Using this architecture, the scaffolded files dealing with the block will live under the block project, and the single PHP file dealing with registering the WordPress plugin will live under the plugin folder, like this:<\/p>\n<pre><code class=\"prettyprint language-bash\"># Block project hierarchy\r\nmy-block\/\r\n\u251c\u2500\u2500build\/\r\n\u2502 \u251c\u2500\u2500 index.asset.php\r\n\u2502 \u2514\u2500\u2500 index.js\r\n\u251c\u2500\u2500 src\/\r\n\u2502 \u251c\u2500\u2500 Block.php\r\n\u2502 \u2514\u2500\u2500 index.js\r\n\u251c\u2500\u2500 .gitignore\r\n\u251c\u2500\u2500 .editorconfig\r\n\u251c\u2500\u2500 package.json\r\n\u251c\u2500\u2500 package-lock.json\r\n\u251c\u2500\u2500 editor.css\r\n\u251c\u2500\u2500 style.css\r\n\u2514\u2500\u2500 composer.json\r\n\r\n# Plugin project hierarchy\r\nmy-plugin\/\r\n\u251c\u2500\u2500 src\/\r\n\u2502 \u2514\u2500\u2500 Plugin.php\r\n\u251c\u2500\u2500 .gitignore\r\n\u251c\u2500\u2500 .editorconfig\r\n\u251c\u2500\u2500 my-plugin.php\r\n\u2514\u2500\u2500 composer.json\r\n<\/code><\/pre>\n<p>Notice the addition of file <code>composer.json<\/code> to both projects. While this file for the block may be empty of dependencies, the plugin one will include the block as a dependency:<\/p>\n<pre><code class=\"prettyprint language-json\">\"require\": {\r\n  \"my-namespace\/my-block\": \"^1.0\"\r\n}\r\n<\/code><\/pre>\n<p>The block registration logic is under <a href=\"https:\/\/github.com\/leoloso\/graphiql-wp-block\/blob\/c8f210d290143628264da49a7a643657d2a8189b\/src\/Block.php\">class <code>Block<\/code><\/a>:<\/p>\n<pre><code class\"prettyprint language-php\">\r\nnamespace Leoloso\\GraphiQLWPBlock;\r\n\r\nclass Block {\r\n\r\n  private $urlPath;\r\n\r\n  public function __construct(string $urlPath)\r\n  {\r\n    $this-&gt;urlPath = \\trailingslashit($urlPath);\r\n  }\r\n\r\n  public function init(): void\r\n  {\r\n    \/\/ Initialize the GraphiQL\r\n    \\add_action('init', [$this, 'initBlock']);\r\n  }\r\n\r\n  public function initBlock(): void\r\n  {\r\n    $dir = dirname(dirname( __FILE__ ));\r\n\r\n    $script_asset_path = \"$dir\/build\/index.asset.php\";\r\n    if ( ! file_exists( $script_asset_path ) ) {\r\n      throw new Error(\r\n        'You need to run `npm start` or `npm run build` for the \"leoloso\/graphiql\" block first.'\r\n      );\r\n    }\r\n\r\n    \/\/ Load the block scripts and styles\r\n    $index_js   = 'build\/index.js';\r\n    $script_asset = require( $script_asset_path );\r\n    \\wp_register_script(\r\n      'leoloso-graphiql-block-editor',\r\n      $this-&gt;urlPath.$index_js,\r\n      $script_asset['dependencies'],\r\n      $script_asset['version']\r\n    );\r\n\r\n    $editor_css = 'editor.css';\r\n    \\wp_register_style(\r\n      'leoloso-graphiql-block-editor',\r\n      $this-&gt;urlPath.$editor_css,\r\n      array(),\r\n      filemtime( \"$dir\/$editor_css\" )\r\n    );\r\n\r\n    $style_css = 'style.css';\r\n    \\wp_register_style(\r\n      'leoloso-graphiql-block',\r\n      $this-&gt;urlPath.$style_css,\r\n      array(),\r\n      filemtime( \"$dir\/$style_css\" )\r\n    );\r\n\r\n    \\register_block_type( 'leoloso\/graphiql', array(\r\n      'editor_script' =&gt; 'leoloso-graphiql-block-editor',\r\n      'editor_style'  =&gt; 'leoloso-graphiql-block-editor',\r\n      'style'         =&gt; 'leoloso-graphiql-block',\r\n    ) );\r\n  }\r\n}\r\n<\/code><\/pre>\n<p>Please notice that, because the block doesn&#8217;t live in a plugin anymore, it doesn&#8217;t know the full URL path to its own assets. Hence, it needs to receive this information by the plugin through variable <code>urlPath<\/code> when initializing the block.<\/p>\n<p>A <code>Plugin<\/code> class can instantiate a new <code>Block<\/code> by executing <a href=\"https:\/\/github.com\/leoloso\/graphiql-block-wp-plugin\/blob\/5e49e6b9f0740478f11ec9cccf0b5d6c6281c43c\/src\/Plugin.php\">this code<\/a>:<\/p>\n<pre><code class\"prettyprint language-php\">\r\nnamespace Leoloso\\GraphiQLBlockWPPlugin;\r\n\r\nclass Plugin {\r\n\r\n  public function init(): void\r\n  {\r\n    $urlPath = \\plugins_url('vendor\/leoloso\/graphiql-wp-block', dirname(__FILE__));\r\n    (new \\Leoloso\\GraphiQLWPBlock\\Block($urlPath))-&gt;init();\r\n  }\r\n}\r\n<\/code><\/pre>\n<p>And finally, the WordPress <a href=\"https:\/\/github.com\/leoloso\/graphiql-block-wp-plugin\/blob\/7dac628591172d9c8382c118a880438a54641f5a\/graphiql-block.php\">plugin registration file<\/a> will load Composer&#8217;s files and then create a new <code>Plugin<\/code> instance:<\/p>\n<pre><code class\"prettyprint language-php\">\r\n\/**\r\n * Plugin Name:     GraphiQL block\r\n * Description:     It adds a block to add a GraphiQL client, to query the GraphQL server\r\n * Version:         0.1.0\r\n * Author:          Leonardo Losoviz\r\n * License:         MIT\r\n * Text Domain:     leoloso\r\n *\r\n * @package         leoloso\r\n *\/\r\n\r\n\/\/ Exit if accessed directly\r\nif (!defined('ABSPATH')) {\r\n\texit;\r\n}\r\ndefine('GRAPHIQL_BLOCK_PLUGIN_URL', plugin_dir_url(__FILE__));\r\ndefine('GRAPHIQL_BLOCK_VERSION', '0.1');\r\n\r\n\/\/ Load Composer\u2019s autoloader\r\nrequire_once (__DIR__.'\/vendor\/autoload.php');\r\n\r\n\/\/ Initialize this plugin\r\n(new \\Leoloso\\GraphiQLBlockWPPlugin\\Plugin())-&gt;init();\r\n<\/code><\/pre>\n<p>That&#8217;s it. Now, through Composer, we have been able to decouple the plugin from the block. If I ever need to include my GraphiQL block inside of a bundle, I only have to replicate the files inside the plugin project.<\/p>\n<h2>Observing changes in the source project and testing site<\/h2>\n<p>As mentioned earlier on, the block file that is included in the website is not <code>src\/index.js<\/code> but <code>build\/index.js<\/code>, which is automatically generated when running <code>npm start<\/code> and modifying the source file. When developing the block, we must have <code>build\/index.js<\/code> be updated in our testing environment, as to be able to test the changes. However, our folder containing the block&#8217;s source files will most likely be a different one, where we store our repository files. Hence, we have a problem here: how can we modify file <code>src\/index.js<\/code> in our repository folder, and have it compiled to <code>build\/index.js<\/code> under the testing site&#8217;s folder?<\/p>\n<p>The first solution that comes to mind is to depend on Composer: update the source files, commit\/push them to the repo, and execute <code>composer update<\/code> on the testing site to download the changes. The problem with this approach is that it makes development much slower, because Composer caches dependencies and refreshes them every 10 minutes or so, so we would have to wait up to 10 minutes to test a change (and, in addition, running <code>composer update<\/code> may also take a minute to execute).<\/p>\n<p>A better solution is to have the <code>npm start<\/code> process compile the source files from their original location, but output them in the testing site folder. Luckily, script <code>wp-scripts start<\/code> (which is the one executed when doing <code>npm start<\/code>) can accept parameter <code>--output-path<\/code>, indicating the folder on which to save the compiled files.<\/p>\n<p>For this, we will need to modify file <code>package.json<\/code> (which defines the JavaScript dependencies and allows to configure script shortcuts) in the block project, from this:<\/p>\n<pre><code class=\"prettyprint language-json\">{\r\n  \"scripts\": {\r\n    \"start\": \"wp-scripts start\"\r\n  }\r\n}\r\n<\/code><\/pre>\n<p>to this:<\/p>\n<pre><code class=\"prettyprint language-json\">{\r\n  \"scripts\": {\r\n    \"start\": \"wp-scripts start --output-path=${OUTPUT_PATH:=build\/}\"\r\n  }\r\n}\r\n<\/code><\/pre>\n<p>In the latter case, we tell <code>wp-scripts start<\/code> to place the compiled files under the folder defined in environment variable <code>OUTPUT_PATH<\/code> or, if not provided, use <code>\"build\/\"<\/code> (which is the default case).<\/p>\n<p>Now, we can tackle the two required possibilities (which can also be executed simultaneously, in 2 different terminal consoles):<\/p>\n<ol>\n<li>Run <code>npm start<\/code> to compile <code>src\/index.js<\/code> into <code>build\/index.js<\/code> in the source repo<\/li>\n<li>Run <code>OUTPUT_PATH=\/path\/to\/testing\/site\/build\/ npm start<\/code> to compile <code>src\/index.js<\/code> into the testing site&#8217;s <code>build\/<\/code> folder, as to be able to test the changes<\/li>\n<\/ol>\n<h2>Enabling hot reloading<\/h2>\n<p>So far so good: we can modify our source files stored in the repository folder, and be able to test them immediately. However, &#8220;immediately&#8221; is not so immediate, because we need to refresh the browser in the WordPress editor screen to see the changes applied to the block. It would be much nicer to have the browser react to the changes automatically, without us having to press the reload button.<\/p>\n<p>Luckily this is doable too! Even though not documented in the package&#8217;s site, the @wordpress\/block package supports hot reloading, i.e. the ability to reflect the changes immediately whenever modifying a block&#8217;s JavaScript code.<\/p>\n<p>To enable it, the WordPress editor must load script under <code>http:\/\/localhost:35729\/livereload.js<\/code>, <a href=\"https:\/\/github.com\/leoloso\/graphiql-wp-block\/blob\/ef836887a97ae5d811c8a586d9748e43e99d19f9\/src\/Block.php#L38\">like this<\/a>:<\/p>\n<pre><code class\"prettyprint language-php\">if (is_admin() &amp;&amp; defined('ENABLE_HOT_RELOADING_FOR_DEV') &amp;&amp; ENABLE_HOT_RELOADING_FOR_DEV) {\r\n  wp_register_script('livereload', 'http:\/\/localhost:35729\/livereload.js');\r\n  wp_enqueue_script('livereload');\r\n}\r\n<\/code><\/pre>\n<p>And then, just for the development environment, add a constant <code>ENABLE_HOT_RELOADING_FOR_DEV<\/code> to file <code>wp-config.php<\/code>:<\/p>\n<pre><code class\"prettyprint language-php\">define('ENABLE_HOT_RELOADING_FOR_DEV', true);\r\n<\/code><\/pre>\n<p>Important: we may run <code>npm start<\/code> several times to observe changes. Port <code>35729<\/code> will be tied to the first one of these instances. Hence, because we want to observe the changes on the testing site, we must first execute <code>OUTPUT_PATH=\/path\/to\/testing\/site\/build\/ npm start<\/code>, and the hot reloading will react on these changes.<\/p>\n<p>Now, whenever updating the block, the changes will be automatically visible in the browser:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-30466\" src=\"https:\/\/www.designbombs.com\/wp-content\/uploads\/2020\/03\/hot-reloading.gif\" alt=\"Hot reloading\" width=\"1060\" height=\"576\" \/><\/p>\n<h2>Conclusion<\/h2>\n<p>Creating a new Gutenberg block is now easier than ever using the new @wordpress\/block package. This tool is not perfect yet: for instance, it doesn&#8217;t allow to specify the block&#8217;s namespace (so we need to resort to a hacky search and replace), and we may want to modify the project&#8217;s output as to decouple the block and the plugin into 2 different entities. However, this tool is certainly good enough to quickly scaffold the new project, keep it updated, and speed up development with hot reloading.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I have finally started creating blocks for Gutenberg, the (not-so-new anymore) editor for WordPress. Since I have not coded with&#8230;<\/p>\n","protected":false},"author":50,"featured_media":30544,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_genesis_hide_title":false,"_genesis_hide_breadcrumbs":false,"_genesis_hide_singular_image":false,"_genesis_hide_footer_widgets":false,"_genesis_custom_body_class":"","_genesis_custom_post_class":"","_genesis_layout":"","_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[51],"tags":[3168,11],"class_list":{"0":"post-30464","1":"post","2":"type-post","3":"status-publish","4":"format-standard","5":"has-post-thumbnail","7":"category-coding","8":"tag-gutenberg","9":"tag-wordpress","10":"entry"},"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v18.1 (Yoast SEO v26.4) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Creating a Gutenberg block using the official new package<\/title>\n<meta name=\"description\" content=\"Create a new WordPress plugin with a Gutenberg block, quick and easy, using the new @wordpress\/block package\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.designbombs.com\/creating-a-gutenberg-block-using-the-official-new-package\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Creating a Gutenberg block using the official new package\" \/>\n<meta property=\"og:description\" content=\"I have finally started creating blocks for Gutenberg, the (not-so-new anymore) editor for WordPress. Since I have not coded with JavaScript in several\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.designbombs.com\/creating-a-gutenberg-block-using-the-official-new-package\/\" \/>\n<meta property=\"og:site_name\" content=\"Design Bombs\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/designbombs\/\" \/>\n<meta property=\"article:published_time\" content=\"2020-03-17T11:35:52+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2020-03-24T11:33:05+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.designbombs.com\/wp-content\/uploads\/2020\/03\/gutenberg-block.png\" \/>\n\t<meta property=\"og:image:width\" content=\"722\" \/>\n\t<meta property=\"og:image:height\" content=\"300\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Leonardo Losoviz\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@losoviz\" \/>\n<meta name=\"twitter:site\" content=\"@designbombs\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Leonardo Losoviz\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"13 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.designbombs.com\/creating-a-gutenberg-block-using-the-official-new-package\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.designbombs.com\/creating-a-gutenberg-block-using-the-official-new-package\/\"},\"author\":{\"name\":\"Leonardo Losoviz\",\"@id\":\"https:\/\/www.designbombs.com\/#\/schema\/person\/4259b761dbd3ee01f8c7e2cd9d74df39\"},\"headline\":\"Creating a Gutenberg block using the official new package\",\"datePublished\":\"2020-03-17T11:35:52+00:00\",\"dateModified\":\"2020-03-24T11:33:05+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.designbombs.com\/creating-a-gutenberg-block-using-the-official-new-package\/\"},\"wordCount\":1936,\"commentCount\":2,\"publisher\":{\"@id\":\"https:\/\/www.designbombs.com\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.designbombs.com\/creating-a-gutenberg-block-using-the-official-new-package\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.designbombs.com\/wp-content\/uploads\/2020\/03\/gutenberg-block.png\",\"keywords\":[\"gutenberg\",\"wordpress\"],\"articleSection\":[\"Coding\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.designbombs.com\/creating-a-gutenberg-block-using-the-official-new-package\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.designbombs.com\/creating-a-gutenberg-block-using-the-official-new-package\/\",\"url\":\"https:\/\/www.designbombs.com\/creating-a-gutenberg-block-using-the-official-new-package\/\",\"name\":\"Creating a Gutenberg block using the official new package\",\"isPartOf\":{\"@id\":\"https:\/\/www.designbombs.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.designbombs.com\/creating-a-gutenberg-block-using-the-official-new-package\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.designbombs.com\/creating-a-gutenberg-block-using-the-official-new-package\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.designbombs.com\/wp-content\/uploads\/2020\/03\/gutenberg-block.png\",\"datePublished\":\"2020-03-17T11:35:52+00:00\",\"dateModified\":\"2020-03-24T11:33:05+00:00\",\"description\":\"Create a new WordPress plugin with a Gutenberg block, quick and easy, using the new @wordpress\/block package\",\"breadcrumb\":{\"@id\":\"https:\/\/www.designbombs.com\/creating-a-gutenberg-block-using-the-official-new-package\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.designbombs.com\/creating-a-gutenberg-block-using-the-official-new-package\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.designbombs.com\/creating-a-gutenberg-block-using-the-official-new-package\/#primaryimage\",\"url\":\"https:\/\/www.designbombs.com\/wp-content\/uploads\/2020\/03\/gutenberg-block.png\",\"contentUrl\":\"https:\/\/www.designbombs.com\/wp-content\/uploads\/2020\/03\/gutenberg-block.png\",\"width\":722,\"height\":300},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.designbombs.com\/creating-a-gutenberg-block-using-the-official-new-package\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.designbombs.com\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Coding\",\"item\":\"https:\/\/www.designbombs.com\/category\/coding\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Creating a Gutenberg block using the official new package\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.designbombs.com\/#website\",\"url\":\"https:\/\/www.designbombs.com\/\",\"name\":\"Design Bombs\",\"description\":\"Droppin&#039; design bombs everyday!\",\"publisher\":{\"@id\":\"https:\/\/www.designbombs.com\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.designbombs.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.designbombs.com\/#organization\",\"name\":\"DesignBombs\",\"url\":\"https:\/\/www.designbombs.com\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.designbombs.com\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.designbombs.com\/wp-content\/uploads\/2019\/04\/db-logo.png\",\"contentUrl\":\"https:\/\/www.designbombs.com\/wp-content\/uploads\/2019\/04\/db-logo.png\",\"width\":219,\"height\":92,\"caption\":\"DesignBombs\"},\"image\":{\"@id\":\"https:\/\/www.designbombs.com\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/designbombs\/\",\"https:\/\/x.com\/designbombs\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.designbombs.com\/#\/schema\/person\/4259b761dbd3ee01f8c7e2cd9d74df39\",\"name\":\"Leonardo Losoviz\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.designbombs.com\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/bb059a4470fd73113804d5dd7430f6a66aaba66ba161798d0fac79b124c74611?s=96&d=https%3A%2F%2Fwww.designbombs.com%2Fwp-content%2Fthemes%2FDesignBombs%2Fimages%2Fgravatar.jpg&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/bb059a4470fd73113804d5dd7430f6a66aaba66ba161798d0fac79b124c74611?s=96&d=https%3A%2F%2Fwww.designbombs.com%2Fwp-content%2Fthemes%2FDesignBombs%2Fimages%2Fgravatar.jpg&r=g\",\"caption\":\"Leonardo Losoviz\"},\"description\":\"Leonardo Losoviz is an open source developer and technical writer, author of GraphQL by PoP, a CMS-agnostic GraphQL server in PHP. Find him on his blog leoloso.com and on Twitter @losoviz.\",\"sameAs\":[\"https:\/\/leoloso.com\",\"https:\/\/x.com\/losoviz\"],\"url\":\"https:\/\/www.designbombs.com\/author\/leo\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Creating a Gutenberg block using the official new package","description":"Create a new WordPress plugin with a Gutenberg block, quick and easy, using the new @wordpress\/block package","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.designbombs.com\/creating-a-gutenberg-block-using-the-official-new-package\/","og_locale":"en_US","og_type":"article","og_title":"Creating a Gutenberg block using the official new package","og_description":"I have finally started creating blocks for Gutenberg, the (not-so-new anymore) editor for WordPress. Since I have not coded with JavaScript in several","og_url":"https:\/\/www.designbombs.com\/creating-a-gutenberg-block-using-the-official-new-package\/","og_site_name":"Design Bombs","article_publisher":"https:\/\/www.facebook.com\/designbombs\/","article_published_time":"2020-03-17T11:35:52+00:00","article_modified_time":"2020-03-24T11:33:05+00:00","og_image":[{"width":722,"height":300,"url":"https:\/\/www.designbombs.com\/wp-content\/uploads\/2020\/03\/gutenberg-block.png","type":"image\/png"}],"author":"Leonardo Losoviz","twitter_card":"summary_large_image","twitter_creator":"@losoviz","twitter_site":"@designbombs","twitter_misc":{"Written by":"Leonardo Losoviz","Est. reading time":"13 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.designbombs.com\/creating-a-gutenberg-block-using-the-official-new-package\/#article","isPartOf":{"@id":"https:\/\/www.designbombs.com\/creating-a-gutenberg-block-using-the-official-new-package\/"},"author":{"name":"Leonardo Losoviz","@id":"https:\/\/www.designbombs.com\/#\/schema\/person\/4259b761dbd3ee01f8c7e2cd9d74df39"},"headline":"Creating a Gutenberg block using the official new package","datePublished":"2020-03-17T11:35:52+00:00","dateModified":"2020-03-24T11:33:05+00:00","mainEntityOfPage":{"@id":"https:\/\/www.designbombs.com\/creating-a-gutenberg-block-using-the-official-new-package\/"},"wordCount":1936,"commentCount":2,"publisher":{"@id":"https:\/\/www.designbombs.com\/#organization"},"image":{"@id":"https:\/\/www.designbombs.com\/creating-a-gutenberg-block-using-the-official-new-package\/#primaryimage"},"thumbnailUrl":"https:\/\/www.designbombs.com\/wp-content\/uploads\/2020\/03\/gutenberg-block.png","keywords":["gutenberg","wordpress"],"articleSection":["Coding"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.designbombs.com\/creating-a-gutenberg-block-using-the-official-new-package\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.designbombs.com\/creating-a-gutenberg-block-using-the-official-new-package\/","url":"https:\/\/www.designbombs.com\/creating-a-gutenberg-block-using-the-official-new-package\/","name":"Creating a Gutenberg block using the official new package","isPartOf":{"@id":"https:\/\/www.designbombs.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.designbombs.com\/creating-a-gutenberg-block-using-the-official-new-package\/#primaryimage"},"image":{"@id":"https:\/\/www.designbombs.com\/creating-a-gutenberg-block-using-the-official-new-package\/#primaryimage"},"thumbnailUrl":"https:\/\/www.designbombs.com\/wp-content\/uploads\/2020\/03\/gutenberg-block.png","datePublished":"2020-03-17T11:35:52+00:00","dateModified":"2020-03-24T11:33:05+00:00","description":"Create a new WordPress plugin with a Gutenberg block, quick and easy, using the new @wordpress\/block package","breadcrumb":{"@id":"https:\/\/www.designbombs.com\/creating-a-gutenberg-block-using-the-official-new-package\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.designbombs.com\/creating-a-gutenberg-block-using-the-official-new-package\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.designbombs.com\/creating-a-gutenberg-block-using-the-official-new-package\/#primaryimage","url":"https:\/\/www.designbombs.com\/wp-content\/uploads\/2020\/03\/gutenberg-block.png","contentUrl":"https:\/\/www.designbombs.com\/wp-content\/uploads\/2020\/03\/gutenberg-block.png","width":722,"height":300},{"@type":"BreadcrumbList","@id":"https:\/\/www.designbombs.com\/creating-a-gutenberg-block-using-the-official-new-package\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.designbombs.com\/"},{"@type":"ListItem","position":2,"name":"Coding","item":"https:\/\/www.designbombs.com\/category\/coding\/"},{"@type":"ListItem","position":3,"name":"Creating a Gutenberg block using the official new package"}]},{"@type":"WebSite","@id":"https:\/\/www.designbombs.com\/#website","url":"https:\/\/www.designbombs.com\/","name":"Design Bombs","description":"Droppin&#039; design bombs everyday!","publisher":{"@id":"https:\/\/www.designbombs.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.designbombs.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.designbombs.com\/#organization","name":"DesignBombs","url":"https:\/\/www.designbombs.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.designbombs.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.designbombs.com\/wp-content\/uploads\/2019\/04\/db-logo.png","contentUrl":"https:\/\/www.designbombs.com\/wp-content\/uploads\/2019\/04\/db-logo.png","width":219,"height":92,"caption":"DesignBombs"},"image":{"@id":"https:\/\/www.designbombs.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/designbombs\/","https:\/\/x.com\/designbombs"]},{"@type":"Person","@id":"https:\/\/www.designbombs.com\/#\/schema\/person\/4259b761dbd3ee01f8c7e2cd9d74df39","name":"Leonardo Losoviz","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.designbombs.com\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/bb059a4470fd73113804d5dd7430f6a66aaba66ba161798d0fac79b124c74611?s=96&d=https%3A%2F%2Fwww.designbombs.com%2Fwp-content%2Fthemes%2FDesignBombs%2Fimages%2Fgravatar.jpg&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/bb059a4470fd73113804d5dd7430f6a66aaba66ba161798d0fac79b124c74611?s=96&d=https%3A%2F%2Fwww.designbombs.com%2Fwp-content%2Fthemes%2FDesignBombs%2Fimages%2Fgravatar.jpg&r=g","caption":"Leonardo Losoviz"},"description":"Leonardo Losoviz is an open source developer and technical writer, author of GraphQL by PoP, a CMS-agnostic GraphQL server in PHP. Find him on his blog leoloso.com and on Twitter @losoviz.","sameAs":["https:\/\/leoloso.com","https:\/\/x.com\/losoviz"],"url":"https:\/\/www.designbombs.com\/author\/leo\/"}]}},"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/www.designbombs.com\/wp-content\/uploads\/2020\/03\/gutenberg-block.png","jetpack-related-posts":[],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.designbombs.com\/wp-json\/wp\/v2\/posts\/30464","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.designbombs.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.designbombs.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.designbombs.com\/wp-json\/wp\/v2\/users\/50"}],"replies":[{"embeddable":true,"href":"https:\/\/www.designbombs.com\/wp-json\/wp\/v2\/comments?post=30464"}],"version-history":[{"count":3,"href":"https:\/\/www.designbombs.com\/wp-json\/wp\/v2\/posts\/30464\/revisions"}],"predecessor-version":[{"id":30556,"href":"https:\/\/www.designbombs.com\/wp-json\/wp\/v2\/posts\/30464\/revisions\/30556"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.designbombs.com\/wp-json\/wp\/v2\/media\/30544"}],"wp:attachment":[{"href":"https:\/\/www.designbombs.com\/wp-json\/wp\/v2\/media?parent=30464"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.designbombs.com\/wp-json\/wp\/v2\/categories?post=30464"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.designbombs.com\/wp-json\/wp\/v2\/tags?post=30464"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}