隨着avalon的發展壯大,我根據CSDN的統計數字,中國前端大概有1%的人在使用avalon了。
avalon的最大優勢是能兼容IE6,並且其API是非常穩定,只是在1.3.7 對ms-duplex的攔截器做了一次改動(但這次改動也向下兼容),1.5中去除avalon.define的舊風格支持,廢掉ms-widget指令改成更強大的自定義標簽指令。相對於其他MVVM框架來說,是非常的良心。此外,配套是非常完善,尤其是oniui,也支持到IE6。至於對移動端啊,微信啊,支持也非常好,難怪每天加群的人這么多。
不過,一個問題是,avalon沒有提供打包機制,雖然官網有教如何用requirejs打包avalon(比如滴滴出行,他們則是用fis3打包avalon ),但也有一些小公司,因為前端團隊實力不濟,無法實現打包。因此就有了這篇文章了。
本文是使用當今最強大的構建工具webpack實現的,各種看官首先得裝上npm。
建立一個新工程(我是將此工程起名為oni), 然后用npm初始化它,目的是建立一個package.json文件:

然后全局安裝以下東西
$ npm install webpack -g $ npm install style-loader css-loader url-loader text-loader -g
然后再到oni目錄下執行npm link命令
$ npm link webpack style-loader css-loader text-loader

雖然看似報了一大堆錯,但好歹也裝上了:

