Dealing with multiple React dom entry points in WordPress Theme Development

After getting so excited with the new WordPress script package which includes the ability of not having to manually setup Webpack and Babel for rapid Gutenberg Block creation, I ran into an issue when I started building a WordPress theme. I have multiple files which I wanted to include different individual React Components in different areas. For example, I wanted a React component in my main blog file page which would consume the WordPress REST API and load all of my posts on the page. But then I wanted another React component to consume the REST API to display a single post on a single post template. If I tried to use the default index.js file, I could not load multiple React Components all in the index.js. I need multiple entry points so I can attach my multiple Blog Posts component to a template with a dom element of app and then a different Single Post React Component to a different template file with a dom element of singlePostApp.

What is the number one rule in development? “DON’T HACK CORE”. Since Webpack comes bundled in WordPress core, I could technically edit (hack) the webpack.config.js file in core but it would get overwritten on the first WordPress update. So again Kudos to the WordPress team for thinking ahead. We can extend the webpack.config file.  They thought ahead and realized that some people would need to customize, edit, or change the webpack.config file and that is what we are going to do in this post.

Here is the documentation from WordPress on extending Webpack:

https://developer.wordpress.org/block-editor/packages/packages-scripts/#provide-your-own-webpack-config

So here is my src folder structure which resides in my themes root file.

Theme src folder structure

 

I have my two main entry point js files.

I then created a new webpack.config.js file in the themes root directory. Here is where I extended the WordPress core Webpack file. I tell my new extended Webpack file to use my two different entry point js files.

const defaultConfig = require("./node_modules/@wordpress/scripts/config/webpack.config");

const path = require( 'path' );

module.exports = {

  ...defaultConfig,

  entry: {

    ...defaultConfig.entry,

    index: path.resolve( process.cwd(), 'src', 'index.js' ),

    SinglePostApp: path.resolve( process.cwd(), 'src', 'SinglePostApp.js' )

  }

};

After running the build command and there are no errors in the terminal, there will be multiple build files.

Theme build folder structure

Here are my main two entry js files. Notice one is attached to a file with a dom element of app. It imports one of my React Components called PostList. My second one is attached to a dom element of singlePostApp which imports a different React Component called SinglePostApp.

index.js

React Entry File

SinglePostApp.js

React Entry File

Now after extending the Webpack config file, I can add different React Components all throughout my theme. I just need to update my custom webpack.config,js file in my theme’s root folder with the new entry point files. Again, time to start creating some cool React Components for my WordPress theme!

 

JavaScript, React JS, WordPress,

WordPress React Ready with Webpack and Babel bundled in core

Thank you WordPress Team! Webpack and Babel now come packaged in WordPress, time to start building some custom Gutenberg Blocks without spending time, a lot of time setting up your local build setup. Being a PHP developer first, dealing with all of the new JavaScript and the React framework, I spent many hours trying to just set up my local WordPress instance just to start building.

Now with the newest version of WordPress 5.2.1, Webpack and Babel come baked into WordPress core ready to compile your ESNext JavaScript code.

Let us take a look and build a very basic block using these new features.

In my plugins folder, I am going to create a new directory using the terminal in my VSCode editor.

mkdir my-esnext-block

then lets cd into the new directory

cd my-esnext-block

now let’s create a package.json file in this directory run this command in your terminal:

npm init

 

npm-init code

The next step is to install the packages required. You can install packages using the npm command npm install. If you pass the –save-dev parameter, npm will write the package as a dev dependency in the package.json file. The –save-exact parameter instructs npm to save an exact version of a dependency, not a range of valid versions. See npm install documentation for more details.
So using the terminal, and you are still in your new plugin directory run:

npm install --save-dev --save-exact @wordpress/scripts

After installing, a node_modules directory is created with the modules and their dependencies which will include everything you need to start coding using React JS and ESNext JS.

Also, if you look at the package.json file it will include a new section:

"devDependencies": {
  "@wordpress/scripts": "3.1.0"
}

The @wordpress/scripts package handles the dependencies and default configuration for Webpack and Babel. The scripts package expects the source file to compile to be found at src/index.js, and will save the compiled output to build/index.js.

With that in mind, let’s set up a basic block. Create a new folder called src and a new file called index.js with the following content:

Since this tutorial mainly covers the wordpress scripts block package, we will just use the block code from the wordpress github repo for examples of gutenberg blocks located here:  https://github.com/WordPress/gutenberg-examples

