Current Situation
Historically, the Graph class is the main entry point in maxGraph. It automatically loads default plugins and style elements. This behavior simplifies evaluation and prototyping by reducing initial setup complexity. However, it is suboptimal for production use, as it bundles unused features, thus increasing the application's bundle size.
For example, many applications might not require all provided shapes, connectors, cell selection features (especially visualization-only apps), panning, or tooltips. Currently, even if these features are unused, they are still bundled due to their defaults being deeply integrated into the Graph class constructor parameters, making them impossible to tree-shake effectively.
Proposed Solution
We must retain the current behavior of the Graph class to maintain compatibility for evaluation purposes. Instead, we propose introducing a new class, provisionally named BaseGraph, that replicates the behavior of Graph without loading any default plugins or styles.
Currently, the Graph class loads defaults through a dedicated method invoked within its constructor. The BaseGraph could override this method with an empty implementation.
Alternative:
Another solution would be moving default style registration into a dedicated plugin, included by default in the Graph class plugin list. Users who wish to exclude defaults can simply omit this plugin.
Caution
This alternative impacts all stories and applications that redefine the plugin list. Further investigation is necessary to evaluate the ease of use and possible side effects.
Additional Enhancements Required
- Export the factory methods used to create default edge markers (not currently available in v0.17.0). This will allow selective registration of defaults.
- Expose internal utility functions currently used for default style loading (e.g., perimeter, edge styles) to facilitate easier integration.
Impact on Current Usage
We need to audit existing instances of Graph within the package, notably in components such as:
- Outline: there is probably no need for plugins, as the interactions with the Graph of the Outline are not managed by plugins
- Editor
To accommodate flexibility, provide mechanisms to configure or override the instantiated class via dependency injection, factory functions, or constructor parameters.
Constructor Improvements for Future-proofing
To immediately avoid potential breaking changes and simplify future enhancements, implement now a single configuration object parameter in constructors instead of multiple parameters. This approach makes it easier to extend configuration without altering method signatures significantly.
Compatibility Strategy
Optionally, experiment with implementing a new DefaultGraph class using a configuration object constructor. The existing Graph class could extend this new class to assess ease of backward compatibility and practical benefits.
Existing Experiments and Impacts
Previous experiments on removing unused defaults:
Tasks
✔ Style Registration Functions
✔ Marker Functions
✔ Update Examples
Create a new selected-features example that mimics the existing js-example and ts-example but configures only the minimal set of features required for the use cases by explicitly opting into:
- only needed plugins (e.g., fit, panning, rubberband, cell selections - note: CellEditorHandler alone adds ~12KB!)
- minimal styling (e.g., perimeter and shape; for edges: only EdgeStyle.OrthConnector))
Tasks:
Note
The current without-defaults examples demonstrate the maximum size reduction by removing all optional features i.e they show the absolute minimal footprint of using maxGraph.
The new selected-features examples will show what happens when some optional features are used (especially related to EdgeStyle, see #759 and #767).
Having those now will make it easier to show the gains when BaseGraph is available, and later when new improvements are added.
These examples will also help track future improvements. For example, today, importing just one static property from EdgeStyle or Perimeter still bundles the entire object. These examples will demonstrate the impact of migrating them to namespaces or other optimizable forms.
✔ Core Architecture Changes
See #776
- Introduce AbstractGraph, with a constructor that accepts a single options parameter
- Create BaseGraph class that extends AbstractGraph but doesn’t register any defaults
- Update Graph class to:
- Update Outline component to use BaseGraph
- Editor will keep using Graph at least for now. It is not usable for now because of Editor.setGraphContainer generates an error as it calls a non existing Graph.int method #367. The usage of the Graph implementation could be reviewed later.
✔ Examples and Integration: use BaseGraph
Current Situation
Historically, the Graph class is the main entry point in maxGraph. It automatically loads default plugins and style elements. This behavior simplifies evaluation and prototyping by reducing initial setup complexity. However, it is suboptimal for production use, as it bundles unused features, thus increasing the application's bundle size.
For example, many applications might not require all provided shapes, connectors, cell selection features (especially visualization-only apps), panning, or tooltips. Currently, even if these features are unused, they are still bundled due to their defaults being deeply integrated into the Graph class constructor parameters, making them impossible to tree-shake effectively.
Proposed Solution
We must retain the current behavior of the Graph class to maintain compatibility for evaluation purposes. Instead, we propose introducing a new class, provisionally named BaseGraph, that replicates the behavior of Graph without loading any default plugins or styles.
Currently, the Graph class loads defaults through a dedicated method invoked within its constructor. The BaseGraph could override this method with an empty implementation.
Alternative:
Another solution would be moving default style registration into a dedicated plugin, included by default in the Graph class plugin list. Users who wish to exclude defaults can simply omit this plugin.
Caution
This alternative impacts all stories and applications that redefine the plugin list. Further investigation is necessary to evaluate the ease of use and possible side effects.
Additional Enhancements Required
Impact on Current Usage
We need to audit existing instances of Graph within the package, notably in components such as:
To accommodate flexibility, provide mechanisms to configure or override the instantiated class via dependency injection, factory functions, or constructor parameters.
Constructor Improvements for Future-proofing
To immediately avoid potential breaking changes and simplify future enhancements, implement now a single configuration object parameter in constructors instead of multiple parameters. This approach makes it easier to extend configuration without altering method signatures significantly.
Compatibility Strategy
Optionally, experiment with implementing a new DefaultGraph class using a configuration object constructor. The existing Graph class could extend this new class to assess ease of backward compatibility and practical benefits.
Existing Experiments and Impacts
Previous experiments on removing unused defaults:
Tasks
✔ Style Registration Functions
✔ Marker Functions
✔ Update Examples
Create a new selected-features example that mimics the existing js-example and ts-example but configures only the minimal set of features required for the use cases by explicitly opting into:
Tasks:
Note
The current without-defaults examples demonstrate the maximum size reduction by removing all optional features i.e they show the absolute minimal footprint of using maxGraph.
The new selected-features examples will show what happens when some optional features are used (especially related to EdgeStyle, see #759 and #767).
Having those now will make it easier to show the gains when BaseGraph is available, and later when new improvements are added.
These examples will also help track future improvements. For example, today, importing just one static property from EdgeStyle or Perimeter still bundles the entire object. These examples will demonstrate the impact of migrating them to namespaces or other optimizable forms.
✔ Core Architecture Changes
See #776
✔ Examples and Integration: use BaseGraph