You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何让bpmn-js暴露可选模块?模块化建模器设计问询

Dynamic Module Management for bpmn-js/diagram-js

Great question! I’ve tackled similar modularity challenges with bpmn-js before, so let me break down what works (and what to watch out for):

First, Context on bpmn-js’s Module System

bpmn-js is built on top of diagram-js’s dependency injection (DI) system, which is designed to initialize modules once at instantiation time rather than support dynamic runtime changes. There’s no official, exposed modules(), addModule(), or removeModule() API—this is intentional, as the core library prioritizes stability over dynamic module swapping.

Workarounds & Stable Solutions

1. Predefined Role-Based Module Arrays (Most Reliable)

The official recommended approach is to define module arrays tailored to each user role upfront, then instantiate a Modeler with the appropriate set. This avoids versioning risks and aligns with bpmn-js’s design:

import BpmnModeler from 'bpmn-js/lib/Modeler';

// Define module sets for different roles
const adminModules = [
  // Base modeling modules
  ...BpmnModeler.prototype._modelingModules,
  // Add admin-specific features
  require('bpmn-js/lib/features/label-editing'),
  require('bpmn-js/lib/features/keyboard'),
  require('bpmn-js/lib/features/comment')
];

const viewerModules = [
  // Base interaction modules
  ...BpmnModeler.prototype._interactionModules,
  // Add viewer-only features
  require('bpmn-js/lib/features/zoomscroll'),
  require('bpmn-js/lib/navigation/movecanvas')
];

// Create role-specific Modeler instances
const adminModeler = new BpmnModeler({ modules: adminModules });
const viewerModeler = new BpmnModeler({ modules: viewerModules });

This relies on accessing the prototype’s module groups (_modelingModules, _interactionModules, _coreModules), which are internal but rarely change across bpmn-js versions—far more stable than traversing node_modules directories.

2. Custom Wrapper Class for Dynamic Management

If you truly need runtime module changes, you can wrap the Modeler to manage a module list and interact with the DI container directly. Note: This has limitations (already initialized components won’t be reloaded), but it works for adding new services/features:

import BpmnModeler from 'bpmn-js/lib/Modeler';

class ModularBpmnModeler extends BpmnModeler {
  constructor(options = {}) {
    // Combine base modules with user-provided ones
    this._managedModules = [
      ...BpmnModeler.prototype._coreModules,
      ...BpmnModeler.prototype._interactionModules,
      ...BpmnModeler.prototype._modelingModules,
      ...(options.modules || [])
    ];

    super({ ...options, modules: this._managedModules });
  }

  // List all modules (use custom __name property or toString for identification)
  modules() {
    return this._managedModules.map(module => 
      module.__name || module.toString().slice(0, 50) // Truncate for readability
    );
  }

  // Add a module at runtime
  addModule(module) {
    const exists = this._managedModules.some(m => m === module);
    if (exists) return;

    this._managedModules.push(module);

    // Register the module with the DI injector if possible
    const injector = this.get('injector');
    if (injector) {
      if (typeof module === 'function') {
        module(injector);
      } else if (typeof module === 'object') {
        Object.keys(module).forEach(key => injector.register(key, module[key]));
      }
    }
  }

  // Remove a module (note: doesn't destroy existing instances)
  removeModule(moduleIdentifier) {
    this._managedModules = this._managedModules.filter(module => {
      const id = module.__name || module.toString().slice(0, 50);
      return id !== moduleIdentifier;
    });
  }
}

// Usage example
const modeler = new ModularBpmnModeler();
modeler.addModule(require('bpmn-js/lib/features/export'));
console.log(modeler.modules());

Key Caveats for Dynamic Management

  • DI Container Limitation: The DI container is built once at instantiation. Adding a module after initialization will register new services, but existing components (like UI elements) won’t automatically update or reload.
  • Module Identification: Since modules are functions/objects, you’ll need to add custom identifiers (like a __name property) to reliably track and remove them.

Are There Hidden Official APIs?

No—bpmn-js and diagram-js don’t expose any hidden module management methods. The prototype’s module groups (_modelingModules, etc.) are the closest thing to a stable "module catalog" you’ll find, and they’re safe to use as long as you test across minor version updates.

内容的提问来源于stack exchange,提问作者Jankapunkt

火山引擎 最新活动