源码共读 | 自动open浏览器JS库

797 阅读4分钟

本文参加了由公众号@若川视野 发起的每周源码共读活动, 点击了解详情一起参与。

【若川视野 x 源码共读】第13期 | open 打开浏览器 点击了解本期详情一起参与

平时使用vue脚手架和vite启动项目后可自动打开浏览器,

vue脚手架配置如下:

module.exports = {
  //...
  devServer: {
    open: true,
  },
};

vite配置如下:

export default defineConfig({
  //... 
	server: {
			open: true,
		},
})

一、学习目标😀

1、了解open库原理。

统、process进程、child_process子进程模块。

3、使用vscode调试代码。

二、源码调试😊

1、open库地址:github.com/sindresorhu…

git clone https://github.com/sindresorhus/open.git

cd open目录
npm i

2、自己跟着源码实现了open功能,并且加了相应注释,更容易理解。

const childProcess = require('child_process');
const isWsl = require('is-wsl');
//WSL是一种允许在Windows操作系统上运行Linux应用程序的兼容层,因此在WSL环境下运行的Node.js进程可能需要特殊处理
const isDocker = require('is-docker'); //检测Node.js进程是否运行在Docker容器
const { platform, arch } = process;

const { promises: fs, constants: fsConstants } = require('fs');

// 一、传参,检查类型
const open = (target, options) => {
	if (typeof target !== 'string') {
		throw new TypeError('Expected a `target`');
	}

	return baseOpen({
		...options,
		target,
	});
};

// 二、开始baseOpen
const baseOpen = async options => {
	options = {
		wait: false,
		background: false,
		newInstance: false,
		allowNonzeroExitCode: false,
		...options,
	};

	let { name: app, arguments: appArguments = [] } = options.app || {};
	appArguments = [...appArguments];

	// 命令行&参数解析
	let command; // 调用系统dos窗口
	const cliArguments = [];
	const childProcessOptions = {};


	// 系统环境兼容,这里只展示window系统代码
	if (platform === 'win32' || (isWsl && !isDocker())) {
		// mountPoint = '/mnt/'
		const mountPoint = await getWslDrivesMountPoint();
		// 四、getWslDrivesMountPoint结束

		command = isWsl
			? `${mountPoint}c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe`
			: `${process.env.SYSTEMROOT}\System32\WindowsPowerShell\v1.0\powershell`;
		// process.env.SYSTEMROOT获取进程环境变量,

		// Windows PowerShell启动进程的参数
		// -NoProfile: 不加载PowerShell的个人资料文件。
		// -NonInteractive: 以非交互方式运行PowerShell(即不需要用户输入)。
		// -ExecutionPolicy: 设置脚本执行策略。
		// Bypass: 跳过所有策略限制。
		// -EncodedCommand: 指示要在命令行中传递Base64编码的PowerShell命令。
		// -WindowStyle: 设定窗口的样式,如:Normal, Hidden , Minimized ,Maximi
		cliArguments.push('-NoProfile', '-NonInteractive', '–ExecutionPolicy', 'Bypass', '-EncodedCommand');

		if (!isWsl) {
			// windowsVerbatimArguments是在 Windows 上不为参数加上引号或转义
			childProcessOptions.windowsVerbatimArguments = true;
		}

		const encodedArguments = ['Start'];

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

		if (options.target) {
			encodedArguments.push(`"${options.target}"`);
		}

		// 使用PowerShell接受的Base64编码命令来允许特殊字符。
		options.target = Buffer.from(encodedArguments.join(' '), 'utf16le').toString('base64');
	}

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

	const subprocess = childProcess.spawn(command, cliArguments, childProcessOptions);

	console.log(subprocess, command, 'subprocess');
	subprocess.unref();

	return subprocess;
};

// 三、getWslDrivesMountPoint开始
const getWslDrivesMountPoint = (() => {
	const defaultMountPoint = '/mnt/';

	let mountPoint;

	return async function () {
		if (mountPoint) {
			return mountPoint;
		}

		const configFilePath = '/etc/wsl.conf';

		let isConfigFileExists = false;

		try {
			// windows下以下try catch没执行, 疑问?
			// configFilePath文件访问权限,fs.constants.X_OK: 检查文件是否可执行
			let res = await fs.access(configFilePath, fsConstants.F_OK);
			isConfigFileExists = true;
			console.log(res, 'res');
			// windows下以下try catch没执行, 疑问?
		} catch {}

		if (!isConfigFileExists) {
			return defaultMountPoint;
		}
	};
})();

module.exports = open;

3、创建test.js文件,调用open方法

open('https://www.baidu.com/');

文件夹目录😁

4、在open路径下,终端执行命令:

node test.js

三、vscode调试node代码😊

1、在行首打断点

2、点击运行调试

选择Node.js

点击单步调试

四、小结

1、is-wsl 包:用于检测当前Node.js进程是否运行在Windows Subsystem for Linux(WSL)环境下的npm模块。WSL是一种允许在Windows操作系统上运行Linux应用程序的兼容层,因此在WSL环境下运行的Node.js进程可能需要特殊处理。

2、process进程:

process.argv属性来获取当前进程的命令行参数数组。

process.env属性来获取当前进程的环境变量。

process.cwd() 方法可以返回当前工作目录的路径。

process.exit() 方法则可以用于在任何时候退出当前进程。

process对象还提供了事件机制,您可以监听特定事件(如exit事件)以执行自定义操作。process.on(eventName, callback) 方法,您可以注册事件处理程序函数来响应不同的进程事件。

process.arch获取操作系统 CPU 架构

process.platform返回操作系统平台

3、fs文件系统

fs.access(path[, mode], callback) 测试用户对 path 指定的文件或目录的权限

fs.fsConstants提供了文件系统相关的一些常量。这些常量包括文件打开和操作模式、文件访问权限等。

在使用fs模块进行文件系统操作时,可以使用fsConstants模块中定义的常量,例如:

  • fs.constants.F_OK: 检查文件是否存在
  • fs.constants.R_OK: 检查文件是否可读
  • fs.constants.W_OK: 检查文件是否可写
  • fs.constants.X_OK: 检查文件是否可执行
  • fs.constants.O_RDONLY: 只读模式打开文件
  • fs.constants.O_WRONLY: 只写模式打开文件
  • fs.constants.O_RDWR: 读写模式打开文件

4、child_process 子进程

child_process.spawn(command[, args][, options]) 是Node创建新进程的方法之一。