const { __, setLocaleData } = wp.i18n;
const { registerBlockType } = wp.blocks;

const blockStyle = {
  backgroundColor: "#900",
  color: "#fff",
  padding: "20px"
};

registerBlockType("gutenberg-examples/example-01-basic-esnext", {
  title: __("Example: HDD Basic (esnext)", "gutenberg-examples"),
  icon: "universal-access-alt",
  category: "layout",
  edit() {
    return <div style={blockStyle}>Hello World, step 1 (from the editor).</div>;
  },
  save() {
    return (
      <div style={blockStyle}>Hello World, step 1 (from the frontend).</div>
    );
  }
});

now lets register our block
we will create our plugins main php file index.php and place the following code in this new file:

<?php
/**
 * Plugin Name: Gutenberg HDD Examples Basic EsNext
 * Plugin URI: https://github.com/WordPress/gutenberg-examples
 * Description: This is a plugin demonstrating how to register new blocks for the Gutenberg editor.
 * Version: 1.0.2
 * Author: the Gutenberg Team
 *
 * @package gutenberg-examples
 */
defined( 'ABSPATH' ) || exit;
/**
 * Load all translations for our plugin from the MO file.
*/
add_action( 'init', 'gutenberg_examples_01_esnext_load_textdomain' );
function gutenberg_examples_01_esnext_load_textdomain() {
	load_plugin_textdomain( 'gutenberg-examples', false, basename( __DIR__ ) . '/languages' );
}
/**
 * Registers all block assets so that they can be enqueued through Gutenberg in
 * the corresponding context.
 *
 * Passes translations to JavaScript.
 */
function gutenberg_examples_01_esnext_register_block() {
	if ( ! function_exists( 'register_block_type' ) ) {
		// Gutenberg is not active.
		return;
	}
	wp_register_script(
		'gutenberg-examples-01-esnext',
		plugins_url( 'build/index.js', __FILE__ ),
		array( 'wp-blocks', 'wp-i18n', 'wp-element' ),
		filemtime( plugin_dir_path( __FILE__ ) . 'build/index.js' )
	);
	register_block_type( 'gutenberg-examples/example-01-basic-esnext', array(
		'editor_script' => 'gutenberg-examples-01-esnext',
	) );
  if ( function_exists( 'wp_set_script_translations' ) ) {
    /**
     * May be extended to wp_set_script_translations( 'my-handle', 'my-domain',
     * plugin_dir_path( MY_PLUGIN ) . 'languages' ) ). For details see
     * https://make.wordpress.org/core/2018/11/09/new-javascript-i18n-support-in-wordpress/
     */
    wp_set_script_translations( 'gutenberg-examples-01-esnext', 'gutenberg-examples' );
  }
}
add_action( 'init', 'gutenberg_examples_01_esnext_register_block' );

 

Now we need to use the wordpress scrips package and convert our React code in our index.js file for the build process. In the package json file we need to tell it what to use to build. Add the following to your package.json file in your new plugins folder.

"scripts": {
  "start": "wp-scripts start",
  "build": "wp-scripts build"
},

for development, you can use ‘npm run start’
for production, you can use ‘npm run build’

Final package.json file:

{
  "name": "my-esnext-block",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "wp-scripts start",
    "build": "wp-scripts build"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@wordpress/scripts": "3.2.1"
  }
}

Now using the terminal run this command:

npm run build

After using  npm run build command and there are no errors in our terminal we should have a build folder with our index.js file located in there.

so here is what our plugin file folder structure looks like:

Plugin folder structure

We should be able to see our new block in the editor

 

 

And here it is on the front end:

front end block view

Again, Kudos to the WordPress team for getting this build package into core and saving everyone so much time. This new feature  allows us to start building new Gutenberg blocks much quicker without the headache of setting up Webpack. Theme developers can start using it also. Just create a package.json file in the theme root directory, create a src/index.js folder file in the theme root, and start writing your React code.  Be sure you are in theme root when you do all of your terminal commands.

JavaScript, React JS, WordPress,

Add Typewriter Text to your webpage

How to add Typewriter Text to a webpage with some easy javascript.
First let create a div where the text will be displayed:
<p id="typewriter"></p>
Here is the simple JavaScript:
<script>
var i = 0;
var txt = 'I am Typewriter Text. See me type.';
var speed = 50;

function typeWriter() {
if (i < txt.length) {
document.getElementById("typewriter").innerHTML += txt.charAt(i);
i++;
setTimeout(typeWriter, speed);
}
}
</script>
JavaScript,