Vue.js 在設(shè)計(jì)思想上追求的是盡可能的靈活。它本身只是一個(gè)界面庫(kù),并不強(qiáng)制使用哪種架構(gòu)。這對(duì)于快速原型開(kāi)發(fā)很有用,但是對(duì)于經(jīng)驗(yàn)欠缺的開(kāi)發(fā)者,用 Vue.js 構(gòu)建大型應(yīng)用可能會(huì)是一個(gè)挑戰(zhàn)。在這里我會(huì)針對(duì)在使用 Vue.js 時(shí)如何組織大型的項(xiàng)目提供一些略帶個(gè)人偏好的建議。
雖然獨(dú)立構(gòu)建的 Vue.js 可以被用作一個(gè)全局變量,但是它通常更適合配合一個(gè)模塊化構(gòu)建系統(tǒng)使用,這可以讓你更好地組織代碼。我的建議是用 CommonJS 模塊格式編寫(xiě)源代碼 (這是 Node.js 使用的格式,也是 Vue.js 源代碼使用的格式),并通過(guò) Webpack 或 Browserify 把它們打包起來(lái)。
更重要的是,Webpack 和 Browserify 不僅僅是模塊打包工具。兩者都提供源碼轉(zhuǎn)換的 API,允許你將你的源碼用其他的預(yù)處理程序進(jìn)行轉(zhuǎn)換。例如,你可以用 babel-loader 或 babelify 直接在你的模塊中使用 ES6/7 的語(yǔ)法。
在一個(gè)典型的 Vue.js 項(xiàng)目里,我們會(huì)希望將我們的代碼拆分成許多的組件,并且在一個(gè)組件里把它所包含的 CSS 樣式、HTML 模板、JavaScript 邏輯封裝在一起。就像上面提到的那樣,借助 Webpack 或 Browserify,并配以相應(yīng)的源碼轉(zhuǎn)換插件,我們就可以這樣編寫(xiě)組件了:
http://wiki.jikexueyuan.com/project/vue-js/images/4.png" alt="" />
如果你喜歡預(yù)處理器,你甚至可以這樣寫(xiě):
http://wiki.jikexueyuan.com/project/vue-js/images/5.png" alt="" />
你可以用 Webpack + vue-loader 或 Browserify + vueify 來(lái)編譯這些單文件的 Vue 組件。如果你同時(shí)使用預(yù)處理器,則推薦用 Webpack 來(lái)進(jìn)行構(gòu)建,因?yàn)?Webpack 的插件 API 提供了更好的文件依賴追蹤和緩存支持。
在 GitHub 上可以找到上面所描述的工作流的代碼示例:
Webpack + vue-loaderBrowserify + vueify官方路由模塊
vue-router正在活躍開(kāi)發(fā)中,即將發(fā)布。
你可以手動(dòng)監(jiān)聽(tīng) hashchange 時(shí)間并利用一個(gè)動(dòng)態(tài)的 <component> 來(lái)實(shí)現(xiàn)一些基本的路由邏輯。
示例:
<div id="app">
<component is="{{currentView}}"></component>
</div>```
```Vue.component('home', { /* ... */ })
Vue.component('page1', { /* ... */ })
var app = new Vue({
el: '#app',
data: {
currentView: 'home'
}
})
// Switching pages in your route handler:
app.currentView = 'page1'
利用這種機(jī)制我們可以很容易地接入獨(dú)立的路由庫(kù),比如 Page.js 或是 Director。
所有的 Vue 實(shí)例都可以直接通過(guò) JSON.stringify() 序列化得到它們?cè)嫉?$data,并不需要做任何額外的工作。社區(qū)已經(jīng)貢獻(xiàn)了 vue-resource 插件,提供了與 RESTful API 協(xié)作的功能。你也可以使用任何你喜歡的 Ajax 組件,比如 $.ajax 或是 SuperAgent。Vue.js 也可以和諸如 Firebase 和 Parse 這樣的 BaaS 服務(wù)完美配合。
任何兼容 CommonJS 構(gòu)建系統(tǒng)的測(cè)試工具都可以。建議使用 Karma 配合其 CommonJS 預(yù)處理插件 對(duì)你的代碼進(jìn)行模塊化測(cè)試。
最佳實(shí)踐是暴露出模塊內(nèi)的原始選項(xiàng)/函數(shù)。參考如下示例:
// my-component.js
module.exports = {
template: '<span>{{msg}}</span>',
data: function () {
return {
msg: 'hello!'
}
}
created: function () {
console.log('my-component created!')
}
}
你可以在你的入口模塊中如下使用這個(gè)文件:
// main.js
var Vue = require('vue')
var app = new Vue({
el: '#app',
data: { /* ... */ },
components: {
'my-component': require('./my-component')
}
})
然后你可以如下測(cè)試該模塊:
// Some Jasmine 2.0 tests
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.message).toBe('hello!')
})
})
因?yàn)?Vue.js 的指令異步響應(yīng)數(shù)據(jù)的更新,當(dāng)你需要在數(shù)據(jù)更新后斷言 DOM 的狀態(tài)時(shí),你需要在一個(gè)
Vue.nextTick回調(diào)里做這件事。
為了縮小體積,最小化后的獨(dú)立版 Vue.js 已去除所有的警告信息,但當(dāng)你用像 Browserify、Webpack 這樣的工具構(gòu)建 Vue.js 應(yīng)用時(shí),并沒(méi)有一個(gè)明顯的辦法來(lái)去除這些警告。
從 0.12.8 開(kāi)始,可以采用如下的方式配置你的構(gòu)建工具來(lái)優(yōu)化最后生成的代碼體積:
使用 Webpack 的 DefinePlugin 來(lái)定義生產(chǎn)環(huán)境參數(shù),這樣警告相關(guān)的代碼會(huì)變得永遠(yuǎn)不會(huì)被執(zhí)行,從而在 UglifyJS 壓縮的時(shí)候會(huì)被自動(dòng)丟掉。比如:
var webpack = require('webpack')
module.exports = {
// ...
plugins: [
// ...
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
})
]
}
只需要在打包命令中把 NODE_ENV 設(shè)置成 "production" 即可。Vue 會(huì)自動(dòng)應(yīng)用 envify 轉(zhuǎn)換并跳過(guò)警告處理。比如:
NODE_ENV=production browserify -e main.js | uglifyjs -c -m > build.js
Vue.js Hackernews Clone 是一個(gè)應(yīng)用的例子,它用 Webpack + vue-loader 代碼組織、Director.js 做路由、HackerNews 官方的 Firebase API 為后端。這不算什么特別大的應(yīng)用,但它結(jié)合并展示了本頁(yè)面討論到的各方面概念。
下一節(jié):擴(kuò)展 Vue