preface

After learning how to generate Node.js files, execute scripts, use CI continuous integration, and automate build tools, you might want to try writing your own

  • Command line arguments are obtained using commander. Js
  • Command line interaction uses Inquirer. Js
  • Directory tree generation uses Treer

Code: Github address

Directory structure:

D:\node-test ... ├ ─ index. Js ├ ─ sh | └ sh1. Js ├ ─ scripts | └ generateComponent. Js ├ ─ components |... | ├ ─ the run - sh. Js...Copy the code
D:\node-test ├─ Components ├─ Component-dir-Tree. json ├─ file.2.js ├─ file.js ├─ index.js ├─ log.js ├─ Node-test-dir-tree. json ├─ Run-sh.js ├─test└ ─ aa ├ ─ bb. Js └ ─ cc └ ─ timeFormat. Js ├ ─ index. The js ├ ─ json ├ ─ a. son └ ─ b.j son ├ ─ package - lock. Json ├ ─ package. The json ├ ─ The README. Md ├ ─ scripts └ ─ generateComponent. Js └ ─ sh └ ─ sh1. JsCopy the code

I. Generated file:

NPM command:

package.json:
{
  ...
  "scripts": {
    "create:comp": "node scripts/generateComponent --path",
  },
  ...
}
Copy the code

The value of the –path parameter can be obtained as follows:

— Path can be set by itself. When it is obtained, [path] will be stored as a key in the program

const program = require('commander'); // Command parameter processing
program
  .version('0.0.1')
  .option('-l --path [path]'.'list of customers in CSV file')
  .parse(process.argv);

// node scripts/generateComponents --path inputName
const inputName = program.path;
log('\ninputName: ',inputName);
Copy the code

Command line interaction simple use of inquirer. Js:

  • nameThe value of the then callback parameter can be found in the matching name.

  • message: Prompt message,

  • The rest is some option data, default values, filtering rules, validation, configuration, etc

The type of a child object in the Questions array can be:

(Excerpt from Inquirer. Js)

  • confirm: Yes /no, type, name, message, [, default] property
  • input: Keyboard input, type, name, message, [, default, filter, validate, Transformer] properties.
  • number: type, name, message, [, default, filter, validate] properties.
  • rawlist: Similar to ol tags, ordered lists, type, name, message, choices, [, default, filter] properties
  • list: Similar to ul tags, unordered lists, type, name, message, choices, [, default, filter] properties
  • checkbox: multi-select, type, name, message, choices, [, default, filter, validate] properties
  • expand: Expand the Menu, Type, name, message, Choices, [, default] properties
  • password: type, name, message, mask, [, default, filter, validate] properties.
  • editor: type, name, message, mask, [, default, filter, validate] properties.
const questions = [
  {
    type: "confirm".name: "override".message: "Whether to override?"}]; inquirer.prompt(questions).then(res= > {  
    if (res.override) {
      log('\n file will be overwritten! ');
      resolve(path);

    } else {
      log('\n Does not overwrite existing files! '); }});Copy the code

More properties:

