全新版本仿網易雲音樂來啦

jacksonX發表於2019-02-25

前言

在前端技術領域中,我們可以切身感受得到技術的更新、變革的速度是非常快的,所以工程師們都會需要時常關注和學習一些新技術、新標準。

因為在工作中負責專案的技術棧相比於業界來說,算比較落後了,所以自己動手來開發一個音樂類 web app,可以嘗試一些新技術棧,或者往一些特定方向深挖學習。

專案開發時間從年末至今,利用工作之餘的時間斷斷續續地開發,主體功能已經大致完成了,接下來也會陸續新增一些新功能上去,也會持續優化程式碼,在此也做一下記錄和總結。

專案資訊

全新版本仿網易雲音樂來啦
線上體驗使用 chrome 移動端除錯體驗

專案地址

技術棧

  • vue:vue 2.6, vue-router, vuex, vue-server-renderer
  • webpack:webpack 4, webpack-dev-middleware, webpack-hot-middleware
  • node:express 4
  • test:karma 4, mocha, sinon-chai, vue/test-utils, eslint

整體架構

後端 api 是使用 NeteaseCloudMusicApi,提供了非常多介面,並且支援 CORS 跨域。

專案分為兩個部分,分別是前端,比如 javascript、css、img、components 等;還有服務端,負責請求響應和服務端渲染,所以專案整體架構如圖:

架構

技術實現

專案剛開始使用 vue-cli 初始化,開箱即用的使用體驗為我省去了不少繁瑣的流程,可以直接上手進行開發。

登入態

使用者登入是首先需要解決的問題,因為許多介面都依賴使用者登入態。最終是將 api 服務和專案分成兩個子域名:

163api.domain.cn    // api
163music.domain.cn  // 專案
複製程式碼

但是後來發現,請求登入介面成功後,使用者 cookie 無法寫入到瀏覽器內,發現原來是 cookie 內的 domain 設定的是 api 子域名,所以導致 163music.domain.cn 下是無法讀取到 cookie 的,但是經過除錯發現,介面在 set cookie 的時候是並沒有設定 domain,解決方案是在 nginx 內加上 proxy_cookie_path 的配置,為 cookie 新增 domain 為 .domain.cn,那麼在其他子域名下就能正常讀取到 cookie(剛開始設定的是替換 domain,然而不會生效):

// nginx.conf
server {
        listen 80;
        server_name 163api.domain.cn;
        location / {
            proxy_pass http://127.0.0.1:3000/;
            proxy_cookie_path ~^(.+)$ "$1; domain=domain.cn";
        }
}
複製程式碼

webpack

在專案開始初期,一切都是那麼的和諧,可以歡騰暢快的開發。開發到中期功能都完成的差不多時候決定新增 ssr 了。vue-cli 3 是可以通過配置檔案 vue.config.js 來實現自定義的 webpack 配置,在加入了 ssr 相關配置之後,就可以成功構建打包了,但我希望程式碼能夠實時過載和模組熱替換,不然開發效率會比較低下。然後,在嘗試了一些改造方案(一番掙扎)之後,還是覺得不能夠很靈活地實現,我決定重新搭建環境 Orz

主要的 webpack 配置是參考 vue-cli,node 程式碼主要參考官方 demo,當程式碼編寫好後就嘗試執行了,結果當然是...滿屏紅色報錯。

全新版本仿網易雲音樂來啦

因為官方 demo 使用的 webpack 3,所以有些配置需要更新,還有一些依賴隨版本升級也需要更新呼叫方法等等。但值得高興的是,錯誤提示都基本是準確的,比如:

// 需要提供 mode 選項
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
複製程式碼
// 配置遷移,需要使用新配置選項
Error: webpack.optimize.UglifyJsPlugin has been removed, please use config.optimization.minimize instead.
複製程式碼

還有可能會缺少各種 loader,需要安裝各種依賴。確保構建流程正常後,就可以開啟瀏覽器內看效果了,但又會發現這樣的報錯:

window is not defined.
複製程式碼

原因是因為一個輪播外掛內包含 window,而在 node 環境內是沒有這個全域性變數的,所以導致了這個報錯。亦或者訪問其他瀏覽器內建物件時,也會出現這樣類似的報錯,所以需要確保程式碼和外掛都可以在 node 環境下正常執行。因為輪播外掛本身是支援 ssr 模式的,所以修改完程式碼後即可正常執行。

最後,專案中共有四份 webpack 配置和兩個構建指令碼。在開發環境下,搭配 webpack-dev-middleware 和 webpack-hot-middleware 來實現了程式碼的熱載入。在生產環境構建時,因為希望能清晰看到錯誤和警告,也想對構建耗時進行統計,所以將構建指令碼拎出來。

build
├── build-production.js        // 生產環境構建指令碼
├── setup-dev-server.js        // 開發環境構建指令碼
├── webpack.base.config.js      // 基本配置
├── webpack.client.config.js    // 客戶端配置
├── webpack.server.config.js    // 服務端配置
└── webpack.test.config.js      // 測試配置
複製程式碼

播放器

音樂播放是最主要的核心功能,底層就是使用 audio 標籤,並且監聽了標籤元素的 canplay、timeupdate、ended 事件來分別實現時長計算、更新當前播放進度、下一首播放。 因為播放器是可以支援“後臺”播放,所以將播放器放到根元件中並且設定隱藏,所以 dom 結構如下:

<div id="app">
    <!-- audio -->
    <player></player>
    <transition :name="transitionName">
        <router-view class="component"></router-view>
    </transition>
    <footBox></footBox>
</div>
複製程式碼

元件資料同步是使用 vuex,比如播放的狀態、歌曲總時長、當前的播放進度等,當歌曲播放完畢時候需要播放下一首,這裡使用的是 eventBus 來做事件觸發,它會比較適合這種類似的場景。

當使用者開啟播放頁面時,我希望音樂是能夠自動播放的,無論使用者是從其他入口進來亦或者是直接重新整理的時候。自動播放是通過 play() 方法去觸發的,前者沒有問題,但是後者在呼叫時就會提示錯誤,錯誤意思是需要使用者進行手勢操作之後才能夠播放,然後嘗試了模擬點選、靜音播放的方案之後發現在 chrome 內依然無效,後來感覺 chrome 這樣做是正確的,應該把網站的控制權交給使用者,讓使用者清楚頁面到底發生了什麼,而不是讓使用者在一堆標籤頁裡尋找是哪個頁面發出了奇怪的聲音。

更新從播放列表進入播放頁後才會自動播放,感謝小夥伴提供解決方案

單元測試

單元測試也是早期規劃的功能之一,開始是參考一些開源專案來搭建,最終選型是 karma + mocha + sinon-chai (官方 demo)。搭建的過程就是摸著石頭過河了,其中也經歷了一些報錯,比如:安裝依賴失敗、配置檔案出錯、缺少依賴外掛等等,然後接近搭建完成後才發現還有官方文件。不得不說是, cli 的確幫開發者節省了非常多配置、搭建的工作,搭建完成之後就可以根據官方文件來編寫用例了,根據官方文件內例子已經可以覆蓋到絕大部分場景,比如模擬瀏覽器渲染、使用者點選等等。但同時也發現一個問題,如果專案程式碼經常發生變更的話,那麼之前的測試用例也可能需要重新編寫了,想知道大家在專案中是怎麼處理或者怎麼看待呢?

以上是在開發過程中遇到一小部分問題,還有過程當中大部分問題描述和解決方案就不在這裡一一展開去講了,大家如果有問題的地方,歡迎大傢俬信或者郵件與我交流。

總結

  • 在專案的開發過程中也參考和使用了很多優秀的開源專案,幫助我快速消化一些功能實現,還有提供了後端 api,不然也沒有開發這個專案的靈感;
  • Vue 生態下有豐富、詳細的官方文件和活躍的社群,基本上遇到的問題都能夠解決,超讚;
  • 專案在立項之初可能只是大腦一閃而過的簡單想法,再回顧這幾個月開發經歷,其實過得是比較充實和富有激情的,就是有點費頭髮 ?;
  • 最後,自知專案中還有很多不足的地方,如果您發現有什麼問題或者有更好的想法,歡迎 issue 或者 pr。如果您覺得專案有參考和學習的價值,可以在 github 上點個 star,謝謝~

全新版本仿網易雲音樂來啦

參考資料

NeteaseCloudMusicApi

vue-awesome-swiper

use nginx to add Domain to a Set-Cookie

Cookies on localhost with explicit domain

mini-css-extract-plugin with SSR

Autoplay Policy Changes

相關文章