高效開(kāi)發(fā) Web 單頁(yè)應(yīng)用解決方案

于 2017 年初,有在 Github 建立并維護(hù)一個(gè)項(xiàng)目:Vue Boilerplate Template,欲成就一款開(kāi)箱即用 Vue + Webpack 的腳手架模版;其目標(biāo)與宗旨是:根據(jù)以往經(jīng)驗(yàn)提供一些參考,對(duì)于如何構(gòu)建中大型 Vue 項(xiàng)目。這蠻久以來(lái),有堅(jiān)持維護(hù)更新,各項(xiàng)主要依賴庫(kù),基本都保持著同步升級(jí);記載這篇文章,即是對(duì)關(guān)于它的設(shè)計(jì)做下更全面的闡述,以起到項(xiàng)目 Wiki 的作用;同時(shí)探討“如何更高效開(kāi)發(fā)單頁(yè)面應(yīng)用”。

題圖來(lái)自 picjumbo.com

關(guān)于此 Vue、Webpack 腳手架模版

這是一個(gè)用以開(kāi)發(fā) Web 單頁(yè)應(yīng)用的腳手架項(xiàng)目;謹(jǐn)以 Vue 為開(kāi)發(fā)框架、Webpack 為構(gòu)建工具,element-ui 為 UI 組件庫(kù);同時(shí)注入了 vue-routervuex、vue-i18n,用以支持單頁(yè)應(yīng)用,復(fù)雜的狀態(tài)管理,以及多語(yǔ)言設(shè)定;另外依賴了 lodashdayjs、js-cookie 等開(kāi)發(fā)工具庫(kù),以提升頁(yè)面開(kāi)發(fā)效率。當(dāng)然,在實(shí)際項(xiàng)目中,可根據(jù)實(shí)際需要自由移除或者修改。在此項(xiàng)目中提供了兩個(gè)演示頁(yè),您可以在線查看。

對(duì)于如何使用這款腳手架模版,例如先決條件,用法等在 README 中已做說(shuō)明,此處就不在贅述。此腳手架模版,是基于 vue-cli 所構(gòu)建,那時(shí) vue-cli 版本還在 2.*;再有就是,主張項(xiàng)目是可以開(kāi)箱即用,像 vuex、 eslint、sass 等都默認(rèn)引入(其好處在于:可以清晰較為全套的項(xiàng)目設(shè)定;倘若無(wú)需多語(yǔ)言,可在此基礎(chǔ)之上做減法,移除 vue-i18n 及相關(guān)代碼即可;二來(lái),也無(wú)需編寫(xiě)些額外代碼,來(lái)支持用戶選擇性注入依賴,以節(jié)省精力,開(kāi)發(fā)更多有價(jià)值的功能;三來(lái),這也算是一種的提倡,像 eslint、 pre-commit 等對(duì)于團(tuán)隊(duì)項(xiàng)目,都是極為必要的存在,默認(rèn)引入,也算理所應(yīng)當(dāng));所以其整個(gè)目錄結(jié)構(gòu)是這樣:

├── LICENSE --------------- 項(xiàng)目許可證(MIT License)文件
├── build ----------------- 存放項(xiàng)目構(gòu)建相關(guān)文件
├── config ---------------- 存放項(xiàng)目構(gòu)建相關(guān)配置文件
├── dist ------------------ 存放項(xiàng)目構(gòu)建后的輸出文件
├── index.ejs ------------- 項(xiàng)目起始文件 (/index.html)
├── package-lock.json ----- 記錄用 npm 修改依賴操作的鎖文件
├── package.json ---------- npm 的 package.json 處理細(xì)節(jié)
├── src ------------------- 項(xiàng)目程序主代碼文件夾
│   ├── App.vue ----------- 應(yīng)用程序的主組件
│   ├── assets ------------ 存放資源:樣式、圖片、字體
│   ├── components -------- 項(xiàng)目自定義的公共組件
│   ├── constants --------- 項(xiàng)目自定義的公共常量
│   ├── filters.js -------- 項(xiàng)目自定義的 vue 過(guò)濾指令
│   ├── global.js --------- 協(xié)助分擔(dān) main.js 工作
│   ├── helper ------------ 項(xiàng)目自定義輔助各類工具
│   ├── locales ----------- 存放(公用)多語(yǔ)言配置
│   ├── main.js ----------- 項(xiàng)目代碼的人口文件
│   ├── mixins ------------ 存放 mixin 代碼相關(guān)
│   ├── router ------------ 存放 & 處理路由相關(guān)
│   ├── store ------------- 存放 & 處理 Vuex 相關(guān)
│   └── views ------------- 存放項(xiàng)目頁(yè)面代碼
├── static ---------------- 靜態(tài)的 assets(不被 webpack 處理)
├── test ------------------ 項(xiàng)目各類測(cè)試相關(guān)
└── yarn.lock ------------- 記錄用 yarn 修改依賴操作的鎖文件

