写点什么

每次启动项目的服务,电脑竟然乖乖的帮我打开了浏览器,100 行源码揭秘!

作者:若川
  • 2022 年 6 月 27 日
  • 本文字数:3164 字

    阅读完需:约 10 分钟

1. 前言

大家好,我是若川为了能帮助到更多对源码感兴趣、想学会看源码、提升自己前端技术能力的同学。我倾力最近组织了源码共读活动,已进行近一年,大家一起交流学习,共同进步,很多人都表示收获颇丰。


想学源码,极力推荐之前我写的《学习源码整体架构系列》 包含jQueryunderscorelodashvuexsentryaxiosreduxkoavue-devtoolsvuex4koa-composevue 3.2 发布vue-thiscreate-vue玩具vite等 10 余篇源码文章。


本文仓库 open-analysis,求个star^_^


最近组织了源码共读活动,大家一起学习源码。于是搜寻各种值得我们学习,且代码行数不多的源码。


我们经常遇到类似场景:每次启动项目的服务,电脑竟然乖乖的帮我打开了浏览器。当然你也可能没有碰到过,但可能有这样的需求。而源码 300 行左右,核心源码不到 100 行。跟我们工作息息相关,非常值得我们学习。


之前写过据说 99% 的人不知道 vue-devtools 还能直接打开对应组件文件?本文原理揭秘,也是跟本文类似原理。


阅读本文,你将学到:


1. 电脑竟然乖乖的帮我打开了浏览器原理和源码实现2. 学会使用 Node.js 强大的 child_process 模块3. 学会调试学习源码4. 等等
复制代码

2. 使用

2.1 在 webpack 中使用

devServer.open


告诉 dev-server 在服务器启动后打开浏览器。 将其设置为 true 以打开您的默认浏览器。


webpack.config.js


module.exports = {  //...  devServer: {    open: true,  },};
复制代码


Usage via the CLI:


npx webpack serve --open
复制代码


To disable:


npx webpack serve --no-open
复制代码


现在大多数都不是直接用 webpack 配置了。而是使用脚手架。那么接着来看我们熟悉的脚手架中,打开浏览器的功能是怎么使用的。

2.2 在 vue-cli 使用

npx @vue/cli create vue3-project# 我的 open-analysis 项目中 vue3-project 文件夹# npm i -g yarn# yarn serve 不会自动打开浏览器yarn serve# --open 参数后会自动打开浏览器yarn serve --open
复制代码

2.3 在 create-react-app 使用

npx create-react-app react-project# 我的 open-analysis 项目中 react-project 文件夹# npm i -g yarn# 默认自动打开了浏览器yarn start
复制代码



终端我用的是 window terminal,推荐我之前的文章:使用 ohmyzsh 打造 windows、ubuntu、mac 系统高效终端命令行工具,用过都说好。


webpackvue-clicreate-react-app,它们三者都有个特点就是不约而同的使用了open


引用 open 分别的代码位置是:



接着我们来学习open原理和源码。

3. 原理

npm 之王 @sindresorhusopen README文档中,英文描述中写了为什么使用它的几条原因。


为什么推荐使用 open


积极维护。支持应用参数。更安全,因为它使用 spawn 而不是 exec。修复了大多数 node-open 的问题。包括适用于 Linux 的最新 xdg-open 脚本。支持 Windows 应用程序的 WSL 路径。
复制代码


一句话概括open原理则是:针对不同的系统,使用Node.js的子进程 child_process 模块的spawn方法,调用系统的命令打开浏览器。


对应的系统命令简单形式则是:


# macopen https://lxchuan12.gitee.io# winstart https://lxchuan12.gitee.io# linuxxdg-open https://lxchuan12.gitee.io
复制代码


windows start 文档


open包描述信息:open


在这里可以看到有哪些 npm 包依赖了 open


我们熟悉的很多 npm 包都依赖了open。这里列举几个。


4. 阅读源码前的准备工作

# 推荐克隆我的项目,保证与文章同步,同时测试文件齐全git clone https://github.com/lxchuan12/open-analysis.git# npm i -g yarncd open && yarn
# 或者克隆官方项目git clone https://github.com/sindresorhus/open.git# npm i -g yarncd open && yarn
复制代码

4.1 写个例子,便于调试源码

由于测试用例相对较为复杂,我们自己动手写个简单的例子,便于我们自己调试。


根据 README,我们在 open-analysis 文件夹下新建一个文件夹 examples ,里面存放一个 index.js。文件内容如下:


// open-analysis/examples/index.js(async () => {    const open = require('../open/index.js');    await open('https://lxchuan12.gitee.io');})();
复制代码


await open('https://lxchuan12.gitee.io'); 打上断点。在终端命令行中执行


node examples/index.js
复制代码


会自动唤起调试模式。如果不支持先阅读这个官方文档配置:Node.js debugging in VS Code,如果还是不行,可以升级到最新版VSCode试试。


跟着调试我们可以进入 open 函数。




4.2 open 打开函数

// open/index.jsconst open = (target, options) => {  if (typeof target !== 'string') {    throw new TypeError('Expected a `target`');  }
return baseOpen({ ...options, target });};
复制代码


