Charlie
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note No publishing access yet

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.

      Your account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

      Your team account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

      Explore these features while you wait
      Complete general settings
      Bookmark and like published notes
      Write a few more notes
      Complete general settings
      Write a few more notes
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note No publishing access yet

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.

    Your account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

    Your team account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

    Explore these features while you wait
    Complete general settings
    Bookmark and like published notes
    Write a few more notes
    Complete general settings
    Write a few more notes
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    1
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # PWA:讓 Web 彷彿手機原生 App 最近遇到一個專案,需要利用 PWA 的技術, 讓網站能建立捷徑到手機主畫面上,而且使用起來像手機 App, 藉著這次專案的機會,來整理一下 PWA 的技巧與更進階的樣式設定。 # 漸進式網頁是什麼? PWA 的全名是 Progressive Web Apps(漸進式網頁應用程式,以下皆簡稱 PWA), 有 PWA 功能的網頁,會跳出「將 App 新增置主畫面」、「安裝 App」的按鈕, 安裝後從主選單點開,同一網頁就不會有網址列, 看起來就像一個原生的 App,還可設定推播通知與離線存取功能。 ### ▍PWA 是什麼時候發展的? 2015 年由 [設計師 Frances Berriman 和 Google Chrome 工程師 Alex Russell](https://infrequently.org/2015/06/progressive-apps-escaping-tabs-without-losing-our-soul/) 提出。 目的是希望瀏覽手機網頁時,能夠像原生 App 一樣有使用者友善的體驗。 2014 年 Google 開發者大會開始提出相關技術,隨後 Google 大力推動 Android 的 PWA 開發。 Firefox 在 2016 年開始支援 PWA 的核心技術(Service Worker)。 Microsoft Edge 和 Apple Safari 在 2018 年隨後跟上。 現在所有主要系統上都可使用(參考自 [vuestore 的整理](https://vuestorefront.io/blog/pwa))。 ### ▍PWA 字面上意思是? 漸進式網路應用程式(Progressive web app)的譯名,可能讓第一次看到的人較難直接理解意涵。 這具有「逐漸增強功能」的意涵,說明這種網站可以是電腦版網頁、行動版網頁, 也可以成為桌面應用程式,甚至離線使用、推播訊息。 讓網站「逐漸成為『應用程式』([They progressively become "apps"](https://infrequently.org/2015/06/progressive-apps-escaping-tabs-without-losing-our-soul/#:~:text=They%20progressively%20become%20%22apps%22))」。 ### ▍PWA 具有哪些特徵? 傳統上,網站不太像是使用者「擁有的東西」而更像是「訪問的地方」。 當使用者不訪問該網站時,該網站不會出現在使用者的裝置上; 當使用者訪問網站時,只能藉由開啟瀏覽器並依賴網路連線到該網站。 雖然與原生 App 相比,網站具有這樣的限制,這樣的限制,但網站也有另一些優勢,例如: * 單一程式碼: * 由於網路是跨平台的,因此網站可藉由單一程式碼,在不同的作業系統和裝置上運行。 * 透過網路分發: * 網路是很好的分發平台。只需使用網址,即可共享和存取網站,無需透過應用程式商店。 此外,PWA 也結合了原生 App 的優點,例如: * 可以安裝在裝置上: * 可以從平台的應用程式商店安裝,也可以直接從網路安裝。 * 可以像原生 App 一樣安裝,並且可以自訂安裝過程。 * 安裝後,PWA 會在裝置上獲得一個應用程式圖示以及原生 App。 * 安裝後,PWA 可以作為獨立應用程式啟動,而不是瀏覽器中的網站。 * 可以在背景和離線狀態下運作: * 在設備沒有網路連線時工作。 * 後台更新內容。 * 響應來自伺服器的推播訊息。 * 使用作業系統通知系統顯示通知。 * 使用整個螢幕,而不是在瀏覽器 UI 中運行。 * 整合到設備中,註冊為共享目標和來源,並存取設備功能。 (參考自:[What is a progressive web app, MDN](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Guides/What_is_a_progressive_web_app)) 整體來說,PWA 有以下數點特性: 1. Progressive 漸進式 - 使用者於瀏覽器中即可操作 (註:各瀏覽器於各平台上支援度不一) 2. Responsive 響應式 - 可操作於桌機、手機或平板等裝置上 3. Connectivity independent 連結獨立 - 可基於service workers架構執行,於離線或在有限網路下操作 4. App-like 近似APP - 類似APP的操作介面 5. Fresh 維持新版 - 因 service worker 架構,讓應用程式隨時都是在更新狀態 6. Safe 安全性 - 必須於加密模式之下進行,因此安全較受到保障 7. Discoverable 可被搜尋 - 透過 manifest 設定檔案及 service worker 使搜尋引擎可正常搜尋到 8. Re-engageable 有互動性 - 透過類似推播方式與使用者更加互動 9. Installable 可安裝 - 可以拉存到手機的桌面,感覺就像是傳統的APP (註:非每種瀏覽器均支援) 10. Linkable 可連結 - 可經由連結輕易分享 (取自:[PWA介紹 (Progressive Web App),優、缺點及範例介紹,Arshire](https://www.arshire.com/blog/pwa)) ### ▍PWA 運行在瀏覽器嗎? 當你在瀏覽器中造訪某個網站時,瀏覽器 UI 讓你很明顯感受到「網頁正在瀏覽器中運行」。 PWA 可以在沒有瀏覽器 UI 的情況下使用,但從技術角度來看,它們仍然是網站。 這意味著 PWA 需要藉由瀏覽器引擎(如 Chrome、Firefox )來管理和運行它們。 相較之下,原生 App 通常由平台作業系統管理該應用程序,提供其運行的環境。 ![image](https://hackmd.io/_uploads/H12W8-YVT.png) ### ▍PWA 有哪些優缺點? ##### 優點 只要將網站製作完成,再透過PWA技術,就可以將網頁轉換成原生App的效果。 對企業來說,不用花大錢額外製作原生App,節省成本。 * 迅速進入手機市場: * Progressive Web Apps(PWA)是最簡單的進入手機市場的方式,可在幾個月內設置完成,並且適用於所有設備。 * 一次提供所有功能: * 使用PWA技術,團隊只需構建一個無縫運行於任何設備的應用程序,無需單獨開發iOS和Android應用。 * 成本效益最佳化: * 由於PWA的全功能,節省時間和降低開發成本,無需支付應用商店費用。 * 降低顧客獲取成本(CAC): * PWA允許用戶直接從移動瀏覽器安裝應用程序,提高試用機會,且無需下載更新。 * 發揮無頭商務的優勢: * PWA使用無頭架構提供卓越的靈活性,並分離前端和後端,使營銷團隊獨立進行更改。 * 優化的SEO結果: * PWA加速Google索引,並且採用標準URL和完整的伺服器端渲染(SSR),有助於提高搜尋引擎排名。 * 降低跳出率: * PWA無論網絡條件如何,均可即時加載,並在離線狀態下工作,降低跳出率。 * 提高參與度、轉換率和收入: * PWA提供優越性能、移動優化和優秀的UX,通過全屏功能、易於訪問以及推送通知提高用戶參與度。 (取自:https://vuestorefront.io/blog/pwa) ##### 缺點 * 瀏覽器/平台的支援度不一 * * [iOS很多不支援](https://www.youtube.com/watch?v=eoUvIm8Pl6I&ab_channel=DevTrends) * 大部分消費者並不清楚如何操作 * 並不是說不懂如何操作網站,而是說不知道該如何把該網站轉成類應用程式的操作模式 * PWA 會比原生 App 耗電量來的高 * 由於它們是用複雜的程式編寫的,手機必須更加努力的轉譯程式碼 (參考自:[PWA,Arshire](https://www.arshire.com/blog/pwa)) # 基礎設定 ### ▍讓網頁可安裝 PWA 最基礎的設定,就是讓網頁可安裝下來,從主畫面進入、沒有瀏覽器 UI。 基礎設定上,我們只需要增加一個 App 用的圖示,以及一個設定檔。 ![image](https://hackmd.io/_uploads/Bk9h_TFVT.png) ##### 程式碼 在你的網頁的 head 中引入 manifest.json,就完成 PWA 的設定。 ```htmlembedded <!doctype html> <html lang="en"> <head> <link rel="manifest" href="manifest.json" /> </head> <body></body> </html> ``` ##### 應用程式圖示 放入自己想要的 Icon,個人建議一開始用 192x192(手機版適用)。 * 圖示大小要正方形,並且與實際大小相同,不然Chrome會無法下載。 ##### 設定檔:manifest.json 瀏覽器是透過這個檔案,來知道如何將網頁安裝在用戶的電腦或行動裝置上。 裡面是對 PWA 顯示的一些設定,有四項必填:name、start_url、display、icons。 通常會放在根目錄。 ``` json { "name": "PWA 範例網", // App 名稱,■■必填■■ "short_name": "PWA", // App 名稱縮寫,顯示空間不足時使用 "description": "這是一個簡單的 PWA 範例。", // App 的描述 "start_url": ".", // 首頁路徑,依 manifest 檔案位置來看,■■必填■■ "display": "standalone", // 顯示模式,■■必填■■ "orientation": "portrait", // 定義預設的顯示方向 "background_color": "#5a0fc8", // 預設背景色 "icons": [ // 圖示,■■必填■■ { "src": "icon.png", // 圖示路徑 "sizes": "192x192", // 圖示尺寸 "type": "image/png" // 圖示格式,可省略 } ] } ``` * display * fullscreen 全螢幕 * standalone 原生 App 模式 * minimal-ui 最基本的瀏覽器 UI * browser 瀏覽器樣式 * orientation * Arial 不限制 * naturl 設備預設的方向 * portrait 直向 * landscape 橫向 ##### 成果 設定完成後,瀏覽器點開網頁,會看到一個下載的圖示,就完成設定。 可以嘗試下載看看,就會變成一個沒有網址列的介面。 手機上的話也可以有類似效果,然而 iOS 使用者需要用 Safari 開啟,並手動將網頁加到主畫面。 (參考自:[Making PWAs installable, MDN](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Guides/Making_PWAs_installable)) ### ▍離線存取功能 離線存取功能是 PWA 的一個重要技術,利用 Service Worker 監控前端事件與回應。 Service Worker 本質上充當位於 Web 應用程式、瀏覽器和網路(如果可用)之間的代理伺服器。 除此之外,它們的目的是創建有效的離線體驗、攔截網路請求並根據網路是否可用採取適當的操作, 以及更新伺服器上的資產。它們還允許存取推播通知和後台同步 API。 Server Worker 是大型商業網展常使用的技術,可以將部分的 JS 程式放在瀏覽器背景執行,以做到像是推播的功能。 ##### 原理 JS 程式是由瀏覽器的主執行緒(Main Thread)負責執行, Service Worker 則是在不同執行緒非同步運行,不會影響網頁的渲染。 一般網頁:客戶端發送http請求給伺服器,伺服器再回應給客戶端。 Service Worker:聽fetch事件,攔截網頁的http請求,藉由 Service Worker 的快取(Catch)功能, 可以選擇由快取取得回應,因此就算離線,使用者也能夠正常離覽網頁。 ![image](https://hackmd.io/_uploads/rkRoTDd4a.png) Service Worker 有自己的生命週期,從下載、安裝到啟用,在不同的生命週期可以利用監聽事件,進行相對應的處理。 **Service Worker 不能直接操作DOM物件**,如果有需要可以透過postMessage()的方法發送訊息,然後透過message事件來溝通。 ##### 主要功能 * 離線瀏覽網頁 * 前面提到的,由快取回應開啟網頁的請求。 * 離線送出表單 * 離線狀態下無法送出表單,這種情況可以先將資料存在IndexedDB,並註冊sync事件,SW 監聽 Background Sync 事件,網路重新連線時,再將 IndexedDB 資料上傳到伺服器,達到離線送出表單的功能。 * 推播通知 * SW 會監聽 PUSH 事件,當收到伺服器發出的推播通知時,會顯示給用戶。 * 加入主畫面(Add to Home Screen, A2HS)」 * serviceWorkerContainer.register() 註冊 SW 檔案 * 註冊成功的話,SW 會運行在全域環境 ##### 操作方法 先提供監聽方法,讓你了解 Service Worker 運作過程 ``` javascript // 監聽 install 事件 self.addEventListener('install', (e) => { console.log('安裝') self.skipWaiting(); }); // 監聽 activate 事件 self.addEventListener('activate', (e) => { console.log('啟用') }); // 監聽 fetch 事件 self.addEventListener('fetch', (e) => { console.log('fetch') }); // 引入 Workbox,一個用於簡化 Service Worker 開發的函式庫 importScripts('https://cdnjs.cloudflare.com/ajax/libs/workbox-sw/7.0.0/workbox-sw.js'); // 註冊 Service Worker 路由,使用 Workbox 的 registerRoute 方法,需要帶入兩個參數 workbox.routing.registerRoute( new RegExp('.*'), // 使用正規表達式匹配所有 URL,.* 表示所有字符零次或多次 new workbox.strategies.NetworkFirst(), // 使用 NetworkFirst 快取策略,優先嘗試從網路獲取資源 ); ``` index.html 寫下這些來註冊 Service Worker。 ```javascript navigator.serviceWorker.register(scriptURL, options) .then(() => { // 註冊成功時執行 }).catch((error) =>{ // 註冊失敗時執行 }); // scriptURL 是 SW 檔案,在這個情況下是 sw.js // options 是 SW 的 scope,預設為「./」,也就是根目錄 // 如果 sw.js 放在網站根目錄,options 可以不用寫 // scriptURL 的相對路徑是相對於 sw.js ``` 註冊前要檢查瀏覽器(navigator)是否支援 Service Worker,等到網頁資源都載入再註冊 Service Worker。 ```javascript if('serviceWorker' in navigator) { window.addEventListener('load', () => { navigator.serviceWorker.register('sw.js') .then(() => console.log('註冊成功')) .catch((err) => console.log('註冊失敗')); }); } ``` 如果有多個 html 可以把註冊程式拉出來,再引入每個 html ##### 成果 可以離線載入。 # 進階技巧 ### ▍各尺寸 Icon 與啟動畫面 主要是 iOS 目前不支援 Web App Manifest API 規範,需要引入自訂 html 標籤來為您的 PWA 設定圖示和啟動畫面。 您需要為 Apple 建立每個尺寸的啟動畫面(splash),並為每個影像建立各自的 html 標籤。 可以藉由套件 [pwa-asset-generator](https://github.com/elegantapp/pwa-asset-generator) 來產生各尺寸的 icon、啟動畫面。 ##### 特性 * 生成類型:圖示、啟動畫面 * 自動更新您的 manifest.json 和 index.html 文件 * 提供 iOS 的深色、淺色啟動畫面選擇 * 因為要生成不同尺寸,建議使用SVG檔 * 用CSS設定樣式 ##### 指令 ```htmlmixed // npx pwa-asset-generator [圖片檔名] -i [index.html路徑] -m [manifest.json路徑] npx pwa-asset-generator logo.svg -i ./index.html -m ./manifest.json ``` 終端機輸入後,在同一層目錄就可以得到: * 圖示:192x192、512x512、180x180(iOS用) * 啟動畫面:30種尺寸 * 在 index.hmlt 寫好引入的標籤 會產出這麼多的圖片! ![image](https://hackmd.io/_uploads/Byzd0RCNT.png) 實際使用時,有時專案的 index.html 與 logo.svg 不會放在同一層, 我會創一個新資料夾與空的 html,把資料都放在同一層,產生檔案與標籤後再移回專案, 就不用一直研究指令如何在不同資料夾取放資料的問題。 以下是一些好用的指令: * 生成類型 * `--icon-only` 圖示 * `--splash-only` 啟動畫面 * `--landscape-only‵` 啟動畫面(僅橫的) * `--portrait-only` 啟動畫面(僅直的) * 帶有透明度的png:`--opaque false` * 設定padding,預設`--padding "calc(50vh - 10%) calc(50vw - 10%)"`,可自行調整 * 設定漸層底色 * `-b "linear-gradient(90deg, rgba(207, 234, 255, 1) 0%, rgba(240, 243, 255, 1) 50%, rgba(223, 205, 255, 1) 100%)"` ![apple-splash-2778-1284](https://hackmd.io/_uploads/Byb0-JyBT.jpg) 另外,他們提供 iOS 的深色、淺色啟動畫面設定。 以下是語法說明,基本上就是想要設定什麼就一直往後加。 ```htmlmixed= // npx pwa-asset-generator [圖片檔名] [圖片資料夾路徑] [iOS啟動畫面:深色] --background [背景色] [僅啟動畫面] --type [輸出類型] --qality [圖片品質] --index [index.html路徑] npx pwa-asset-generator light-logo.svg ./assets --dark-mode --background dimgrey --splash-only --type jpeg --quality 80 --index ./src/app/index.html // npx pwa-asset-generator [圖片檔名] [圖片資料夾路徑] --background [背景色] [僅啟動畫面] --type [輸出類型] --qality [圖片品質] --index [index.html路徑] npx pwa-asset-generator dark-logo.svg ./assets --background lightgray --splash-only --type jpeg --quality 80 --index ./src/app/index.html ``` ### ▍樣式設定(iOS) * Add a Short Name 在 manifest.json 設定 PWA 的短名稱,如果使用者的介面不允許太多字時可自動調整。 * Make the Status Bar transparent 預設情況下,iOS 的 PWA 頂部狀態列會為黑底,可用 meta 標籤使其透明。 ```htmlmixed <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/> <meta name="viewport" content="initial-scale=1, viewport-fit=cover" /> ``` 而 iPhone 的瀏海可能會擋到 Header 文字,可以做以下設定。 ```css header { padding-top: env(safe-area-inset-top); } ``` * 固定 header 在使用手機App時,header 通常會固定在畫面上方, 讓 PWA 網站加入這樣的設定可以增進使用者體驗。 ```css @media screen and (display-mode: standalone) { position: fixed; } ``` * 禁止使用者縮放 手機瀏覽器可以輕易縮放網頁大小, 但一般原生 App 沒有這樣的功能,我們可以停用縮放功能來達到這個效果。 ```htmlmixed <meta name="viewport" content="initial-scale=1, viewport-fit=cover, user-scalable=no" /> ``` * Set the tap highlight color to transparent 預設情況下,iOS 的 PWA 會像網頁一樣以灰色方塊突出顯示所有連結點擊。 關掉灰色顯示會更接近原生 App 的樣式。 ```css body { -webkit-tap-highlight-color: transparent; } ``` ### ▍自動安裝功能(Android) 若您的網站是可安裝的 PWA 網頁,那麼瀏覽器將顯示按鈕來顯示此網頁可安裝。 ![image](https://hackmd.io/_uploads/HJnCiN1Ba.png) 但是,我們也可以自己製作觸發安裝的按鈕,也能讓使用者更容易發現。 ```htmlmixed <button class="addBtn">安裝程式</button> ``` ```javascript // 檢查是否安裝 window.addEventListener("beforeinstallprompt", async (event) => { const relatedApps = await navigator.getInstalledRelatedApps(); // Search for a specific installed platform-specific app const psApp = relatedApps.find((app) => app.id === "com.example.myapp"); if (psApp) { event.preventDefault(); // Update UI as appropriate } }); // 安裝 let deferredPrompt; // 將事件隱藏用(??) const addBtn = document.querySelector('.addBtn'); addBtn.style.display = 'none'; window.addEventListener('beforeinstallprompt', (e) => { // 防止在 Chrome 67 之前的版本中自動顯示安裝提示 e.preventDefault(); // 將事件隱藏以便稍後觸發 deferredPrompt = e; // 更新UI以通知用戶可以將應用添加到主屏幕 addBtn.style.display = 'block'; addBtn.addEventListener('click', (e) => { // 顯示安裝提示 deferredPrompt.prompt(); // 等待用戶響應安裝提示 deferredPrompt.userChoice.then((choiceResult) => { if (choiceResult.outcome === 'accepted') { console.log('使用者接受 A2HS 的請求。'); // 隱藏顯示 A2HS 按鈕的用戶界面 addBtn.style.display = 'none'; } else { console.log('使用者拒絕 A2HS 的請求。'); } deferredPrompt = null; }); }); }); ``` (參考自:[Trigger installation from your PWA, MDN](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/How_to/Trigger_install_prompt)、[ホーム画面に追加, MDN](https://developer.mozilla.org/ja/docs/Web/Progressive_web_apps/Guides/Making_PWAs_installable)) ### ▍分享功能 也可以觸發瀏覽器的分享功能,讓別人看看你的 PWA 網站。 ```javascript // sharing.js const shareBtn = document.querySelector('.shareBtn'); shareBtn.onclick = async (filesArray) => { if (navigator.canShare) { navigator.share({ url: 'https://charliewuuu.github.io/PWA/', title: 'PWA 超酷!', text: 'PWA 超酷!我學會怎麼建立一個 PWA 程式了!', }); } }; ``` <!-- # 可能提問 ### 如果我有很多頁要怎麼辦? *在每一頁都要引入server-worker?* ### 有沒有效能問題? *畢竟這個app是藉由瀏覽器運行,等於多一層系統,會不會很吃資源?* ### 還有什麼其他功能? 推播功能等。 ### PWA會是未來的趨勢嗎? 不一定。根據國外的報導(2021的下半年),雖然GOOGLE努力推廣多年,但是PWA架構並沒有很普及,對大多數人來說還是相對較新的概念。2018年曾有許多科技網站大力吹捧PWA將會取代傳統APP,不過許多之前用PWA開發模式的網站已變更回單純網站。 --> # 參考資料 * 網站 * 文件 * MDN:[Progressive web apps](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps) * MDN:[What is a progressive web app](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Guides/What_is_a_progressive_web_app) * MDN:[Making PWAs installable](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Guides/Making_PWAs_installable) * MDN:[ホーム画面に追加](https://developer.mozilla.org/ja/docs/Web/Progressive_web_apps/Guides/Making_PWAs_installable) * 樣式教學文 * Sam Selikoff:[8 Tips to Make Your Website Feel Like an iOS App](https://samselikoff.com/blog/8-tips-to-make-your-website-feel-like-an-ios-app) * 提出 PWA 此名詞的文章 * Alex Russell:[Progressive Web Apps: Escaping Tabs Without Losing Our Soul](https://infrequently.org/2015/06/progressive-apps-escaping-tabs-without-losing-our-soul/) * 首次提出 service worker 與 menifest 的開發者大會 * [Chrome Dev Summit 2014](https://web.dev/case-studies/chrome-dev-summit) * PWA 的發展歷史以及商業上的好處 * [vuestore:PWA](https://vuestorefront.io/blog/pwa) * PWA 介紹,寫得很清楚,優缺點、普及性與對發展性的存疑都很清楚 * [Arshire:PWA](https://www.arshire.com/blog/pwa) * Youtube * PWA 初步介紹,有很簡單的教學步驟 * Fireship:[Progressive Web Apps in 100 Seconds // Build a PWA from Scratch](https://www.youtube.com/watch?v=sFsRylCQblw) * PWA 的進階功能,例如分享功能 * Fireship:[7 Web Features You Didn’t Know Existed](https://www.youtube.com/watch?v=ppwagkhrZJs&ab_channel=Fireship) * 書 * [HTML/CSS/JavaScript與前端框架的完美結合:使用Bootstrap與PWA技術, 新手從這開始!](https://www.tenlong.com.tw/products/9786263333109?list_name=c-css)

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password
    or
    Sign in via Facebook Sign in via X(Twitter) Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    By signing in, you agree to our terms of service.

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully