在沒有框架的情況下設計和構建漸進式 Web 應用程序(第 3 部分)

已發表: 2022-03-10
快速總結 ↬本文總結了一個由三部分組成的系列,關於使用 vanilla JavaScript 設計和編寫基本 Web 應用程序的試驗和磨難。 在第一部分中,我們介紹了原因,第二部分主要討論瞭如何進行,這部分最後通過研究項目是如何結束的以及從經驗中學到了什麼來結束。

回到本系列的第一部分,我們解釋了為什麼會出現這個項目。 即渴望了解如何使用原生 JavaScript 製作小型 Web 應用程序,並希望讓非設計開發人員稍微從事他的設計工作。

在第二部分中,我們採用了一些基本的初始設計,並通過一些工具和技術選擇來啟動和運行。 我們介紹了設計的某些部分如何以及為何發生變化,以及這些變化的後果。

在這最後一部分中,我們將介紹將基本的 Web 應用程序轉變為漸進式 Web 應用程序 (PWA) 並“交付”應用程序,然後再查看通過使簡單的 Web 應用程序輸入/輸出獲得的最有價值的經驗教訓:

  • JavaScript 數組方法的巨大價值;
  • 調試;
  • 當你是唯一的開發者時,你就是另一個開發者;
  • 設計就是開發;
  • 持續的維護和安全問題;
  • 在不失去理智、動力或兩者兼而有之的情況下從事業餘項目;
  • 運送一些產品勝過不運送任何產品。

因此,在學習經驗教訓之前,讓我們看看如何將用 HTML、CSS 和 JavaScript 編寫的基本 Web 應用程序轉變為漸進式 Web 應用程序 (PWA)。

就製作這個小型 Web 應用程序所花費的總時間而言,我估計大概需要兩到三週。 然而,由於它是在晚上以 30-60 分鐘的時間完成的,從第一次提交到我在 2018 年 8 月上傳我認為的“1.0”版本實際上花了大約一年的時間。因為我得到了應用程序'功能完成”,或者更簡單地說,在我滿意的階段,我預計會有一個大的最後推動。 你看,我沒有做任何事情來將應用程序變成一個漸進式 Web 應用程序。 事實證明,這實際上是整個過程中最簡單的部分。

跳躍後更多! 繼續往下看↓

製作漸進式 Web 應用程序

好消息是,在將一個基於 JavaScript 的小應用程序轉變為“漸進式 Web 應用程序”時,有很多工具可以讓生活變得輕鬆。 如果您回想本系列的第一部分,您會記得成為 Progressive Web App 意味著滿足一組標準。

要了解您的 Web 應用程序如何衡量,您的第一站可能應該是 Google Chrome 的 Lighthouse 工具。 您可以在“審核”選項卡下找到 Progressive Web App 審核。

這是我第一次通過它運行時 Lighthouse 告訴我的。

Chrome 開發工具顯示 Progressive Web App 結果為 55/100
Progressive Web App 的初始分數並不高。 (大預覽)

一開始,In/Out 的 Progressive Web App 的得分僅為55100 。 然而,我在不到一個小時的時間裡就把它從那裡帶到了100100

提高分數的權宜之計與我的能力無關。 只是因為 Lighthouse 準確地告訴了我需要做什麼!

必要步驟的一些示例:包括一個manifest.json文件(本質上是一個提供有關應用程序元數據的 JSON 文件),在頭部添加一大堆元標記,將 CSS 中內聯的圖像切換為標準 URL 引用圖像,並添加一堆主屏幕圖像。

製作許多主屏幕圖像、創建清單文件和添加一堆元標記可能在一小時內完成很多工作,但有一些很棒的 Web 應用程序可以幫助您構建 Web 應用程序。 這多好啊! 我使用了 https://app-manifest.firebaseapp.com。 向它提供有關您的應用程序和徽標的一些數據,點擊提交,它會為您提供一個包含您需要的所有內容的 zip 文件! 從那裡開始,這只是複制和粘貼的時間。

由於缺乏知識,我推遲了一段時間的事情,比如服務工作者,也很容易添加,這要歸功於大量的博客文章和專門針對服務工作者的網站,比如 https://serviceworke.rs。 有了 Service Worker,這意味著應用程序可以離線工作,這是漸進式 Web 應用程序的必要功能。

