In daily development, we often use some scaffolding, such as create-react-app and VUe-CLI, to facilitate the rapid construction of our projects and the convention of basic specifications.

This article will set up a simple scaffolding name:simple-create-react (a simplified version of create-react-app, with some common libraries optional), to introduce the scaffolding construction process, the core of the whole process is the command line query process + template file generation.

Initialization package

npm init -y

Add two items to package.json

"bin":{
	testCli:"./main.js"
}
"private":false
Copy the code

TestCli in the bin directory means that if we type testCli on the command line, the contents of main.js will be called.

Private :false indicates that the content is public, that is, can be published by NPM

Add it to main.js

#! /usr/bin/env node
Copy the code

Where #! /usr/bin/env this line of code is used when the system is running on this line to look up the node configuration and call the corresponding interpreter to run the subsequent node program

Then we need to test the code, which may use either NPM link or NPM install -g. So when you run testCli from the command line, you can see the code you wrote in main.js, and say hello world

console.log("Hello World")
Copy the code

NPM link: Link the current package globally — NPM unlink

NPM install -g: installs the current package globally — NPM uninstall -g

Two, add functions

Interactive command – usecommander

const { program } = require('commander')

program
    .version('0.1.0 from')  / / version - version
    .command('init <name> [branch]') // Initialize the command
    .description('Initialize the project file')
    .action( (name,branch) = > { / / get the name
        console.log('Hello World') // Output
    })

program.parse(process.argv) // Parse variables
Copy the code

The arguments may be

or [optional], Angle brackets must be optional

File pull – usedownload-git-repo

download("direct:https://github.com/oniya24/simple-create-react_template.git", targetPath,{ clone:true }, // Target path (err)=>{// Callback function console.log(err)}Copy the code

‘git clone’ failed with status 128

Change git to direct: http://url

Command line interaction – useinquirer

program
    .version('0.1.0 from')
    .command('init <name>')
    .description('Initialize template')
    .action( (name) = > {
        inquirer.prompt([
            {
                name:"description".message:"Please enter a description"}, {name:"author".message:"Please enter author"
            }
        ]).then((paramater) = >{
            console.log(paramater);
        })})
Copy the code

Prompt submits an array of queries, where name is the key value and message is the input prompt,

{description: XXX, author: yyy}

Replace template content — usehandlebars

// Enter the source template
const source = "<p>description is {{description}} , author is {{ author }}</p> ";
// Parse the template
const template = Handlebars.compile(source);
// Definition of content
const paramater = { description: 'xxx'.author: 'yyy' };
// Replace the content
console.log(template(paramater));
// description is xxx,author is yyy
Copy the code

We can replace the content of the configuration file with this template, so we need to modify the package.json of the template, and then replace the content with the variables queried by Inquirier after downloading the template successfully

// package.json

author: "{{ author }}".description: "{{ description }}"
Copy the code

After the code is pulled, the FS module first checks whether there is a package.json file. If there is, the file content is read, and the file content is replaced by handlebars before being written into the file.

const content = fs.readFileSync(packagePath).toString();
const template = Handlebars.compile(content);
const result = template(paramater);
fs.writeFileSync(packagePath,result);
Copy the code

Beautify the command line – usechalk ora

Highlight the information printed from the terminal: Chalk.

Terminal loading effect: ORA, loading effect during code pull

const spinner = ora("Template download ^.^ Please wait");
spinner.start();
spinner.success();
chalk.green('It worked');
chalk.red('Failed')
Copy the code

The overall code

Static pull code: github.com/oniya24/sim… For staticFillPull

3. You can select configuration items

We found that the basic functionality was implemented, but two problems remained:

  1. Static code is pulled. For some configurations we do not need, such as react-router and loadsh cannot be selected
  2. After pulling the code, you need to do it yourselfnpm install, cannot be used directly

How to add on demand — Inquirer’s Type + Handlebars judgment

After checking the data, we found that our Inquirer has a powerful function and can also support confirm judgment or list selection by changing type. Therefore, we can use Inquirer to realize the selected part, and then change package.json according to the results obtained by our query.

Confirm – {type: 'confirm'}

Take type, name, message, [default] properties. default is expected to be a boolean if used.

In package.json we need to use the template notation, and here we look again at handlebars documentation and see that it supports judgment statements (nice!).

Official document: handlebarsjs.com/guide/

{{#if isReactRedux}}
 "react-redux": "^ 7.2.0",
 {{/if}}
 {{#if isReactRouterDom}}
 "react-router-dom": "^ 5.1.2." ",
 {{/if}}
 {{#if redux}}
 "redux": "^ 4.0.5",
 {{/if}}
Copy the code

This completes the optional configuration and allows you to add or delete configurations as you wish.

How to implement the node command — child_process

Process.cwd () returns the current execution directory

Start a child process with spawn() of child_process to execute a command with arguments (command, [args], [option]).

Add three parameters: CWD command execution directory, stdio:”inherit” inherit the input and output streams of the parent process, shell: execute in shell

Unlike the exec() method, which starts a child process to execute commands, exec() has a callback function that values the state of the child process

const spawn = require('child_process').spawn;
const chalk = require("chalk");

let runInstall = async function(cwd,callback,executable = 'npm',args = ['install']){
    console.log(chalk.greenBright("Installing project dependencies... \n"));
    // Execute executable args to the NPM install dependency
    await new Promise((resolve, reject) = > {
        const installProcess = 
        spawn(executable, args, { cwd: cwd,stdio: "inherit".shell: true });
        // File directory, inherit the parent process input and output [that is, the console can see the child process output], open shell
        installProcess.on('exit'.() = > {
            console.log(chalk.greenBright("Dependency installation complete!"));
            resolve();
        });
        installProcess.on('error'.(err) = >{
            console.log(chalk.red("Dependent installation failed"));
            reject(err);
        })
    }).then(() = >{ callback(); })
    .catch((err) = > { console.log(chalk.red("Error occurred"));console.log(err) });

}
Copy the code

Fourth, package release

— main.js

— utils

—— outputFunc

—— npmInstall

—— inquirerArr

Added the same name file judgment, and then the overall structure optimization, you can be ready to release!

Configuration changes

Make changes to the package.json configuration before publishing

Name: indicates the package name, which must be unique. Version: indicates the version number. The version number needs to be changed each time the package is released to the NPM. Main: the entry file, import/require keyword, separated by Spaces from the final word that you want the user to search for. Author: author private: Indicates whether the parameter is private. You need to change it tofalseBefore publishing to NPMCopy the code

release

NPM login login

NPM publish packageName Publish

Possible problems

1.Private mode enable, only admin can publishthis module [no_perms] Private mode enable, only admin can publish this module: clitest error:403This is because we set taobao mirror, HTTPS:/ / registry.npm.taobao.org/, sets the registry to the original imageNPM config set registry= HTTP://registry.npmjs.org

2.Error If you believethis might be a permissions issue, please double-check the
npm ERR! permissions of the file and its containing directories, or try running
npm ERR! the command again as root/Administrator (though thisClean the cache: delete the.npmrc file under C: Users\Administrator\ and log in again (another possible reason is to forget to log in and cover your face QAQ).3.For packaging use, replace __dirname with process.cwd()Copy the code

After a successful release, you can use it happily!

NPM install -g simple-create-react global installation

Simple-create-react init projectName Pulls the template for initialization

As shown in figure:

Five, the summary

  1. Command line interaction is implemented using Commander
  2. Pull repository code through download-git-repo
  3. You can use the Inquirer to select and fill in related items to implement optional configurations
  4. Replace the package.json template with Handlebars
  5. Beautify the command line output with chalk and ORA
  6. Start the child process with the child_process module to implement the dependent NPM install

Source: github.com/oniya24/sim…

Reference:

  • Juejin. Cn/post / 684490…
  • www.npmjs.com/package/inq…
  • www.npmjs.com/package/com…
  • Github.com/tccsg/dg-cl…
  • Juejin. Cn/post / 684490…