Global Script Injector

While the <scripts-injector> custom element provides a powerful declarative approach to lazy-loading scripts by encapsulating logic within a Web Component, there are scenarios where a non-web-component solution is preferable to maintain a cleaner DOM structure or to aggregate script loading rules globally.

To accommodate these use cases, we provide the Global Script Injector.

Need a more straightforward approach?

Use the Web Component with scripts-injector and declarative triggers. Read the main docs →


What is it?

The Global Script Injector utilizes a centralized JSON configuration (<script type="ecopages/global-injector-map">) and plain HTML data-eco-trigger attributes. It leverages the exact same robust interaction-tracking and intersection-observer logic as the <scripts-injector>, but completely decoupled from custom elements.


Configuration

Define a single global JSON map that associates arbitrary "trigger IDs" with their respective loading conditions (on:idle, on:interaction, on:visible) and target scripts:

<script type="ecopages/global-injector-map">
{
  "analytics-trigger": {
    "on:idle": { 
      "scripts": ["/_assets/tracker.js"] 
    }
  },
  "complex-ui-loader": {
    "on:interaction": {
      "value": "mouseenter,focusin",
      "scripts": ["/_assets/heavy-ui.js"]
    },
    "on:visible": {
      "value": "200px",
      "scripts": ["/_assets/lazy-image.js"]
    }
  }
}
</script>

HTML Attributes

Any standard HTML element can opt into these triggers by referencing the keys from the global map using a data-eco-trigger attribute. This keeps your component structure pristine without deeply nesting wrapper elements.

<!-- Loads analytics.js on idle as defined in the global map -->
<div class="page-wrapper" data-eco-trigger="analytics-trigger">...</div>
 
<!-- Loads heavy-ui.js on hover and lazy-image.js when visible -->
<button data-eco-trigger="complex-ui-loader">Load Complex UI</button>

Initialization

Unlike the Web Component which autoregisters, the Global Injector must be explicitly initialized. Provide this in your main entrypoint or layout component:

import { initGlobalInjector } from '@ecopages/scripts-injector/global';
 
const injector = initGlobalInjector();
 
// Example: wire into your framework/router lifecycle
router.onAfterNavigate(() => {
  injector.refresh();
});
 
app.onDispose(() => {
  injector.cleanup();
});

Behind the scenes, initGlobalInjector will:

  1. Parse your <script type="ecopages/global-injector-map"> blocks.
  2. Query the DOM for any [data-eco-trigger] elements.
  3. Observe the DOM for any newly added elements via a MutationObserver.
  4. Return a handle with refresh() and cleanup() so your framework controls lifecycle integration.
  5. Bind on:idle, IntersectionObserver (on:visible), and DOM event listeners (on:interaction) exactly like the Web Component does.

Compatibility & Deduplication

The Global Injector and <scripts-injector> can be used side-by-side seamlessly. Both implementations avoid duplicate <script> tag injection by checking existing scripts and tracking in-flight loads.

If <scripts-injector> and initGlobalInjector() both try to lazy-load the same script URL, duplicate script injection is prevented and already-present scripts are reused.