項(xiàng)目背后的環(huán)境設(shè)定

先從環(huán)境說(shuō)起;眾所周知,鑒于 JavaScript 的發(fā)展歷史,隨著其版本的不斷更新,更多新語(yǔ)法和代碼特性被引入進(jìn)來(lái),使得編寫(xiě) JavaScript 體驗(yàn)持續(xù)邁向更好。雖然部分瀏覽器沒(méi)有能提供很好的支持,但此腳手架已然引入 babel 系依賴,您可以放心放心 ES6 甚至更超前版本,而不用擔(dān)心造成兼容性問(wèn)題。同樣,對(duì)于 CSS 也是一樣,這里已引入 autoprefixer,并作了相應(yīng)設(shè)定,您可以放心使用新特性、預(yù)處理語(yǔ)言等,而不用關(guān)注瀏覽器供應(yīng)商前綴。


(Update@18-05-28) 參考 vue-cli3 ( 實(shí)際上是 creat-react-app ) 對(duì)開(kāi)發(fā)體驗(yàn)做了優(yōu)化:

  • 對(duì)本地開(kāi)發(fā)地址端口使用進(jìn)行優(yōu)化:如果???定端口(如: 8080)被占用,則遞增向上尋找新的可用端口(如:8081 / 8082 / ... );
  • 對(duì)自動(dòng)在瀏覽器打開(kāi)本地開(kāi)發(fā)地址做了優(yōu)化:如存在已經(jīng)打開(kāi),則不重新打開(kāi)新的 Tab(適用于 OS X 系統(tǒng));

具體詳情,可以參見(jiàn) vue-boilerplate-template | 提升本地開(kāi)發(fā)體驗(yàn)。

代碼及提交規(guī)則約束

這是至關(guān)重要的,對(duì)于代碼的設(shè)計(jì)和編寫(xiě);因?yàn)椋?strong>代碼首先是寫(xiě)給人,然后才是寫(xiě)給機(jī)器 —— 出自《代碼大全》。在設(shè)計(jì)代碼時(shí)候,為其賦予可讀性而花費(fèi)的時(shí)間和努力,絕對(duì)物有所值;然而,要求每位成員自覺(jué)保持代碼統(tǒng)一質(zhì)量/風(fēng)格,這種事情的難度,不亞于靠一己之力去上青天。所以 eslint 系依賴,絕對(duì)是團(tuán)隊(duì)項(xiàng)目必裝神器;并將其注入于 Gitpre-commit 鉤子內(nèi),以強(qiáng)制約定盡可能統(tǒng)一代碼風(fēng)格;此時(shí)江山一統(tǒng),方有可傳萬(wàn)世之機(jī)。另外,對(duì)于代碼的提交,也是同理,圖一時(shí)之省心,而提交的無(wú)意義 message,這并不是好習(xí)慣;因?yàn)?strong>當(dāng)你回頭再看,你會(huì)發(fā)覺(jué)所有錯(cuò)的事情,都發(fā)生在最對(duì)的時(shí)間里。幸好的是,對(duì)于這些工作,此腳手架已經(jīng)幫您做好;當(dāng)然您可以根據(jù)團(tuán)隊(duì)整體喜好而作調(diào)整。

