Skip to content

Versioning and Isolation

Andre Kless edited this page Dec 28, 2025 · 12 revisions

Overview

Versioning and dependency management are a fundamental challenge in large-scale web applications.

Traditional JavaScript frameworks typically assume a single shared runtime per application, where all components execute within the same framework instance and version and share a common dependency graph. This often leads to version conflicts, tight coupling, and complex build pipelines.

CCM addresses these issues by treating framework versions and component versions as isolated, first-class entities. This enables multiple versions of the framework and multiple versions of the same component to coexist on the same web page without conflict.

Framework Versioning

The currently active framework version can be queried programmatically:

<!DOCTYPE html>
<meta charset="UTF-8">
<body>
<script src="https://ccmjs.github.io/framework/versions/ccm-28.0.0.js"></script>
<script>
  console.log(ccm.version); // '28.0.0'
</script>

Everything around ccmjs is encapsulated in a single global namespace: window.ccm. The first ccmjs version loaded on a web page initializes this object and uses it as a version registry. Each framework version registers itself under its own version key. The window.ccm object therefore acts as a version registry rather than a shared runtime.

Example:

window.ccm = {
  "27.5.0": { /* ccmjs v27.5.0 */ },
  "28.0.0": { /* ccmjs v28.0.0 */ }
};

Each entry represents a fully independent framework instance. Every ccmjs version operates exclusively within its own namespace. As a result, different parts of a web page may operate on different ccmjs versions simultaneously.

The first loaded ccmjs version is additionally exposed directly as window.ccm, allowing calls such as ccm.start() without explicit version addressing.

Component Versioning

Each CCM component is uniquely identified by its name and may optionally declare a version:

// ccm.quiz-2.1.0.js
export const component = {
  name: 'quiz',
  version: "2.1.0",
  ccm: 'https://ccmjs.github.io/framework/ccm-28.0.0.js',
  config: {/*...*/},
  Instance: function () {
    this.start = async () => {/*...*/};
  }
};

If the version is omitted, the component is treated as the latest version. Component versions are not merely informational. They are part of the component’s identity and affect loading, instantiation, and dependency resolution.

By convention, the filename of a versioned component must contain the version number to be valid.

Binding Between Components and Framework Versions

Each CCM component explicitly references the ccmjs version it depends on. As a result, a component is always instantiated by the framework version it references. If a component reuses another component that depends on a different ccmjs version, then the required framework version is automatically loaded and the reused component is instantiated in its own namespace.

The framework version used by the component can be adjusted at runtime during embedding via the config:

<!DOCTYPE html>
<meta charset="UTF-8">
<body>
<script src="https://ccmjs.github.io/framework/versions/ccm-28.0.0.js"></script>
<script>
  ccm.start("https://ccmjs.github.io/quiz/versions/ccm.quiz-2.1.0.mjs", {
    ccm: "https://ccmjs.github.io/framework/versions/ccm-27.5.0.js"
  }, document.body);
</script>

The ccm.start() call is internally delegated to the corresponding framework instance.

There is no shared global state between versions and no accidental overwriting of components, enabling long-term compatibility and independent evolution of framework and component versions.

Clone this wiki locally