背景说明
为了实现对扩展开放,对修改关闭
的开闭原则,CabloyJS从不同的维度思考可以扩展的方式。对于不同的功能,CabloyJS针对功能的特点提供了相应的扩展机制。除此之外,还提供了Module Monkey
机制,可以深度替换所有模块的前端和后端组件,实现高度的定制开发(二次开发)。Module Monkey
机制一般不轻易使用,是最后的大招
Module Monkey是什么
对于CabloyJS内置的模块,以及第三方提供的模块,如果我们想对这些模块提供的某些页面、功能、逻辑进行改造,一般有两种方法:
- Fork分支:If the module provides the source code, we can fork a branch and modify it on this branch
- Module Monkey:使用CabloyJS提供的
Module Monkey
机制,使我们可以像猴子🐒一样,很轻易的对模块的某些组件进行替换
下面,我们使用模块test-partymonkey-monkey
来Monkey另一个模块test-party
创建Module Monkey
模块test-partymonkey-monkey
由套件test-party
提供,只需安装套件test-party
即可
- 1$ npm run cli :store:sync test-party
下面以模块test-mymonkey-monkey
为例,来演示如何新建一个Module Monkey:
- 1$ npm run cli :create:module test-mymonkey-monkey -- --template=module
模块后缀:
-monkey
- 模块必须添加后缀
-monkey
,从而告知系统这个模块是一个Monkey
前端Monkey
通过Monkey机制,可以替换前端的页面路由
、Vuex Store
、Config
和组件
,等等
注入monkey
在模块前端注入一个monkey对象
src/suite-vendor/test-party/modules/test-partymonkey-monkey/front/src/main.js
- 1 return cb({
- 2 ...
- 3 monkey: require('./monkey.js').default(Vue),
- 4 });
定义monkey
src/suite-vendor/test-party/modules/test-partymonkey-monkey/front/src/monkey.js
- 1import monkeyerPage from './pages/monkeyer.vue';
- 2import monkeyerComponent from './components/monkeyerComponent.vue';
- 3
- 4// eslint-disable-next-line
- 5export default function(Vue) {
- 6
- 7 function monkeyRoute(moduleSelf, module, routePath, routeComponent) {
- 8 const route = module.options.routes.find(item => item.path === routePath);
- 9 if (route) {
- 10 route.module = moduleSelf;
- 11 route.component = routeComponent;
- 12 }
- 13 }
- 14
- 15 function monkeyStore(moduleSelf, module) {
- 16 const store = module.options.store;
- 17 // monkey getters: message2
- 18 const _message2 = store.getters.message2;
- 19 store.getters.message2 = function(state) {
- 20 const res = _message2(state);
- 21 console.log('monkey-store message2:', res);
- 22 return res;
- 23 };
- 24 // monkey mutations: setMessage
- 25 const _setMessage = store.mutations.setMessage;
- 26 store.mutations.setMessage = function(state, message) {
- 27 _setMessage(state, message);
- 28 console.log('monkey-store setMessage:', state.message);
- 29 };
- 30 }
- 31
- 32 function monkeyConfig(moduleSelf, module) {
- 33 const config = module.options.config;
- 34 config.monkeyed = true;
- 35 }
- 36
- 37 function monkeyComponent(moduleSelf, module, componentName, component) {
- 38 component.module = moduleSelf;
- 39 module.options.components[componentName] = component;
- 40 }
- 41
- 42 return {
- 43 moduleLoaded({ module }) {
- 44 if (module.name !== 'test-party') return;
- 45 const moduleSelf = Vue.prototype.$meta.module.get('test-partymonkey');
- 46 // route
- 47 monkeyRoute(moduleSelf, module, 'kitchen-sink/monkey/monkeyee', monkeyerPage);
- 48 // store
- 49 monkeyStore(moduleSelf, module);
- 50 // config
- 51 monkeyConfig(moduleSelf, module);
- 52 // component
- 53 monkeyComponent(moduleSelf, module, 'monkeyeeComponent', monkeyerComponent);
- 54 },
- 55 };
- 56
- 57}
后端Monkey
通过Monkey机制,可以替换后端的API路由
和Config
,等等
注入monkey
在模块后端注入一个monkey对象
src/suite-vendor/test-party/modules/test-partymonkey-monkey/backend/src/main.js
- 1 ...
- 2 // monkey
- 3 const monkey = require('./monkey.js')(app);
- 4
- 5 return {
- 6 ...
- 7 monkey,
- 8 };
定义monkey
src/suite-vendor/test-party/modules/test-partymonkey-monkey/backend/src/monkey.js
- 1module.exports = app => {
- 2 // eslint-disable-next-line
- 3 const moduleInfo = app.meta.mockUtil.parseInfoFromPackage(__dirname);
- 4
- 5 function monkeyRoute(module, routePath, routeController) {
- 6 const route = module.main.routes.find(item => item.path === routePath);
- 7 if (route) {
- 8 route.controller = routeController;
- 9 }
- 10 }
- 11
- 12 function monkeyConfig(module, config) {
- 13 config.monkeyed = true;
- 14 }
- 15
- 16 const monkey = {
- 17 moduleLoaded({ module }) {
- 18 if (module.info.relativeName !== 'test-party') return;
- 19 // route
- 20 monkeyRoute(module, 'test/monkey/monkeyee/test', {
- 21 module: moduleInfo.relativeName,
- 22 name: 'monkeyer',
- 23 });
- 24 },
- 25 configLoaded({ module, config }) {
- 26 if (module.info.relativeName !== 'test-party') return;
- 27 // config
- 28 monkeyConfig(module, config);
- 29 },
- 30 };
- 31 return monkey;
- 32};
评论: