Skip to content

๐Ÿ“ฆ Loading Resources

Andre Kless edited this page Mar 26, 2026 · 1 revision

In ccmjs, resources are treated as declarative dependencies that are resolved at runtime. Resource loading follows the same dependency model that is used for components and datasets.

ccm.load() is the low-level service that powers this mechanism and can also be used directly.

Examples:

const data = await ccm.load('data.json'); // {"foo":"bar"}

Load multiple resources:

const results = await ccm.load('data.json', 'hello.html'); // [{"foo":"bar"}, "Hello, world!"]

๐Ÿงพ Syntax

ccm.load( ...resources ) โ†’ Promise<any>

Parameters:

  • ...resources โ€” One or more resources to load (URLs or resource objects).
    Resources can be provided individually or nested in arrays to control parallel and sequential loading.

Returns:

A Promise that

  • resolves when all resources load successfully
  • rejects when at least one resource fails
  • resolves/rejects with either a single value or an array of values/errors

โš ๏ธ Error Handling

If at least one resource fails, the Promise is rejected โ€” but all resources are still attempted to be loaded. This means:

  • Successful resources appear normally in the result array.
  • Failed resources appear at their corresponding index as an Error object.
  • The Promise rejects with the entire result array, allowing detailed inspection.
  • The order of results always matches the order of the input resources.

๐Ÿ”€ Parallel/Sequential Loading

The parallel and sequential loading can be flexibly controlled as deep as desired. Each array level alternates between parallel and sequential execution. Top-level entries are loaded in parallel. Each nested array switches the execution mode.

Example:

ccm.load(
  'hello.html',     // Array Level 0: Parallel
  [
    'style.css',    // Array Level 1: Sequential
    'image.png',
    [
      'data.json',  // Array Level 2: Parallel
      'script.js'
    ],
    'logo.gif'
  ],
  'picture.jpg'
);

The example loads the resources in the following timeline:

Resource Timeline
hello.html ******------------------
style.css ******------------------
image.png ------******------------
data.json ------------******------
script.js ------------******------
logo.gif ------------------******
picture.jpg ******------------------

๐Ÿงฉ Resource Objects

Instead of a string, a resource may also be passed as an object.

Example:

ccm.load({ url: 'script.js', type: 'module' });

Configurable Properties:

Property Type Description Applies to resource types
url string Required. URL of the resource.
type string Explicit resource type ('css', 'image', 'js', 'module', 'json', 'xml'). If omitted, the type is inferred from the file extension. Unknown extensions default to 'json'.
context Element DOM context into which the resource will be loaded (default: <head>). css, js
attr object HTML attributes to apply to the generated <link>/<script> tag. css, js
params object HTTP GET/POST parameters to send. json

๐ŸŒ‘ Shadow DOM Support

ccm.load() can load resources directly into a Shadow DOM. To do so, pass the shadow root as the context property of the resource object.

Example:

const host = document.createElement('div');
const root = host.attachShadow({ mode: 'open' });

ccm.load({
  url: 'styles.css',
  context: root      // the <link> element will be appended here
});

If a ccmjs instance is passed as context, the resource is automatically loaded into the instanceโ€™s Shadow DOM root.

const instance = await ccm.instance( 'ccm.quiz.js' );

ccm.load({
  url: 'styles.css',
  context: instance
});

๐Ÿ–ผ๏ธ Image Preloading

ccm.load() can be used to preload image files. This helps ensure that images can be displayed without delay when they are needed. All common web image formats are supported, including PNG, JPEG, SVG, WebP, and AVIF.

๐Ÿ” Loading with SRI

ccm.load() supports loading CSS and JavaScript files with Subresource Integrity (SRI).

Example:

ccm.load({
  url: 'script.js',
  attr: {
    integrity: 'sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=',
    crossorigin: 'anonymous'
  }
});

The <head> then contains:

<script src="script.js"
        integrity="sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU="
        crossorigin="anonymous"></script>

ccm.load() also supports SRI when loading JavaScript modules:

const exports = await ccm.load({
  url: 'script.js',
  type: 'module',
  attr: {
    integrity: 'sha384-HUXdHqTt4miSLn4X4gaWsM8XlJuzTYeaIeI23MDnpjnUW2vRxWiDnG4XZBM49Vs9',
    crossorigin: 'anonymous'
  }
});

Behind the scenes, module files are first fetched and verified against the SRI hash. Only if the hash matches, the verified source code is executed as a module (via a Blob URL), without a second network request.

๐Ÿ“ฆ Loading Module Exports

When loading ES modules with ccm.load(), it is possible to request specific exports instead of the entire module object. This is done by appending one or more hash fragments (#) to the module URL.

Example:

const data = await ccm.load('module.mjs#data');

Note: When loading specific module exports (e.g. module.mjs#data), the browser still downloads the entire module file. The export selection happens client-side after the module has been imported. This mechanism improves dependency clarity and configuration expressiveness, but it does not reduce the network transfer size.

You can also access nested properties using dot notation:

const value = await ccm.load('module.mjs#data.foo');

This returns the property foo of the exported object data.

Multiple exports can be requested by adding additional hash fragments:

const result = await ccm.load('module.mjs#data#name');

Result:

{
  data: { ... },
  name: "John"
}

This mechanism is particularly useful for declaring dependencies on specific functions:

{
  mapper: [ "ccm.load", "./mapper.mjs#json2json" ]
}

The property mapper will contain the exported function json2json. This enables fine-grained declarative dependencies inside ccmjs configurations.

In ccmjs, dependencies are not limited to resources, components, or data โ€” functions can also be injected declaratively.

๐Ÿ“ก Loading Data

When loading data, ccm.load() internally calls the browserโ€™s Fetch API. The value of resource.url becomes the fetch URL, and the remaining fields of the resource object are passed to fetch() as the init object. The returned value depends on the response content type and is automatically parsed as JSON when possible.

Example transformation:

ccm.load({
  url: 'https://example.com/api/user',
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  params: { name: 'Mika' }
});

becomes:

fetch('https://example.com/api/user', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: '{"name":"Mika"}'
});

๐Ÿ—‚๏ธ Loading XML

ccm.load() supports loading XML files. When the resource type is 'xml' (either detected from the file extension or set explicitly), the result is parsed as XML and returned as a DOM Document object.

Example:

const xml = await ccm.load( 'config.xml' );

console.log( xml instanceof Document );   // true
console.log( xml.querySelector('title')?.textContent );

ccm.load() uses fetch() internally, reads the response as text, and parses it via the browserโ€™s XML parser (DOMParser). The resulting Document behaves like any other XML DOM document: elements can be queried, modified, and traversed.

โš–๏ธ Differentiation

Unlike fetch(), ccm.load()

  • integrates directly into CCMโ€™s declarative dependency system,
  • supports structured parallel/sequential resolution,
  • automatically injects resources into DOM or Shadow DOM contexts,
  • and provides built-in support for SRI, and XML parsing.