bird's eye view of mountains

Create a NPX Script

  • ElPuas

  • 10/31/2022

So I have been doing websites for quite a long time, and I had used many tools for spinning up my websites, starting with Yeoman, Yoga, CRA, and more recently with npx. npx is a tool intended to help round out the experience of using packages from the npm registry — the same way npm makes it super easy to install and manage dependencies hosted on the registry, npx makes it easy to use CLI tools and other executables hosted on the registry.

Now that I’m learning FSE, I want to easily scaffold a blank block-based theme that I can use to build new WP websites, I know I always can go to my GitHub repo and clone it, so you might have used create-react-app starter command to spin up new React projects, so I gave me the task to create my own starter commands.

This command will install the necessary dependencies for my new project. It’s a great way to start a new project from a template.

NPM

We need to create an npm package, the key command to do this is npm init, click here to learn more about this command.

If you check their documentation it says that it needs your package name to start with create- and you should have a script listed in the bin to execute the necessary setup process.

Open your terminal and type npm initand follow the prompt instructions, in my case I will name my package create-block-theme.

My package.json looks now like this:

{
  "name": "create-block-theme",
  "version": "1.0.0",
  "description": "Scaffold a block based theme",
  "main": "index.js",
  "author": "Alfredo Navas",
  "license": "ISC"
}

BIN

On my package.json I’m going to add a bin key and give a path to a script I will create later, called create-block-theme.js .

{
  "name": "create-block-theme",
  "version": "1.0.0",
  "description": "Scaffold a block based theme",
  "main": "index.js",
  "bin": {
    "create-block-theme": "bin/create-block-theme.js"
  },
  "author": "Alfredo Navas",
  "license": "ISC"
}

Our Script

Now, let's create our executable file under bin folder, I name my script create-block-theme.js All executable files must have a shebang #! /usr/bin/env node header.

#! /usr/bin/env node
console.log("The Blue Unicorn")

That's all for a basic setup. Run: npm i -g to install this package locally. Open the terminal and run:

npx create-block-theme

It will output: The Blue Unicorn.

process.argv

All command-line arguments are accessible via argv (argument values) property of the process. The first argument is the path to the executor, the second is the path to our executable .js file. So when parsing input you should start from the third argument.

I want to provide the repository's name from the command line, which is captured by process.argv, and another constant with the git command that will clone my GitHub repository followed by the constant I already created.

Since I already have a repo that contains a basic block-based theme, it should look like this:

const themeName = process.arg[2];
const gitCloneCommand = `git clone https://github.com/elpuas/create-block-based-theme.git ${themeName}`;

I also need another constant which contains the command to enter the newly created repository and install the dependencies, that we do:

const npmInstallDepsCommand = `cd ${themeName} && npm install`;

Let's also print a helpful message for our users on the console so the progress is visible to the callers of the command.

My complete code look like this:

a#! /usr/bin/env node
const themeName = process.argv[2];
const gitCheckoutCommand = `git clone https://github.com/elpuas/create-block-based-theme.git ${repoName}`;
const npmInstallCommand = `cd ${themeName} && npm install`;

console.log(`Creating a new WordPress theme called ${themeName}...`);

Running the Commands

Now we need a way to run these commands, lets's create a new function for that, called fireCommand, this function will take command and do something.

In order to run these commands from node I will import a function called exact sync from child-process .

As the exact sync name implies it will run the command and wait for it to complete, this command may throw errors, so is better to run this command in a try/catch block.

const { execSync } = require('child_process');

const fireCommand = (command) => {
    try {
        execSync(command, { stdio: 'inherit' });
    } catch (error) {
        console.error(`Failed to execute ${command}`, error);
        return false;
    }
    return true;
};

I will call the fireCommand and pass the gitCheckoutCommand as an argument, lets's store the result of this operation in a variable, and if the command doesn’t succeed quit the process, otherwise print the next step on the console.

const checkedOut = runCommand(gitCheckoutCommand);

if (!checkedOut) {
    console.error('Failed to checkout the repo');
    process.exit(-1);
}

console.log(`Installing dependencies for ${themeName}...`);

The next step is cd into the directory and installs our dependencies, lets's run fireCommand one more time.

const installed = runCommand(npmInstallCommand);

if (!installed) {
    console.error('Failed to install dependencies');
    process.exit(-1);
}

Finally, let's add a greetings message, letting the user that the process was successful, and which are the next steps.

console.log(`Success! Created ${themeName} at ${process.cwd()}/${themeName}`);
console.log('Inside that directory, you can run several commands:');
console.log('  npm run start && npm run build');

Publish to NPM

Now that we have our code you can install it locally, by running npm i once install you can run npx create-block-theme and your theme will be installed locally, but make it available to the world.

Let’s publish to npm I have updated the name of my repo to avoid collisions with other packages, my final package.json is the following:

{
  "name": "@elpuas/create-block-theme",
  "email": "elpuas@gmail.com",
  "version": "1.0.0",
  "description": "Scaffold a block based theme",
  "main": "index.js",
  "keywords": ["theme","block","scaffold", "create-block-theme"],
  "bin": {
    "create-block-theme": "bin/create-block-theme.js"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/elpuas/create-block-theme.git"
  },
  "author": "Alfredo Navas",
  "license": "ISC"
}

If you don’t have an account yet go to https://www.npmjs.com/ and create one.

now you need to run the following commands:

npm login
npm publish

Awesome, now I can run npx @elpuas/create-block-theme my-new-theme and wait for the magic to happen. Now you know how to create your own starter commands, if you like this article please share it!

© 2024 Built with Gatsby by El.Puas