如何使用前端技術開發一個桌面跨端應用

本文將會講述一個完整的跨端桌面應用 代碼畫板 的構建,會涉及到整個軟件開發流程,從開始的設計、編碼、到最後產品成型、包裝等。

本文不僅僅是一篇技術方面的專業文章,更會有很多產品方面的設計思想和將技術轉換成生產力的思考,我將結合我自己的使用場景完全的講解整個開發流程,當然涉及到設計方面的不一定具有普遍實用性,多數情況下都是我自己的一些喜好,我只關心自己的需求。

同時本文只從整體上講思路,也會有個別的技術細節和常規套路,有興趣的也可以直接去 github 上看 源碼,文章會比較長,如果你只想知道一些拿來即用的「乾貨」,或許這篇文章並不是一個好的選擇


一、定位需求

事情的起因是這樣的,因爲我們內部會有一些培訓會議。會經常現場演示一些代碼片段。比如說我們講到 React 的時候會現場寫一些組件,讓大家能直觀的感受到 React 的一些功能。

但是通常由於條件所所限,會議總會遇到一些意外。比如斷網、投影分辨率低看不清文字等

起初我們用的是在線版的 codepen,但是感覺並不是那麼好用。比如不能方便的修改字體大小,必須要在連網的情況下才能使用。另外它的 UI 設計不是很緊湊,通常我們展示代碼的時候都投影是寸土寸金的,應該有一個簡潔又不失功能的 UI 界面,能全屏展示…

於是我解決自己實現一個這樣的輪子,那麼大概的需求目標是有了:

  1. 離線可用
  2. 可以改變界面字體大小
  3. 更加簡潔的 UI

二、整體設計

應用風格

代碼畫板解決的是 臨時性 的一些 演示代碼 的需求,所以它的本質屬性是一個拿來即用的工具,它不應該有更復雜的功能,比如用戶登錄、代碼片段的管理等。這些需求不是它要解決的。代碼畫板會提供一個簡單的導出成 HTML 文件的功能,可以方便用戶存儲整個 HTML 文件。

既然是用來演示代碼的,那麼它的界面上應該只有兩個東西,一個是 代碼,一個就是 預覽。像代碼/控制檯切換的功能都做成 tab 的形式,正常情況不需要讓他們展示出來。像 codepen 那樣把所有的代碼編輯器功能都展示出來我認爲是不對的。

codepen-demo

codepen 的界面給人感覺非常複雜,有很多功能點。當然我並不是在批評它,codepen 做爲一個需要商業化運營的軟件,勢必會做的非常複雜,這樣才能滿足更多用戶的需求。然而程序員寫軟件則可以完全按照自己的想法來,哪怕這個應用只給自己一個人用呢。

hello-code-sketch

桌面應用的設計

桌面應用的設計和 web 界面的設計還是有些細微區別的,同樣的基於 electron 的應用,有的應用會讓人感覺很「原生」,有的則一眼就能看出來是用 CSS 畫的。我在設計代碼畫板的時候也儘量向原生靠近,避免產生落差感。比如禁用鼠標手型圖標、在按鈕或者非可選元素上禁止用戶選擇:

cursor: default;
user-select: none

因爲實際上用戶在使用一款應用的時候感性的因素影響佔很大一部分,比如說有人不喜歡 electron 可能就是因爲看到過 electron 裏面嵌一個完整的 web 頁面的操作,這就讓人很反感。但是這不是 electron 的問題,而是應用設計者的問題。

應用標識的設計

說實話應用 logo 設計我也是業餘水平,但是聊勝於無。既然水平不行,那就儘量設計的不難看就行了。可以參考一些好的設計。我用 sketch 畫出 logo 的外形,sketch 有很多 macOS 的模塊可以從網上下載下來,直接基於模板修改就可以了。

代碼畫板主要的界面是分割開的兩個面板,左邊是代碼,右邊是預覽。所以我就大概畫了一個形狀

code-sketch-icon

這個 logo 有個問題就是線條過多,小尺寸的時候看不清楚。這個問題我暫時先忽略了,畢竟我還不是專業的,後續有好的創意可以再改

默認設置

代碼畫板也 不會有 設置界面,因爲常用的設置都預定義好了,你不需要配置。頂多改變下代碼字體的大小。使用編輯器的通用快捷鍵 command++/- 就解決了,或者插入三方庫,直接使用編輯器的通用命令快捷鍵 command+p 調出。我們的思路就是把複雜的東西幫用戶隱藏在後臺,觀衆只需要關注演員臺上的一分鐘,而不必瞭解其它細節。

