Skip to content

GLSP-1742: Rework client feature configuration with lazy feature definitions - #33

Open
haydar-metin wants to merge 1 commit into
server-feature-modules-capabilitiesfrom
client-feature-configuration
Open

haydar-metin wants to merge 1 commit into
server-feature-modules-capabilitiesfrom
client-feature-configuration

Conversation

@haydar-metin

@haydar-metin haydar-metin commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

What it does

Reworks the client container configuration around lazily loaded feature definitions that are referenced by stable, namespaced keys. Stacked on #21 (GLSP-1741), which should be merged first.

  • Add namespaced feature keys (FeatureKey, GLSPFeatureKey) to the protocol; CapabilityKey is now an alias of FeatureKey
  • Add FeatureDefinition (defineFeature, FeatureDefinition.toModuleOptions, FeatureDefinition.fromModule) and resolve container configurations before loading (resolveFeatures, loadFeatures, initializeContainerAsync):
    • remove/replace by key without importing the implementation
    • requires (hard) and extends (soft) dependencies, dependency ordering
    • FeatureResolutionErrors for duplicates, missing dependencies, cycles, mismatching modules and invalid ids (top-level, add and replace entries)
    • a warning when a removed key or module is not configured (e.g. a misspelled key)
  • Define all client features next to their modules (*-feature.ts, e.g. boundsFeatureDef for boundsModule) with the key registries GLSPClientFeature, GLSPStandaloneFeature and SprottyFeature; modules derive their feature id and requirements from their definition
  • Load the default features lazily via dynamic import(): initializeDiagramContainer is now async and uses DEFAULT_FEATURES, GLSPOptionalFeatures and STANDALONE_FEATURES instead of DEFAULT_MODULES and STANDALONE_MODULES
  • The GLSPClientFeature.Default feature is always loaded first; a replacement that declares dependencies is rejected
  • Move the standalone-only modules to integration/standalone
  • Prefix the wrapped sprotty modules with sprotty (e.g. sprottyButtonModule)
  • Add sideEffects metadata (@eclipse-glsp/protocol keeps di/re-decorate as side effect) and a bundle test that guards that the sources stay splittable
  • Server: define all feature keys in GLSPServerFeature (server-feature-keys.ts), reference required features by key and rename the ServerFeature service identifier to ServerFeatureDescription
  • Update the workflow examples and document the configuration and migration in the client README

Note

Lazy loading currently means that a removed feature's module is never evaluated (no registration code, no stylesheet injection). It does not reduce the bundle size for adopters yet: the published lib is CommonJS, where import() compiles to require, which bundlers treat as a static dependency. See follow-ups.

Closes eclipse-glsp/glsp#1742

How to test

  • pnpm build && pnpm test: see container-configuration.spec.ts, client-init.spec.ts and client-feature-definitions.bundle.spec.ts
  • pnpm dev: the standalone workflow example removes GLSPClientFeature.ToolPalette by key in examples/workflow-standalone/src/common/di.config.ts. Verify that the diagram loads without the tool palette and that all other features work as before
  • Try an invalid configuration, e.g. { remove: GLSPClientFeature.ElementTemplate }, and check that it fails with a FeatureResolutionError stating that glsp.nodeCreationTool requires glsp.elementTemplate

Follow-ups

  • Ship an ES module build of lib (dual CJS/ESM) so that bundlers can split removed features into separate chunks. Importing through the index barrel also needs work: with esbuild, the export * of every feature module keeps modules that import a stylesheet (a declared side effect) in the entry chunk, even with ESM. One option is to load a feature's stylesheet in its load() factory instead of in the module file
  • Update the Theia and VS Code integrations: their diagram container factories have to await initializeDiagramContainer

Changelog

  • This PR should be mentioned in the changelog
  • This PR introduces a breaking change (if yes, provide more details below for the changelog and the migration guide)

Breaking changes (see the migration section in packages/client/client/README.md):

  • initializeDiagramContainer is async and returns a Promise<Container>. Container factories that call it (e.g. createWorkflowDiagramContainer) become async as well:
    const container = await initializeDiagramContainer(c, ...config);
  • DEFAULT_MODULES and STANDALONE_MODULES are removed. Use DEFAULT_FEATURES and STANDALONE_FEATURES (lists of FeatureDefinitions); STANDALONE_MODULE_CONFIG is still available
  • accessibilityModule, gridModule, helperLineModule and debugModule are also available as GLSPOptionalFeatures.Accessibility, .Grid, .HelperLine and .Debug (the module objects still work)
  • The wrapped sprotty modules in @eclipse-glsp/sprotty are renamed: buttonModule, edgeEditModule, edgeIntersectionModule, edgeJunctionModule, edgeLayoutModule, expandModule, fadeModule, modelSourceModule, moveModule, openModule and updateModule become sprottyButtonModule, sprottyEdgeEditModule, … Their feature ids are now FeatureKey.toId(SprottyFeature.X) instead of plain Symbols
  • Removing a feature that another configured feature requires now fails with a FeatureResolutionError instead of silently skipping the dependent feature. In the defaults, NodeCreationTool requires ElementTemplate and Zorder requires Bounds, so remove the dependent feature as well
  • Default feature modules use key-based feature ids (FeatureKey.toId(GLSPClientFeature.X)). A replace with a custom module only matches a default feature if it uses the same feature id; prefer defineFeature(GLSPClientFeature.X, ...)
  • Standalone-only modules and classes (standaloneDefaultModule, standaloneShortcutsModule, saveModule, undoRedoModule, CopyPasteStartup, …) moved to src/integration/standalone. Imports from the package entry point are unaffected; deep imports from @eclipse-glsp/client/lib/... must be updated
  • Server: the ServerFeature service identifier is renamed to ServerFeatureDescription. container.bind(ServerFeature) becomes container.bind(ServerFeatureDescription)

@haydar-metin
haydar-metin added this pull request to stack #34 September 28, 2026 13:15
@haydar-metin
haydar-metin force-pushed the client-feature-configuration branch 2 times, most recently from e3f8501 to 20a0e96 Compare September 29, 2026 12:48
…nitions

- Add namespaced feature keys (`FeatureKey`, `GLSPFeatureKey`) to the
  protocol; `CapabilityKey` is now an alias of `FeatureKey`
- Add `FeatureDefinition` (`defineFeature`, `toModuleOptions`) and resolve
  container configurations before loading (`resolveFeatures`,
  `loadFeatures`, `initializeContainerAsync`): remove/replace by key,
  `requires`/`extends` dependencies, dependency ordering and
  `FeatureResolutionError`s for duplicates, missing dependencies, cycles,
  mismatching modules and invalid ids (also in `add`/`replace`), and warn
  about removed keys that are not configured
- Define all client features next to their modules (`*-feature.ts`, e.g.
  `boundsFeatureDef` for `boundsModule`) with
  key registries `GLSPClientFeature`, `GLSPStandaloneFeature` and
  `SprottyFeature`; modules derive their options from their definition
- Load default features lazily via dynamic `import()`:
  `initializeDiagramContainer` is now async and uses
  `DEFAULT_FEATURES`, `GLSPOptionalFeatures` and `STANDALONE_FEATURES`
  instead of `DEFAULT_MODULES` and
  `STANDALONE_MODULES`
- Move standalone-only modules to `integration/standalone`
- Prefix the wrapped sprotty modules with `sprotty` (e.g.
  `sprottyButtonModule`)
- Reject a replacement of the default client feature that declares
  dependencies, as it is always loaded first
- Add `sideEffects` metadata (protocol keeps `di/re-decorate` as side
  effect) and a bundle test that guards that the sources stay splittable.
  The published lib is still CommonJS, so removed features are not yet
  excluded from adopter bundles
- Server: define all feature keys in `GLSPServerFeature`
  (`server-feature-keys.ts`), reference required features by key and rename
  the `ServerFeature` service identifier to `ServerFeatureDescription`
- Update the workflow examples and document the configuration and
  migration in the client README

Part of: eclipse-glsp/glsp#1742
@haydar-metin
haydar-metin force-pushed the client-feature-configuration branch from 20a0e96 to c215bb8 Compare September 30, 2026 11:22
@github-actions

github-actions Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Previews for commit c215bb8

Demo This pull request Current main
Workflow diagram open open
MCP demo open open


This project is built with `pnpm` and is available from npm via [@eclipse-glsp/client](https://www.npmjs.com/package/@eclipse-glsp/client).

## Configuring features

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Todo: move this to a proper migration.md / changelog.md file

@haydar-metin
haydar-metin marked this pull request as ready for review September 30, 2026 11:31

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant