Command line template creation page tutorial

One, foreword

In everyday business development, we often develop similar pages in different projects, or even in the same project.

The basic operation of that guy is to go through the old project and copy the code to change (waste time).

Today we are going to look at a project that allows you to create specific page code in your project with a single command.

Second, preparation

We need to push the project to NPM to realize this function, so those who do not have an NPM account should create an NPM account in advance. And create a Git repository for the project.

Create a Git repository

Execute NPM init in the repository to give the project an initialized package.json.

And add the address of the repository to the package.json file

{..."repository": {
    "url": "https://github.com/xxx/xxx.git"}}Copy the code

Create a command line

Start by installing a dependency for your project

yarn

or

npm
Copy the code

Add another.gitignore file

node_modules
* lock.json;
Copy the code

Define the command header

Start by customizing a command line. Such as:

I want to see the version number of the project through -v.

Cblock add Page pageName to create a file.

That requires defining the name of the cblock.

Add some code to package.json:

{
  "bin": {
    "cblock": "lib/index.js"}}Copy the code

If the command line header is cblock, it will go to the lib/index.js file by default.

2. Create a file entry

From the file path above, we can see that we need to create the lib/index.js file in the root directory.

#! /usr/bin/env node

require(".. /bin/index");
Copy the code

Many of you must be curious #! /usr/bin/env node

Used to indicate that the script file will be executed using Node.

/usr/bin/env is used to tell the user to look for node in the path directory.

#! The /usr/bin/env node allows the system to dynamically look up nodes to solve the problem of different user Settings on different machines.

The command must be placed in the first line. Otherwise, it will not take effect.

Through the require (“.. /bin/index”); We also need to create a bin/index.js file in the following directory.

3, implementation,-vViewing the Version Number

Here we need to install a Commander library. Yarn add commander.

After the installation we will implement bin/index.js code

#! /usr/bin/env node

const { program } = require("commander");

/** * command line parsing */
const commanderAction = (command, type, name) = > {
  console.log(command, type, name);
};

program
  .version("0.0.1"."-v --version -V")
  .arguments("<command> <type> <name>")
  .action(commanderAction)
  .parse(process.argv);

// Code parsing is below
Copy the code

Okay, so once we’ve written the simplest code we’re going to send out an NPM package

Note here, NPM can not use Taobao source, to switch to NPM source.

NPM publish --access=public // Publish private packages NPM publish --access=publicCopy the code

After executing the command, open the NPM official website and enter our package name to see if the version is released successfully. The following figure confirms that we have successfully released the NPM package.

4, test,-vThe command

Open the terminal and type:

# global install
yarn global add @dlijs/createpage

cblock -v

cblock add page Foo
Copy the code

We can obtain the following result:

5. Code parsing

First we go to the CommanderJS website

  • programcommanderGlobal object of.
  • versionFor the set version, the default option is-V--versionAfter the version is set, the current version number is displayed.
  • argumentsUsed to specify command line arguments.
  • actionThe method of executing a command. After entering the command line, press Enter to execute the commandactionAnd can bring out the command-line arguments you typed.
  • .parse(process.argv)Processing parameters (not correctly understood)

4. Establish a local test environment

Then we need to implement the business logic, we will need to constantly test, constantly modify, then we can not send a NPM version every test, that is too expensive. So we need to set up a local test environment.

At the root of our createpage, type the command line YARN link.

The functionality is to do local project testing.

First let’s create a test project for Alita or UMI.

After installing the dependencies, type in the following order in the root directory of demo:

# Change the project name to your own project
yarn add @dlijs/createpage

yarn link @dlijs/createpage
Copy the code

After typing, you should see the following screenshot:

At this time. We go to the bin/index.js folder to change the version number.

program.version("Hundreds"."-v --version -V");
Copy the code

After saving, we’ll type under demo:

npx cblock -v
Copy the code

The test demo has succeeded in the local project on link. Now we can verify this as soon as we modify the CBlock project.

5. Verify the correctness of command lines

Now we are ready to write the core business of the project.

Before writing the project, we can install a colors-CLI library to print color-coded words on the console.

Then create the/SRC/Components folder under the root of your project, and create two simple components in that folder.

Before we develop, let’s think about the logic of this piece of content.

The first step is to determine whether the command line conforms to the specification. If it does not, there is no need to continue. End with an error message.

Next to determine whether the user input pageName has a corresponding component name. If yes, copy the file again. If not, we will be prompted that the component does not exist under our project. Please modify pageName and re-enter the command.

First we change the commanderAction method.

Custom methods in the code are added below