快捷鍵/可用性

由於代碼畫板的界面非常簡單,在一些細小的必要功能就得添加一些快捷鍵。比如:切換 HTML/CSS/JS/Console 代碼編輯器,我在每個 tab 上加了數字標號,暗示它是有順序有快捷鍵的,而且這個切換方式和 Chrome tab 切換的邏輯一致,使用 command+數字 就可以實現,萬一還是有人不會用的話,可以去看幫助文檔。裏面有所有的快捷鍵。

cs-tab

界面中間的分割條可以自定義拖動,雙擊重置平分界面

cs-spliter

剛開始的時候我把每個 tab 頁籤都分割成單獨的面板,因爲我覺得這個能拖動自定義面板大小的交互實在是太爽了,忍不住想去拖動它。但是後來想想,其實並沒有必要,我們寫代碼時應該更專注於代碼本身,如果只有兩個面板,那麼這個界面無論是認知還是使用起來就沒有任何困難。

因爲我們並不需要把一堆的功能的界面摔給用戶,讓他們自己去選擇。

三、技術調研

實現控制檯

通過使用流行的幾款在線代碼運行工具,我發現他們有一個共同的問題:控制檯很難用。無法像 Chrome Console 那樣展示任意類型的 JS 值。比如我想 log 一段嵌套的 JS 對象:

console.log({ a: { b: 1, c: { d: [1, 2, 3] } }})

大多數都展示成這樣的:

[object Object] {
  a: [object Object] {
    b: 1
  }
}

Chrome 是這樣的:

chrome-console

顯然 Chrome 控制檯中更直觀。所以我們需要在前面的基礎上加一個需求,即:實現一個基於 DOM 的日誌展示界面(無限級聯選擇)

日誌界面應該有下面這些功能:

  1. 展示任意 JS 類型的數據
  2. Primitive 類型的數據顯示不同的顏色(number - 藍色,string - 綠色)
  3. Object 類型默認摺疊起來,點擊按鈕展示子級,屬性過多需要展示縮略信息
  4. 數組前應該有長度標記
  5. 能展示 JS 運行時的報錯 Error 信息

集成現代化的前端框工作流

現代化的前端寫頁面肯定不是 HTML/CSS/JS 一把梭了,至少應該有 Sass/Babel 的支持吧。

Sass 嵌套能讓你少寫很多選擇器,當然 Less 也可以,但是在我們的這個應用裏面區別不大,一般來說臨時性的寫一些代碼很少會用到它們的細節功能。有 變量 和 選擇器 嵌套就夠了

Babel 主要是解決了寫 React 的問題,不用再安裝一大堆的構建工具了,直接使用 UMDReact/ReactDOM 就可以了,而且 electron 內嵌的 chromium 也支持了 es6 的 class 寫法,實際上 Babel 主要的目的還是用來轉譯 JSX

注意這裏是有一個我認爲是 剛性 的需求,比如臨時忽然有個想法,或者想驗證一段代碼的話,正常情況是使用你的編輯器,新建 demo.html/demo.css/demo.js 等這些操作。但是這些動作太浪費時間了。有了代碼畫板以後,直接打應用就可以開始 coding 了,真正能做到開箱即用。

提高程序的擴展性

我們在寫 demo 頁面時通常是要引用很多第三方類庫的,比如:Bootstrp/jQuery 等。我希望有一種方法可以方便的引用到這些庫,直接把庫文件的 link/script 標籤插入到代碼畫板的 HTML 中,但是前端框架真的是太多了,又不能一個個去扣來寫死到頁面,就算是寫死了隨着框架版本的升級,可能就無法滿足我們的需求。

以前寫頁面時經常會用到 bootcdn,無意中發現它提供了相關 API,可以直接拿來使用。接下來就得想辦法讓用戶通過界面選擇即可。

這個 API 有三層數據結構:庫 - 版本 - 資源鏈接。這個功能要用界面來實現肯定會非常臃腫,界面上可能會放很多按鈕。這就違背了「更簡潔」的需求目標。

這時就得參考下我們經常使用的一些軟件是如何解決 簡潔性 和 功能性 需求之間的矛盾問題的,我比較喜歡 Sublime Text 的一些界面設計,Command Palette 是我經常使用的,所以我決定再模擬一個 Command Palette 來實現插入第三方庫的需求。而且重要的是這個 Command Palette 並不一定只用來實現這一個功能,或者後期會有一些別的功能需要添加,那這個 Command Palette 也是個很好的入口。