雖然與使應用程序成為 PWA 沒有嚴格的關係,但 Chrome 開發工具的“覆蓋”選項卡也非常有用。 在幾個月來對設計和代碼進行瞭如此多的零星迭代之後,清楚地表明哪裡有冗餘代碼是很有用的。 我發現一些舊函數在代碼庫中亂扔垃圾,我只是忘記了!

簡而言之,在完成了 Lighthouse 審計建議後,我感覺自己就像老師的寵物:

在 Lighthouse Progressive Web App 審核中獲得 100/100
Lighthouse 通過準確告訴您要更改的內容來輕鬆獲得高分。 (大預覽)

現實情況是,將應用程序變成一個漸進式 Web 應用程序實際上非常簡單。

隨著最後的開發工作結束,我將這個小應用程序上傳到我網站的一個子域,就是這樣。

回顧展

自從停止開發我的小 Web 應用程序以來已經過去了幾個月。

從那以後的幾個月裡,我一直在隨意使用該應用程序。 現實情況是,我所做的大部分團隊運動組織仍然通過短信進行。 然而,這個應用程序絕對比寫下誰進出誰比每場比賽晚上找一張紙更容易。

因此,事實是,它幾乎不是一項不可或缺的服務。 它也沒有為開發或設計設置任何標準。 我也不能告訴你我對此感到 100% 滿意。 我剛到了一個我很樂意放棄它的地步。

但這從來都不是練習的重點。 我從經驗中學到了很多。 以下是我認為最重要的要點。

設計就是發展

一開始,我並沒有足夠重視設計。 我開始這個項目時認為,我用墊子和筆或在 Sketch 應用程序中繪製草圖的時間,是可以更好地用於編碼的時間。 然而,當我直接開始編寫代碼時,我常常只是一個忙碌的傻瓜。 首先以盡可能低的保真度探索概念,從長遠來看可以節省更多時間。

一開始有很多情況下,他們花了幾個小時在代碼中工作,卻發現從用戶體驗的角度來看它存在根本性的缺陷。

我現在的看法是,紙和鉛筆是最好的規劃、設計和編碼工具。 面臨的每一個重大問題主要是用紙和鉛筆解決的; 文本編輯器只是執行解決方案的一種手段。 如果沒有在紙上有意義的東西,它就沒有機會在代碼中工作。

接下來我學會了欣賞,我不知道為什麼花了這麼長時間才弄清楚,設計是迭代的。 我下意識地接受了一個大寫字母“D”的設計師的神話。 有人四處走動,筆直地舉起自動鉛筆,在字體上打蠟,啜飲一口純白色(顯然是豆漿),然後隨意地將完全形成的視覺完美呈現給這個世界。

這與“天才”程序員的概念不同,是一個神話。 如果您是設計新手,但正在嘗試自己的手,我建議您不要沉迷於第一個激起您興奮的想法。 嘗試變化是如此便宜,所以擁抱這種可能性。 我喜歡 In/Out 設計的所有東西在最初的設計中都不存在。

我相信是小說家邁克爾·克萊頓(Michael Crichton)創造了格言:“書不是寫出來的——它們是被改寫的”。 接受每個創作過程本質上是相同的。 請注意,相信這個過程會減輕焦慮,而練習會改善您的審美理解和判斷。

你是你項目中的另一個開發者

我不確定這是否特別適用於偶爾進行的項目,但我做了以下魯莽的假設:

“我不需要記錄任何這些,因為它只是我,顯然我會理解它,因為我寫了它。”

沒有東西會離事實很遠!

有時晚上,在我必須在項目上工作的 30 分鐘內,我除了試圖理解六個月前編寫的函數外,什麼也沒做。 代碼重新定位花了這麼長時間的主要原因是缺乏高質量的註釋以及命名不當的變量和函數參數。

在我的日常工作中,我非常勤奮地評論代碼,總是認真地擔心其他人可能需要理解我正在寫的東西。 然而,在這種情況下,我是另一個人。 你真的認為你會記得你在六個月內編寫的代碼塊是如何工作的嗎? 你不會的。 相信我,花點時間評論一下吧!

我已經閱讀了一篇題為“你的語法熒光筆在評論的重要性上是錯誤的”的博客文章。 基本前提是語法高亮不應該淡出註釋,它們應該是最重要的。 我傾向於同意,如果我不能很快找到一個可以解決這個問題的代碼編輯器主題,我可能不得不自己調整一個來達到這個目的!

調試

當您遇到錯誤並且編寫了所有代碼時,建議錯誤可能源自鍵盤和椅子之間是不公平的。 但是,在假設之前,我建議您測試您最基本的假設。 例如,我記得我花了兩個多小時來解決我認為是由於我的代碼引起的問題。 在 iOS 中,我只是無法讓我的輸入框接受文本輸入。 我不記得為什麼它以前沒有阻止我,但我確實記得我對這個問題的挫敗感。

原來這是由於 Safari 中的一個尚未修復的錯誤造成的。 事實證明,在 Safari 中,如果您有:

 * { user-select: none; }

在您的樣式表中,輸入框不會接受任何輸入。 您可以使用以下方法解決此問題:

 * { user-select: none; } input[type] { user-select: text; }

這是我在“應用程序重置”CSS 重置中採用的方法。 然而,真正令人沮喪的是我已經學會了這一點,後來又忘記了。 當我終於在解決問題的同時檢查 WebKit 錯誤跟踪時,我發現一年多前我已經在錯誤報告線程中編寫了一個解決方法,並完成了縮減!

想用數據構建? 學習 JavaScript 數組方法

也許通過這個應用程序構建練習,我的 JavaScript 技能取得的最大進步就是熟悉了 JavaScript 數組方法。 我現在每天都使用它們來滿足我所有的迭代和數據操作需求。 我不能足夠強調map()filter()every()findIndex()find()reduce()等方法的有用性。 您幾乎可以用它們解決任何數據問題。 如果您的武器庫中還沒有它們,請立即為 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array 添加書籤,並儘快挖掘。 我自己對我喜歡的數組方法的總結記錄在這裡。

ES6 引入了其他用於操作數組的節省時間的方法,例如SetRestSpread 。 在我分享一個例子時,請盡情享受; 如果你想從一個簡單的平面數組中刪除重複項,曾經有很多麻煩。 不再。

考慮這個帶有重複條目“Mr Pink”的數組的簡單示例:

 let myArray = [ "Mr Orange", "Mr Pink", "Mr Brown", "Mr White", "Mr Blue", "Mr Pink" ];

要使用 ES6 JavaScript 消除重複項,您現在只需執行以下操作:

 let deDuped = [...new Set(myArray)]; // deDuped logs ["Mr Orange", "Mr Pink", "Mr Brown", "Mr White", "Mr Blue"]

過去需要手動解決方案或訪問庫的東西現在已融入該語言。 誠然,在諸如短數組上聽起來可能沒什麼大不了的,但想像一下在查看具有數百個條目和重複項的數組時可以節省多少時間。

維護和安全

您構建的任何使用 NPM 的東西,即使只是用於構建工具,也可能容易受到安全問題的影響。 GitHub 在讓您了解潛在問題方面做得很好,但仍然存在一些維護負擔。

對於僅僅是一個副項目的東西,在積極開發之後的幾個月和幾年裡,這可能會有點痛苦。

現實情況是,每次更新依賴項以修復安全問題時,都會引入破壞構建的可能性。

幾個月來,我的package.json看起來像這樣:

 { "dependencies": { "gulp": "^3.9.1", "postcss": "^6.0.22", "postcss-assets": "^5.0.0" }, "name": "In Out", "version": "1.0.0", "description": "simple utility to see who's in and who's out", "main": "index.js", "author": "Ben Frain", "license": "MIT", "devDependencies": { "autoprefixer": "^8.5.1", "browser-sync": "^2.24.6", "cssnano": "^4.0.4", "del": "^3.0.0", "gulp-htmlmin": "^4.0.0", "gulp-postcss": "^7.0.1", "gulp-sourcemaps": "^2.6.4", "gulp-typescript": "^4.0.2", "gulp-uglify": "^3.0.1", "postcss-color-function": "^4.0.1", "postcss-import": "^11.1.0", "postcss-mixins": "^6.2.0", "postcss-nested": "^3.0.0", "postcss-simple-vars": "^4.1.0", "typescript": "^2.8.3" } }

到 2019 年 6 月,我從 GitHub 收到了以下警告:

GitHub 界面突出顯示構建工具依賴項的安全問題
將依賴項列在 GitHub 上意味著很少出現安全警告。 (大預覽)

沒有一個與我直接使用的插件相關,它們都是我使用的構建工具的子依賴項。 這就是 JavaScript 包的雙刃劍。 就應用本身而言,In/Out 沒有問題; 那沒有使用任何項目依賴項。 但由於代碼在 GitHub 上,我覺得有責任嘗試解決問題。

可以手動更新包,只需對 package.json 進行一些選擇更改。 然而,Yarn 和 NPM 都有自己的更新命令。 我選擇運行yarn upgrade-interactive ,它為您提供了一種從終端更新內容的簡單方法。

使用 Yarn 升級軟件包的 CLI 界面
Yarn 使升級項目依賴項更加可預測。 (大預覽)

看起來很簡單,甚至還有一個小彩色鍵可以告訴您哪些更新是最重要的。

您可以添加--latest標誌以更新到依賴項的最新主要版本,而不僅僅是最新的修補版本。 一分錢​​……

麻煩的是,在 JavaScript 包世界中事情發展得很快,所以將一些包更新到最新版本然後嘗試構建會導致以下結果:

Gulp 構建錯誤
Gulp 構建錯誤(大預覽)

因此,我回滾了我的package.json文件並在這次沒有--latest標誌的情況下再次嘗試。 這解決了我的安全問題。 說實話,這不是我周一晚上玩得最開心的一次。

這涉及到任何副項目的重要部分。 對您的期望保持現實。

附帶項目

我不知道你是不是也一樣,但我發現一種​​頭暈目眩的樂觀和興奮讓我開始項目,如果有的話,尷尬和內疚讓我完成它們。

如果說我在業餘時間製作這個小應用程序的經歷充滿樂趣,那將是一個謊言。 有時我希望我永遠不會對任何人開口。 但現在它完成了,我 100% 相信投入時間是值得的。

也就是說,可以通過現實地了解理解和解決您面臨的問題需要多長時間來減輕對此類副項目的挫敗感。 每晚只有30分鐘,一周幾個晚上? 你仍然可以完成一個業餘項目; 如果您的步伐緩慢,請不要感到不滿。 如果事情不能讓您全神貫注,請準備好比您可能習慣的更慢和更穩定的步伐。 確實如此,無論是編碼、完成課程、學習雜耍還是寫一系列文章來說明為什麼要花這麼長時間才能編寫一個小型 Web 應用程序!

簡單的目標設定

您不需要花哨的過程來設定目標。 但這可能有助於將事情分解為小/短任務。 像“為下拉菜單編寫 CSS”這樣簡單的事情在有限的時間內完全可以實現。 而“研究和實現狀態管理的設計模式”可能不是。 把事情分解。 然後,就像樂高一樣,小塊拼湊在一起。

考慮到這個過程是為了解決更大的問題,我想起了著名的比爾蓋茨名言:

“大多數人都高估了自己一年能做的事,卻低估了自己十年內能做的事。”

這是來自一個幫助根除脊髓灰質炎的人。 比爾知道他的東西。 聽聽比爾。

運送東西總比什麼都不運送好

在“發布”這個 Web 應用程序之前,我查看了代碼並且非常沮喪。

儘管我從完全幼稚和缺乏經驗的角度開始了這段旅程,但在我如何構建代碼(如果你能原諒如此宏大的術語)方面,我做出了一些體面的選擇。 我研究並實現了一種設計模式,並享受了該模式所提供的一切。 可悲的是,當我越來越不顧一切地想要完成這個項目時,我沒能保持紀律。 目前的代碼是一個真正的大雜燴,而且效率低下。

幾個月以來,我開始意識到這些缺點並不重要。 並不真地。

我很喜歡 Helmuth von Moltke 的這句話。

“除了與主要敵對力量的第一次接觸之外,沒有任何行動計劃可以確定地延伸。”

