Vuejs技術(shù)棧從CLI到打包上線實(shí)戰(zhàn)全解析

Vuejs技術(shù)棧從CLI到打包上線實(shí)戰(zhàn)全解析

閱讀目錄

前言

本文是自己學(xué)習(xí)vue項(xiàng)目實(shí)踐中轉(zhuǎn)載學(xué)習(xí)的一些總結(jié)角塑,針對(duì)Vue2及相關(guān)技術(shù)棧锯七,實(shí)踐中版本為2.3.3牡属。

開發(fā)前須知

vue-cli

在開發(fā)前咐鹤,我們要至少通讀一遍vue官方文檔和API(看官方文檔是最重要的,勝過看五十、一百篇博客),英文閱讀能力還行的建議閱讀英文文檔缰冤,中文文檔內(nèi)容會(huì)稍落后,還要通讀相關(guān)的vue-router喳魏、axios锋谐、vuex等。

一般來說我們都是先利用vue-cli來搭建項(xiàng)目基本架構(gòu)截酷。

vue-cli官方temaplte地址涮拗,我們選擇webpack版本,建議看看其文檔vue-webpack-boilerplate了解基本用法和項(xiàng)目配置等迂苛。

深入地了解vue-cli的webpack配置請(qǐng)查看vue-cli#2.0 webpack 配置分析

打造團(tuán)隊(duì)的腳手架

vue-cli雖然強(qiáng)大三热,但是它有很多個(gè)步驟要我們?nèi)ミx擇配置,而實(shí)際上公司業(yè)務(wù)很多配置是固定的三幻,比如我們公司規(guī)定了要安裝vue-router就漾、要使用Standard風(fēng)格Eslint等,還規(guī)定了必須使用sass念搬,這樣在vue-cli配置完成后還必須要npm install node-sass和sass-loader抑堡,還有axios等也是一定要安裝的。所以不應(yīng)該每次新建一個(gè)項(xiàng)目都去一步步選擇vue-cli的那些配置然后還要去安裝sass等朗徊,應(yīng)該在vue-cli基礎(chǔ)上根據(jù)公司自身的情況打造團(tuán)隊(duì)的腳手架首妖,只需運(yùn)行腳手架,就可以初始化整個(gè)項(xiàng)目爷恳。

目錄結(jié)構(gòu)

建議在src/目錄增加views或pages目錄來存放對(duì)應(yīng)路由的組件有缆,添加api目錄,根據(jù)項(xiàng)目情況增加filters、vuex等目錄棚壁。components目錄存放公共組件或者全局組件杯矩。每個(gè)組件目錄可以將圖片等資源放在一起。組件的子組件目錄建議命名為children放在父組件目錄下袖外。如home組件目錄為home/home.vue史隆,子組件banner路徑為home/chldren/banner/banner.vue。

靜態(tài)資源處理

vue-webpack-boilerplate文檔中有靜態(tài)資源處理的詳細(xì)說明曼验,但發(fā)現(xiàn)還有很多人都不知道逆害,因此在這里稍微提一下。

vue-webpack-boilerplate的項(xiàng)目結(jié)構(gòu)中蚣驼,我們有靜態(tài)資源兩個(gè)目錄:src/assets和static/

assets目錄中的文件會(huì)被webpack處理,只支持相對(duì)路徑形式相艇,assets/logo.png會(huì)被編譯為./assets/logo.png颖杏,不支持/assets/logo.png

在js中,我們可以這樣獲取文件資源路徑

require('./assets/logo.png')

以下帶~前綴類似require效果

<img src="~assets/logo.png">

static目錄中的靜態(tài)資源不會(huì)被webpack處理坛芽,這里適合放一些外部不需要webpack處理的資源留储,build后的靜態(tài)資源都會(huì)被放進(jìn)這個(gè)目錄。

vue組件化

關(guān)于vue組件化咙轩,360奇舞團(tuán)前端工程師鐘恒的pptVue.js實(shí)踐 如何使用Vue2.0開發(fā)富交互式WEB應(yīng)用寫得非常好获讳,本節(jié)內(nèi)容也是出自其中。ppt中提到組件化帶來的新問題:通信活喊、復(fù)用丐膝、耦合,以及如何解決钾菊。

通信

1)props和events:props down帅矗,events up

2)函數(shù)調(diào)用:this.refs

3)組件樹: parent.parent

4)共享state

5)eventbus

6)vue技術(shù)棧之外的如localstorage等

復(fù)用

1)冗余:if、else if煞烫、else判斷執(zhí)行不同的代碼

