1. 前言
大家好,我是若川。最近組織了源碼共讀活動,感興趣的可以加我微信 ruochuan12 參與,已進行三個月了,大家一起交流學習,共同進步。
想學源碼,極力推薦之前我寫的《學習源碼整體架構系列》 包含jQuery
、underscore
、lodash
、vuex
、sentry
、axios
、redux
、koa
、vue-devtools
、vuex4
、koa-compose
、vue-next-release
、vue-this
、create-vue
、玩具vite
等10余篇源碼文章。
本文倉庫 open-analysis,求個star^_^[1]
最近組織了源碼共讀活動,大家一起學習源碼。于是搜尋各種值得我們學習,且代碼行數不多的源碼。
我們經常遇到類似場景:每次啟動項目的服務,電腦竟然乖乖的幫我打開了瀏覽器。當然你也可能沒有碰到過,但可能有這樣的需求。而源碼300行左右,核心源碼不到100行。跟我們工作息息相關,非常值得我們學習。
之前寫過據說 99% 的人不知道 vue-devtools 還能直接打開對應組件文件?本文原理揭秘,也是跟本文類似原理。
閱讀本文,你將學到:
1.?電腦竟然乖乖的幫我打開了瀏覽器原理和源碼實現
2.?學會使用?Node.js?強大的?child_process?模塊
3.?學會調試學習源碼
4.?等等
2. 使用
2.1 在 webpack 中使用
devServer.open[2]
告訴 dev-server[3] 在服務器啟動后打開瀏覽器。將其設置為 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 系統高效終端命令行工具,用過都說好。
webpack
、vue-cli
和create-react-app
,它們三者都有個特點就是不約而同的使用了open[4]。
引用 open
分別的代碼位置是:
webpack-dev-server[5]
vue-cli[6]
create-react-app[7]
接著我們來學習open
原理和源碼。
3. 原理
在 npm
之王 @sindresorhus[8] 的 open README文檔[9]中,英文描述中寫了為什么使用它的幾條原因。
為什么推薦使用 open
積極維護。
支持應用參數。
更安全,因為它使用?spawn?而不是?exec。
修復了大多數 node-open 的問題。
包括適用于 Linux 的最新 xdg-open 腳本。
支持 Windows 應用程序的 WSL 路徑。
一句話概括open
原理則是:針對不同的系統,使用Node.js
的子進程 child_process
模塊的spawn
方法,調用系統的命令打開瀏覽器。
對應的系統命令簡單形式則是:
#?mac
open?https://lxchuan12.gitee.io
#?win
start?https://lxchuan12.gitee.io
#?linux
xdg-open?https://lxchuan12.gitee.io
windows start 文檔[10]
open
包描述信息:open[11]
在這里可以看到有哪些 npm 包依賴了 open[12]
我們熟悉的很多 npm
包都依賴了open
。這里列舉幾個。
webpack-dev-server[13]
react-dev-utils[14]
@vue/cli-shared-utils[15]
patch-package[16]
lighthouse[17]
release-it[18]
4. 閱讀源碼前的準備工作
#?推薦克隆我的項目,保證與文章同步,同時測試文件齊全
git?clone?https://github.com/lxchuan12/open-analysis.git
#?npm?i?-g?yarn
cd?open?&&?yarn#?或者克隆官方項目
git?clone?https://github.com/sindresorhus/open.git
#?npm?i?-g?yarn
cd?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[19],如果還是不行,可以升級到最新版VSCode
試試。
跟著調試我們可以進入 open
函數。


4.2 open 打開函數
//?open/index.js
const?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.js
const?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
方法,調用系統的命令打開瀏覽器。
對應的系統命令簡單形式則是:
#?mac
open?https://lxchuan12.gitee.io
#?win
start?https://lxchuan12.gitee.io
#?linux
xdg-open?https://lxchuan12.gitee.io
5. 總結
一句話概括open
原理則是:針對不同的系統,使用Node.js
的子進程 child_process
模塊的spawn
方法,調用系統的命令打開瀏覽器。
本文從日常常見的場景每次啟動服務就能自動打開瀏覽器出發,先講述了日常在webpack
、vue-cli
、create-react-app
如何使用該功能,最后從源碼層面解讀了open[20]的原理和源碼實現。工作常用的知識能做到知其然,知其所以然,就比很多人厲害了。
因為文章不宜過長,所以未全面展開講述源碼中所有細節。非常建議讀者朋友按照文中方法使用VSCode
調試 open
源碼。學會調試源碼后,源碼并沒有想象中的那么難。
最后可以持續關注我@若川。歡迎加我微信 ruochuan12 交流,參與 源碼共讀 活動,大家一起學習源碼,共同進步。
參考資料
[1]
本文倉庫 open-analysis,求個star^_^: https://github.com/lxchuan12/open-analysis.git
[2]更多參考資料可以點擊閱讀原文查看
最近組建了一個江西人的前端交流群,如果你是江西人可以加我微信?ruochuan12?私信 江西?拉你進群。
推薦閱讀
1個月,200+人,一起讀了4周源碼
我歷時3年才寫了10余篇源碼文章,但收獲了100w+閱讀
老姚淺談:怎么學JavaScript?
我在阿里招前端,該怎么幫你(可進面試群)
·················?若川簡介?·················
你好,我是若川,畢業于江西高校。現在是一名前端開發“工程師”。寫有《學習源碼整體架構系列》10余篇,在知乎、掘金收獲超百萬閱讀。
從2014年起,每年都會寫一篇年度總結,已經寫了7篇,點擊查看年度總結。
同時,最近組織了源碼共讀活動,幫助1000+前端人學會看源碼。公眾號愿景:幫助5年內前端人走向前列。
識別上方二維碼加我微信、拉你進源碼共讀群
今日話題
略。歡迎分享、收藏、點贊、在看我的公眾號文章~