這被解釋為:

“沒有計劃能在與敵人的第一次接觸中倖存下來”。

也許我們可以進一步歸結為“狗屎發生”?

我可以通過以下類比推測我對所發布的內容的接受程度。

如果一個朋友宣布他們將嘗試參加他們的第一次馬拉鬆比賽,那麼他們越過終點線將是最重要的——我不會因為他們的完成時間而責備他們。

我並沒有打算編寫最好的 Web 應用程序。 我給自己設定的職責只是設計和製造一個。

更具體地說,從開發的角度來看,我想了解如何構建 Web 應用程序的基礎知識。 從設計的角度來看,我想為自己嘗試解決一些(儘管很簡單)的設計問題。 製作這個小應用程序遇到了這些挑戰,然後是一些挑戰。 整個應用程序的 JavaScript 文件只有 5KB(壓縮後)。 我很難使用任何框架來處理一個小文件。 除了也許 Svelte。

如果您正在為自己設定這種性質的挑戰,並期望在某個時候“交付”某些東西,請在一開始就寫下您這樣做的原因。 將這些原因放在您的腦海中,並以它們為指導。 一切最終都是某種妥協。 不要讓遠大的理想阻礙你完成你打算做的事情。

概括

總的來說,自從我從事 In/Out 工作已經一年了,我的感受大致分為三個方面:我後悔的事情、我想要改進/修復的事情以及未來的可能性。

我後悔的事

正如已經提到的,我很失望我沒有堅持我認為更優雅的方法來更改應用程序的狀態並將其呈現到 DOM。 正如本系列的第二部分所討論的那樣,觀察者模式以可預測的方式解決瞭如此多的問題,最終被拋棄了,因為“交付”項目成為了優先事項。

起初我對我的代碼感到尷尬,但在接下來的幾個月裡,我變得更加哲學化了。 如果我後來沒有使用更多的步行技術,這個項目很有可能永遠不會結束。 將一些需要改進的東西帶到這個世界上仍然感覺比它根本沒有被誕生到這個世界上要好。

改善輸入/輸出

除了選擇語義標記之外,我沒有為可訪問性提供任何啟示。 當我構建 In/Out 時,我對標準的網頁可訪問性很有信心,但對處理應用程序的知識還不夠。 我現在在該領域做了更多的工作/研究,所以我很樂意花時間做體面的工作,使這個應用程序更易於訪問。

“添加人員”功能的修訂設計的實施很匆忙。 這不是一場災難,只是比我想要的要粗暴一些。 讓它更光滑會很好。

我也沒有考慮更大的屏幕。 考慮讓它在更大尺寸上工作的設計挑戰會很有趣,而不僅僅是讓它成為一個內容管。

可能性

使用 localStorage 可以滿足我的簡單需求,但是擁有一個“適當的”數據存儲會很好,因此不必擔心備份數據。 添加登錄功能還將打開與另一個人共享遊戲組織的可能性。 或者也許每個玩家都可以標記他們是否在玩自己? 令人驚訝的是,您可以從如此簡單而卑微的開端設想有多少探索途徑。

用於 iOS 應用程序開發的 SwiftUI 也很有趣。 對於只使用過網絡語言的人來說,乍一看,SwiftUI 看起來像是我現在有勇氣嘗試的東西。 我可能會嘗試使用 SwiftUI 重建 In/Out — 只是為了有一些特定的東西來構建和比較開發經驗和結果。

所以,是時候總結一下,給你 TL;DR 版本的所有這一切。

如果您想了解某些東西在網絡上的工作原理,我建議您跳過抽象。 拋棄框架,無論是 CSS 還是 JavaScript,直到你真正理解它們對你有什麼好處。

設計是迭代的,擁抱這個過程。

在您可以使用的最低保真度介質中解決問題。 如果你可以在 Sketch 中測試這個想法,就不要去編碼。 如果您可以使用筆和紙,請不要在 Sketch 中繪製它。 先寫出邏輯。 然後寫成代碼。

現實一點,但永遠不要沮喪。 養成每天只花 30 分鐘做某事的習慣就能取得成果。 無論您的追求採取何種形式,這一事實都是真實的。