if(this.type === 'editing') {
  // some editing code
} else if(this.type === 'preview') {
  // some preview code
} else if(this.type === 'present') {
  // some present code
} else {
  // some base code
}

2)包裝:slots

// plugin-page.vue
<div>
  <slot name="page">
    i am a page
  </slot>
</div>

// present-plugin-page.vue
<div class="PresetPluginPage">
  <plugin-page ref="page">
    <h1 slot="page">
      i am a present page
    </h1>
  </plugin-page>
</div>

//output
<div class="PresetPluginPage">
  <div>
    <h1>
      i am a present page
    </h1>
  </div>
</div>

3)繼承:mixins

// define a mixin object
var myMixin = {
  created: function () {
    this.hello()
  },
  methods: {
    hello: function () {
      console.log('hello from mixin!')
    }
  }
}
// define a component that uses this mixin
var Component = Vue.extend({
  mixins: [myMixin]
})
var component = new Component() 
// -> "hello from mixin!"

組件耦合

1)組件耦合帶來的問題:

  • 單組件修改困難
  • 組合新組件困難
  • 組件debug困難

2)解耦

解耦的本質(zhì)就是將變化分離

一浑此、組件功能單一

// wrong
<control-input type="number"></control-input>
// right
<control-number></control-number>

二、采用穩(wěn)定的接口

// wrong
this.$parent.$parent.$refs['resource-image'].open()
// right
bus.$emit('open-resource-image')

三滞详、處理好共享的部分

bindEvents (remove) {
  let method = remove
    ? 'removeEventListener'
    : 'addEventListener'
  window[method]('resize', this.handleResize)
}

3)與服務(wù)端解耦

this.$http.get('/user/detail')
.then(({body}) => {
  this.user = JSON.parse(body).data
}, err => {
  console.error(err)
})

user.detail().then(detail => this.detail = detail)
  1. 服務(wù)端與前端體系不一

  2. 同步異步轉(zhuǎn)換

  3. 多服務(wù)端/跨域的代碼

  4. 統(tǒng)一的錯(cuò)誤處理代碼

vuex使用中的一些注意事項(xiàng)

1)不要濫用vuex

使用Vuex并不意味著你需要將所有的狀態(tài)放入Vuex凛俱。雖然將所有的狀態(tài)放到Vuex會(huì)使?fàn)顟B(tài)變化更顯式和易調(diào)試,但也會(huì)使代碼變得冗長和不直觀料饥。如果有些狀態(tài)嚴(yán)格屬于單個(gè)組件蒲犬,最好還是作為組件的局部狀態(tài)。你應(yīng)該根據(jù)你的應(yīng)用開發(fā)需要進(jìn)行權(quán)衡和確定岸啡。

2)最好在根實(shí)例中注冊(cè)store選項(xiàng)暖哨,該store實(shí)例會(huì)注入到根組件下的所有子組件中,子組件可以通過this.$store訪問,當(dāng)狀態(tài)較多時(shí)使用建議mapState輔助函數(shù)篇裁。

3)polyfill

本次項(xiàng)目中使用了vuex沛慢,因此為兼容IE9等低版本,須引入promise的polyfill--es6-promise达布。npm install后在main.js:

import 'es6-promise/auto'

開發(fā)中的常見問題

引入axios

為了和后端進(jìn)行數(shù)據(jù)交互团甲,我們一般引入axios庫。在main.js中如下將其加入vue的原型中黍聂,這樣可以在組件中通過this.$http來獲取axios:

Object.defineProperty(Vue.prototype, '$http', { value: axios })
// 或者 Object.defineProperty(Vue.prototype, '$axios', { value: axios })

這次實(shí)踐中未采用這種做法躺苦,而是創(chuàng)建了一個(gè)getData.js進(jìn)行了統(tǒng)一管理:

import axios from 'axios'

const getSomething = (param1,param2) => axios.get(url产还,{
  params: {
    param1: param1,
    param2: param2
  }
})

export {
  getSomething
}

在單文件組件中import getSomething方法再進(jìn)行調(diào)用即可匹厘。

引入iconfont

直接在main.js中import你下載的iconfont.css即可

js中判斷環(huán)境

常見的需求是開發(fā)環(huán)境須console,而線上環(huán)境不可以console脐区。默認(rèn)環(huán)境有'development'愈诚、'production'、'testing'三種牛隅。

if (process.env.NODE_ENV !== 'production') {
  console.log(data)
}