所提供的全局性方法

對(duì)于代碼的編寫(xiě)效率,也是尤為的重要;畢竟:“天下武功,唯快不破;即便說(shuō)輕功不表武功,但速度決定了你我の距離”;更嚴(yán)肅的作證這個(gè)觀點(diǎn)是:只有快速完成需求,才有時(shí)間去學(xué)習(xí)更多、或在關(guān)鍵點(diǎn)上作優(yōu)化。故此,在此腳手架中,已將常用的工具、插件、方法,通過(guò)添加至 Vue 全局實(shí)例,以方便調(diào)用;譬如:通過(guò)添加至 Vue.prototype,或者全局 mixin(minxns/globalMixin.js) 以及過(guò)濾(filters.js)等;

import _ from '@helper/lodash.js'
import { $apis, $utils } from '@helper'

Vue.prototype.$_ = _
Vue.prototype.$apis = $apis
Vue.prototype.$utils = $utils

如上這般,您就不用在使用時(shí)候反復(fù) import, 直接像這樣 this.$_.debounce 使用即可,從而大幅度節(jié)省您的編寫(xiě)時(shí)間開(kāi)支;對(duì)于其中 $ 符號(hào),是個(gè)人偏愛(ài)的標(biāo)記,以方便知曉其是來(lái)自全局;當(dāng)然,您可以修改為您所歡喜的記號(hào)。您可以看到在 helper 文件夾下,特意開(kāi)辟出一個(gè)文件 lodash.js,用以優(yōu)化對(duì) lodash 的使用,同時(shí)也是為了方便使用;這在 《Webpack 打包優(yōu)化之體積篇》的 盡量使用模塊化引入 中有過(guò)詳細(xì)敘述。同理,您可以對(duì)所引入的各類庫(kù),進(jìn)行再次封裝,以使得再項(xiàng)目中可便捷調(diào)用,同時(shí)可以統(tǒng)一修改、更替,而無(wú)需操作調(diào)用的地方。另外,值得一提的是對(duì)于 HTTP 請(qǐng)求相關(guān)的處理。

更優(yōu)雅的處理 Http 請(qǐng)求

下面是一個(gè)上古時(shí)代關(guān)于處理 Http 請(qǐng)求的實(shí)例;以現(xiàn)在的視角來(lái)看,它顯得有些極端,甚至有些不可思議,卻是至今仍然屢見(jiàn)不鮮的玩法(即使用的是當(dāng)下流行的 MVVM 框架,即便 Query.ajax 也是支持鏈?zhǔn)秸{(diào)用);然而,不乏有勤勞的開(kāi)發(fā)者,不厭其煩的寫(xiě)著類似的代碼,這本身倒也沒(méi)什么;但當(dāng)交給別人去維護(hù)、或者去讀的時(shí)候,容易造成身心上的創(chuàng)傷。

$.ajax({
  type: "GET",
  url: "xxx/getYyyContent",
  data: { username: $("#username").val() },
  dataType: "json",
  success: function (data) {
    const textContent = data.data.textContent
    $('#text-content').html(textContent)
  },
  error: function (error) {
    // Do something to handle Error
  },
  complete: function (error) {
    // 做額外的處理無(wú)論請(qǐng)求成功或失敗
  }
});

大道至簡(jiǎn),優(yōu)秀的開(kāi)發(fā)流程,一定是便于編寫(xiě)和維護(hù)!本腳手架引用類庫(kù) axiosq,并對(duì)其進(jìn)行簡(jiǎn)單封裝,以處理 Http 請(qǐng)求相關(guān);使其能夠支持鏈?zhǔn)秸{(diào)用,同時(shí)對(duì)返回?cái)?shù)據(jù)統(tǒng)一處理,精簡(jiǎn)返回內(nèi)容,使得在獲取到最終結(jié)果處,可以盡可能簡(jiǎn)單,詳見(jiàn) helper/ajax.js;另外,推薦開(kāi)發(fā)者將接口,按照功能模塊規(guī)劃,分門(mén)別類以存放至統(tǒng)一文件夾下,如 helper/apis;如此清晰明了,方便調(diào)用,且對(duì)于多人協(xié)作開(kāi)發(fā),又不相互響應(yīng),減少不必要的沖突。類似善用配置,以表驅(qū)動(dòng)法的編程手法,應(yīng)該活學(xué)活用,貫穿始終;具體更詳細(xì)的陳述,可參見(jiàn) 如何漂亮使用 Vue 之基礎(chǔ)篇。倘若以此法來(lái)處理 Http 請(qǐng)求,那如上磨人的示例,即可修改為如下模樣:

const params = { username: this.form.username }
this.$apis.xxx.getYyyContent(params).then(result => {
  this.textContent = result.textContent
}).catch(error => {
  // Do something to handle Error
}).fin(() => {
  // 做額外的處理無(wú)論請(qǐng)求成功或失敗
})

貼心的路由(Router)配置

使用 MVVM 框架 + *-router 來(lái)創(chuàng)建單頁(yè)應(yīng)用,已成為一種主流。在此腳手架中,已將 vue-router 添加進(jìn)來(lái),并進(jìn)行了處理;并附有示例:router/routes/demo.js;您可以自由的添加路由及頁(yè)面映射,來(lái)豐盈您的應(yīng)用程序;同時(shí),您還能為其配置各種頁(yè)面信息(如:標(biāo)題、是否須權(quán)限驗(yàn)證等)。 對(duì)于路由配置,更為貼心的配置,在處理與導(dǎo)航欄(/側(cè)邊欄)相關(guān)部分。

在前后端分離的現(xiàn)代化 Web 應(yīng)用中,導(dǎo)航欄配置一般由前后端共同作用:后端負(fù)責(zé)給予相關(guān)配置數(shù)據(jù),前端則掌管數(shù)據(jù)與頁(yè)面的映射;為了節(jié)省工作量,深度拷貝前端路由配置,遞歸遍歷移除無(wú)需在導(dǎo)航欄展示項(xiàng),再融合后端數(shù)據(jù),即可組裝出一套后臺(tái)可配置的應(yīng)用導(dǎo)航列表,而不用牽扯改動(dòng)前端。當(dāng)然,您可以根據(jù)業(yè)務(wù)需求,添加更多設(shè)定,使得程序擁有更佳的訪問(wèn)、維護(hù)體驗(yàn)。比如:為避免每次刷新界面,都發(fā)起請(qǐng)求導(dǎo)航欄數(shù)據(jù),應(yīng)將持久化存儲(chǔ)(Eg:localStorage)等等。

完善的 Webpack 打包優(yōu)化

這是此腳手架一大亮點(diǎn),即保持著對(duì)主流依賴庫(kù)的更新及優(yōu)化,如:webpack、element-ui 等。使用 webpack 來(lái)構(gòu)建 Web 應(yīng)用程序,如何使其呈現(xiàn)良好的構(gòu)建速度、優(yōu)化構(gòu)建后包體積/文件數(shù)量、提升其運(yùn)行效率等,是每位前端開(kāi)發(fā)者都該去了解的。在這方面,也作了很多學(xué)習(xí)與嘗試,并將些經(jīng)驗(yàn)記載于:Webpack 打包優(yōu)化之體積篇 & Webpack 打包優(yōu)化之速度篇。關(guān)于其配置方案,參見(jiàn) Vue Webpack Config;當(dāng)然,十分歡迎提出您寶貴的建議,協(xié)助進(jìn)一步完善之。另外,值得一提的是,關(guān)于構(gòu)建包的體積與文件數(shù)的平衡:避免造成體量很大或很小的包;對(duì)此,Webpack 方面也提供很多插件來(lái)輔助這件事,譬如:LimitChunkCountPlugin、MinChunkSizePlugin。鑒于 HTTP 工作機(jī)制,在不破壞按需加載的基礎(chǔ)上,使得所構(gòu)建出的 js 文件,數(shù)量盡可能少,文件又不過(guò)大(100kb ~ 500kb)是一個(gè)不錯(cuò)的選擇,當(dāng)然這里指的的是服務(wù)端開(kāi)啟 gip 壓縮的情況下;如果是由前端負(fù)責(zé)開(kāi)啟 gzip 壓縮,這個(gè) Size 上限應(yīng)該更低些為宜。除了外,考慮通過(guò) HTTP/2 來(lái)對(duì)項(xiàng)目項(xiàng)目進(jìn)行優(yōu)化,是另一個(gè)緯度的解決方案,在此就不多做探討。

支持漸進(jìn)式 Web 應(yīng)用程序

漸進(jìn)式 Web 應(yīng)用程序(PWAProgressive Web App):它的存在,使得在網(wǎng)絡(luò)上提供驚人用戶體驗(yàn)的新方式,它為構(gòu)建高質(zhì)量的漸進(jìn)式 Web 應(yīng)用程序,提供了令人難以置信的優(yōu)勢(shì),可以輕松取悅用戶,增加參與度并增加轉(zhuǎn)化次數(shù)。所以這已經(jīng)成為了現(xiàn)代化 Web 應(yīng)用程序必做工作。本腳手架對(duì) PWA 的支持,選擇參考了 vuejs-templates/pwa,其中用到 sw-precache-webpack-plugin 插件協(xié)助生成 service-worker.js。鑒于 serviceWorker 本身的些許限制,此模版默認(rèn)不引入此功能,取消此行被注釋的代碼,即可打開(kāi)該功能。關(guān)于這部分更多,可參見(jiàn)優(yōu)化網(wǎng)頁(yè) Performance、Progressive、Accessibility、Best Practices 相關(guān)提交 & 陳述。推薦您使用 Lighthouse 谷歌瀏覽擴(kuò)展,來(lái)對(duì)自己的 Web 應(yīng)用跑分,以查糾項(xiàng)目中潛存的可優(yōu)化點(diǎn)。

需要補(bǔ)充說(shuō)明的是:您可以在項(xiàng)目全局搜索 ~@CHANGE@~ 關(guān)鍵字,這是對(duì)于可變化設(shè)定的標(biāo)記;您可以根據(jù)項(xiàng)目實(shí)際所需,對(duì)該部分進(jìn)行修改。

腳手架提供的默認(rèn)命令

您知道,npmyarn 亦同)允許在 package.json 文件里面,使用 scripts 字段定義腳本命令。它支持通配符、變量、鉤子、外部傳參、支持并發(fā) & 異步執(zhí)行等等;所以,完全可以借助 npm script,打造屬于自己的高效工作流。在此腳手架中,默認(rèn)只是些提供了簡(jiǎn)單命令,您可以在自己的腳本中,結(jié)合您歡喜的工具,如 gulpbash 等,來(lái)塑造屬于您的高效工作流。下面對(duì)默認(rèn)命令略作說(shuō)明:

npm (yarn) 命令 功能描述
yarn start 運(yùn)行項(xiàng)目以開(kāi)發(fā)環(huán)境,是 yarn run dev 的快捷版方式
yarn run build:dll 構(gòu)建出 vendor.dll.js,依據(jù) webpack.dll.conf.js
yarn run build 構(gòu)建項(xiàng)目,以生產(chǎn)環(huán)境
yarn run jarvis 運(yùn)行 webpack-jarvis(非常智能的基于瀏覽器的Webpack儀表板)在 http://localhost:1337/
yarn run analyz 對(duì)所構(gòu)建的包進(jìn)行可視化呈現(xiàn),在 http://localhost:8888/
yarn run preview 對(duì)項(xiàng)目進(jìn)行在本地預(yù)覽,以生產(chǎn)環(huán)境,在 http://localhost:3000/
yarn run pretest 對(duì)生產(chǎn)環(huán)境所構(gòu)建的包進(jìn)行簡(jiǎn)單的“預(yù)測(cè)”:在 http://localhost:3000/