然后 我們安裝avalon依賴,由於要用oniui,只能使用1.4.* 版本,並且只能沒有加載器的版本(帶shim字樣的),請到這里下載https://github.com/RubyLouvre/avalon/tree/master/dist ,將里面的avalon.shim.js下載回來,放到dev/avalon目錄下。
然后 我們開始裝oniui。oniui是一個龐大的UI庫,為了滿足去哪兒各條業務線千奇百計的需求,組件非常豐富,功能強大無比! 我們沒有必要將它們全部裝上。我們可以在這里(https://github.com/RubyLouvre/avalon.oniui)一覽其全貌,挑選自己需要的組件(readme里有中文名)
比如,我們用手風琴(accordion)組件,那么打開里面的avalon.accordion.js的源碼,看其依賴情況:

會發現它依賴於avalon.getModel.js,這是在它的上級目錄;還有它的模板文件,與它同目錄; 還有一些樣式。accordion的目錄下有許多東西,為了節省時間,我們可以全部拷下來放到dev目錄下。

然后 我們在oni的根目錄下建立webpack的配置文件webpack.package.js,內容如下:
var webpack = require("webpack"); var path = require("path"); module.exports = { entry: "./dev/index", //我們開發時的入口文件 output: {path: path.join(__dirname, "dist"), filename: "bundle.js"}, //頁面引用的文件 module: { loaders: [ {test: /\.css$/, loader: 'style-loader!css-loader'} ] }, resolve: { extensions: ['.js',"",".css"], alias: { avalon: './avalon/avalon.shim',//在正常情況下我們以CommonJS風格引用avalon,以require('avalon') "../avalon": './avalon/avalon.shim'//由於oniui都以是../avalon來引用avalon的,需要在這里進行別名 } } }
dev下的index.js是這樣的:
var avalon = require("avalon") require("./accordion/avalon.accordion") avalon.define({ $id: "test", aaa: "Hello Avalon!" }) // 具體參考這里 https://github.com/RubyLouvre/avalon.oniui/blob/master/accordion/avalon.accordion.ex1.html avalon.define({ $id: "test", aaa: "Hello Avalon!", $opts:{ data: [{ 'title': '標題1', 'content': '正文1fasdfsdaf
' }, { 'title': '標題2', 'content': '正文2' }], accordionClass: "oni-accordion-customClass", initIndex: 1, width: "500", onBeforeSwitch: function() { avalon.log(this); avalon.log(arguments); avalon.log("onBeforeSwitch callback"); }, onSwitch: function() { avalon.log("onSwitch callback"); }, multiple: true } })
然后我們在控制台下,定位到oni目錄下,輸入webpack開始打包,報了一堆錯誤

其實我對webpack也不怎么熟,主要是參考如下中文教程開始玩的
我思度一下,估計沒有像我這樣混用CommonJS與AMD兩種風格,問題是出在加載CSS上,難道正則有問題嗎?試了好久,沒有辦法,自己寫預加載器,從avalon.accordion的源碼中干掉css!字樣。
具體過程如下,在oni/node_modules目錄下建立一個amdcss-loader目錄,結構如下:

package.json內容如下(這個不能少)
{ "author": { "name": "RubyLouvre" }, "dependencies": {}, "description": "Webpack的預處理器,處理AMD風格的模塊依賴列表中的css!字符串", "license": "MIT", "main": "index.js", "name": "amdcss-loader", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "version": "0.0.1" }
index.js內容如下:
module.exports = function (source) { this.cacheable && this.cacheable(); source = source.replace(/css\!/g, "") this.callback(null, source); };
將webpack.config.js修改如下:
var webpack = require("webpack"); var path = require("path"); module.exports = { entry: './dev/index', //我們開發時的入口文件 output: {path: path.join(__dirname, "dist"), filename: "bundle.js"}, //頁面引用的文件 module: { loaders: [ {test: /\.css$/, loader: 'style-loader!css-loader'} ], preLoaders: [ {test: /\.js$/, loader: "amdcss-loader"} ] }, resolve: { extensions: ['.js', "", ".css"], alias: { avalon: './avalon/avalon.shim', //在正常情況下我們以CommonJS風格引用avalon,以require('avalon') "../avalon": './avalon/avalon.shim'//由於oniui都以是../avalon來引用avalon的,需要在這里進行別名 } } }
再打包就成功了!

好了,我們需要一個頁面看一下效果。oniui目錄下,建立一個index.html
<!DOCTYPE html> <html> <head> <title>TODO supply a title</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <script src="dist/bundle.js"></script> <style> body{ padding:2em; } </style> </head> <body ms-controller="test"> <h1>{{aaa}}</h1> <div ms-widget="accordion,$,$opts"></div> </body> </html>
然后打開你的頁面就行看到效果了(我是使用netBeans直接運行,大家也可以試一下webpack-dev-server)

我們再看一下如何結合jquery一起使用,jquery我們還是使用兼容IE6的版本,可以到這里下回來,放到dev/jquery目錄下!
我們繼續修改webpack.config.js
var webpack = require("webpack"); var path = require("path"); module.exports = { entry: './dev/index', //我們開發時的入口文件 output: {path: path.join(__dirname, "dist"), filename: "bundle.js"}, //頁面引用的文件 module: { loaders: [ {test: /\.css$/, loader: 'style-loader!css-loader'} ], preLoaders: [ {test: /\.js$/, loader: "amdcss-loader"} ] }, resolve: { extensions: ['.js', "", ".css"], alias: { jquery: "./jquery/jquery.js", avalon: './avalon/avalon.shim', //在正常情況下我們以CommonJS風格引用avalon,以require('avalon') "../avalon": './avalon/avalon.shim'//由於oniui都以是../avalon來引用avalon的,需要在這里進行別名 } } }
然后修改dev/index.js
var avalon = require("avalon") require("./accordion/avalon.accordion") var $ = require("jquery") avalon.define({ $id: "test", aaa: "Hello Avalon!", $opts:{ data: [{ 'title': '標題1', 'content': '正文1fasdfsdaf
' }, { 'title': '標題2', 'content': '正文2' }], accordionClass: "oni-accordion-customClass", initIndex: 1, width: "500", onBeforeSwitch: function() { avalon.log(this); avalon.log(arguments); avalon.log("onBeforeSwitch callback"); }, onSwitch: function() { avalon.log("onSwitch callback"); }, multiple: true } }) $(function(){ $("這是jQuery生成的").appendTo("body") })
重新運行webpack命令,jquery就打包進去!

不過,我其實不希望大家將jquery與avalon都打包進去的,因為這兩個庫比較常用,幾乎每個頁面都有,建立放到CDN中,用script獨立引入。詳見 《Webpack 性能優化 (一)(使用別名做重定向)》一文。
至此,本文完畢。我是希望avalon社區能使用更強大的工具進行打包,而不是用requriejs之流了。