設(shè)置數(shù)據(jù)模擬請(qǐng)求Mock

數(shù)據(jù)模擬請(qǐng)求利用了mock.js,配置文檔炕柔,不過這個(gè)只是簡單的數(shù)據(jù)模擬,沒有生成文檔的功媒佣,更全面的文檔匕累、Mock.js、可視化默伍、Rest欢嘿、接口過渡、文檔修改提醒也糊、支持本地部署等功能可以使用阿里RAP际插。

npm install mockjs安裝后,可在/src/api目錄下新建data.js显设,引入mockjs框弛,后可在程序入口或api入口根據(jù)開發(fā)環(huán)境來引入data.js,下面是幾個(gè)示例:

import Mock from 'mockjs'
let data = Mock.mock({
  'list|1-10': [{
      'id|+1': 1
  }]
}) // mock一個(gè)數(shù)據(jù)
console.log(JSON.stringify(data, null, 4))

import Mock from 'mockjs'
Mock.setup({ timeout: '300‐500' })
Mock.mock(/\/login/, { code: 0 }) // 攔截login請(qǐng)求捕捂,返回對(duì)象{ code: 0 }

import Mock from 'mockjs'
Mock.setup({ timeout: '300‐500' })
Mock.mock(sitemap.cms.banners, {
  results: []
}) // 攔截sitemap中cms.banners請(qǐng)求瑟枫,返回對(duì)象{ results: [] }

seo

可以使用服務(wù)端渲染或者預(yù)渲染,預(yù)渲染webpack插件github地址指攒。

Webpack

實(shí)際項(xiàng)目中還是不可避免地要修改webpack配置慷妙,如果不知道怎么改的話就去查看webpack的配置分析去進(jìn)行修改。

配置全局變量

要設(shè)置全局變量可以在build中的webpack.base.conf.js中配置externals允悦,與module同級(jí):

externals: {
  sitemap: 'sitemap'
}   

然后在eslinttrc.js的module.exports添加這樣一個(gè)配置:

globals: {
  'sitemap': false
}

根據(jù)環(huán)境的不同加載不同的js

在這個(gè)項(xiàng)目中要根據(jù)環(huán)境(開發(fā)環(huán)境膝擂、測試環(huán)境、生產(chǎn)環(huán)境)的不同加載不同的sitemap.js,這個(gè)sitemap.js會(huì)暴露出一個(gè)全局的sitemap變量架馋,sitemap變量是個(gè)由api地址構(gòu)成的json對(duì)象狞山。利用HtmlWebpackPlugin插件的option選項(xiàng)來實(shí)現(xiàn)。

在index.html中這樣寫:

<script src="<%= htmlWebpackPlugin.options.src %>"></script>

然后在build中的各自conf.js的HtmlWebpackPlugin設(shè)置不同的src叉寂,如在開發(fā)環(huán)境中添加src那一行:

new HtmlWebpackPlugin({
  filename: 'index.html',
  template: 'index.html',
  src: '//dev.example.com/api/sitemap.js',
  inject: true
})

配置alias(別名)

在webpack.base.conf.js萍启,vue-cli已經(jīng)默認(rèn)配置好了src目錄的別名為@,建議配置src下一級(jí)目錄的別名屏鳍,這樣能減少重復(fù)書寫也更美觀勘纯,如下添加src、pages钓瞭、components別名:

resolve: {
  extensions: ['.js', '.vue', '.json'],
  alias: {
    'vue$': 'vue/dist/vue.esm.js',
    '@': resolve('src'),
    'src': resolve('src'),
    'pages': resolve('src/pages'),
    'components':  resolve('src/components')
  }
}

圖片壓縮

可以使用webpack插件image-webpack-loader來壓縮處理圖片驳遵。

多頁面

實(shí)際就是添加多個(gè)入口js然后再修改相應(yīng)配置,網(wǎng)上資料很多山涡,一搜就知道了堤结。

eslint

我們有時(shí)候需要關(guān)閉某些代碼檢查,具體配置參見Configuring ESLint - ESLint中文佳鳖,下面是常見的兩個(gè):

1)關(guān)閉eslint

/* eslint-disable */

alert('foo')

/* eslint-enable */

2)關(guān)閉禁止new

/* eslint-disable no-new */

優(yōu)化和其他

優(yōu)化

1)由于vue的追蹤對(duì)象變化原理基于使用Object.defineProperty,在處理大量數(shù)據(jù)并且不需要追蹤對(duì)象變化時(shí)媒惕,可通過Object.freeze(data)凍結(jié)對(duì)象達(dá)到優(yōu)化數(shù)據(jù)渲染處理

2)vue-router路由懶加載系吩。當(dāng)打包構(gòu)建應(yīng)用時(shí),javascript包會(huì)變得非常大妒蔚,影響頁面加載穿挨。如果我們能把不同路由對(duì)應(yīng)的組件分割成不同的代碼塊,然后當(dāng)路由被訪問的時(shí)候才加載對(duì)應(yīng)組件肴盏,這樣就更加高效了科盛。

其他

1)使用表驅(qū)動(dòng)法來注冊(cè)全局filter、指令等菜皂,如在src下新建filters目錄贞绵,index.js中import所有全局過濾器:

import milliFormat from './milliFormat'
import reverse from './reverse'

export default {
  milliFormat,
  reverse
}

然后在main.js中注冊(cè)

import commonFiltes from './filters/index'

Object.keys(commonFiltes).forEach(key => Vue.filter(key, commonFiltes[key]))

2)對(duì)于一些強(qiáng)耦合的組件如collapse和collapse-item,可以使用parent和children來進(jìn)行通信恍飘,沒必要像elementUI一樣自己實(shí)現(xiàn)組件的broadcast和dispatch榨崩,我還發(fā)現(xiàn)有UI庫竟然是使用bus來通信的,這樣導(dǎo)致同一個(gè)頁面要是有兩個(gè)collapse章母,就會(huì)互相影響母蛛。

3)在根組件上注冊(cè)公共過濾器后,除了在“Mustache”語法中使用乳怎,還可在組件中通過this.root.options.filters.datetime(data)獲取datetime過濾器彩郊。

打包上線

優(yōu)化分析

npm run build --report進(jìn)行打包大小分析,可視化地看到有什么地方需要優(yōu)化。

測試build后的文件

build成功后有個(gè)tip提示你build后的文件需要部署在http服務(wù)器上秫逝,不能通過file協(xié)議打開恕出。

我們可以通過node-static來啟動(dòng)服務(wù)】甑牵可以寫一個(gè)js配置文件通過node來啟動(dòng)剃根,或者CLI中輸入static dist(先安裝node-static):

$ static dist
serving "dist" at http://127.0.0.1:8080

更多如設(shè)置端口等請(qǐng)點(diǎn)擊上面的鏈接查看文檔。

后語

本文最重要的是文章中給出的一些鏈接,尤其是開發(fā)前須知章節(jié)中的鏈接,最好點(diǎn)進(jìn)去通讀一下妓美。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末刀崖,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子熬甫,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件渣慕,死亡現(xiàn)場離奇詭異,居然都是意外死亡抱慌,警方通過查閱死者的電腦和手機(jī)逊桦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來抑进,“玉大人强经,你說我怎么就攤上這事∷律” “怎么了匿情?”我有些...
    開封第一講書人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長信殊。 經(jīng)常有香客問我炬称,道長,這世上最難降的妖魔是什么涡拘? 我笑而不...
    開封第一講書人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任玲躯,我火速辦了婚禮,結(jié)果婚禮上鳄乏,老公的妹妹穿的比我還像新娘府蔗。我一直安慰自己,他們只是感情好汞窗,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開白布姓赤。 她就那樣靜靜地躺著,像睡著了一般仲吏。 火紅的嫁衣襯著肌膚如雪不铆。 梳的紋絲不亂的頭發(fā)上蝌焚,一...
    開封第一講書人閱讀 52,441評(píng)論 1 310
  • 那天,我揣著相機(jī)與錄音誓斥,去河邊找鬼只洒。 笑死,一個(gè)胖子當(dāng)著我的面吹牛劳坑,可吹牛的內(nèi)容都是我干的毕谴。 我是一名探鬼主播,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼距芬,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼涝开!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起框仔,我...
    開封第一講書人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤舀武,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后离斩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體银舱,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年跛梗,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了寻馏。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡核偿,死狀恐怖诚欠,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情宪祥,我是刑警寧澤聂薪,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布家乘,位于F島的核電站蝗羊,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏仁锯。R本人自食惡果不足惜耀找,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望业崖。 院中可真熱鬧野芒,春花似錦、人聲如沸双炕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽妇斤。三九已至摇锋,卻和暖如春丹拯,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背荸恕。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來泰國打工乖酬, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人融求。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓咬像,卻偏偏與公主長得像,于是被迫代替她去往敵國和親生宛。 傳聞我的和親對(duì)象是個(gè)殘疾皇子县昂,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359