有時想看些新聞、時事,但不想被單一媒體的觀點所侷限,所以自製一個新聞的 Web App,藉由串接集成的 Taiwan News API,獲取各方新聞媒體的報導。
Client 連結
原生 Vanilla.js🤣 撰寫前端 Client App,受到 React.js 和 Vue.js 的啟發,嘗試運用框架的核心理念,自訂 Webpack 環境,打造出專屬的專案架構。一方面可強化原生控制資料、事件、畫面三者的能力,另一方面能反思框架存在的意義、想解決什麼問題呢?
-
使用自己簡單封裝的 XMLHttpRequest 工具,發送 AJAX GET 請求,獲取類別(top, entertainment, sports, business, health, technology, science)對應的新聞,預設每頁為 10 筆報導(會根據裝置尺寸調整)。
-
已獲取的資料會利用記憶體快取(memory cache)並附加一個能判斷資料是否過期的 timestamp(類似 Cookie 的
Max-Age),再將這個加工過的資料儲存至localStorage,設定 5 分鐘後過期,需要重新請求資料,以確保新聞的即時性。(程式碼 L67~L127) -
標題區塊
Header根據不同頁面顯示相應的訊息和連結。 -
點擊上方導覽列
Navbar,更換新聞的類別,並即時更新 URL Search parameters(?category=technology),操控瀏覽器歷史紀錄(history.pushState)和監聽popstate事件。 -
點擊新聞卡
NewsCard開啟有獨特 name 的分頁,讓點擊相同新聞卡時跳至同樣的分頁,不會重複開啟同一則新聞;另外用滑鼠中鍵或是右鍵(context menu)的「在新分頁中開啟連結」則可重複開啟。 -
啟用圖片 lazy loading 以及增設圖片
load事件,首次載入完成時觸發 fade-in 動畫;若瀏覽器有啟用快取(cache)機制則用HTMLImageElement.complete屬性判斷載入完成的時機來觸發 fade-in 動畫。 -
行動裝置(Mobile device)裝置可透過左滑、右滑的手勢切換新聞類別。(程式碼)
-
當滾動至底部時觸發
loadMoreNews()載入更多新聞,如果還有資料就加入提示PullHint「載入更多新聞中」,更新頁數並填充下 10 筆報導。 -
可對想追蹤、收藏的新聞報導點擊書籤圖示,使用
localStorage儲存已收藏的新聞資料陣列,實現跨頁攜帶資料,加到書籤收藏頁(collection.html)。 -
固定在左下角的部件組
Widgets,hover 後會展開內部組件,其一可進行主題模式(theme mode)的切換(預設採用使用者偏好的系統設定prefers-color-scheme);另一點擊後回到頁面頂部。 -
手機、平板與電腦的 RWD(Responsive Web Design)。
-
取出
localStorage的新聞資料陣列,展示出已收藏的全部新聞報導。 -
點擊新聞卡
NewsCard開啟有獨特 name 的分頁,讓點擊相同新聞卡時跳至同樣的分頁,不會重複開啟同一則新聞;另外用滑鼠中鍵或是右鍵(context menu)的「在新分頁中開啟連結」則可重複開啟。 -
可切換成管理模式進行整個
localStorage新聞資料陣列的操作。 -
固定在左下角的部件組
Widgets,hover 後會展開內部組件,其一可進行主題模式(theme mode)的切換(預設採用使用者偏好的系統設定prefers-color-scheme);其二點擊後回到頁面頂部。 -
手機、平板與電腦的 RWD(Responsive Web Design)。
-
使用 RegExp 注入資料到類 html 格式的自訂 .tpl 檔案。(
injectTpl()) -
幫助整理 object 的結構、URL 的參數、form data 的格式等等。(程式碼 L13~L65)
-
操作卷軸和 DOM 相關屬性、新增 Web Components。(程式碼)
-
建立事件管理用的 class、實作 debounce 和 throttle。(程式碼)
-
Webpack5
-
plugins
-
定義全域的環境變數
NODE_ENV,可判斷環境是"development"或"production"做出相應處理。 -
進入點(entry)主要分成 index.html 和 collections.html 兩頁面,共同的依賴包為 common.js。可以根據設定自動注入 title 名稱、SEO-friendly 標籤和解決需手動引入 JavaScript 與 CSS 的困擾。
-
"development"環境下會以 CSS 注入 style 標籤的形式加到 HTML 中,但在"production"環境需要將 CSS 獨立抽離成靜態檔案,有利於提升效能與維護性,因此使用此 plugin。 -
視覺化分析工具,查看套件、模組的體積。
-
-
loaders
-
搭配 Webpack 並與以下核心、preset 和 plugin 進行語法轉譯(transpiling)。
-
babel 的核心,負責讀取設定,提供執行轉譯的 API。
-
讓專案使用新的 JavaScript 語法,並根據瀏覽器環境(browserslist)添加需要的 polyfill,進而節省處理兼容所花費的時間。
-
@babel/plugin-transform-runtime
進一步減少 bundle size。處理語法兼容經常會加上 helper function,此 plugin 可以在使用相同 helper function 時,預設以 import 的方式。
-
-
載入自訂的 .tpl 檔案之原始內容(utf-8)
-
將特定檔案拷貝到目標資料夾,並返回對應的 URL
-
-
Others
-
Proxy Server 連結
由於 News API 需要驗證 API Key 才能使用,為避免 API Key 在前端洩漏以及方便後續功能的擴充,所以用 Koa2 架設一個 Proxy Server,簡單路由後使用 Axios 帶上 API Key 到 Request Header 中,然後對目標 API 發送請求,最後獲得所需的新聞資料並回傳給前端。
-
環境變數(Environment variables)
使用
dotenv讀取 .env 和 .env.local 的環境變數。-
.env: 新增檔案命名為 .env,裡面放上本地開發用伺服器的 HOSTNAME 和 PORT。
HOSTNAME=127.0.0.1 PORT=8080 -
.env.local: 放上 Taiwan News API Request Header 之
X-Api-Key要驗的NEWS_API_KEY,可放多支 key 增加請求次數(要用 NEWS_API_KEY 開頭)。NEWS_API_KEY0=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx NEWS_API_KEY1=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx NEWS_API_KEY2=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx NEWS_API_KEY3=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx NEWS_API_KEY4=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-
-
- 創建
Axios的實例(instance),設定預設的選項,方便重複使用。 - 使用實例的 Interceptors,管理 Request 和 Response 過程發生的事情,例如處理 429 Too many requests 狀況(每支 API Key 有限制請求次數),更換成另一支 API Key。
- 創建
-
/api或/api/news: 接收前端的 GET Request,調用中介層函式的getNews -
getNews(ctx): koa2 會調用此中介層函式,放入包裝過、便於開發的ctx參數(HTTPreq和res等)。用於回傳新聞資料及處理例外事件。