open 打開(kāi)瀏覽器的過(guò)程原理示例解析
有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
前言
啟動(dòng)項(xiàng)目時(shí),在本地服務(wù)器啟動(dòng)后會(huì)自動(dòng)幫我們打開(kāi)瀏覽器,程序是如何做到呢?又是哪些代碼在起作用呢?希望通過(guò)本章節(jié)的學(xué)習(xí),達(dá)成如下目標(biāo):
- 學(xué)習(xí)程序自動(dòng)打開(kāi)瀏覽的原理
- 學(xué)會(huì)使用 Node.js 強(qiáng)大的 child_process 模塊
源碼地址:sindresorhus/open
使用
配置 webpack 的 devServer 選項(xiàng):
module.exports = { //... devServer: { open: true, }, };
告訴 dev-server 在服務(wù)器啟動(dòng)后打開(kāi)瀏覽器。將其設(shè)置為 true 以打開(kāi)默認(rèn)瀏覽器。
如果你使用的是 ue-cli
,則在啟動(dòng)命令后面添加參數(shù) --open
:
# yarn serve 不會(huì)自動(dòng)打開(kāi)瀏覽器 yarn serve # --open 參數(shù)后會(huì)自動(dòng)打開(kāi)瀏覽器 yarn serve --open
open
無(wú)論是webpack還是vue-cli,他們能夠?qū)崿F(xiàn)在瀏覽器中打開(kāi)網(wǎng)頁(yè)的功能,主要依賴 open 這個(gè)包。
看一下他的 slogan :
Open stuff like URLs, files, executables. Cross-platform.
打開(kāi)像 URL、文件、可執(zhí)行文件之類的東西。跨平臺(tái)。
它有以下優(yōu)點(diǎn):
- 這個(gè)倉(cāng)庫(kù)更新維護(hù)及時(shí)
- 豐富的參數(shù)
- 安全性
- 解決了大多數(shù) node-open 產(chǎn)生的問(wèn)題
- 跨平臺(tái)
得益于以上優(yōu)點(diǎn),這個(gè)包每周有兩千多萬(wàn)的下載量:
open 的實(shí)現(xiàn)原理
入口文件:
定位到 open
函數(shù):
const open = (target, options) => { if (typeof target !== 'string') { throw new TypeError('Expected a `target`'); } return baseOpen({ ...options, target }); };
可以看到核心實(shí)現(xiàn)邏輯在 baseOpen
函數(shù):
const path = require('path'); const childProcess = require('child_process'); const {promises: fs, constants: fsConstants} = require('fs'); const {platform, arch} = process; 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'; if (options.wait) { cliArguments.push('--wait-apps'); } // ...省略一些判斷, } else if (platform === 'win32' || (isWsl && !isDocker())) { const mountPoint = await getWslDrivesMountPoint(); command = isWsl ? `${mountPoint}c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe` : `${process.env.SYSTEMROOT}\\System32\\WindowsPowerShell\\v1.0\\powershell`; cliArguments.push( '-NoProfile', '-NonInteractive', '–ExecutionPolicy', 'Bypass', '-EncodedCommand' ); 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. options.target = Buffer.from(encodedArguments.join(' '), 'utf16le').toString('base64'); } else { // ...省略 其他情況 } if (options.target) { cliArguments.push(options.target); } if (platform === 'darwin' && appArguments.length > 0) { cliArguments.push('--args', ...appArguments); } const subprocess = childProcess.spawn(command, cliArguments, childProcessOptions); if (options.wait) { return new Promise((resolve, reject) => { subprocess.once('error', reject); subprocess.once('close', exitCode => { if (options.allowNonzeroExitCode && exitCode > 0) { reject(new Error(`Exited with code ${exitCode}`)); return; } resolve(subprocess); }); }); } subprocess.unref(); return subprocess; };
首先程序,使用 Node.js 中的 process.platform
屬性來(lái)獲取當(dāng)前操作系統(tǒng)平臺(tái)的值。字符串 'darwin' 用于標(biāo)識(shí) macOS。'win32' 則表示 windows操作系統(tǒng)了。
對(duì)不同操作系統(tǒng)進(jìn)行不同的參數(shù)組織:
macos
: 根據(jù)options
中的參數(shù)一一添加到cliArguments
變量中windows
: 主要是獲取powershell程序的路徑。- wsl:根據(jù)子系統(tǒng)掛載點(diǎn)路徑獲取
- win:根據(jù) process.env.SYSTEMROOT 獲取操作系統(tǒng)的根路徑
process.env.SYSTEMROOT
是一個(gè)由 Node.js 提供的全局變量,表示當(dāng)前系統(tǒng)的根目錄的路徑。 在 Windows 操作系統(tǒng)中,根目錄通常是 C:\Windows
。在其他操作系統(tǒng)中,此變量的值可能為空或不存在。
之后使用 Node.js child_process
模塊中的 childProcess.spawn
函數(shù),以啟動(dòng)新的子進(jìn)程并執(zhí)行命令。
它將 command
和 cliArguments
變量作為參數(shù)傳遞給 childProcess.spawn
,以及一個(gè)名為 childProcessOptions
的對(duì)象,該對(duì)象包含子進(jìn)程的選項(xiàng)。
childProcess.spawn
函數(shù)返回一個(gè)表示已生成子進(jìn)程的 ChildProcess
對(duì)象。如果 options.wait
屬性為 true
,則代碼會(huì)返回一個(gè)新的 Promise,該P(yáng)romise 對(duì)象根據(jù)子進(jìn)程的回調(diào)函數(shù)做出reject或者resolve回應(yīng)。
兩個(gè)事件:
- 'error' 事件偵聽(tīng) 器會(huì)監(jiān)控到發(fā)生的錯(cuò)誤,reject.
- 'close' 事件偵聽(tīng) 器會(huì)在退出代碼為零(或
options.allowNonzeroExitCode
屬性為true
)時(shí)使用subprocess
對(duì)象解析承諾。如果退出代碼為非零且options.allowNonzeroExitCode
屬性為false
,則 reject('錯(cuò)誤代碼')
最后使用 subprocess.unref 方法保持子進(jìn)程運(yùn)行,目的是為了使子進(jìn)程在后臺(tái)運(yùn)行。
總結(jié)
總的來(lái)說(shuō),open原理是:針對(duì)不同的系統(tǒng),使用Node.js的子進(jìn)程 child_process 模塊的spawn方法,調(diào)用系統(tǒng)的命令打開(kāi)瀏覽器。
通過(guò)本章節(jié)課程的學(xué)習(xí),學(xué)習(xí)到了如何使用 nodejs 的內(nèi)置模塊對(duì)操作系統(tǒng)類型的判斷以及childProcess創(chuàng)建子進(jìn)程的方式,更多關(guān)于open打開(kāi)瀏覽器原理的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
微信小程序Server端環(huán)境配置詳解(SSL, Nginx HTTPS,TLS 1.2 升級(jí))
這篇文章主要介紹了微信小程序Server端環(huán)境配置詳解(SSL, Nginx HTTPS,TLS 1.2 升級(jí))的相關(guān)資料,需要的朋友可以參考下2017-01-01mini?webpack打包基礎(chǔ)解決包緩存和環(huán)依賴
這篇文章主要為大家介紹了mini?webpack打包基礎(chǔ)解決包緩存和環(huán)依賴示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09JS處理數(shù)據(jù)實(shí)現(xiàn)分頁(yè)功能
這篇文章介紹了JS處理數(shù)據(jù)實(shí)現(xiàn)分頁(yè)功能的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-01-01微信小程序 底部導(dǎo)航欄目開(kāi)發(fā)資料
這篇文章主要介紹了微信小程序 底部導(dǎo)航欄目開(kāi)發(fā)資料的相關(guān)資料,微信小程序底部想要有一個(gè)漂亮的導(dǎo)航欄目,不知道怎么制作,于是百度找到了本篇文章,分享給大家,需要的朋友可以參考下2016-12-12前端JavaScript徹底弄懂函數(shù)柯里化curry
隨著主流JavaScript中函數(shù)式編程的迅速發(fā)展, 函數(shù)柯里化在許多應(yīng)用程序中已經(jīng)變得很普遍。 了解它們是什么,它們?nèi)绾喂ぷ饕约叭绾纬浞掷盟鼈兎浅V匾?。本篇文章小編九向大家詳?xì)介紹JavaScript函數(shù)柯里化,需要的小伙伴可以參考下面文字內(nèi)容2021-09-09前端算法leetcode109題解有序鏈表轉(zhuǎn)換二叉搜索樹(shù)
這篇文章主要為大家介紹了前端算法leetcode109題解有序鏈表轉(zhuǎn)換二叉搜索樹(shù)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09微信小程序 跳轉(zhuǎn)傳參數(shù)與傳對(duì)象詳解及實(shí)例代碼
這篇文章主要介紹了微信小程序 跳轉(zhuǎn)傳參數(shù)與傳對(duì)象詳解及實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下2017-03-03