淺談webpack下的AOP式無侵入注入
說起來, 面向切面編程(AOP)自從誕生之日起,一直都是計(jì)算機(jī)科學(xué)領(lǐng)域十分熱門的話題,但是很奇怪的是,在前端圈子里,探討AOP的文章似乎并不是多,而且多數(shù)拘泥在給出理論,然后實(shí)現(xiàn)個(gè)片段的定式)難免陷入了形而上學(xué)的尷尬境地,本文列舉了兩個(gè)生產(chǎn)環(huán)境的實(shí)際例子論述webpack和AOP預(yù)編譯處理的結(jié)合,意在拋磚引玉。當(dāng)然,筆者能力有限,如果有覺得不妥之處,還請(qǐng)大家積極的反饋出來, 共同進(jìn)步哈。
重要的概念
AOP: 面向切面編程,通過預(yù)編譯方式和運(yùn)行期動(dòng)態(tài)代理實(shí)現(xiàn)程序功能的統(tǒng)一維護(hù)的一種技術(shù)。
Joint point:表示在程序中明確定義的點(diǎn),典型的包括方法調(diào)用,對(duì)類成員的訪問以及異常處理程序塊的執(zhí)行等等,它自身還可以嵌套其它 joint point。
Advice:Advice 定義了在 pointcut 里面定義的程序點(diǎn)具體要做的操作,它通過 before、after 和 around 來區(qū)別是在每個(gè) joint point 之前、之后還是代替執(zhí)行的代碼。
通過前面的定義,我們可以提煉出一句更簡(jiǎn)單的定義,利用靜/動(dòng)態(tài)的方式使代碼塊在何時(shí)/何地運(yùn)行。
性能統(tǒng)計(jì)
項(xiàng)目的背景是一個(gè)利用vue+webpack打造的多頁(yè)面應(yīng)用 (多入口點(diǎn)),她的結(jié)構(gòu)大概是這個(gè)樣子的
var baseConf = { // code here entry: { index: 'src/index', list: 'src/list', detail: 'src/detail', // and so on ... }, // code here }
然后以index入口點(diǎn)舉例,大概代碼為src/index/index.js
import Vue from 'vue' import App from './app' new Vue({ el: '#app', render: h => h(App) })
期望引入一個(gè)vue插件,能夠自動(dòng)的監(jiān)控當(dāng)前頁(yè)面的性能,于是,代碼看起來像是這個(gè)樣子
import Vue from 'vue' Vue.use(performance) //性能統(tǒng)計(jì) import App from './app' new Vue({ el: '#app', render: h => h(App) })
由于這種方式意味著每個(gè)入口點(diǎn)均需要進(jìn)行修改,(實(shí)際上這個(gè)項(xiàng)目的入口點(diǎn)超過30個(gè),而且隨時(shí)可能繼續(xù)增加下去)簡(jiǎn)直就是一個(gè)體力活。所以,讓我們用AOP的思想來考慮一下如何處理這個(gè)問題
首先觀察入口點(diǎn)邏輯
原:引入vue -> 引入app組件 -> 實(shí)例化vue組件
新:引入vue -> 應(yīng)用性能統(tǒng)計(jì)組件 -> 引入app組件 -> 實(shí)例化vue組件
套用到我們的定義上,可以輕松的得到
Joint point(何處) 引入vue
advice(何時(shí)) 之后
這樣理論上的東西似乎閉著眼睛都可以推論出來,但是如何將這樣的步驟替換到每一個(gè)入口點(diǎn)就是一個(gè)大問題了orz。幸運(yùn)的是這是一個(gè)import,而翻閱webpack的文檔恰好有著這樣一個(gè)神奇的屬性--alias
resolve: { alias: { 'vue$': resolve('src/vueHook.js') }
src/vueHook.js
import vue from 'vue/dist/vue.common' vue.use(performance) export default vue
這樣,我們就完成了一個(gè)vue的全局鉤子模塊,我們按照步驟歸納,并且找到注入的位置 ,最后利用替換的方式成功的完成了無侵入式的組件應(yīng)用
code spliting
可能上面的例子有點(diǎn)小打小鬧的感覺,那么我們換一個(gè)案例,再來體驗(yàn)一下這種靜態(tài)替換式的注入的威力,我們采用官方支持較差的react作為參考(vue在code spliting方面做得真心是超級(jí)棒~)
import SingleImage from '../../component-modules/magic-single-image/src/index'; import DoubleImage from '../../component-modules/magic-double-image/src/index'; import ThreeImage from '../../component-modules/magic-three-image/src/index'; // many component here switch (componentName) { case 'SingleImage': PreviewingComponent = SingleImage; break; case 'DoubleImage': PreviewingComponent = DoubleImage; break; case 'ThreeImage': PreviewingComponent = ThreeImage; break; // many component here } return(<PreviewingComponent></PreviewingComponent>)
一段中規(guī)中矩的代碼,對(duì)吧?相信大家已經(jīng)發(fā)現(xiàn)了,在上述的代碼里面似乎并不是每個(gè)組件都是必須的,那么,基于以上的思考,可以對(duì)上面組件進(jìn)行按需加載處理。 Bundle.jsx
import React, { Component, PropTypes } from 'react'; class Bundle extends Component { static propTypes = { load: PropTypes.func, children: PropTypes.func, } state = { mod: null, } componentWillMount() { this.load(this.props); } componentWillReceiveProps(nextProps) { if (nextProps.load !== this.props.load) { this.load(nextProps); } } load(props) { this.setState({ mod: null, }); props.load().then((mod) => { this.setState({ // handle both es imports and cjs mod: mod.default ? mod.default : mod, }); }); } render() { return this.state.mod ? this.props.children(this.state.mod) : null; } } export default Bundle;
以及相應(yīng)的alias hook
export default ( <Bundle load={() => import(/* webpackChunkName: "widget" */ `../../component-modules/magic-single-image/src/index` )} > {Widget => <Widget {...props} />} </Bundle> )
思考,當(dāng)組件多的時(shí)候每一個(gè)模塊都需要一個(gè)人口點(diǎn)嗎,可以從webpack.context角度簡(jiǎn)化這個(gè)問題嗎?
以上兩個(gè)例子均是模塊引用作為join point來進(jìn)行注入操作的,而且完成了無侵入式的功能增強(qiáng),這得益于webpack將js模塊作為一等公民。我們擁有著超多的權(quán)利完成靜態(tài)式的注入工作。 本文并沒有在技術(shù)上涉及太多,還是那句話,拋磚引玉哈~~~
以上這篇淺談webpack下的AOP式無侵入注入就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Bootstrap滾動(dòng)監(jiān)聽(Scrollspy)插件詳解
滾動(dòng)監(jiān)聽插件是用來根據(jù)滾動(dòng)條所處在的位置自動(dòng)更新導(dǎo)航項(xiàng)目, 顯示導(dǎo)航項(xiàng)目高亮顯示。這篇文章主要介紹了Bootstrap滾動(dòng)監(jiān)聽(Scrollspy)插件的相關(guān)資料,需要的朋友可以參考下2016-04-04JS簡(jiǎn)單實(shí)現(xiàn)點(diǎn)擊按鈕或文字顯示遮罩層的方法
這篇文章主要介紹了JS簡(jiǎn)單實(shí)現(xiàn)點(diǎn)擊按鈕或文字顯示遮罩層的方法,涉及javascript鼠標(biāo)事件響應(yīng)及頁(yè)面元素屬性動(dòng)態(tài)操作相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2017-04-04javascript eval()應(yīng)用實(shí)例 select
javascript eval應(yīng)用小例子。實(shí)例代碼就是控制checkbox的選擇與取消的函數(shù),非常不錯(cuò)。2009-07-07在原生不支持的舊環(huán)境中添加兼容的Object.keys實(shí)現(xiàn)方法
下面小編就為大家?guī)硪黄谠恢С值呐f環(huán)境中添加兼容的Object.keys實(shí)現(xiàn)方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-09-09js手機(jī)號(hào)4位顯示空格,銀行卡每4位顯示空格效果
這篇文章主要介紹了js手機(jī)號(hào)4位顯示空格,銀行卡每4位顯示空格效果,手機(jī)號(hào)和銀行卡號(hào),按照每4位顯示一個(gè)空格的需求,非常具有實(shí)用價(jià)值,需要的朋友可以參考下。2017-03-03