提及來, 面向切面編程(AOP)自從誕生之日起,一直都是計算機科學領域十分熱門的話題,可是很奇怪的是,在前端圈子裏,探討AOP的文章彷佛並非多,並且多數拘泥在給出理論,而後實現個片斷的定式)不免陷入了形而上學的尷尬境地,本文列舉了兩個生產環境的實際例子論述webpack和AOP預編譯處理的結合,意在拋磚引玉。固然,筆者能力有限,若是有以爲不妥之處,還請你們積極的反饋出來, 共同進步哈。前端
AOP: 面向切面編程,經過預編譯方式和運行期動態代理實現程序功能的統一維護的一種技術。vue
Joint point:表示在程序中明肯定義的點,典型的包括方法調用,對類成員的訪問以及異常處理程序塊的執行等等,它自身還能夠嵌套其它 joint point。react
Advice:Advice 定義了在 pointcut 裏面定義的程序點具體要作的操做,它經過 before、after 和 around 來區別是在每一個 joint point 以前、以後仍是代替執行的代碼。webpack
經過前面的定義,咱們能夠提煉出一句更簡單的定義,利用靜/動態的方式使代碼塊在什麼時候/何地運行。web
項目的背景是一個利用vue+webpack打造的多頁面應用 (多入口點),她的結構大概是這個樣子的編程
var baseConf = { // code here entry: { index: 'src/index', list: 'src/list', detail: 'src/detail', // and so on ... }, // code here }
而後以index入口點舉例,大概代碼爲src/index/index.jsapp
import Vue from 'vue' import App from './app' new Vue({ el: '#app', render: h => h(App) })
指望引入一個vue插件,可以自動的監控當前頁面的性能,因而,代碼看起來像是這個樣子post
import Vue from 'vue' Vue.use(performance) //性能統計 import App from './app' new Vue({ el: '#app', render: h => h(App) })
因爲這種方式意味着每一個入口點均須要進行修改,(實際上這個項目的入口點超過30個,並且隨時可能繼續增長下去)簡直就是一個體力活。因此,讓咱們用AOP的思想來考慮一下如何處理這個問題性能
首先觀察入口點邏輯this
原:引入vue -> 引入app組件 -> 實例化vue組件
新:引入vue -> 應用性能統計組件 -> 引入app組件 -> 實例化vue組件
套用到咱們的定義上,能夠輕鬆的獲得
這樣理論上的東西彷佛閉着眼睛均可以推論出來,可是如何將這樣的步驟替換到每個入口點就是一個大問題了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的全局鉤子模塊,咱們按照步驟概括,而且找到注入的位置 ,最後利用替換的方式成功的完成了無侵入式的組件應用
可能上面的例子有點小打小鬧的感受,那麼咱們換一個案例,再來體驗一下這種靜態替換式的注入的威力,咱們採用官方支持較差的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>)
一段中規中矩的代碼,對吧?相信你們已經發現了,在上述的代碼裏面彷佛並非每一個組件都是必須的,那麼,基於以上的思考,能夠對上面組件進行按需加載處理。 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;
以及相應的alias hook
export default ( <Bundle load={() => import(/* webpackChunkName: "widget" */ `../../component-modules/magic-single-image/src/index` )} > {Widget => <Widget {...props} />} </Bundle> )
思考,當組件多的時候每個模塊都須要一我的口點嗎,能夠從webpack.context角度簡化這個問題嗎?
以上兩個例子均是模塊引用做爲join point來進行注入操做的,並且完成了無侵入式的功能加強,這得益於webpack將js模塊做爲一等公民。咱們擁有着超多的權利完成靜態式的注入工做。 本文並無在技術上涉及太多,仍是那句話,拋磚引玉哈~~~
若是你喜歡咱們的文章,關注咱們的公衆號和咱們互動吧。