閱讀113 返回首頁    go 阿裏雲 go 技術社區[雲棲]


vue工具

生產環境部署

開啟生產環境模式

開發時,Vue會提供很多警告來幫你解決常見的錯誤與陷阱。生產時,這些警告語句卻沒有用,反而會增加你的載荷量。再次,有些警告檢查有小的運行時開銷,生產環境模式下是可以避免的

不用打包工具

如果用Webpack或Browserify類似的打包工具時,生產狀態會在Vue源碼中由process.env.NODE_ENV決定,默認在開發狀態。Webpack與Browserify兩個打包工具都提供方法來覆蓋此變量並使用生產狀態,警告語句也會被精簡掉。每一個vue-cli模板有預先配置好的打包工具,但了解怎樣配置會更好

webpack

使用Webpack的DefinePlugin來指定生產環境,以便在壓縮時可以讓UglifyJS自動刪除代碼塊內的警告語句。例如配置:

var webpack = require('webpack')
module.exports = {
  // ...
  plugins: [
    // ...
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: '"production"'
      }
    }),
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      }
    })
  ]
}

Browserify

運行打包命令,設置NODE_ENV為"production"。等於告訴vueify避免引入熱重載和開發相關代碼。使用一個全局envify轉換bundle文件。這可以精簡掉包含在Vue源碼中所有環境變量條件相關代碼塊內的警告語句。例如:

NODE_ENV=production browserify -g envify -e main.js | uglifyjs -c -m > build.js

Rollup

const replace = require('rollup-plugin-replace')
rollup({
  // ...
  plugins: [
    replace({
      'process.env.NODE_ENV': JSON.stringify( 'production' )
    })
  ]
}).then(...)

預編譯模板

當需要處理DOM內或JavaScript內的模板時,“從模板到渲染函數”的編譯就會在線上發生。通常情況下這種處理是足夠快的,但是如果你的應用對性能很敏感最好還是回避。預編譯模板最簡單的方式就是使用單文件組件--相關的構建設置會自動把預編譯處理好,所以構建好的代碼已經包含了編譯出來的渲染函數而不是原始的模板字符串。如果使用Webpack並且喜歡分離JavaScript和模板文件,可以使用vue-template-loader,它也可以在構建過程中把模板文件轉換成為JavaScript渲染函數。

提取組件的css

當使用單文件組件時,組件內的CSS會以

跟蹤運行時錯誤

如果在組件渲染時出現運行錯誤,錯誤將會被傳遞至全局Vue.config.errorHandler配置函數(如果已設置)。利用這個鉤子函數和錯誤跟蹤服務(如Sentry,它為Vue提供官方集成),可能是個不錯的主意

單文件組件

介紹

在很多Vue項目中,我們使用Vue.component來定義全局組件,緊接著用new Vue({el: '#container'}) 在每個頁麵內指定一個容器元素

這種方式在很多中小規模的項目中運作的很好,在這些項目裏JavaScript隻被用來加強特定的視圖。但當在更複雜的項目中,或者你的前端完全由JavaScript驅動的時候,下麵這些缺點將變得非常明顯:

1.全局定義(Global definitions)強製要求每個component中的命名不得重複

2.字符串模板(String templates)缺乏語法高亮,在HTML有多行的時候,需要用到醜陋的\
3.不支持CSS(No CSS support)意味著當HTML和JavaScript組件化時,CSS明顯被遺漏

4.沒有構建步驟(No build step)限製隻能使用HTML和ES5 JavaScript,而不能使用預處理器,如Pug(formerly Jade)和 Babel

文件擴展名為.vue 的 single-file components(單文件組件)為以上所有問題提供了解決方法,並且還可以使用Webpack或Browserify等構建工具

現在我們獲得:完整語法高亮、CommonJS模塊、組件化的CSS

正如說過的,可以使用預處理器來構建簡潔和功能更豐富的組件,比如Pug,Babel(with ES2015 modules),和Stylus

這些特定的語言隻是例子,你可以隻是簡單地使用Babel,TypeScript,SCSS,PostCSS--或者其他任何能夠幫助你提高生產力的預處理器。如果搭配vue-loader使用Webpack,它也是把CSS Modules當作第一公民來對待的

怎麼看待關注點分離

一個重要的事情值得注意:關注點分離不等於文件類型分離。在現代UI開發中,我們已經發現相比於把代碼庫分離成三個大的層次並將其相互交織起來,把它們劃分為鬆散耦合的組件再將其組合起來更合理一些。在一個組件裏,其模板、邏輯和樣式是內部耦合的,並且把他們搭配在一起實際上使得組件更加內聚且更可維護。即便你不喜歡單文件組件,你仍然可以把JavaScript、CSS分離成獨立的文件然後做到熱重載和預編譯

<!-- my-component.vue -->
<template>
  <div>This will be pre-compiled</div>
</template>
<script src="./my-component.js"></script>
<style src="./my-component.css"></style>

起步

針對剛接觸js模塊開發係統的用戶

有了.vue組件,我們就進入了高級JavaScript應用領域。如果沒有準備好的話,意味著還需要學會使用一些附加的工具:

在花些時日了解這些資源後,建議參考webpack-simple。隻要遵循指示,就能很快地運行一個用到.vue組件,ES2015和熱重載(hot-reloading)的Vue項目!

這個模板使用Webpack,一個能將多個模塊打包成最終應用的模塊打包工具。在Webpack中,每個模塊被打包到bundle之前都由一個相應的“loader”來轉換,Vue也提供vue-loader插件來執行.vue單文件組件的轉換。這個webpack-simple模板已經為你準備好了所有的東西

單元測試

配置和工具

任何兼容基於模塊的構建係統都可以正常使用,例如可以使用Karma進行自動化測試。它有很多社區版的插件,包括對Webpack和Browserify的支持

簡單地斷言

在測試的代碼結構方麵,你不必為了可測試在你的組件中做任何特殊的操作。隻要導出原始設置就可以了:

<template>
  <span>{{ message }}</span>
</template>
<script>
  export default {
    data () {
      return {
        message: 'hello!'
      }
    },
    created () {
      this.message = 'bye!'
    }
  }
</script>

當測試的組件時,所要做的就是導入對象和 Vue 然後使用許多常見的斷言:

// 導入 Vue.js 和組件,進行測試
import Vue from 'vue'
import MyComponent from 'path/to/MyComponent.vue'
// 這裏是一些 Jasmine 2.0 的測試,你也可以使用你喜歡的任何斷言庫或測試工具。
describe('MyComponent', () => {
  // 檢查原始組件選項
  it('has a created hook', () => {
    expect(typeof MyComponent.created).toBe('function')
  })
  // 評估原始組件選項中的函數的結果
  it('sets the correct default data', () => {
    expect(typeof MyComponent.data).toBe('function')
    const defaultData = MyComponent.data()
    expect(defaultData.message).toBe('hello!')
  })
  // 檢查 mount 中的組件實例
  it('correctly sets the message when created', () => {
    const vm = new Vue(MyComponent).$mount()
    expect(vm.message).toBe('bye!')
  })
  // 創建一個實例並檢查渲染輸出
  it('renders the correct message', () => {
    const Ctor = Vue.extend(MyComponent)
    const vm = new Ctor().$mount()
    expect(vm.$el.textContent).toBe('bye!')
  })
})

編寫可被測試的組件

很多組件的渲染輸出由它的props決定。事實上,如果一個組件的渲染輸出完全取決於它的props,那麼它會讓測試變得簡單,就好像斷言不同參數的純函數的返回值。看下麵這個例子:

<template>
  <p>{{ msg }}</p>
</template>
<script>
  export default {
    props: ['msg']
  }
</script>

你可以在不同的 props 中,通過 propsData 選項斷言它的渲染輸出:

import Vue from 'vue'
import MyComponent from './MyComponent.vue'
// 掛載元素並返回已渲染的文本的工具函數
function getRenderedText (Component, propsData) {
  const Ctor = Vue.extend(Component)
  const vm = new Ctor({ propsData: propsData }).$mount()
  return vm.$el.textContent
}
describe('MyComponent', () => {
  it('renders correctly with different props', () => {
    expect(getRenderedText(MyComponent, {
      msg: 'Hello'
    })).toBe('Hello')
    expect(getRenderedText(MyComponent, {
      msg: 'Bye'
    })).toBe('Bye')
  })
})

斷言異步更新

由於Vue進行異步更新DOM的情況,一些依賴DOM更新結果的斷言必須在Vue.nextTick回調中進行:

// 在狀態更新後檢查生成的 HTML
it('updates the rendered message when vm.message updates', done => {
  const vm = new Vue(MyComponent).$mount()
  vm.message = 'foo'
  // 在狀態改變後和斷言 DOM 更新前等待一刻
  Vue.nextTick(() => {
    expect(vm.$el.textContent).toBe('foo')
    done()
  })
})

我們計劃做一個通用的測試工具集,讓不同策略的渲染輸出(例如忽略子組件的基本渲染)和斷言變得更簡單

TypeScript支持

從2.2.0起針對TS+Webpack 2用戶的重要改動

在Vue2.2裏,我們引入了新機製,把dist文件都作為ES模塊發布。這在webpack 2中屬於默認行為。遺憾的是,這個改動會引入一個會破壞兼容性的意外改動。在TypeScript+webpack 2裏,import Vue = require('vue')會返回一個綜合的ES模塊對象,而不是Vue對象本身。我們計劃在未來把所有官方類型聲明都改成ES-風格的導出方式

發布為NPM包的官方聲明文件

靜態類型係統能幫助你有效防止潛在的運行時錯誤,而且隨著應用日漸豐滿會更加顯著。這就是為什麼Vue不僅僅為Vue core提供針對TypeScript的官方類型聲明,還為Vue Router和Vuex也提供了相應的聲明文件。而且,我們已經把他們發布於NPM,最新版本的TypeScript也知道該如何自己從NPM包裏解析類型聲明。這意味著隻要你成功地通過NPM安裝了,就不再需要任何額外的工具輔助,即可在Vue中使用TypeScript

推薦配置

{ // tsconfig.json
  "compilerOptions": {
    // ... 已省略其它選項
    "allowSyntheticDefaultImports": true,
    "lib": [
      "dom",
      "es5",
      "es2015.promise"
    ]
  }
}

請注意:allowSyntheticDefaultImports選項允許你使用下列語法:

import Vue from 'vue'

而不是這種:

import Vue = require('vue') // 注:老語法

我們更為推薦前者(ES模塊語法),因為他跟原生的ES用法更為一致,而且在未來,我們計劃把官方聲明全部搬遷到ES風格的導出方式。另外,如果你是搭配webpack 2使用TypeScript,那麼以下配置也很推薦:

{
  "compilerOptions": {
    // ... 已省略其他配置
    "module": "es2015",
    "moduleResolution": "node"
  }
}

這句選項告訴TypeScript不要處理ES模塊引入語句(譯注:import .. from ..)。這樣webpack 2就可以充分利用其基於ES模塊的tree-shaking

使用Vue的類型聲明

Vue的類型聲明導出了很多有效的類型聲明。比如,標記一個導出的組件選項對象(e.g. 在 .vue 文件中):

import Vue, { ComponentOptions }  from 'vue'
// 聲明該組件的類型
interface MyComponent extends Vue {
  message: string
  onClick (): void
}
export default {
  template: '<button @click="onClick">Click!</button>',
  data: function () {
    return {
      message: 'Hello!'
    }
  },
  methods: {
    onClick: function () {
      // TypeScript 知道 `this` 是類型為 MyComponent 的對象
      // 因此 `this.message` 會是一個 string
      window.alert(this.message)
    }
  }
// 我們需要顯式地標注導出選項對象為 MyComponent 類型
} as ComponentOptions<MyComponent>

不幸的是,這裏也有一些局限性:

1.TypeScript不能推斷出Vue API裏的所有類型。比如,他們不知道我們data 函數中返回的message屬性會被添加到MyComponent實例中。這意味著如果我們給message賦值一個數字或者布爾值,linter和編譯器並不能拋出一個“該值應該是字符串”的錯誤。

2.因為第一條的局限, 如上的類型注釋可能會很羅嗦。TypeScript不能正確推導message的類型,是唯一迫使我們手動聲明它是string的原因。好消息是,vue-class-component能解決以上的兩個問題。這是一個官方的姐妹庫,它能允許你把組件聲明為一個原生的JavaScript類,外加一個@Component的修飾符。為了舉例說明,我們把上麵的例子重寫一下吧:

import Vue from 'vue'
import Component from 'vue-class-component'
@Component({ // @Component 修飾符注明了此類為一個 Vue 組件  
  template: '<button @click="onClick">Click!</button>' // 所有的組件選項都可以放在這裏
})
export default class MyComponent extends Vue {  
  message: string = 'Hello!' // 初始數據可以直接聲明為實例的屬性  
  onClick (): void { // 組件方法也可以直接聲明為實例的方法
    window.alert(this.message)
  }
}

有了這種備選語法,我們的組件定義不僅更加短小,而且TypeScript也能在無需顯式接口聲明的情況下,正確推斷message和onClick的類型。這個策略甚至能讓你處理計算屬性(computed),生命周期鉤子以及render函數的類型

生命vue插件補充的類型

插件可以增加Vue的全局/實例屬性和組件選項。在這些情況下,在TypeScript中製作插件需要類型聲明。慶幸的是,TypeScript有一個特性來補充現有的類型,叫做模塊補充(module augmentation)

例如,聲明一個string類型的實例屬性$myProperty:

import Vue from 'vue' // 1. 確保在聲明補充的類型之前導入 'vue'
declare module 'vue/types/vue' { // 2. 定製一個文件設置你想要補充的類型;在types/vue.d.ts裏Vue有構造函數類型
  interface Vue { // 3. 聲明為 Vue 補充的東西 
    $myProperty: string
  }
}

在項目中包含了上述作為聲明文件的代碼後(像 my-property.d.ts),就可以在Vue實例上使用 $myProperty 了

var vm = new Vue()
console.log(vm.$myProperty) // 將會順利編譯通過

你也可以聲明額外的屬性和組件選項:

import Vue from 'vue'
declare module 'vue/types/vue' {  
  namespace Vue { // 可以使用 `namespace` 替代 `interface`來聲明全局屬性
    const $myGlobal: string
  }
}
declare module 'vue/types/options' { // ComponentOptions 聲明於 types/options.d.ts 之中
  interface ComponentOptions<V extends Vue> {
    myOption?: string
  }
}

上述的聲明允許下麵的代碼順利編譯通過:

console.log(Vue.$myGlobal) // 全局屬性
var vm = new Vue({ // 額外的組件選項
  myOption: 'Hello'
})

最後更新:2017-09-16 16:03:49

  上一篇:go  MySQL 數據恢複方法(一)
  下一篇:go  物聯網加速 “無人經濟 ”時代到來