First, look at package.json

Each project has a package.json file in its root directory, which defines the various modules needed for the project and the configuration information for the project. Here is a complete package.json file

{
  "name": "vue-cli"."version": "2.9.3"."description": "A simple CLI for scaffolding Vue.js projects."."preferGlobal": true."bin": {
    "vue": "bin/vue"."vue-init": "bin/vue-init"."vue-list": "bin/vue-list"
  },
  "repository": {
    "type": ""."url": ""
  },
  "keywords": []."author": "litongqian"."license": "MIT"."bugs": {
    "url": ""
  },
  "homepage": ""."scripts": {
    "test": "npm run lint && npm run e2e"."start": "node index.js"
  },
  "dependencies": {
    "async": "^ 2.4.0." "."chalk": "^ 2.1.0." ",},"devDependencies": {
    "chai": "^ 4.1.2." "."eslint": "^ 3.19.0",},"engines": {
    "node": "> = 6.0.0"}}Copy the code

1. The Scripts field is displayed

The NPM command line abbreviation for the command to run the script, such as start, specifies the command to execute when running NPM run start.

2. Bin field

The bin entry is used to specify the location of the executable file corresponding to each internal command

"bin": {
    "vue": "bin/vue"."vue-init": "bin/vue-init"."vue-list": "bin/vue-list"
  },Copy the code

The preceding code specifies that the executable file corresponding to the vue command is vue in the bin subdirectory.

3. npm link

Project Directory:



When developing modules, such as the myModule module above, and want to use it in hello, we can use the relative path require(‘./ myModule ‘) to load the module.

You can also use the module id require(‘ myModule ‘) to load a custom module from Node into node_modules. The solution is to map the module to the global node_modules directory, generating a symbolic link to the local directory of the module.


NPM Link does just that, creating the symbolic link automatically.

  • Imagine a scenario where you develop a modulemymoduleDirectory forhello/mymoduleTo use this module for your own project, first, in the modules directory (hello/mymodule) running undernpm linkCommand.

hello/mymodule$ npm link
Copy the code



The above command generates a symbolic link file in NPM’s global modules directory with the name of the module specified in the package.json file.

/usr/local/lib/node_modules/mymodule -> /Users/tongqianli/Desktop/work/hello/mymoduleCopy the code

At this point, you can use the global module directory /usr/local/lib/node_modules/myModule to have the myModule module, but you can’t reference it in the project

This can be resolved by adding a path:

Every operating system has a PATH environment variable. When the system calls a command, it will look for the registered PATH in the PATH variable. If there is a registered PATH, it will call, otherwise it will prompt that the command was not found.

-> export PATH=$PATH: # append /usr/bin to PATH variable
-> export NODE_PATH="/usr/lib/node_modules; /usr/local/lib/node_modules" # specifies the NODE_PATH variable
Copy the code

The NODE_PATH is a registered environment variable used by NODE to find the path provided by the module. We can specify the NODE_PATH environment variable using the above method.

A better approach:

Switch to the project directory, run the NPM link command again, and specify the module name.

hello tongqianli$ npm link mymoduleCopy the code

The above command generates a local node_modules/ myModule mapping to the global node_modules/ myModule, and the global mapping to the local hello/ myModule.

/Users/tongqianli/Desktop/work/hello/node_modules/mymodule 
-> /usr/local/lib/node_modules/mymodule 
-> /Users/tongqianli/Desktop/work/hello/mymoduleCopy the code

You can then load the module in your project.

var myModule = require('myModule');
Copy the code

This way, any changes to MyModule can be reflected directly in the project.

If your project no longer needs the module, you can use the NPM unlink command in the project directory to remove the symbolic link.

hello tongqianli$ npm unlink mymoduleCopy the code

2. Executable scripts

Write a simple script hello

$ mkdir
hello
Create a folder 
$
cd
hello && touch 
Hello # Create command file

#! /usr/bin/env node
console.log('hello world');
Copy the code

1. The first line of a script usually specifies the interpreter through which the script must be executed. In the line#!Character, this character is called Shebang, so this line is called a Shebang line.

#!The following is the location of the script interpreter, which is typical for Bash scripts/bin/shor/bin/bash.

The interpreter for node scripts is /usr/local/bin/node

The above command usesenvCommand (this command is always on/usr/binDirectory) to return the location of the Node executable

#! /usr/bin/env NAMEWhat this syntax means is, let the Shell find$PATHThe first match in the environment variableNAME. This is useful if you don’t know the exact path of a command, or if you want to be compatible with other users’ machines.

#! /usr/bin/env node indicates that node is used as the script interpreter and can be run directly without node./hello. Env is used to find the node path, so as to avoid problems caused by different node installation paths.

If you open /usr/bin/env, you can view PATH. The operating system uses the PATH to find the node




Execute permission and path

As mentioned earlier, the script can be executed directly as long as the Shebang line is specified. One prerequisite for this is that the script has execution permission. You can use the following command to grant execution permission to the script.

# Give execute permission to all users
$ chmod +x hello

# Give all users read and execute permissions
$ chmod +rx hello
# or
$ chmod 755 hello

Give only read and execute permission to the script owner
$ chmod u+rx hello
Copy the code

The script’s permissions are usually set to either 755 (the owner has all permissions and everyone else has read and execute) or 700 (only the owner can execute).


Then, modify the permissions for Hello.

$ chmod 755 hello
$./helloCopy the code



If you want to remove the PATH before hello, you can add the PATH of hello to the environment variable PATH. A better alternative, however, is to create package.json in the current directory and write the following.