跟着断点,我们来看最终调用的 baseOpen。这个函数比较长,重点可以猜到是:const subprocess = childProcess.spawn(command, cliArguments, childProcessOptions);这句,我们可以打算断点调试。

4.3 baseOpen 基础打开函数

// open/index.jsconst childProcess = require('child_process');const localXdgOpenPath = path.join(__dirname, 'xdg-open');
const {platform, arch} = process;// 调试时我们可以自行调整修改平台,便于调试各个平台异同,比如 mac、win、linux// const {arch} = process;// mac// const platform = 'darwin';// win// const platform = 'win32';// const platform = '其他';
const baseOpen = async options => { options = { wait: false, background: false, newInstance: false, allowNonzeroExitCode: false, ...options }; // 省略部分代码 // 命令 let command; // 命令行参数 const cliArguments = []; // 子进程选项 const childProcessOptions = {}; if (platform === 'darwin') { command = 'open'; // 省略 mac 部分代码 } else if (platform === 'win32' || (isWsl && !isDocker())) { // 省略 window 或者 window 子系统代码 const encodedArguments = ['Start']; } else { const useSystemXdgOpen = process.versions.electron || platform === 'android' || isBundled || !exeLocalXdgOpen; command = useSystemXdgOpen ? 'xdg-open' : localXdgOpenPath; // 省略 linux 代码 } // 省略部分代码 const subprocess = childProcess.spawn(command, cliArguments, childProcessOptions); // 省略部分代码 subprocess.unref();
return subprocess;}
复制代码


由此我们可以看出:


一句话概括open原理则是:针对不同的系统,使用Node.js的子进程 child_process 模块的spawn方法,调用系统的命令打开浏览器。


对应的系统命令简单形式则是:


# macopen https://lxchuan12.gitee.io# winstart https://lxchuan12.gitee.io# linuxxdg-open https://lxchuan12.gitee.io
复制代码

5. 总结

一句话概括open原理则是:针对不同的系统,使用Node.js的子进程 child_process 模块的spawn方法,调用系统的命令打开浏览器。


本文从日常常见的场景每次启动服务就能自动打开浏览器出发,先讲述了日常在webpackvue-clicreate-react-app如何使用该功能,最后从源码层面解读了open的原理和源码实现。工作常用的知识能做到知其然,知其所以然,就比很多人厉害了。


因为文章不宜过长,所以未全面展开讲述源码中所有细节。非常建议读者朋友按照文中方法使用VSCode调试 open 源码。学会调试源码后,源码并没有想象中的那么难


最后可以持续关注我 @若川。欢迎与我交流,参与 源码共读 活动,每周大家一起学习 200 行左右的源码,共同进步。

发布于: 刚刚阅读数: 6
用户头像

若川

关注

还未添加个人签名 2018.09.11 加入

https://lxchuan12.gitee.io

评论

发布
暂无评论
每次启动项目的服务,电脑竟然乖乖的帮我打开了浏览器,100行源码揭秘!_JavaScript_若川_InfoQ写作社区