/** * command line parsing */
const commanderAction = (command, type, name) = > {
  // Determine whether the command line conforms to the specification
  if (verifyCommand(command, type) === "page") {
    // Check whether the pageName entered by the user is in the project folder
    if (checkNameExist(getComponents(), name)) {
      console.log("File migration is ready.");
    } else {
      // If there is no such thing, just go to the endexitNoExistName(); }}else {
    // The command line does not conform to the specificationexitCommander(); }};Copy the code

Write two methods in the /bin/index.js file:

const color = require("colors-cli");

/ / end commander
const exitCommander = () = > {
  console.error(color.red("The command number entered is incorrect. For the time being, only:"));
  console.log(color.red("cblock add page <name>"));
  console.log(color.red("Please re-enter ~"));
  process.exit();
};

// Failed to find blocks and ended the project
const exitNoExistName = () = > {
  console.log(color.red("Could not find the block, please confirm the block name!"));
  console.log(color.red("Please re-enter ~"));
  process.exit();
};
Copy the code

The verifyCommand method is in the directory /bin/utils/index.js.

To start writing this method, let’s install a few libraries: FS, FS-extra, and PATH.

const fs = require("fs");
const { readdirSync } = require("fs-extra");
const { join } = require("path");

module.exports = {
  // Check whether the command is' add 'or' page '.
  verifyCommand: (command, type) = > {
    if (command === "add") {
      if (["page"."pages"."p"].indexOf(type) ! = = -1) {
        return "page"; }}return "";
  },
  // Read the names of all files and folders in the/SRC /components folder
  getComponents: (path = ".. /.. /src/components") = > {
    return readdirSync(join(__dirname, path)).filter((pkg) = > {
      return pkg.charAt(0)! = =".";
    });
  },
  // Check whether the pageName entered by the user is in our project
  checkNameExist: (list = [], name) = > {
    if(list.indexOf(name) ! = = -1) {
      return true;
    }
    return false; }};Copy the code

After writing these methods, remember to import these methods in the /bin/index.js file:

const { verifyCommand, checkNameExist, getComponents } = require("./utils");
Copy the code

Okay so now let’s test that out.

File recursive migration

We are going to copy the page to the/SRC /pages/blockTemplate folder of the test project.

Before implementing the feature, let’s consider the logic of this:

  • We need to make a judgment call before migrating the code/src/pages/blockTemplateWhether the component already exists in the directory. If one already exists, the operation is terminated with a prompt.
  • Try copying the first layer of files under this folder first.
  • Implement the above steps and then think about how to recursively copy files.

/bin/index.js

const createBlockFile = require("./createBlockFile");

/** * command line parsing */
const commanderAction = (command, type, name) = > {
  if (verifyCommand(command, type) === "page") {
    if (checkNameExist(getComponents(), name)) {
      createBlockFile(type, name);
    } else{}...// Omit some code here
};
Copy the code

Create a new createBlockfile.js file in the /bin directory to handle the recursive copy of the file.

To determine whether the component exists, implement createBlockfile.js or continue to implement it in utils/index.js:

module.exports = {
  checkBlockExist: (name) = > {
    let dirName = process.cwd(); // Returns the current working directory of the Node.js process
    const filePath = join(dirName, "src/pages"."blockTemplate");
    if (fs.existsSync(filePath)) {
      if (fs.existsSync(join(filePath, name))) {
        return false;
      }
      return true;
    } else {
      return true; }}};Copy the code

/bin/createBlockFile.js

const color = require("colors-cli");
const { copy } = require("fs-extra");
const { join } = require("path");
const { checkBlockExist, getComponents } = require("./utils");

module.exports = function createBlockFile(type, name) {
  const flag = checkBlockExist(name);

  const copyFolder = (path) = > {
    let dName = process.cwd();
    const currentPath = `.. /.. /src/components/${path}`; // Get the path to the component
    const fileList = getComponents(currentPath); // Get the file name under the file
    fileList.forEach((item) = > {
      // Check whether it is a file or folder
      // There are better ways to do this
      if (item.indexOf(".")! = = -1) {
        const targetPath = join(__dirname, `.. /src/components/${path}`, item); // The file path under the component library
        const createPath = join(
          dName,
          "src/pages"."blockTemplate",
          path,
          item
        ); // Path to the demo file
        console.log(color.green("write:"), createPath);
        copy(targetPath, createPath);
      } else {
        // Migrate code recursively
        copyFolder(`${path}/${item}`); }}); };if (flag) {
    copyFolder(name);
    console.log("\n", color.green(Block created successfully!!), "\n");
  } else {
    console.log(
      color.blue("/src/blockTemplate "),
      color.red('path is already contained${name}Folder, please redefine the page name! `)); }};Copy the code

It is easiest to write the whole set of code directly, some of the code has been added to the annotations, small partners can understand the line by line.

I won’t say much, but I’ll go directly to the screenshot to see the effect.

The code address

Writing is not easy, click a star and then go ~