使用此腳手架的線上項(xiàng)目

  • 「傾城之鏈|NICE LINKS」:一個(gè)開(kāi)放平臺(tái),旨在云集全球優(yōu)秀網(wǎng)站,探索互聯(lián)網(wǎng)中更廣闊的世界;在這里,你可以輕松發(fā)現(xiàn)、學(xué)習(xí)、分享更多有用或有趣的事物。

項(xiàng)目待優(yōu)化的那些方向

  • 完善單元測(cè)試相關(guān);在代碼層面,做好單元測(cè)試,有助于提升代碼質(zhì)量,從而使得項(xiàng)目質(zhì)量、后續(xù)維護(hù)都可以更好??紤]將在之后的版本中,參考 Vue Test Utils 對(duì)這塊兒進(jìn)行完善。
  • SEO 優(yōu)化相關(guān);這是多方都應(yīng)該考慮的問(wèn)題;但在項(xiàng)目設(shè)計(jì)層面,可以考慮服務(wù)端渲染來(lái)極大提升 SEO (如:Nuxt);但這對(duì)于已經(jīng)處于開(kāi)發(fā)階段的項(xiàng)目,涉及需要更多的調(diào)整,相比于其他的可選方案。「傾城之鏈|NICE LINKS」 是基于 prerender,在 nginx 層面,針對(duì)瀏覽器作預(yù)渲染以優(yōu)化 SEO,現(xiàn)在看起來(lái)效果可以。 另外可以選擇的方案是運(yùn)用 Prerender SPA Plugin,在 Webpack 構(gòu)建項(xiàng)目時(shí)預(yù)渲染靜態(tài) html 內(nèi)容,;在未來(lái)版本中,會(huì)考慮針對(duì)這塊兒給出一個(gè)相對(duì)折中的方案。
  • 塑造更便捷的前端開(kāi)發(fā)環(huán)境;這里所言的開(kāi)箱即用,仍需要在您已經(jīng)安裝高版本 node 的前提;這對(duì)于新晉開(kāi)發(fā)著并不是友好;如果,您使用的是基于 windows 系統(tǒng)的環(huán)境,并不能保證這套腳手架可以很順利運(yùn)行(??);因此,有考慮借助 Docker 等工具,優(yōu)化前端開(kāi)發(fā)環(huán)境,使其可以更新便捷,而無(wú)需依賴更多。

寫(xiě)在最后的結(jié)語(yǔ)

對(duì)于分享,您的海量包容和意見(jiàn)建議,是促進(jìn)彼此都能更上一層樓的關(guān)鍵。輸出文字,總是比寫(xiě)代碼辛苦的多;在付出多時(shí)的敲敲打打之后,希望可以得到您寶貴的意見(jiàn)和建議,使得此腳手架可以更進(jìn)一步,以惠及到更多的人。最后,推薦您體驗(yàn)個(gè)人最新作品 ~ 「傾城之鏈|NICE LINKS」傾心締造,癡心為你,希望您會(huì)喜歡。

@2018-05-13 于深圳.南山 Last Modify: 2018-05-20


你可能感興趣(/有用)的文章:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 由于工作的特殊性質(zhì),我在野外集中上班一段時(shí)間,然后在集中放假休息。上班期間,開(kāi)始的前幾年,早上7::00起床吃飯、...
    一座l孤島閱讀 857評(píng)論 0 4
  • 11月5日杭州馬拉松半馬跑完了,可也沒(méi)有什么太興奮的。也許因?yàn)橹白约阂呀?jīng)跑過(guò)兩個(gè)半馬,對(duì)自己順利完賽還是很有把握...
    風(fēng)箏_云游四海閱讀 1,290評(píng)論 2 4
  • 第十一章 道可道?道不可道 馬青竹難得的沒(méi)有吊兒郎當(dāng),當(dāng)一個(gè)人認(rèn)真的時(shí)候,做什么都快,尤其是當(dāng)這個(gè)人還很有悟性的時(shí)...
    睢寧三哥閱讀 554評(píng)論 0 1

友情鏈接更多精彩內(nèi)容