Command Palette

使用 electron 實現桌面應用

實現離線可用很多方法,比如使用 PWA 技術。但是 PWA 並不能給我帶來一種原生應用的那種可靠感,相反 electron 剛好可以解決我的顧慮。同時它可以把你的應用打包成各個平臺(macOS/Window/Linux)的原生應用。唯一的缺點就是安裝包確實很大,一般來講一個 electron 應用 安裝完 至少要 100 多兆,不過我覺得還能接受,畢竟硬盤存儲現在已經很廉價了。

有人可能對 electron 有抗拒,覺得 electron 應用太龐大、佔系統資源什麼的,不過我們做的這個應用並不需要常駐系統,臨時性的使用一下,用完就關閉,正常寫生產環境的代碼肯定還是要換回 編輯器/IDE 的。同時因爲 electron 降低了寫桌面應用的門檻,確實有很多人把一個完整的在線的網頁直接嵌進去,這也是有問題的。

electron 還有一個好處,因爲它完全基於 HTML/CSS/JS 來實現 UI(可以使用 Chrome only 的一些新功能),那我們理論上可以在做桌面應用時順手把 web 應用也做了。這就可以同時支持各個系統下的原生應用,並且有 web 在線版本。如果你不願意使用原生應用,直接登錄 web.code-sketch.com 使用在線版也沒是一種選擇。這樣就使得我們的應用具有真正的 跨端 能力。

由於我們團隊都使用了 macbook,所以我優先支持 macOS 的開發,另外 macOS Mojave 的系統級別的暗色主題我也比較喜歡,剛好實現支持 mojave 暗色主題這個需求也做上。

三、框架的選擇

大方向確定了,像框架選擇這個就簡單了,基於 electron 的應用,需要你區分開 render/main process 來選擇。

Render process

渲染進程 就是 electron 中界面的實現部分 ,一般來說就是一個 webview,選自己喜歡的框架即可。我使用 React 來實現界面。樣式方面就不再使用框架了,因爲我們的界面原則上沒有複雜的元素,直接手寫 CSS,300 行內基本上就可以解決問題。可能有人會覺得這不可能,實際情況是當你寫樣式只跑在 Chrome 裏面的時候那感覺完全爽到飛起,CSS variable/flex/grid/calc/vh/rem 什麼的都可以拿來用,實現一個功能的成本就降低了很多。

我使用 Codemirror 來做爲主界面的代碼編輯器,Monaco 也是一個好選擇,但是它有點過於龐大了,而且如果想要自定義功能得自己寫很多實現

主界面上的分割組件,使用了 React-split

Main process

主進程 就是 electron 應用程序的進程,主要的區別在於主進程中可以調用一些與原生操作系統交互的 API,比如對話框、系統風格主題等。並且有 node 的運行時,可以引用 NPM 包。當然渲染進程也可以有 node 支持,但是我建議渲染進程中就只放一些純前端的邏輯,這樣的話方便後期把應用分離成 web 版

因爲我們要集成 Sass 編譯功能,如果你也經歷過 node-sass 的各種問題,那就應該果斷選擇 dart-sass — 使用 dart 實現,編譯成了原生的 JS,沒有依賴問題。dart-sass 我放在了 main process 中,因爲我試過放在 render process 中會有各種報錯。如果 web 端要實現這個功能就需要其它的解決辦法了,比如做成一個 http 服務,讓 web 調 http 服務。

Babel 的話我是放在了 渲染進程 中以 script 標籤的方式調用,這樣即使在 web 端 Babel 編譯也是可用的。

總之如果你使用 electron 構建應用並且引入的第三方 NPM 包可以 支持 運行在客戶端(瀏覽器)上,那就儘量把包放在渲染進程裏面。

構建工具

我使用 Parcel 來構建 React 而不是 Create React App。後者用來寫個小應用還可以,稍微大一點的,需要定製化一些東西你就得 eject 出來一大堆 webpack 配置文件,即便是我已經用 webpack 開發過幾個項目了,但是說實話我還是沒用會 webpack。寫 webpack 配置的時間足夠我自己寫 npm script 來滿足自己的需求了。

原生應用打

使用 electron-builder 來打包到平臺原生應用,並且如果你有 Apple 開發者賬號的話應用還可以提交到 AppStore 上去。

我目前的打包參數是這麼配置的:

{
    "build": {
        "productName": "Code Sketch",
        "extends": null,
        "directories": { "output": "release" },
        "files": [
            "icon.icns",
            "main.js",
            "src/*.js",
            "所有需要的文件",
            "package.json",
            "node_modules/@babel",
            "node_modules/sass"
        ],
        "mac": {
            "icon": "icon.icns",
            "category": "public.app-category.productivity",
            "target": [ "dmg" ]
        }
    }
}

在你的 package.json 中添加 build 字段,productName, directories 這些按自己需要更改即可

四、分離開發環境

區分開開發環境

代碼畫板項目開過過程中涉及兩個關鍵環境

  1. Parcel 構建環境(渲染進程):Parcel 可以爲你提供一些現在 JS 的轉譯工作,因此你可以放心使用例如 ES6 的 JS 新特性
  2. Node.JS 運行環境(主進程+渲染進程):這個取決於你的 electron 版本中集成的是 node 版本,比如:Node 10 中就沒有 ES Module,這意味着你如果要在 electron 主進程 是無法識別 import 這樣的語句的,但是渲染進程由於你使用了 Parcel 編譯,則無需考慮

這裏溫馨提示下:想要做到 electron 中的 渲染進程與主進程之間共享 JS 代碼是非常困難的。就算是有辦法也會特別的彆扭,我的建議是儘量分離這兩個進程中的代碼,主進程主要做一些系統級別的 API 調用、事件分發等,業務邏輯儘量放在渲染進程中去做

如果非要共享,那建議單獨做成一個 NPM 包分別做爲主進程運行時依賴,和渲染進程的 Parcel 編譯依賴,唯一的缺點就是實際上共享的代碼會有兩份。

渲染進程中調用 node API 可能會和 Parcel 打包工具衝突,一般在調用比如文件模塊時,可以加上 window.require(‘fs’) 這樣就可以兼容兩個環境:

get ipc() {
    if (window.require) {
        return window.require('electron').ipcRenderer
    } else {
        return { on() {}, send() {}, sendToHost() {} }
    }
}
this.ipc.send('event', data)

這樣的話你在瀏覽器端調試也不會產生報錯。一般情況下,建議當你用渲染進程中的 JS 引用(require)包的時候都加上 window. 前綴就可以了。因爲渲染進程中 window 是全局變量,調用 require 和調用 window.require 是等價的

開發流程

通常在測試的時候應用會調用一些 electron 內置的系統級別 API,這部分調用通常需要啓動 electron,但是有時候只有渲染進程中 UI 界面上的改動,就不用再啓動 electron 了,直接在瀏覽器裏面測試即可。使用 Parcel 運行一個本地的服務,這樣就可以在瀏覽器裏面調試頁面。整個開發過程需要兩個命令(NPM Script):

啓動 Parcel 編譯服務器

"scripts": {
    "start": "./node_modules/.bin/parcel index.html -p 2044"
}

調試 electron 原生功能,注意設置 ELECTRON_START_URL

"scripts": {
    "dev": "ELECTRON_START_URL=http://localhost:2044 yarn electron",
}

技術難點

整個應用只有兩個功能是需要我們自己寫代碼實現的:日誌控制檯,Sublime 命令行。我們分別來分析下這兩個模塊的難點。

日誌控制檯 的難點在於,我們需要打印任意類型的 JS 值。如果你對 JS 瞭解比較多的話自然會想到在 JS 中所有的東西都是 對象,即 Object,那麼實際上當你想打印一個變量的時候,其實你只要把整個 Object 遞歸的遍歷出來,然後做成一個無限級的下拉菜單就可以了。看起來大概想下面這樣:

logger

Sublime 命令行 實際上開發起來還是比較簡單的,使用 React 很簡單就實現了功能,比較麻煩的是調用 bootcdn 的接口,過程中我發現接口返回數據量還是挺大的,有必要做上一層 localStorage 緩存,加快二次打開速度。

然而在使用的過程中你會發現當我想插入一個前端庫需要很多操作,因爲有 三級選擇:庫-版本-CDN 鏈接。雖然這個流程解決了 所有用戶 的使用問題,但是卻損害了 大部分 用戶的體驗。這個時候插入一個常用庫的成本就很高了,所以我們就要加上一些快捷入口,來實現一鍵插入流行框架。

sublime-commend-p

我們寫代碼的思路是滿足所有用戶的使用需求,但是一個好產品的思路是先滿足大多數用戶(80%)的常規需求,再讓其餘的用戶(20%)可以有選擇

還有一個問題比較典型就是 React 這類框架在渲染大列表並且進行過濾(關鍵字查詢)時性能的問題。注意這個性能問題 並不是 引入框架產生的,真正的原因是當你渲染的 HTML 節點數以千計的時候,批量操作 DOM 會使得 DOM Render 特別慢。

所以說當我們遇到性能問題的時候應該去查找問題的根源,而不是停留在框架使用上,實際上在 DOM 操作這個層面來講 jQuery 提供了更多的性能優化,比如自身的緩存系統,以致於當你在使用的時候很難發現有性能問題。但是在類 React 框架中它們框架本身的重點並不在於解決你應用的性能問題。

類似我們上面講到的,實際上 jQuery 幫助你屏蔽了很多舞臺背後的東西,以致於你可以不用操心技術細節,你甚至可以把 jQuery 當做一個 產品 來使用,而類 React 框架你卻要親力親爲的用他來設計你的代碼。

話題再轉回性能問題。這時候需要我們去實現一個類似於 react-window  的功能,讓列表元素根據滾動按需加載。這可能是一種通用的解決大列表加載的方案,但是我的解決方法更粗暴,因爲我們的下拉過濾功能使用時用戶只關注 最佳的匹配項 即可,後面匹配程度不高的項可以直接限制數量裁剪就行了嘛。很少有用戶會一直滾動到下面去查找某個選項,如果有,那就說明我們這個匹配做的有問題。

slice() {
    const idx = (this.props.itemsPerPage || 50) * (this.state.activeFrame + 1)
    return this.props.items.slice(0, idx)
}

整個匹配篩選的狀態大概是這樣的:

this.state = {
    // 當前第N步選擇
    step: 0,
    // 當前步驟數據
    items: [],
    // 是否顯示
    active: false,
    // 當前選中項
    current: {},
    // 過濾關鍵字
    keyword: ''
}

這個 items 是當前步驟的所有數據,實際上我們這個組件是支持無限級的擴展的,那麼我們通過組件的 props 傳入所有層級的數據,然後持久存儲在內存中。這個 所有層級的數據 是數據結構層面的,實際上它可能是通過異步接口獲取的。

再來看看我們組件提供的所有 props

static defaultProps = {
    step: 0,
    active: false,
    data: [[]],    // 無限層級數據 [[], [], [], ...]
    // 數據的主鍵,用於鉤子函數返回用戶選擇的結果集
    pk: 'id',

    autoFocus: true,
    activeCls: 'active',
    delay: 300,
    defaultSelected: 0,
    placeholder: '',
    async: false,
    alias: [],
    done: () => {}
}

這些數據都可以通過組件的 props 傳入,這就意味着我們的這個組件纔是真正的組件,別人也可以使用這樣的功能,而他們並不用在意裏面的細節,使用者只需要做好類似調用自己接口的這種業務邏輯。

組件的調用大概是這樣的:

<CommandPalette step={0}
    key="CommandPalette"
    async={injectData}
    done={this.done.bind(this)}
    alias={alias}
    aliasClick={this.aliasClick.bind(this)}
    data={[ [], [], [] ]}

async 這個 props 實際上是一個異步調用的鉤子方法,它會回傳給你組件上當前操作的相關數據狀態,通過這些數據使用者就可以按自己的需求在不同的步驟上調用不同的方法

export const injectData = (step, item, results, cb) => {
    const API = 'https://api.bootcdn.cn/libraries'

    if (step === 0) {
        fetchData(`${API}.min.json`)
            .then(processLibraryData)
            .then(cb)
    } else if (step === 1) {
        // ...
    } else if (step === 2) {
        // ...
    }
}

另外關於 React 這裏安利下自己翻譯過的一個教程:React 模式,裏面講到 18 種短小精悍的 React 模式案例,非常簡單易懂。

還有一個小竅門,我們在適配暗色主題時,傳統的方法是直接寫兩套主題 CSS 代碼,實際上我們要使用 CSS Variable 的話完全沒必要生成兩套了,背景色,字體都做成 CSS 變量,切換的時候只需要動態往頁面插入更新過的 CSS 變量值即可

系統的一些參數想直接傳給渲染進程也是比較麻煩的,我的做法是直接從主進程中的 loadUrl 方法上以 queryString 的方式傳到渲染頁面的 URL 上

const query = {
    theme: osTheme,
    app_path: app.getAppPath(),
    home_dir: app.getPath('home')
}

mainWindow.loadURL(process.env.ELECTRON_START_URL ? url.format({
    slashes: true,
    protocol: 'http:',
    hostname: 'localhost',
    port: 2044,
    query
}) : url.format({
    slashes: true,
    protocol: 'file:',
    pathname: path.resolve(app.getAppPath(), './dist/index.html'),
    query
}))

像程序運行時的一些參數(比如程序的根目錄)也可以這麼動態傳過去,而且還有一個好處就是你甚至可以在渲染進程中測試與這些參數相關的功能。

五、宣傳

demo 視頻錄製

我會把最終所有功能的使用方法錄製成一個視頻,萬一有人不不想下載你的軟件,只是要了解一下,這就是個很好的方法。我同時上傳到了 Youtube 和 bilibili 這兩個平臺,其它的都有廣告就沒必要了

使用 Quicktime Player 即可,錄製完使用 iMovie 轉碼成兩倍速率的 mp4。如果你有興趣還可以加上一段音樂什麼的,讓視頻看起來更靈動

域名申請

域名是一個能讓用戶記住你產品的方法,如果你做的是一個成型的產品,那就一定要申請個域名。

我總是有這樣的體驗,有的時候看到一個非常不錯的產品但由於當時沒需求就忽略了,想起來或者突然有需求的時候缺記不起來名字叫什麼了。

事實上代碼畫板最開始我給他起的名字是 code playground,這個更直觀,但是名字太長,而且想用到的一些域名呀、Github 名、NPM 包都被註冊了。

想來想去就換成了 code sketch,這和符合我們的設計初衷,即:一邊是代碼,一邊是效果/草圖

域名申請我一般會上 Godaddy,不用備案,.com 域名一年 ¥65.00,然後 DNS 服務器轉到了 cloudflare,後續域名也會直接轉到 cloudflare。因爲據說以後在 cloudflare 上續費域名最便宜

網站搭建

宣傳網站直接放在 github pages 上,做個自定義域即可,實在是太方便了。而且還有 SSL 支持,Github 真的是業界良心

web 版的代碼畫板,由於我們把渲染進程中的代碼分離開發,所以直接把 parcel 打包出來的靜態文件也做成 github pages 就可以了,爽歪歪,網站就等於一分錢不花了。後續做一些 web 版的增強功能時,可以做成前後端分離的 http 服務,這就是後話了

加入 Google analytics 代碼

GA 可以讓你瞭解網站的用戶分佈情況,清楚的知道網站訪問的波動。比如說你把自己的鏈接放到某個網站上分享了,GA 裏面就能看出來所有的推薦來源和波動,對於運營來說是非常有必要的

廣告語

這個我還真想了好長時間,基於我對於代碼畫板的定義,我覺得它應該是一個我們有一個想法的時候需要快速去實現一個 demo 的地方,想來想去就定了一段看起來文鄒鄒的話,雖然聽名字根本不知道它是幹啥用的,但是沒關係,程序員寫東西就是要有個性,因爲我的受衆只有自己。

First place where the code was written...
一個你最初寫代碼的地方...

六、彙總使用到的庫與工具

麻雀雖小,五臟俱全。我們來看下代碼畫板總共用到了多少東西:

  • 框架/庫

    • electronjs
    • react
    • babeljs
  • NPM 模塊

    • codemirror 及其插件
    • react-split
    • sublime-command-palette
  • 打包/工具

    • parceljs
    • electron-builder
    • bootcdn
  • 設計與素材

七、結語總結

實事上我自己的開發這個應用的時候並沒有嚴格按照這篇文章的順序執行,而是想到一些實現一些,可能一個功能實現了後來覺得不好又幹掉了,是不斷的取捨、提煉的結果。

開發中我也不斷的問自己這個功能是否有必要,如果可有可無那是不是可以去掉,這樣才能使得用戶更加關注於代碼本身。

整個開發過程中自己實現的功能模塊並不多,只有控制檯、命令行窗口是自己實現的,其它的功能基本上都是靠社區現有的工具庫來完成的,從這一點來說前端技術的生態還是挺好的。這使得當我從整體上構思一個產品時我不必在意那些細節,雖然過程中還是能感覺到前端工具/庫的割裂感,但是整體而言還是向好的,畢竟工具對於開發者只是一種選擇的。

八、引用

  1. https://github.com/keelii/code-sketch
  2. http://www.tweaknow.com/appicongenerator.php
  3. http://benschwarz.github.io/gallery-css/
  4. https://addyosmani.com/blog/react-window/
  5. https://github.com/keelii/reactpatterns.cn

原文:https://mp.weixin.qq.com/s/Lbnx0aYdRa5iDhOkCgEWjg

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章