Summary of the process of developing a new npm package in Monorepo

This week, I need to develop an npm package in my work to supplement other existing pacakge. The entire repository adopts the form of monorepo to record the pitfalls and new technologies learned during the whole process

Use of Lerna

The venom warehouse adopts the monorepo method

Monorepo is a different way of organizing code from multirepo. First, let’s explain what monorepo and multirepo are. Both are ways to manage and organize code. As the name suggests, monorepo is to put all related projects in one repository (such as React, Angular, Babel, Google…), while multirepo is divided into multiple repositories by module.

Monorepo与MultiRepo

Monorepo——大型前端项目的代码管理方式

In general, monorepo is to manage multiple projects in the same repository, and lerna is a framework or way to implement monorepo.

This is its GitHub address: https://github.com/lerna/lerna

First of all, we can initialize the configuration and file directory of lerna in a folder through the lerna init command

1
2
3
4
lerna-repo/
packages/
package.json
lerna.json

Lerna.json is the configuration item of lerna (in the readme of git), package.json is the configuration item of the entire repository, and the following packages are folders, each folder is a mulitrepo practice repository, which is the most common form of repository we usually have, but there is no own .git

Two modes: Fixed and Independent

In Fixed mode, the versions of all repositories in the entire lerna repository are the version field in package.json in the root directory, that is to say, they are all the same, that is to say, all packages should be upgraded together, even if you only change one of them.

In Independent mode, the version field of package.json in the root directory becomes independent, and each repository’s own version is in package.json in its own directory

Public dependence

Most of the devDependencies can be extracted into the root directory dependencies of the lerna repository through the lerna link convert command

  • This can reduce the space occupied by repeated dependencies

  • Make sure that each pacakge uses the same version (if each package uses a different version at the beginning, it seems to be the maximum version used after extraction)

  • Reduce dependency installation time

Common commands

Lerna init: Initialize lerna configuration

Lerna bootstrap: Install all dependencies

Lerna publishes a new version

Lerna exec: execute command (–scope can specify in which pacakge to execute)

Lerna create: Create a new package

Lerna link: Symbolically link together all Lerna packages that depend on each other in the current Lerna repository (this has not been used yet, I use npm link for local debugging)

For others, you can refer to the github repository.

Npm

Executing npm link in the root directory of the package you want to be used by other packages will create a mapping in the global directory, i.e. from global/a - > a

Calling npm link a in the package that will use a (this a is specified in the name field in the package.json of the package a) will establish the mapping of b/node_modules/a - > global/a - > a.

If you modify a at this time, it will be updated directly in b.

npm link

NPM

Usually, applications can only handle messages from within. If you want to intercept messages sent from the outside, you need a technology called hook (Hook). Imagine that you can’t control the process of npm test, but what if you really want to automatically handle something before test? Every time you manually execute something before test, is it annoying, annoying, annoying? Even if you don’t get bored, you will forget!

At this time, we will use our Hook. The following instructions are all Hooks, which can be defined in the scripts property of package.json and will be executed at a specified time in the lifecycle, which is the above-mentioned “intercepting and processing external messages”, which is very convenient for developers (maybe you want to do something bad?)

  • prepublish: Execute before publishing the package. (Also executed when npm install is executed in the package directory)

  • postpublish: execute after the package is published

  • preinstall: execute before the package is installed

  • postinstall: execute after the package is installed

  • preuninstall: execute before the package is uninstalled

  • postuninstall: execute after the package is uninstalled

  • preversion: Execute before modifying the version of the package

  • postversion: executed after modifying the version of the package

  • pretest, posttest: Executed when test is executed within the package, where pretest precedes posttest

  • prestop, poststop: Executed when stop is executed within the package, where prestop precedes poststop

  • prestart, poststart: Executed when start is executed within the package, where prestart precedes poststart

  • prerestart, postrestart: Executed when the restart script is executed in the package, where prerestart precedes postrestart. Note: If the specified restart script is not displayed in the scripts, stop is automatically called before start

The above Hooks are predefined by npm, that is to say, when you execute npm install, if you define preinstall and postinstall in the scripts, they will be automatically executed before/after npm install, no need for you to worry! awesome, is there any?

Also, any custom script (executed via npm run-script < script name >) can also be prefixed with pre and post to make hooks for it. For example: premyscript, myscript, postmyscript

That is, the pretest script will also run before npm test

Verdccio set up local repository (verification hook)

In order to test the effect of postinstall, but do not want to directly upload the unfinished package directly, you can create your own private repository locally. Here I useVerdccio

It is very simple to use, you can directly see the link above

There are currently three pitfalls:

  1. First, you must create a new user, otherwise you cannot publish (there may be other ways)
  2. If you want to install from npm after publishing the package, but the package your package depends on does not, an error will be reported. You can modify the configuration item at this time. The mac is in~/.config/verdaccio/config.yaml
1
2
3
4
5
uplinks:
npmjs:
url: https://npm.org
yarn:
url: https://npm.org/

Configure upstream links

  1. If you want to delete an existing repository, it is also very simple, because all will be stored in the local~/.local/share/verdaccio/storage.

Node get repository address

There is a requirement to obtain the repository address of git through node. At first, I wanted to read .git/config.

It was later discovered that the command line can be executed with child_process:

1
2
3
4
const gitRemoteUrl = childProcess.execSync(
'git config --get remote.origin.url',
);
return gitRemoteUrl ? gitRemoteUrl.toString() : noGitRepositoryUrl;

How to specify what files are packaged

Since the script executed in my postinstall is independent and is not used in the index.js and its dependencies pointed to by the main of pacakge.json, after packaging and publishing, my script is not in the packaged directory. At this time You need to specify in the files of package.json to put my script in.

Npm

img