淺談webpack下的AOP式無侵入注入
說起來, 面向切面編程(AOP)自從誕生之日起,一直都是計算機科學(xué)領(lǐng)域十分熱門的話題,但是很奇怪的是,在前端圈子里,探討AOP的文章似乎并不是多,而且多數(shù)拘泥在給出理論,然后實現(xiàn)個片段的定式)難免陷入了形而上學(xué)的尷尬境地,本文列舉了兩個生產(chǎn)環(huán)境的實際例子論述webpack和AOP預(yù)編譯處理的結(jié)合,意在拋磚引玉。當(dāng)然,筆者能力有限,如果有覺得不妥之處,還請大家積極的反饋出來, 共同進步哈。
重要的概念
AOP: 面向切面編程,通過預(yù)編譯方式和運行期動態(tài)代理實現(xiàn)程序功能的統(tǒng)一維護的一種技術(shù)。
Joint point:表示在程序中明確定義的點,典型的包括方法調(diào)用,對類成員的訪問以及異常處理程序塊的執(zhí)行等等,它自身還可以嵌套其它 joint point。
Advice:Advice 定義了在 pointcut 里面定義的程序點具體要做的操作,它通過 before、after 和 around 來區(qū)別是在每個 joint point 之前、之后還是代替執(zhí)行的代碼。
通過前面的定義,我們可以提煉出一句更簡單的定義,利用靜/動態(tài)的方式使代碼塊在何時/何地運行。
性能統(tǒng)計
項目的背景是一個利用vue+webpack打造的多頁面應(yīng)用 (多入口點),她的結(jié)構(gòu)大概是這個樣子的
var baseConf = {
// code here
entry: {
index: 'src/index',
list: 'src/list',
detail: 'src/detail',
// and so on ...
},
// code here
}
然后以index入口點舉例,大概代碼為src/index/index.js
import Vue from 'vue'
import App from './app'
new Vue({
el: '#app',
render: h => h(App)
})
期望引入一個vue插件,能夠自動的監(jiān)控當(dāng)前頁面的性能,于是,代碼看起來像是這個樣子
import Vue from 'vue'
Vue.use(performance) //性能統(tǒng)計
import App from './app'
new Vue({
el: '#app',
render: h => h(App)
})
由于這種方式意味著每個入口點均需要進行修改,(實際上這個項目的入口點超過30個,而且隨時可能繼續(xù)增加下去)簡直就是一個體力活。所以,讓我們用AOP的思想來考慮一下如何處理這個問題
首先觀察入口點邏輯
原:引入vue -> 引入app組件 -> 實例化vue組件
新:引入vue -> 應(yīng)用性能統(tǒng)計組件 -> 引入app組件 -> 實例化vue組件
套用到我們的定義上,可以輕松的得到
Joint point(何處) 引入vue
advice(何時) 之后
這樣理論上的東西似乎閉著眼睛都可以推論出來,但是如何將這樣的步驟替換到每一個入口點就是一個大問題了orz。幸運的是這是一個import,而翻閱webpack的文檔恰好有著這樣一個神奇的屬性--alias
resolve: {
alias: {
'vue$': resolve('src/vueHook.js')
}
src/vueHook.js
import vue from 'vue/dist/vue.common' vue.use(performance) export default vue
這樣,我們就完成了一個vue的全局鉤子模塊,我們按照步驟歸納,并且找到注入的位置 ,最后利用替換的方式成功的完成了無侵入式的組件應(yīng)用
code spliting
可能上面的例子有點小打小鬧的感覺,那么我們換一個案例,再來體驗一下這種靜態(tài)替換式的注入的威力,我們采用官方支持較差的react作為參考(vue在code spliting方面做得真心是超級棒~)
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ī)中矩的代碼,對吧?相信大家已經(jīng)發(fā)現(xià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)組件多的時候每一個模塊都需要一個人口點嗎,可以從webpack.context角度簡化這個問題嗎?
以上兩個例子均是模塊引用作為join point來進行注入操作的,而且完成了無侵入式的功能增強,這得益于webpack將js模塊作為一等公民。我們擁有著超多的權(quán)利完成靜態(tài)式的注入工作。 本文并沒有在技術(shù)上涉及太多,還是那句話,拋磚引玉哈~~~
以上這篇淺談webpack下的AOP式無侵入注入就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
CountUp.js實現(xiàn)數(shù)字滾動增值效果
這篇文章主要為大家詳細介紹了CountUp.js實現(xiàn)數(shù)字滾動增值效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-10-10
document.compatMode的CSS1compat使用介紹
這篇文章主要介紹了document.compatMode的CSS1compat使用,需要的朋友可以參考下2014-04-04
window.addeventjs事件驅(qū)動函數(shù)集合addEvent等
addEvent()、removeEvent()、handleEvent()、fixEvent()[2008-02-02
[Web]防止用戶復(fù)制頁面內(nèi)容和另存頁面的方法
原理就是利用js控制一些復(fù)制等事件,但破解也簡單,這里就不說了。2009-02-02

