This article is participating in node.js advanced technology essay, click to see more details

Source code learning is always a bit boring, but in the long run it pays to stick with it.

But, if you are very engaged, yet very exciting! — — — — — leng hammer

What is the Open library?

Open is NodeJs’s cross-platform library for opening urls, files, or executables. Many common libraries, for example, rely on it to wake up the browser and open a specific URL. This article will also cover the basic usage and implementation principles of Open based on 8.4.0. The following is an example of sending:

  • The installation
# installation
npm install open -S
Copy the code
  • NodeJsEnvironmental usesendWake up the browser
// Open Baidu using the default browser
open('https://www.baidu.com');

// Use firefox to open Baidu
open('https://www.baidu.com', {
  app: {
    name: 'firefox',}});Copy the code

My default browser is Chrome:

In addition to evoking the browser, it can also evoke the image viewer, etc., not to go into details. Now that you know how to use send, it’s the same as before. Let’s use the send source code to analyze how to invoke the browser.

Open evokes browser principles

Guys might be using different operating systems, some might be Windows, some might be macOS, etc., so let’s remember how to call system commands on those operating systems. At this time the small partner said, this is not simple, direct terminal type command bai! For example, common commands like CD to enter a specified path, ls to view a list of resources and so on. Which command is used to invoke software on Windows and macOS?

Commands to invoke programs are provided in the operating system. For example, in MacOS and IOS, the app can be invoked using the open command in the terminal. In Windows, the program can be invoked using the PowerShell command with the help of PowerShell.

MAC terminal
open https://www.baidu.com Open Baidu using the default browser
open -a "google chrome" https://www.baidu.com # Specify Google Browser to open Baidu

# Windows Terminal
PowerShell Start https://www.baidu.com Open Baidu using the default browser
Copy the code

Actually speaking of this, I think that even if you don’t know before, now you can basically think about the approximate implementation of the library!!

The core implementation of the library is to determine different operating systems, using node child processes to execute different system commands. Let’s look at the body of the library first:

/** * external exposure method, open program */
const open = (target, options) = > {
  if (typeoftarget ! = ='string') {
    throw new TypeError('Expected a `target`');
  }

  returnbaseOpen({ ... options, target }); };module.exports = open;
Copy the code

You simply determine the parameter type and call the baseOpen method to pass in the user parameter evocator. Let’s look at the baseOpen implementation:

// Obtain system environment parameters
const { platform, arch } = process;

const baseOpen = async options => {
  // merge initialization parameters, omit some parameter initialization code
  options = {
    wait: false.background: false.newInstance: false.allowNonzeroExitCode: false. options };let command;
  const cliArguments = [];
  const childProcessOptions = {};
	
  /** * MacOS, IOS */
  if (platform === 'darwin') {
    / /...
  }
	
  /** ** Windows, Windows under Linux */
  else if (platform === 'win32'|| (isWsl && ! isDocker())) {/ /...
  }
	
  // Linux or other systems
  else {}

  if (options.target) {
    cliArguments.push(options.target);
  }

  if (platform === 'darwin' && appArguments.length > 0) {
    cliArguments.push('--args'. appArguments); }// Start a child process with spawn, execute command, and pass in the corresponding cliArguments argument
  const subprocess = childProcess.spawn(command, cliArguments, childProcessOptions);

  if (options.wait) {
    // ...
  }

  // Instead of waiting for the child to exit, the parent exits independently of the child
  subprocess.unref();

  return subprocess;
}
Copy the code

The general structure can be seen here:

  • Judge the current system environment for different processing, generate the corresponding call program system command
    • macOSsystem
    • windossystem
    • linuxsystem
  • usingnodeThe child processes execute system commands that invoke the program

The point of special interest here is the spawn child start part:

const subprocess = childProcess.spawn(command, cliArguments, {
  // Ignore file descriptors in child processes
  stdio: 'ignore'.// Let the child process continue running after the parent process exits
  detached: true});// The parent process no longer waits for the child process to exit
subprocess.unref();
Copy the code

Detached: true, to let the child process continue running after the parent exits, subprocess.unref(); Make the parent process no longer wait for the child process to exit.

Let’s take a look at the processing logic for each system:

  • Parameter implementation in Windows:
/** ** Windows, Windows under Linux */
else if (platform === 'win32'|| (isWsl && ! isDocker())) {// Get the driver entry address of Windows operating system in Linux
  const mountPoint = await getWslDrivesMountPoint();

  * -iswsl specifies whether the process is running in the Windows subsystem of Linux. * -process.env. SYSTEMROOT specifies the system path. C:\Windows */
  command = isWsl
    ?  `${mountPoint}C/Windows/System32 / WindowsPowerShell/v1.0 / powershell. Exe `
    :  `${process.env.SYSTEMROOT}\ \ System32 \ \ WindowsPowerShell \ \ v1.0 \ \ powershell `;

  /** * You can enter PowserShell -help in CMD terminal to view the Help documents for related parameters: * -noprofile does not use a user profile * -noninteractive does not display interactive prompts to the user * - ExecutionPolicy Bypass sets the default ExecutionPolicy of the session to Bypass * -encodedcommand The command accepts the Base64 encoding string. Used to support the use of special characters */ in arguments
  cliArguments.push(
    '-NoProfile'.'-NonInteractive'.'- ExecutionPolicy'.'Bypass'.'-EncodedCommand'
  );

  if(! isWsl) { childProcessOptions.windowsVerbatimArguments =true;
  }

  // The parameter to encode
  const encodedArguments = ['Start'];

  if (options.wait) {
    encodedArguments.push('-Wait');
  }

  // If the startup app is specified, the specified app is used, otherwise the default launcher is used
  // The default launcher is used when the options.target parameter is concatenated directly after the Start command
  if (app) {
    // Double quote with double quotes to ensure the inner quotes are passed through.
    // Inner quotes are delimited for PowerShell interpretation with backticks.
    encodedArguments.push(` \ ` ""${app}\ ` "" `.'-ArgumentList');
    if(options.target) { appArguments.unshift(options.target); }}else if (options.target) {
    encodedArguments.push(`"${options.target}"`);
  }

  if (appArguments.length > 0) {
    appArguments = appArguments.map(arg= > ` \ ` ""${arg}\ ` "" `);
    encodedArguments.push(appArguments.join(', '));
  }

  // Using Base64-encoded command, accepted by PowerShell, 
  // to allow special characters.
  // Convert the parameters to base64 using Buffer
  options.target = Buffer.from(
    encodedArguments.join(' '),
    'utf16le',). ToString ('base64');
}
Copy the code

The detailed implementation is mostly in the comments, but note that Windows supports complex characters by passing the -encodedCommand parameter to execute base64 data when the program is opened through the PowerShell program. The base64 character data conversion utilizes Buffer objects.

  • MacOS system under the implementation
/** * MacOS, IOS */
if (platform === 'darwin') {
  command = 'open';

  if (options.wait) {
    cliArguments.push('--wait-apps');
  }

  if (options.background) {
    cliArguments.push('--background');
  }

  if (options.newInstance) {
    cliArguments.push('--new');
  }

  if (app) {
    cliArguments.push('-a', app); }}Copy the code

MacOS is also concatenation parameters, and logic editing is simple, there is nothing to say. Linux is not much to say, if you are interested, you can browse. So to summarize the core implementation of the Open library principle:

const { spawn } = require('child_process');

const { platform } = process;

function open(target) {
  let command;
  const commandArgs = [];

  if (platform === 'darwin') {
    command = 'open';
    commandArgs.push(target);
  } else if (platform === 'win32') {
    const startArgs = [];
    command = 'PowerShell';
    commandArgs.push(
      '-NoProfile'.'-NonInteractive'.'- ExecutionPolicy'.'Bypass'.'-EncodedCommand',); startArgs.push('Start');
    startArgs.push(target);
    commandArgs.push(
      Buffer.from(startArgs.join(' '), 'utf16le').toString('base64')); } spawn(command, commandArgs).unref(); }// Test to evoke effect
open('https://www.baidu.com');
Copy the code

Run the Node script on the terminal to test the effect:

# Terminal run the script # node index.jsCopy the code

The principle of summary

The principle of open library to open applications is to use the node child process to directly or indirectly execute the system startup command:

  • windowsA system orlinuxUnder thewindowsSystem, usepowershellThe program was introduced intoStartCommand and start parameters call up the program, directly usingPowerShellSo can commands.
  • MacOSandIOSDown system utilizationopenSystem command.
  • linuxbyxdg-openArousal.

conclusion

If you enjoyed this article, welcome friends to ❤ ️ ❤ ️ ❤ ️ thumb up 👍 👍 collection 👍 👍 forward ❤ ️ ❤ ️ ❤ ️ ha ~ ~ ~ also recommend you to read my other articles:

  • Detail “FinalHandler” source code NodeJs service error response principle
  • Weekly downloads of 50 million “MIME” library source code to achieve full parsing
  • Take a look at how the Node Attachment download service works in the Content-Disposition source code
  • Explain the implementation principle of NodeJs static file hosting service in “Send” source code
  • Explain the Node middleware model architecture in the source code of Connect
  • NodeJS techniques in live-Server source code
  • Ts Masters: 22 examples that delve into the most esoteric of Ts’s advanced type tools
  • Here are 28 Canvas libraries that will make you say wow
  • In-depth explanation of VsCode advanced debugging and use skills in various scenarios