preface

Lerna is a multi-package management tool that can help us manage and maintain multiple packages in a unified manner, greatly improving the development efficiency. It is often used for scaffolding development and component library development. Lerna itself integrates YARgs and can register commands itself.

Read this article, you gain

    1. Learn debugging source code techniques
    1. How lerna executes a command will help you understand the scaffolding process

Lerna’s Github address

1. Use the process

It is recommended to go to the official website to learn about the use process and basic commands. This article will not take too much space to draw a picture for you to understand the use of lerna basic commands ~:

2. Install lerna

npm install lerna --save
Copy the code

3. Prepare for webStorm source debugging

(1). Open webStorm’s Prefences panel, select the Node package, and the built-in library will highlight the modulators

(2). Uncheck the following two boxes to enable debug mode to run under node_mudules

(3). Found under node_modulesLerna and @ lernaThese two file packages

Enable debug mode in node_modules/lerna/cli.js and add parameters

Add the parameter init

(4). Start the test

Put a breakpoint on line 12 of cli.js to start the test

4. Start debugginglerna initThe command

Now that we have configured the debug parameters and the commands, let’s see how the lerna init command is executed \

Lerna /package.json (bin

  "bin": {
    "lerna": "cli.js"
  },
Copy the code

In ps: bin, key is lerna and value is cli.js. This detail is very important and also an important detail of scaffolding. After bin is installed, Lerna can be directly executed

(2). First in cli.js

#! /usr/bin/env node
const importLocal = require("import-local")
if (importLocal(__filename)) {
  require("npmlog").info("cli"."using local version of lerna");
} else {
  console.log("test start")
  require(".")(process.argv.slice(2));
}

Copy the code

ps:

    1. process.argv.slice(2)That’s the argument after you intercept lerna, and in this case, init
    1. Require (“.”) looks strange, but actually loads the./index.js file and passes the argument
    1. The beginning of the #! The /usr/bin/env node is an important part of scaffolding that tells the system to use the Node environment when executing commands

(3) enter lerna/index.js

If you go in here, you’ll see that you’ve imported a bunch of packages from @lerna, and you’ve got a main function

function main(argv) {
  const context = {
    lernaVersion: pkg.version,
  };
  return cli()
    .command(addCmd)
    .command(bootstrapCmd)
    .command(changedCmd)
    .command(cleanCmd)
    .command(createCmd)
    .command(diffCmd)
    .command(execCmd)
    .command(importCmd)
    .command(infoCmd)
    .command(initCmd)
    .command(linkCmd)
    .command(listCmd)
    .command(publishCmd)
    .command(runCmd)
    .command(versionCmd)
    .parse(argv, context);
}
Copy the code

ps:

    1. Argv, the positional argument to main, is the command argument passed in from cli.js (init).
    1. Returns a cli() function and registers a lot of life
    1. Without further ado, what does the cli() function do

5. Debugging @ lerna/cli

When you enter the @lerna/cli/index.js file, you suddenly realize that the CLI () function is an instance of yargs and has some parameters configured. Here’s an interesting one:

  • 1. In this paper,
    const cli = yargs(argv, cwd);
    .wrap(cli.terminalWidth())
    Copy the code

    Ps: Here an instance of YARgs is generated and the terminal is set to full screen

Cli ().command() is used to register commands to execute different modules according to different command parameters, so the next step is the @lerna/init module

6. Debugging @ lerna/init

(1)进入到 @lerna/init/command 当中(是参考@lerna/cli.js的initCmd路径)

  1. Here the command and handle execution functions are registered in the CLI () function (yargs instance)
  2. Handle executes the function and passes the argument argv and calls @lerna/init/index

(2) into the @ lerna/init/index

The first thing that pops into your eye: Factory InitCommand

  • 1. Factory returns an instance of InitCommand
  • 2.InitCommand inherits the Commder class
  • Argv is passed to the commder class
  • The 4.com der class verifies the argv parameter
  • 5. One piece of code piqued my curiosity
  execute() {
    let chain = Promise.resolve();
    chain = chain.then(() = > this.ensurePackageJSON());
    chain = chain.then(() = > this.ensureLernaConfig());
    chain = chain.then(() = > this.ensurePackagesDir());
    return chain.then(() = > {
      this.logger.success(""."Initialized Lerna files");
    });
  }
Copy the code

This is a great way to control the order of asynchronous execution. If you are interested, check out the Event loop and Promise specifications!

  • 6. EnsurePackageJSON ensureLernaConfig, ensurePackagesDir logic EnsurePackageJSON creates a json file, a config file, and a packages folder, respectively. We don’t need to get into the logic, but it is interesting to note that ensurePackageJSON uses write-json-file as an NPM package

Extra meals:

(1). How does Lerna call between internal packages?

Internal intermediate calls are very common in LERNA, so we must be able to master this knowledge

  1. Create two packages
lerna create cli
lerna create test
Copy the code

Ps: At this point we have created two packages, and we are going to introduce the methods of the test package into the CLI package

  1. Write methods to the test package in /lib/test.js(entry file)

Test /lib/test.js is not created by lerna, but by package.json

module.exports = test1;

function test1() {
    console.log("This is a test, hee-hee-hee.")}Copy the code
  1. Package. json registers the test package in the CLI package
  "dependencies": {
    "@well-cli-pro/test": "file:.. /.. /utils/test"
  },
Copy the code
  1. Method to invoke the test package in cli/lib/cli.js

const test = require('@well-cli-pro/test')

test()

Copy the code
  1. Run cli/lib/cli.js. If the following command output is displayed, the call is successful ~

(2). Describes the write-json-file package

NPM install write-json-file NPM install write-json-file

const writeJsonFile = require('write-json-file');
const log = require("npmlog");
// Create json file with indent as indent
writeJsonFile('foo.json', {test: 123}, {indent:1});Copy the code

conclusion

From the beginning to the end, I take you to debug lerna source code, and walk you through the process of command execution step by step, understand lerNA command execution logic, I believe you have a new understanding of the business like scaffolding, interested students can continue to delve into the source code of other packages