{
  "name": "hello"."bin": {
    "hello": "./hello"}}Copy the code

Then run the NPM link command. If you don’t understand, look up

$ npm linkCopy the code




The executable script bin/hello maps to the global node_modules/hello/hello, and the global node_modules/hello maps to the local hello, so you can use hello

3. Command line arguments

Command line arguments can be obtained using the system variable process.argv.

Modifying the Hello Script

#! /usr/bin/env node
console.log('hello ', process.argv);Copy the code

Argv [0] is the node installation path, argv[1] is the main module file, and the rest are subcommands or parameters.


$ hello a b c
# process.argv = ['/usr/local/bin/node', '/usr/local/bin/hello', 'a', 'b', 'c' ]


The script can use the child_process module to create a child process to execute Unix system commands to modify Hello

The exec method is used to execute bash commands. The exec method can take up to two arguments. The first argument is the shell command to be executed, and the second argument is a callback function that takes three arguments: the error that occurred, the output of standard output, and the output of standard error.


#! /usr/bin/env node
var name = process.argv[2];
var exec = require('child_process').exec;

var child = exec('echo hello ' + name, function(err, stdout, stderr) {
  if (err) throw err;
  console.log(stdout);
});Copy the code

Run $hello litongqian

If we want to see all the files, modify Hello

var name = process.argv[2];
var exec = require('child_process').exec;

var child = exec(name, function(err, stdout, stderr) {
  if (err) throw err;
  console.log(stdout);
});Copy the code

Run $hello ls

There are three files in the hello directory



Fourth, ShellJS module

The shell.js module rewraps child_process to make it easier to call system commands. It needs to be installed after use.

npm install --save shelljs
Copy the code

Then, rewrite the script.

#! /usr/bin/env node
var name = process.argv[2];
var shell = require("shelljs");

shell.exec("echo hello " + name);Copy the code

5. Yargs module

Shelljs only works out how to call shell commands, while the Yargs module works out how to handle command-line arguments. It also needs to be installed.

$ npm install --save yargs
Copy the code

The Yargs module provides the Argv object, which is used to read command-line arguments. See the rewritten hello.

#! /usr/bin/env node
var argv = require('yargs').argv;

console.log('hello ', argv.name);
Copy the code

When used, either of the following can be used.

$ hello --name=tom
hello tom

$ hello --name tom
hello tom
Copy the code

That is, the original return value of process.argv is as follows.

$ node hello --name=tom
[ 'node'.'/usr/local/bin/hell'.'--name=tom' ]
Copy the code

Yargs can change the above result to an object where each parameter item is a key-value pair.

Issue command packages

To publish via NPM Publish, ensure that you have an NPM account. For details, see the official NPM document.

This article uses native Node.js to develop the command tool, while Vue-CLI uses commander.js to simplify the development of the command tool.

Understand the execution process, learn the corresponding module, it is ok! This article throws a brick


Finally: Sometimes the command lines we use are not globally installed, but locally installed

1. Package. json bin field

The bin entry is used to specify the location of the executable file corresponding to each internal command.

"name":"someTool"."bin": {
  "someTool": "./bin/someTool.js"
}
Copy the code

The above code specifies that the executable file corresponding to the someTool command is sometool.js in the bin subdirectory.

When a project relies on the above someTool tool, it is only installed locally at the same time

{
  "name": "myproject"."devDependencies": {
    "someTool": "latest"
  },
  "scripts": {
    start: 'someTool build'// equivalent to start:'./node_modules/someTool/someTool.js build'}}Copy the code

NPM will look for this file and set up a symbolic link under node_modules/.bin/. In the example above, sometool.js creates a symbolic link npm_modules/.bin/someTool. Since the node_modules/.bin/ directory adds the system PATH variable at runtime, these scripts can be invoked directly by command without a PATH when running NPM.

So, you can write something like this in shorthand.

scripts: {  
  start: './node_modules/someTool/someTool.js build'} // write scripts: {start:'someTool build'
}

Copy the code

All node_modules/.bin/ commands can be run in the NPM run format. On the command line, type NPM run and then press TAB to display all available commands.

1. npm run

In the above code, the scripts field specifies two commands

start

npm run-script start
npm run start
someTool build
npm run
npm run-script

The NPM run command automatically adds node_modules/.bin to the environment variable $PATH, so you don’t need to use the PATH to call the command in the scripts field. This avoids the need to install the NPM module globally.

NPM run, if run without any arguments, lists all the scripts in package.json that can be executed.

NPM has two built-in shorthand commands. NPM test is equivalent to NPM run test, and NPM start is equivalent to NPM run start.

NPM run creates a Shell, executes the specified command, and temporarily adds node_modules/.bin to the PATH variable, which means the local module can run directly.

For example, you run the ESLint install command.

$ npm i eslint --save-dev
Copy the code

When you run the above command, you get two results. First, ESLint is installed into the node_modules subdirectory of the current directory; Second, the node_modules/.bin directory generates a symbolic link node_modules/.bin/eslint that points to the executable script of the ESLint module.

Then, you can reference the esLint script without a path in the package.json script property.

{
  "name": "Test Project"."devDependencies": {
    "eslint": "^ 1.10.3." "
  },
  "scripts": {
    "lint": "eslint ."}}Copy the code

When running NPM run Lint, it will automatically execute./node_modules/.bin/eslint.

If you run NPM run without any arguments, all commands under the scripts property are listed.

$ npm run
Available scripts in the user-service package:
  lint
     jshint **.js
  test
    mocha test/Copy the code

That’s it! That’s it!