在《屠龍少年終成惡龍,前端轉產品的我給前端挖了個坑》這篇文章里,有講到我是如何把我們的前端帶坑里去。同時評論區(qū)有一條評論 你那個demo.exe是用什么實現(xiàn)的?可以直接套殼現(xiàn)有的系統(tǒng)? 看起來好像是在坑外徘徊不定若有所思的樣子。因此我打算寫本文把他踹坑里去,能踹一個是一個。
不想用 electron 和 tauri ?那我們一起來寫個像 electron 的垃圾玩意吧~ 我們的目標是:前端程序員無需會三方語言就可獨立完成桌面程序,創(chuàng)建托盤程序和服務、讀寫文件、處理進程、剪貼板這些都沒有問題,預計整體體積不超過1M。
我當前已經使用 nodejs 開發(fā)一個命令行程序,這個程序的工具方式是,從網絡上獲取動態(tài)的配置,然后讀取這個配置進行啟動。啟動后就能去做其他額外的事情了,而不需要管這個程序。因為這個程序只是一個輔助工具。
但是目前有一些痛點:
每次啟動的時候我都得先找到項目目錄,然后運行 node xxx.js,然后啟動一個黑框框,然后我再最小化這個框。啟動步驟相當麻煩并且有一個不用管的窗口在任務欄,相當?shù)K眼。
有很多方法可以處理啟動問題,比如 pm2/快捷鏈接/全局安裝/制作 PKG 安裝包等。但各自有各自的問題,這里不一一列舉。
對于有一個黑框需要最小化到任務欄問題,我嘗試過使用 node child_process 的 detached=false, windowsHide=true 等參數(shù)配合 pm2 都是沒有用的,黑框還是會彈出。 假設有用,我要的也不僅如此。
我覺得這個工具不錯,我想要把這個工具發(fā)給別人使用,雖然這個工具是 nodejs 寫的,但我不希望別人還要去學習安裝 nodejs 環(huán)境。雖然這個工具是命令行啟動,并支持參數(shù)配置,但我希望像常規(guī)程序一樣,別人點擊一個圖標就能啟動,可以從界面上配置參數(shù)??梢栽诮缑嫔峡吹匠绦虻膶崟r日志,最小化之后,變成一個小圖標在任務欄,不占空間不礙眼。
那么問題來了,因為我經常用 html/css/js 畫界面,對很多前端組件庫比較熟悉,所以我打算用前端寫界面。但 js 是跑在瀏覽器里的,讀取不了保存在電腦里的配置文件,更實現(xiàn)不了托盤圖標功能,也運行不了 node 程序。
據(jù)我所知,像這種想使用前端語言開發(fā)界面,又需要與操作系統(tǒng)進行交互的功能,有不少方案。下面是我對他們的調研結果:
名稱 | 前端 | 后端 | 體積 MB | 內存 MB | 放棄原因 | 備注 |
nodegui | chromium | nodejs | 100 | 100 | 體積大 | |
miniblink49 | Chromium | nodejs | ? | ? | 體積大 | 僅支持 window |
NW.js | Chromium | nodejs | 100 | 100 | 體積大 | |
electron | Chromium | nodejs | 100 | 100 | 體積大 | |
Wails | webview | go | 8M | ? | 需其他語言 | |
Tauri | webview | rust | 1 | ? | 需其他語言 | |
Qt | 可選 | C++ | 30 | ? | 需其他語言 | |
wpf | 可選 | C# | ? | ? | 需其他語言 | 僅支持 window |
Muon | Chromium | go | 42 | 26 | 需其他語言 | |
Sciter | Sciter | QuickJS | 5 | ? | 與普通瀏覽器和 nodejs 可能有差異 | |
gluon | 瀏覽器 | nodejs | 1 | 80 | 生態(tài)小,例如沒有找到托盤圖標實現(xiàn)方式 | |
neutralino | 瀏覽器 | API | 2M | 60 | api 不多 |
當前大家比較火有 electron 和 tauri。四年前我使用過 electron 做過一個桌面劃詞程序,由于涉及到系統(tǒng)操作,所以需要安裝 node-gyp/pytohn/visual studio 等依賴來進行本地編譯,能否操作成功與 electron/node/node-ffi 等版本兼容性有很大的關系,安裝過程和 electron 的體積都給我留下了不好的印象,另外 electron 里的主進程、渲染進程、通信的一些使用上的差異,也讓我覺得不那么便利,所以我放棄 electron 。
接下來就是 tauri,它由于不打包 nodejs 和 chromium ,所以體積較小。但我看他官網上的 demo,就連啟動都 rust 代碼。
雖然代碼沒幾行,但我也是相當拒絕:說好的只使用前端語言就能寫桌面程序呢?
所以我放棄了 tauri 。原因是我真想找一個不使用三方語言就能做桌面程序的工具。我發(fā)現(xiàn) neutralino 比較貼近我的需求,但它當前還很年輕,很多 api 和示例都沒有。這相當于如果遇到了操作系統(tǒng)層面上的問題,只要他不提供 api 我就沒法操作,因為我不會寫原生代碼,所以又放棄了 neutralino 。
所以就自己做一個吧。
準備使用當前了解的一個語言做一個基于 webview 的工具,我們暫且叫 main。它加載好前端頁面,并向前端頁面注入 api 并連接上 websockets 。如果前端有什么對系統(tǒng)操作的訴求,告訴 main 即可,由 main 完成,對于前端而言,就像調用一個普通的 js 方法一樣,傳參、處理結果、完事。
語言名為 aardio ,由于“各種原因”這里不做過多敘述。后面文檔中統(tǒng)一稱其為語言。
那么為什么都去搞一個語言了不搞 rust 這些?有幾點考慮:
程序的整體架構是這樣的:
下面這個圖片演示了啟動程序時,有一個綠色的進度條,然后進入界面。
目前已過可行性驗證階段,給客戶做了一個文件管理系統(tǒng)程序,類似一個網盤,頁面由前端完成,然后文件的下載、預覽、同步這些交給 main 提供的 api。
下面這個圖片演示了在 web 中關閉程序。
對于自己的話,做了一個 ai 助手,對接的開源 ai-ui,已發(fā)給同事使用,也沒有問題。做了一個文章開關提到的助手程序,自己使用。
再次演示一下透明窗口,上面的啟動時的進度條也是使用透明窗口完成的。
演示自定義窗口標題和托盤。
程序啟動時的進度條也是使用 html 實現(xiàn)的
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>loading...</title>
<style>
body,
html {
height: 100%;
overflow: hidden;
}
body {
display: flex;
align-items: center;
justify-content: center;
}
@property --progress {
syntax: '<percentage>';
inherits: false;
initial-value: 0%;
}
.g-progress {
margin: auto;
width: 240px;
height: 10px;
border-radius: 25px;
background: linear-gradient(90deg, #0f0, #0ff var(--progress), transparent 0);
border: 1px solid #eee;
transition: .3s --progress;
}
</style>
</head>
<body>
<div class="box">
<div id="progress" class="g-progress progress-bar-striped" style="--progress: 10%"></div>
</div>
</body>
</html>
官方示例中給到的 webview 交互示例通過 external 注入到頁面的 window 上,通過此方法能讓 js 中的數(shù)據(jù)和 main 進行類型轉換(比如 js 里傳一個 number,那么到 main 里也是 number),還提供了一些可以直接啟用 main 里對象方法的操作。好用是好用,但是與 nodejs 交互的時候,沒有這種自動轉換的功能,而且示例中的 node 服務連接很慢。
為了讓 main 支持 webview 和 nodejs,并且使用方法統(tǒng)一,并且加快啟動速度,查了一些資料,發(fā)生像這種跨語言通信通常都是使用 rpc 協(xié)議完成的,有 json-rpc/http-rpc/rpc-ws 等,為了實時性更強,我選擇了 websockets 這種方式, 我 npm 社區(qū)中發(fā)現(xiàn)有 www.npmjs.com/package/rpc… 這個包可用,還兼容 node 和瀏覽器,嘗試過后選擇了它,這解決了跨語言通信問題。
另一個問題是,mian 中有很多方法是現(xiàn)成的。比如以下代碼在 main 中可以使用:
// 有一個 winform 對象
winform.hitMax() // 最大化
winform.show() // 顯示窗口
winform.hwnd // 獲取窗口句柄
winform.hitCaption() // 拖動窗口
winform.text="title" // 設置窗口標題
// ... 上百個現(xiàn)在的方法和屬性
如果我們要為 js 提供 api, 我們是每個屬性和方法都得去寫嗎?這又麻煩,代碼又還臃腫。
經過一波掙扎,我想起了使用代理這種方式去實現(xiàn),還是 js。
const obj=new Proxy(
{},
{
get: function (target, key, receiver) {
console.log(`getting ${key}!`);
return Reflect.get(target, key, receiver);
},
set: function (target, key, value, receiver) {
console.log(`setting ${key}!`);
return Reflect.set(target, key, value, receiver);
},
}
);
根據(jù) proxy,我們可以實現(xiàn)攔截到某個對象的方法調用和屬性訪問、設置等。再加上深層代理的話,像 winform.process.close() 這種有任何層方法屬性都沒有問題。
同時,在 main 中我們有這樣的代碼,來處理 proxy 攔截到的每個 key path:
我們把攔截到的 path ,比如在 js 里寫 winform.process.close(true) 的時候,我們把攔截到的 winform.process.close 和參數(shù) true 通過 rpc-ws 提供的 call 方法傳給 main,這時候 main 根據(jù) path 去動態(tài)調用函數(shù)并把參數(shù)傳進去。我們把執(zhí)行結果又丟給 call 方法返回給我們的 js 即可。
那么問題又來了,既然都實現(xiàn)了在 js 里調用方法和訪問屬性都像在寫 main 中的代碼一樣,那真的就能不能以 js 的形式去寫 main 的代碼呢?看了一天的教程,發(fā)現(xiàn)這水很深啊,約等于創(chuàng)造一門語言,怕了怕了,逃。
但是思路著要有吧?好的:
如果簡單一些呢,我們依然可以使用 proxy,實現(xiàn)操作符的攔截,從而實現(xiàn)一些簡單的加減乘除的操作。然這沒什么用啊,我們要實現(xiàn)的是比如用 js 里對 winform 對象進行遍歷之前,我們就要做一個生成器之類的東西,在生成器的每一步里,去獲取 main 里的遍歷結果。感覺上好像能實現(xiàn),實際我也不知道我在說什么。但是就算實現(xiàn)了,像這種遍歷器,頻繁的語言交互應該會消耗大量時間,感覺應該得不償失。
所以在 js 里獲得 main 中語言的編寫體驗,就不實現(xiàn)啦。如果我們真的要在 js 里寫另一種語言,我們開放一個類似 js 的 eval 的功能。它可以向 main 傳原生代碼和參數(shù)。
// 創(chuàng)建目錄
const dir=`C:/my/`
await ws.call(`run`, [
`
fsys.createDir(arg)
`, dir])
例如上面這段代碼,直接傳送目錄參數(shù) C:/my/ 到 arg,使用原生語言 fsys.createDir(arg) 去執(zhí)行。
計劃一:使用 main 去做更多的桌面 app,以此促進 main 的完善。
計劃二:為某個當前成熟的 ui 框架制定一套 css 皮膚,例如 win7 皮膚 ,例如 element-ui 樣子很 web,但應用了這個皮膚之后,整體頁面風格和控件都看起來就像原生 win7 桌面程序一樣。
計劃三:盡快完成 api 的封裝和文檔,讓前端朋友只調用指定的 js api 即可完成托盤、進程、剪貼板、IO等系統(tǒng)操作。我們封裝的 api 盡量向 neutralino 靠近,做到最小成本的遷移。等它成熟后,可以遷入,沒成熟之前我們也能自己用著。
可以幫我們封裝 api,這需要你了解 main 的語言;可以用 main 來做些小工具嘗試一下,這就是最好的幫助;可以做操作系統(tǒng)風格皮膚,等你做好了,electron 和 tauri 他們都能用,因為他只是 css;或者可以點個 star https://github.com/wll8/sys-shim
好了,餅畫了,牛吹了,坑挖了,我要去玩了。
作者:程序媛李李李李李蕾
鏈接:https://juejin.cn/post/7304538151480803366
了解一樣東西,我認為最重要的莫過于了解Ta的過去,Ta的現(xiàn)狀,以及Ta的未來.學習CSS也不外乎如此.
通過網絡學習一樣新東西,最大的困惑就是----網上的文章,寫得非常好.但就是碎片化,不系統(tǒng).而且還有個情況就是:有些問題,大神們覺得很簡單,不屑一提或者毫無意識的內容或知識,對于那些剛入門的人因為不知道,也沒人點播,有可能會在這個問題上迷茫很久.這一點我體會頗深.
經驗分享:入門階段不要管好那么多細節(jié),記憶之類的東西,盡快地入門才是最重要的.其實入門,無非就是對所學內容形成一套概念,知其然,所以然.大概的就成了.
一開始不要在W3C網站上學習,因為內容太多,雖然很系統(tǒng),但是我一點都不相信你會有耐心全部看下來!
一開始學習,首先找些小的實戰(zhàn)項目看看,小編上方推薦的裙里就有免費的網課做小項目的課堂,里面講的非常細,一開始可能有一些不是很懂,但是你只要堅持聽完一節(jié)網課,學習到老師們的代碼風格和做項目的思路,對你的幫助是非常大的。
我覺得最好的方式是實踐出來的。如果你沒有一個網站或者一個服務器等等之類的。你可以用Github去做一個自己的博客,雖然是靜態(tài)的但是也是夠的。
可以按下面的步驟來學習,一個網站正常情況下由三部分組成:
1. Head 頂部導航
2. Content 內容
3. Footer 頂部導航
對于Head來說有不同的玩法,而首先你需要學會的是ul li a 這三個基礎的HTML,而對于大部分前端程序員來說。要手動寫一個水平導航可以說是一個入門的標志,還有豎直的導航,浮動的導航等等。
接著你還會遇到的問題是如何處理底部的footer,讓他一直在最下面的。而不會亂跑,
大概需要的過程
1. 學會分析一個網頁的結構
2. 理解每部分的原理
3. 手動寫CSS
小編就分享到這里了,關注小編,可以看小編的更多優(yōu)質文章。
取一個網頁,我們需要了解一下網頁的結構,如果想要深入學習,建議看一下《網頁設計與制作》,這本書講述較為詳細,推薦閱讀。
網頁的三大組成部分——HTML、CSS、JavaScript,如果把網頁比作一個人的話,HTML相當于骨架,JavaScript相當于肌肉,而CSS相當于皮膚,三者結合起來形成一個完整的網頁。
網頁基本結構
HTML(Hyter Markup Language 超文本標記語言),主要是通過HTML標記對網頁中的文本、圖片、聲音等內容進行描述。HTML提供了很多種標記,如段落標記(p標簽)、圖片標記(img標簽)、視頻標記(video標簽)等,網頁中需要定義什么內容,就可以用相應的標記描述。
首頁源代碼
從圖可見,網頁內容是通過HTML標記(圖中帶有“<>”的符號)描述的,整個網頁由各種標簽嵌套而成。
HTML其實是一個純文本文件,只是網頁的一個骨架,只有HTML的網頁其實并不美觀,為了讓網頁看起來更好看,我們需要借助CSS。
CSS(Cascading Style Sheets 層疊樣式表),“層疊”指的當HTML中引用了數(shù)個樣式文件,并且樣式發(fā)生沖突時,瀏覽器能依據(jù)層疊順序處理,“樣式”指的是網頁文字、圖片等的大小、顏色、排列等格式。
body {
font: 12px/1.14 SF Pro Display,PingFang SC,Hiragino Sans GB,Microsoft YaHei,WenQuanYi Micro Hei,Helvetica Neue,Arial,sans-serif;
-webkit-font-smoothing: antialiased;
color: #333;
outline: 0;
}
font、color、outline即樣式設置
CSS的位置很靈活,即可以嵌入在HTML文檔中,也可以時一個單獨的外部文件,如果是獨立的文件,則必須以.css為擴展名,使用link標簽引入文件。上圖CSS顯示為內嵌方式,一般集中放在HTML文檔頭部(<head>標簽內)。
JavaScript,簡稱JS,是一種腳本語言,可使網頁具有交互性(HTML和CSS制作的網頁是靜態(tài)網頁),js腳本語言使得用戶與信息是一種實時、動態(tài)、交互的頁面功能,如頁面效果切換、動畫效果、頁面游戲等,它還可以控制cookies,包括創(chuàng)建和修改等。
JavaScript通常也是以單獨文件形式加載,后綴為js,在HTML中通過script標簽引入,如<scrip src="jquery-2.1.0.js" type="text/javascript"></script>。
我們可以把互聯(lián)網看作一張大網,而爬蟲(即網絡爬蟲)就是在網上爬行的蜘蛛,把網的節(jié)點比作一個個網頁,爬蟲爬到一個節(jié)點就相當于訪問了該頁面,獲取了其信息,節(jié)點之間的線就像與網頁與網頁之間的鏈接關系,蜘蛛可順著節(jié)點連接繼續(xù)爬行到下一個節(jié)點,即通過一個網頁爬取另一個網頁,這樣整個網的節(jié)點都可以被爬取到了。
那么爬蟲的基本過程可以簡單概述為:獲取網頁——提取信息——保存數(shù)據(jù)。
靜態(tài)網頁:用HTML代碼編寫的頁面,每個網頁都有一個固定的URL,加載速度快,編寫簡單,但可維護性差、交互性差,不能根據(jù)URL靈活多變地顯示內容。
動態(tài)網頁:以數(shù)據(jù)庫技術為基礎,可以大大降低網站維護的工作量,它可以動態(tài)解析URL參數(shù)的變化,關聯(lián)數(shù)據(jù)庫并動態(tài)呈現(xiàn)不同的頁面內容,可以實現(xiàn)用戶登錄與注冊功能。
*請認真填寫需求信息,我們會在24小時內與您取得聯(lián)系。