Vue.js 構建大型應用

2018-04-12 14:24 更新

構建大型應用

新: 使用腳手架工具 vue-cli 可以快速地構建項目:單文件 Vue 組件,熱加載,保存時檢查代碼,單元測試等。

Vue.js 的設計思想是專注與靈活——它只是一個界面庫,不強制使用哪個架構。它能很好地與已有項目整合,不過對于經驗欠缺的開發(fā)者,從頭開始構建大型應用可能是一個挑戰(zhàn)。

Vue.js 生態(tài)系統(tǒng)提供了一系列的工具與庫,用于構建大型單頁應用。這些部分會感覺開始更像一個『框架』,但是它們本質上只是一套推薦的技術棧而已 - 你依然可以對各個部分進行選擇和替換。

模塊化

對于大型項目,為了更好地管理代碼使用模塊構建系統(tǒng)非常必要。推薦代碼使用 CommonJS 或 ES6 模塊,然后使用 WebpackBrowserify 打包。

Webpack 和 Browserify 不只是模塊打包器。兩者都提供了源碼轉換 API,通過它可以用其它預處理器轉換源碼。例如,借助 babel-loaderbabelify 代碼可以使用 ES2015/2016 語法。

如果你之前沒有用過它們,我強烈推薦你閱讀一些教程,了解模塊打包器,然后使用最新的 ECMAScript 特性寫 JavaScript。

單文件組件

在典型的 Vue.js 項目中,我們會把界面拆分為多個小組件,每個組件在同一地方封裝它的 CSS 樣式,模板和 JavaScript 定義,這么做比較好。如上所述,使用 Webpack 或 Browserify 以及合適的源碼轉換器,我們可以這樣寫組件:

img src

如果你喜歡預處理器,甚至可以這么做:

img src

你可以使用 Webpack + vue-loader 或 Browserify + vueify 構建這些單文件 Vue 組件。推薦使用 Webpack,因為它的加載器 API 提供更好的文件依賴追蹤/緩存以及一些 Browserify 沒有的轉換功能。

最快的構建方式是使用官方出品的腳手架工具 vue-cli。你也可以在 GitHub 上查看官方的構建模板:

路由

對于單頁應用,推薦使用官方庫 vue-router。詳細請查看它的文檔。

如果你只需要非常簡單的路由邏輯,可以這么做,監(jiān)聽 hashchange 事件并使用動態(tài)組件:

示例:

<div id="app">
  <component :is="currentView"></component>
</div>
Vue.component('home', { /* ... */ })
Vue.component('page1', { /* ... */ })
var app = new Vue({
  el: '#app',
  data: {
    currentView: 'home'
  }
})
// 在路由處理器中切換頁面
app.currentView = 'page1'

利用這種機制也可以非常容易地配合其它路由庫,如 Page.jsDirector

與服務器通信

Vue 實例的原始數據 $data 能直接用 JSON.stringify() 序列化。社區(qū)貢獻了一個插件 vue-resource,提供一種容易的方式與 RESTful APIs 配合。也可以使用任何自己喜歡的 Ajax 庫,如 $.ajaxSuperAgent。Vue.js 也能很好地與無后端服務配合,如 Firebase 和 Parse。

狀態(tài)管理

在大型應用中,狀態(tài)管理常常變得復雜,因為狀態(tài)分散在許多組件內。常常忽略 Vue.js 應用的來源是原生的數據對象—— Vue 實例代理訪問它。因此,如果一個狀態(tài)要被多個實例共享,應避免復制它:

var sourceOfTruth = {}

var vmA = new Vue({
  data: sourceOfTruth
})

var vmB = new Vue({
  data: sourceOfTruth
})

現在每當 sourceOfTruth 被修改后,vmAvmB 將自動更新它們的視圖。擴展這個思路,我們可以實現 store 模式

var store = {
  state: {
    message: 'Hello!'
  },
  actionA: function () {
    this.state.message = 'action A triggered'
  },
  actionB: function () {
    this.state.message = 'action B triggered'
  }
}

var vmA = new Vue({
  data: {
    privateState: {},
    sharedState: store.state
  }
})

var vmB = new Vue({
  data: {
    privateState: {},
    sharedState: store.state
  }
})

我們把所有的 action 放在 store 內,action 修改 store 的狀態(tài)。集中管理狀態(tài)更易于理解狀態(tài)將怎樣變化。組件仍然可以擁有和管理它的私有狀態(tài)。

狀態(tài)管理

有一點要注意,不要在 action 中替換原始的狀態(tài)對象——為了觀察到變化,組件和 store 需要共享這個對象。

如果我們約定,組件不可以直接修改 store 的狀態(tài),而應當派發(fā)事件,通知 store 執(zhí)行 action,那么我們基本上實現了 Flux 架構。此約定的好處是,我們能記錄 store 所有的狀態(tài)變化,并且在此之上實現高級的調試幫助函數,如修改日志,快照,歷史回滾等。

Flux 架構常用于 React 應用中,但它的核心理念也可以適用于 Vue.js 應用。比如 Vuex 就是一個借鑒于 Flux,但是專門為 Vue.js 所設計的狀態(tài)管理方案。React 生態(tài)圈中最流行的 Flux 實現 Redux 也可以通過簡單的綁定和 Vue 一起使用。

單元測試

任何支持模塊構建系統(tǒng)的單元測試工具都可以。推薦使用 Karma。它有許多插件,支持 WebpackBrowserify。用法見它們的文檔。

代碼測試的最佳實踐是導出組件模塊的選項/函數。例如:

// my-component.js
module.exports = {
  template: '<span>{{msg}}</span>',
  data: function () {
    return {
      msg: 'hello!'
    }
  }
  created: function () {
    console.log('my-component created!')
  }
}

在入口模塊中使用這個模塊:

// main.js
var Vue = require('vue')
var app = new Vue({
  el: '#app',
  data: { /* ... */ },
  components: {
    'my-component': require('./my-component')
  }
})

測試這個模塊:

// Jasmine 2.0 測試
describe('my-component', function () {
  // require source module
  var myComponent = require('../src/my-component')
  it('should have a created hook', function () {
    expect(typeof myComponent.created).toBe('function')
  })
  it('should set correct default data', function () {
    expect(typeof myComponent.data).toBe('function')
    var defaultData = myComponent.data()
    expect(defaultData.msg).toBe('hello!')
  })
})

Karma 的示例配置:Webpack, Browserify。

因為 Vue.js 指令是異步更新,如果想在修改數據之后修改 DOM ,應當在 `Vue.nextTick` 的回調中操作。

生產發(fā)布

為了更小的文件體積,Vue.js 的壓縮版本刪除所有的警告,但是在使用 Browserify 或 Webpack 等工具構建 Vue.js 應用時,壓縮需要一些配置。

Webpack

使用插件 DefinePlugin 將當前環(huán)境指定為生產環(huán)境,警告將在 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",然后運行打包命令。Vue 會自動應用 envify 并讓警告塊不能運行。例如:

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

應用示例

Vue.js Hackernews Clone 這個應用示例使用 Webpack + vue-loader 組織代碼,使用 vue-router 作為路由器,HackerNews 官方的 Firebase API 作為后端。它當然不是大應用,但是它綜合演示了本頁討論的概念。

以上內容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號