205 lines
7.2 KiB
JavaScript
205 lines
7.2 KiB
JavaScript
import path from 'path';
|
|
import Module from '@/arch/module';
|
|
import EventEmitter from 'events';
|
|
import kebabCase from 'lodash/kebabCase';
|
|
import isObject from 'lodash/isObject';
|
|
import sortBy from 'lodash/sortBy';
|
|
import moduleRequire from '_app/generated/module.require';
|
|
import merge from 'lodash/merge';
|
|
|
|
export const moduleFilter = moduleName => true;
|
|
export const config = { moduleFilter };
|
|
|
|
let moduleCfg = require('_app/etc/modules.config.json');
|
|
|
|
try {
|
|
moduleCfg = merge(moduleCfg, require(`_app/etc/modules.${process.env.NODE_ENV}.json`));
|
|
} catch (e) {
|
|
if (process.env.NODE_ENV === 'development') {
|
|
console.log(`Skip load of modules.${process.env.NODE_ENV}.json`);
|
|
}
|
|
}
|
|
|
|
try {
|
|
moduleCfg = merge(moduleCfg, require('_app/etc/modules.local.json'));
|
|
} catch (e) {
|
|
if (process.env.NODE_ENV === 'development') {
|
|
console.log('Skip load of modules.local.json');
|
|
}
|
|
}
|
|
|
|
export const ModuleLoaderInterceptor = new EventEmitter();
|
|
|
|
const modules = {};
|
|
|
|
export function localModuleLoader(router) {
|
|
const requireModule = require.context('_modules', true, /module.init.js$/);
|
|
let moduleInitQueue = [];
|
|
|
|
requireModule.keys().forEach(fn => {
|
|
const pathData = fn.split('/');
|
|
const moduleVendor = pathData[1];
|
|
const moduleName = pathData[2];
|
|
const fullModuleName =
|
|
moduleName.search(/integration/) !== -1 && moduleName.search(/module/) !== -1
|
|
? `${moduleVendor}_${moduleName}Module`
|
|
: `${moduleVendor}_${moduleName}`;
|
|
|
|
const md = requireModule(fn);
|
|
const moduleInitData = md.ModuleConfig || { enabled: false };
|
|
|
|
const moduleEnabled =
|
|
(typeof moduleInitData.enabled !== 'undefined' ? moduleInitData.enabled : false) &&
|
|
(Object.prototype.hasOwnProperty.call(moduleCfg, fullModuleName)
|
|
? isObject(moduleCfg[fullModuleName])
|
|
? (Object.prototype.hasOwnProperty.call(moduleCfg[fullModuleName], 'type')
|
|
? moduleCfg[fullModuleName].type === 'local'
|
|
: false) &&
|
|
(Object.prototype.hasOwnProperty.call(moduleCfg[fullModuleName], 'enabled')
|
|
? moduleCfg[fullModuleName].enabled
|
|
: false) &&
|
|
(Object.prototype.hasOwnProperty.call(moduleCfg[fullModuleName], 'ref')
|
|
? moduleCfg[fullModuleName].ref === fullModuleName
|
|
: false)
|
|
: false
|
|
: false);
|
|
|
|
if (moduleEnabled) {
|
|
moduleInitQueue.push({
|
|
module: md,
|
|
order: Object.prototype.hasOwnProperty.call(moduleInitData, 'loadOrder')
|
|
? moduleInitData.loadOrder
|
|
: 999,
|
|
moduleInitData,
|
|
fullModuleName,
|
|
fn,
|
|
type: 'local',
|
|
});
|
|
}
|
|
});
|
|
|
|
// Require package modules
|
|
if (moduleRequire.length > 0) {
|
|
moduleRequire.forEach(requireFn => {
|
|
const md = requireFn();
|
|
|
|
if (!Object.prototype.hasOwnProperty.call(md, 'ModuleConfig')) {
|
|
throw new Error(
|
|
`Vendor module cannot be initialized. All vendor modules must export ModuleConfig object property.`,
|
|
);
|
|
}
|
|
|
|
if (!Object.prototype.hasOwnProperty.call(md, 'init')) {
|
|
throw new Error(
|
|
`Vendor module cannot be initialized. All vendor modules must export init function property`,
|
|
);
|
|
}
|
|
|
|
const moduleConfig = md.ModuleConfig;
|
|
if (!Object.prototype.hasOwnProperty.call(moduleConfig, 'moduleName')) {
|
|
throw new Error(
|
|
`Vendor module cannot be initialized. All vendor modules must have a name matching the pattern Vendor_ModuleName`,
|
|
);
|
|
}
|
|
|
|
if (
|
|
moduleInitQueue.findIndex(el => {
|
|
return el.fullModuleName === moduleConfig.moduleName;
|
|
}) === -1
|
|
) {
|
|
moduleInitQueue.push({
|
|
module: md,
|
|
order: Object.prototype.hasOwnProperty.call(moduleConfig, 'loadOrder')
|
|
? moduleConfig.loadOrder
|
|
: 999,
|
|
moduleInitData: moduleConfig,
|
|
fullModuleName: moduleConfig.moduleName,
|
|
type: 'package',
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
const internalModule = require.context('_internal', true, /module.init.js$/);
|
|
|
|
internalModule.keys().forEach(fn => {
|
|
const pathData = fn.split('/');
|
|
const moduleName = pathData[1];
|
|
const fullModuleName =
|
|
moduleName.search(/integration/) !== -1 && moduleName.search(/module/) !== -1
|
|
? `${moduleName}Module`
|
|
: `${moduleName}`;
|
|
|
|
const md = internalModule(fn);
|
|
const moduleInitData = md.ModuleConfig || { fullModuleName: moduleName };
|
|
|
|
moduleInitQueue.push({
|
|
module: md,
|
|
order: Object.prototype.hasOwnProperty.call(moduleInitData, 'loadOrder') ? moduleInitData.loadOrder : 999,
|
|
moduleInitData,
|
|
fullModuleName,
|
|
fn,
|
|
type: 'internal',
|
|
});
|
|
});
|
|
|
|
// Sort modules load order
|
|
moduleInitQueue = sortBy(moduleInitQueue, 'order');
|
|
|
|
// Initializing modules sync
|
|
moduleInitQueue.forEach(({ module, moduleInitData, fullModuleName, fn = undefined, type = 'unknown' }) => {
|
|
if (!config.moduleFilter(fullModuleName)) {
|
|
return;
|
|
}
|
|
|
|
if (process.env.NODE_ENV === 'development') {
|
|
console.log(`Initializing ${type} module ${fullModuleName}...`);
|
|
}
|
|
|
|
const moduleInstance = module.init(
|
|
new Module(
|
|
moduleInitData.routerPrefix || kebabCase(fullModuleName),
|
|
moduleInitData.moduleName || fullModuleName,
|
|
),
|
|
router,
|
|
);
|
|
|
|
if (typeof moduleInstance === 'undefined') {
|
|
throw new Error(
|
|
`Error while initializing module ${fullModuleName}: the context must be returned from init() method`,
|
|
);
|
|
}
|
|
|
|
modules[fullModuleName] = {
|
|
path: typeof fn !== 'undefined' ? path.resolve(__dirname, '..', 'modules', fn) : 'NODE_PACKAGE',
|
|
moduleInstance: moduleInstance,
|
|
};
|
|
|
|
if (process.env.NODE_ENV === 'development') {
|
|
console.info(`${fullModuleName} has been initialized`);
|
|
}
|
|
});
|
|
|
|
if (process.env.NODE_ENV === 'development') {
|
|
console.log("All modules has been initialized successfully. You can run 'system.getModuleList()'");
|
|
|
|
window.system.getModuleList = getModuleList;
|
|
}
|
|
|
|
Object.keys(modules).forEach(m => {
|
|
const mdInstance = modules[m].moduleInstance;
|
|
ModuleLoaderInterceptor.emit(m, mdInstance);
|
|
modules[m].moduleInstance = mdInstance;
|
|
router.addRoutes([...modules[m].moduleInstance.getRoutes()]);
|
|
});
|
|
|
|
// All modules loaded successfully
|
|
ModuleLoaderInterceptor.emit('loaded', router);
|
|
|
|
return modules;
|
|
}
|
|
|
|
export function getModuleList() {
|
|
return modules;
|
|
}
|