{
  /* Preferred way: with promise */
  filter() {
    return new Promise(/* etc... * /);
  },

  /* Legacy way: with this.async */
  validate: function (input) {
    // Declare function as asynchronous, and save the done callback
    var done = this.async();

    // Do async stuff
    setTimeout(function() {
      if (typeofinput ! = ='number') {
        // Pass the return value in the done callback
        done('You need to provide a number');
        return;
      }
      // Pass the return value in the done callback
      done(null.true);
    }, 3000); }}Copy the code

Generated file scripts/generateComponent. Js:

const fs = require('fs');
const path = require('path');
const program = require('commander'); // Command parameter processing
const inquirer = require('inquirer'); / / select
const chalk = require('chalk');

const log = (. text) = > console.log(... text);const componentDir = path.resolve(__dirname, '.. /components');

const newComp = ` const fs = require('fs'); const path = require('path'); Console. log(' This is an auto-generated component'); `;

// NPM scripts cannot accept parameters
// Node is required to run the passed argument
program
  .version('0.0.1')
  .option('-l --path [path]'.'list of customers in CSV file')
  .parse(process.argv);

// node scripts/generateComponents --path inputName
const inputName = program.path;
log('\ninputName: ',inputName);

const questions = [
  {
    type: "confirm".name: "override".message: "Whether to override?"}]; mkdir(componentDir +` \ \${inputName||'noname'}`)
.then(path= > {
  log('\n Start generating files... ');

  return new Promise((resolve) = > {
    fs.writeFile(path+'\\index.js', newComp, 'utf-8', err => {
      if (err) throw err;
      
      log(`\n${path}\\index.js file created successfully! \n`);
      resolve();
    });
  });

}).catch(err= > {
  throw err;
});

// Create directory
function mkdir(path) {
  return new Promise((resolve) = > {
    if (fs.existsSync(path)) {
      log(`\n${path}: folder already exists);

      // Command line interaction
      inquirer.prompt(questions).then(res= > {  
        if (res.override) {
          log('\n file will be overwritten! ');
          resolve(path);

        } else {
          log('\n Does not overwrite existing files! '); }}); }else {
      fs.mkdirSync(path);
      
      log('\n folder created successfully! '); resolve(path); }})}module.export = {
  mkdir
}

Copy the code

Command line printed prompt

  • A new file
$ npm run create:comp aa

> test@1.0.0 create:comp D:\node-test
> node scripts/generateComponent --path "aa"


inputName:  aaFolder created successfully! Start generating files...D: \node-test\components\aa\index.jsFile created successfully!Copy the code
  • File already exists
$ npm run create:comp aa

> test@1.0.0 create:comp D:\node-test
> node scripts/generateComponent --path "aa"


inputName:  aa

D: \node-test\components\aa: Folder already exists? Whether to override?NoDo not overwrite existing files!Copy the code

Ii. Execute the script:

Execute the script using the exec of the child_process child process

The following is excerpted fromNode. Js Chinese website

By default, pipes for stdin, stdout, and stderr are set up between the parent Node.js process and the derived child process. These pipes have limited (and platform-specific) capacity. If the child process writes stdout beyond this limit without capturing the output, the child process blocks waiting for the pipeline buffer to accept more data. This is the same behavior as pipes in the shell. If the output is not consumed, the {stdio: ‘ignore’} option is used.

The child_process.spawn() method spawns child processes asynchronously without blocking the Node.js event loop. The child_process.spawnsync () method provides the equivalent functionality in a synchronous manner, but blocks the event loop until the derived process exits or terminates.

For convenience, the child_process module provides some synchronous and asynchronous alternatives to child_process.spawn() and child_process.spawnsync (). Note that each of these alternative methods is implemented based on child_process.spawn() or child_process.spawnsync ().

  • child_process.exec(): Derive ashellAnd in theshellTo run the command, and when finishedstdoutstderrPass to the callback function.
  • child_process.execFile(): similar tochild_process.exec(), except that it spawns commands directly by default and does not spawn firstshell.
  • child_process.fork(): Spawn a new oneNode.jsProcess, and invoke the specified module by setting up an IPC communication channel that allows messages to be sent between parent and child processes.
  • child_process.execSync(): child_process.exec()The synchronized version of theNode.jsEvent loop.
  • child_process.execFileSync(): child_process.execFile()The synchronized version of theNode.jsEvent loop. For some use cases, such as automatedshellScript, synchronous approach may be more convenient. But in most cases, the synchronous approach has a significant impact on performance because it stops the event loop until the spawned process completes.

NPM command:

package.json:
{
  ...
  "scripts": {
    "sh": "node components/run-sh.js",},... }Copy the code
  • Sh /sh1.js:

To use the NPM command, configure scripts in package.json, as shown above

const fs = require('fs');

const isDir = dir= > fs.statSync(dir).isDirectory();

/** * returns the relevant shell script */

 // Prints the specified directory
function ls(dir=null) {
  if (dir) {
    log('dir: ', dir);
    return `cd ${dir} && ls`;
  }
  return "ls";
}

/** * build front-end project * @param {project path} dir * @param {execute NPM command} CMD */
function buildFE(dir, cmd) {
  if(! dir || ! isDir(dir) || ! cmd)return;
  log('build-dir: ', dir);
  return `cd ${dir} && ${cmd}`;
}

module.exports = {
  ls,
  buildFE
}
Copy the code
  • Execute the script components/run-sh.js
// exec executes the shell command
const { exec } = require('child_process');
const path = require('path');
require('./log');
const timeFormat = require('./timeFormat');
const { ls, buildFE } = require('.. /sh/sh1.js');
// console.log('sh: ',sh);

const shdir = path.resolve(__dirname, '.. /sh');

// Prints the specified path directory
//exec(ls('/code/react-t1'), (err, stdout, stderr) => {
// if (err) throw err;
// if ( stderr) log('stderr: ', stderr);
  
// // Displays the contents of the command executed
// log('stdout: ', stdout);

// let nowTime = timeFormat({timestamp: new Date(), hasTime: true });
// log('time: ', nowTime);
/ /})


let nowTime = timeFormat({timestamp: new Date(), hasTime: true });
log('start--time: ', nowTime);

exec(buildFE('/code/react-t1'.'npm run build'), (err, stdout, stderr) => {
  if (err) throw err;
  if ( stderr) log('stderr: ', stderr);

  // Print the contents of the command executed
  log('stdout: ', stdout);

  nowTime = timeFormat({timestamp: new Date(), hasTime: true });
  log('end--time: ', nowTime);
})

Copy the code
  • Command line printing:
$ npm run sh

> test@1.0.0 sh D:\node-test
> node components/run-sh.js

==log== start--time:  2019-05-08 16:29:24
==log== build-dir:  /code/react-t1
==log== stdout:
> react-t1@0.1.0 build D:\code\react-t1
> node scripts/build.js

Creating an optimized production build...
Compiled successfully.

File sizes after gzip:

  62.73 KB  docs\static\js\4.1fe71077.chunk.js
  48.9 KB   docs\static\js\7.70929cf8.chunk.js
  14.3 KB   docs\static\js\3.fe3cf9bc.chunk.js
  13.3 KB   docs\static\js\0.e70acbb7.chunk.js
  3.22 KB   docs\static\js\1.6f7cac0f.chunk.js
  3.05 KB   docs\static\js\2.ba0e413c.chunk.js
  1.94 KB   docs\static\js\main.eb84215c.chunk.js
  1.48 KB   docs\static\js\runtime~main.ff53614d.js
  634 B     docs\static\css\main.fde90119.chunk.css
  592 B     docs\static\js\8.d5307ac7.chunk.js
  438 B     docs\static\js\9.1544082f.chunk.js
  434 B     docs\static\css\0.451ae571.chunk.css

The project was built assuming it is hosted at ./.
You can control this with the homepage field in your package.json.

The docs folder is ready to be deployed.

Find out more about deployment here:

  https://bit.ly/CRA-deploy= =log= =end--time: the 2019-05-08 16:29:31 = =log= =stderr:  { parser:"babylon"}is deprecated; we now treat it as { parser:"babel"}.Copy the code