builder-isv
Version:
ISV 模块本地预览与云构建器
165 lines (142 loc) • 4.75 kB
JavaScript
/**
* @author 龙喜<xiaolong.lxl@alibaba-inc.com>
* @description 渲染器工厂
*/
;
const fs = require('fs');
const path = require('path');
const config = require('../config');
const Renderer = require('./renderer');
const moduleFactory = new (require('./moduleFactory'));
const utils = require('../lib/utils');
// https://nodejs.org/dist/latest-v6.x/docs/api/events.html
const EventEmitter = require('events');
const Base = require('./base');
let singleton;
module.exports = class RendererFactory extends EventEmitter {
constructor(invokeType) {
if (singleton) {
return singleton;
}
super();
singleton = this;
this.invokeType = invokeType || Base.INVOKE_TYPE_PREVIEW;
/**
* 渲染器上下文 pool
* @type {Renderer[]} rendererPool
*/
this.rendererPool = [];
// renderer 等待队列,优先满足最先等待者
this.rendererWaiters = [];
}
// pool renderer 最大数量
// 使用 getter 的方式兼容 Node.js 4.x.x
static get MAX_RENDERER() {
return 3;
}
/**
* 获取匹配的渲染器上下文
* @param type 模块类型
* @param name 模块名称
* @param inputDir INVOKE_TYPE_BUILD 情况下传递
* @param outputDir INVOKE_TYPE_BUILD 情况下传递
* @returns {*}
*/
*getRenderer(type, name, inputDir, outputDir) {
let module = moduleFactory.getModule(type, name, inputDir);
// 预览
if (this.invokeType === Base.INVOKE_TYPE_PREVIEW) {
let rendererContext = yield this.getRendererFromPool(module);
if (rendererContext.id === `${module.moduleType}/${module.moduleName}`) {
utils.log.verbose('获取到上次使用的渲染器实例');
return rendererContext;
} else {
utils.log.verbose('获取到渲染器实例,重新设置上下文');
rendererContext.config(module);
try {
rendererContext.build();
} catch (e) {
utils.log.verbose('构建器已经运行过了');
}
return rendererContext;
}
} else {
// 云构建
module.outputDir = outputDir;
return this.createRendererContext(module);
}
}
/**
* 从渲染器上下文 pool 获取匹配的渲染器上下文(受限于 MAX_RENDERER,可能会阻塞)
* @param module
* @returns {*}
*/
*getRendererFromPool(module) {
// 如果匹配到上次此模块使用的 renderer,直接复用
let nameMatchedRenderer = this.rendererPool.filter((rendererContext) => {
return rendererContext.id === `${module.moduleType}/${module.moduleName}`;
});
if (nameMatchedRenderer.length) {
return nameMatchedRenderer[0];
}
// 否则,如果未达到 pool 最大值,新增匹配的 renderer
if (this.rendererPool.length < RendererFactory.MAX_RENDERER) {
utils.log.verbose('新增渲染器到渲染器池');
this.rendererPool.push(this.createRendererContext(module));
return this.rendererPool[this.rendererPool.length - 1];
} else {
// 获取空闲的 renderer
let idleRenderer = this.rendererPool.filter((rendererContext) => {
return rendererContext.status !== 1;
});
if (idleRenderer.length) {
utils.log.verbose('找到空闲的渲染器');
return idleRenderer[0];
} else {
utils.log.verbose('等待渲染器释放');
// 等待空闲的 renderer
return new Promise((resolve, reject) => {
this.rendererWaiters.push({
module: module,
callback: (rendererContext) => {
if (rendererContext) {
resolve(rendererContext);
} else {
reject(new Error('找不到匹配的渲染器'));
}
}
});
});
}
}
}
/**
* 创建一个 renderer context
* @returns {*|exports|module.exports}
*/
createRendererContext(module) {
let rendererContext = new Renderer(module);
if (this.invokeType === Base.INVOKE_TYPE_PREVIEW) {
rendererContext.addListener('compileFinished', () => {
utils.log.verbose('渲染器释放,通知等待队列');
this.distributeIdleRenderers();
});
}
rendererContext.build();
return rendererContext;
}
/**
* 将空闲的 renderer 分配给等待者
*/
distributeIdleRenderers() {
// 获取空闲的 renderer
let idleRenderer = this.rendererPool.filter((rendererContext) => {
return rendererContext.status !== 1;
});
while (this.rendererWaiters.length > 0 && idleRenderer.length > 0) {
this.rendererWaiters[0].callback(idleRenderer[0]);
this.rendererWaiters.shift();
idleRenderer.shift();
}
}
};