primers

Nodemon is a cli tool that allows you to restart a service after changing the code, but how does it work? We’re going to build a little wheel to explore

By learning how to build a wheel, you can get a deeper understanding of the principles

B station supporting video

The principle of

Think about how we can manually update it without using Ndoemon.

// main.js
const Koa = require("koa");
const app = new Koa();
app.use((ctx) = > {
  ctx.body = "hi my name is cuixiaorui";
});
app.listen(3000);
Copy the code

Manual update steps:

  1. Change the value of ctx.body in the main.js file

  2. Close the current service and re-execute node main.js

Ndoemon helps us automate both of these steps so that we can just focus on modifying the files and restarting the service is a repetitive task. Programs are best suited to solve repetitive problems

That said, we only need to implement the above two steps in code, which is how Nodemon works.

So how do you translate the above two steps into concrete code?

On closer analysis, you’ll see that modifying the main.js file actually translates to watching the file change. If you modify the code, the file must have changed

Shutting down the current service is more specific by shutting down the process and executing the node main.js command

Observe the file changes

How do you observe file changes in nodeJS?

If you are familiar with the NodeJS API, you will notice that there is a watch method under the FS module. Its function is to observe file changes, but this API is not very friendly and has many problems on the Mac platform

There’s an even better tool in the community, Chokidar, you can check out his README,

It specifically solves a series of problems of Fs. watch

Ok, we have selected the tool, so let’s see how to use it.

const chokidar = require("chokidar");
chokidar.watch(["main.js"]).on("all".(event, path) = > {
  console.log(event, path);
});

Copy the code

Watch the specific file by chokidar.watch, in this case main.js, and by listening for the all event. So we can get messages when files change

Well, that’s done. Let’s move on

Run the node main.js command

The next step is to explore how to execute the node main.js command. There are two ways to execute the command in nodejs

  1. exec

  2. spawn

Both of these functions are under the child_process module. Use a subprocess to help you execute commands

We can understand the concept of child process: we are currently executing the main process is dad, dad is working, but he wants to drink water (execute node main.js), if he goes, then he will affect the work at hand, so how can he not affect the work at hand to drink water? Just ask your son to go. The child process is the son.

So what’s the difference between exec and spawn?

Let’s experiment and execute the test.js script at the same time

//test.js
console.log("test.js");

setTimeout(() = > {
  console.log("set timeout");
}, 500);


Copy the code

Exec executes synchronously, waiting for all scripts to be executed before making a callback

exec("node test.js".(err,stdout) = >{
  console.log(stdout);
 }); 
Copy the code

Spawn is based on a stream, which sends data as a stream after execution

spawn("node"["test.js"] and {stdio:[process.stdin,process.stdout,process.stderr]
}) 
Copy the code

You can see the difference in the video

Then we can combine the code for observing the file with the code for executing the command

chokidar.watch(["main.js"]).on("all".(event, path) = > {
  spawn("node"["main.js"] and {stdio:[process.stdin,process.stdout,process.stderr]
  }) 
});
Copy the code

However, if we change the main.js code, it will give us an error

Tell us the port is occupied! Why is it occupied?

This is because we didn’t turn off the service we opened before, so if we open one, we will have this problem

So again, how do you shut down the previous process?

Close the process

If we look closely at the Spawn API, you will see that it returns a chidlProcess object. And there’s a method in this object called kill

We can use this method to shut down the process

  childProcess && childProcess.kill();

  childProcess = spawn("node"["main.js"] and {stdio: [process.stdin, process.stdout, process.stderr],
  });
Copy the code

Use the childProcess variable to store it, and then check if it exists, then kill it to shut down the previous process

At this point, the core of Nodemon will have been implemented, but there are still too many points to optimize.

Use anti-shaking to optimize

If we keep it in main.js, you’ll see that it will always raise the All event, which will spawn more often than we need to spawn the last time all is called. This is the best scenario to use

function debounce(fn, delay) {
  let id;
  return () = > {
    clearTimeout(id);

    id = setTimeout(() = > {
      fn();
    }, delay);
  };
}
Copy the code

Next we wrap the logic to execute spawn into a function

function restart() {
  console.log("restart");
  childProcess && childProcess.kill();

  childProcess = spawn("node"["main.js"] and {stdio: [process.stdin, process.stdout, process.stderr],
  });
}

let debounceRestart = debounce(restart, 500)

Copy the code

Finally, run debounceRestart inside the watch

chokidar.watch(["main.js"]).on("all".(event, path) = > {
  console.log(event, path);

  debounceRestart();
});
Copy the code

So how do you change main.js so that it’s only called once

conclusion

Take a look at what we’ve learned with this little wheel!

  • Observe the file changes

    • fs.watch

    • chokidar

  • Execute commands using exec and spawn in nodejs

  • Image stabilization

If you read it carefully, you will find that we started from the problem, converted the actual problem into concrete code, and gradually completed the implementation of the simplified version of Nodemon.

In fact, that’s what writing any program is all about: finding problems and solving them. Iteratively refine the program.

The skill of splitting problems is Tasking Tasking.

Tasking Tasking can increase your ability to write programs by at least 50 percent

Tasking requires constant and deliberate practice

And the best way to practice this is to build your own wheels, which I also call the wheel building learning method.

Follow me later to share more on the wheel

The article will be first posted to my official account atcui CXR

A link to the

code

B standing video

chokidar

The exec and spawn