Skip to main content

Third-Party Frontend Libraries

Oidis does not support standard npm import for frontend libraries. Instead, third-party libraries are downloaded at build time, served as static resources, and loaded via <script> tags. This page covers the full integration process.

Architecture Overview​

1. JSONP Config           →  Declares library source and output paths
2. package.conf.jsonp → Registers config in the builder's import chain
3. Oidis Builder → Downloads files (CDI) or copies from node_modules
4. Static Resource → Served at /resource/libs/{libName}/*
5. FrontEndLoader → Injects <script> tag into page head
6. Runtime Access → declare const LibName : any; (global scope)

Step 1: JSONP Configuration​

Create a .jsonp config file in bin/project/configs/ that declares the library source, license, and output paths.

CDI (Content Delivery Interface) — Download from URL​

For libraries available on CDN (jsDelivr, cdnjs, etc.):

Io.Oidis.Builder.DAO.Resources.Data({
$interface: "IProjectSolution",
dependencies: {
chartjs: {
location: {
type: "cdi",
files: [
{
src: "https://cdn.jsdelivr.net/npm/chart.js@4.5.1/dist/chart.umd.min.js",
dest: "chart.umd.min.js"
}
]
}
}
},
licensesRegister: {
chartjs: {
version: ">= 4.5.1",
description: "Simple yet flexible JavaScript charting library for the modern web.",
author: "Chart.js Contributors",
license: "MIT",
format: "source code",
location: ["[application-name][.exe]/resource/libs/chartjs"]
}
},
target: {
resources: {
chartjs: {
input: "dependencies/chartjs/*",
output: "resource/libs/chartjs/*",
skipReplace: true
}
},
requestPatterns: {
chartjs: "/resource/libs/chartjs/*"
}
}
});

Key sections:

SectionPurpose
dependencies.{name}.locationSource: type: "cdi" downloads from URL to dependencies/{name}/
licensesRegister.{name}License metadata — must be BSD-3-Clause compatible
target.resources.{name}Copy from input → output (relative to build/target/)
target.requestPatterns.{name}HTTP route the server will serve the files on

NPM Source — From node_modules​

For libraries installed via npm (useful when CDN files are not available):

Io.Oidis.Builder.DAO.Resources.Data({
$interface: "IProjectSolution",
nodejsConfig: {
devDependencies: {
"html5-qrcode": "2.3.4"
}
},
licensesRegister: { ... },
target: {
resources: {
html5QRcode: {
input: "dependencies/nodejs/build/node_modules/html5-qrcode/html5-qrcode.min.js",
output: "resource/libs/html5QRcode/html5-qrcode.min.js",
skipReplace: true
}
},
requestPatterns: {
html5QRcode: "/resource/libs/html5QRcode/*"
}
}
});

Multiple Files (JS + CSS)​

Some libraries require both JavaScript and CSS:

dependencies: {
graphiql: {
location: {
type: "cdi",
files: [
{
src: "https://cdn.jsdelivr.net/npm/graphiql@5.2.2/dist/index.min.js",
dest: "graphiql.min.js"
},
{
src: "https://cdn.jsdelivr.net/npm/graphiql@5.2.2/dist/style.min.css",
dest: "graphiql.min.css"
}
]
}
}
}

Step 2: Register in package.conf.jsonp​

The JSONP config file alone is not enough — it must be imported in the project's package.conf.jsonp so the builder can discover and process it. Without this step, the builder ignores the config entirely and the library files are never downloaded or copied.

Io.Oidis.Builder.DAO.Resources.Data({
$interface: "IProjectSolution",
imports: {
commons: "bin/project/configs/commons.jsonp",
bootstrap: "bin/project/configs/bootstrap.jsonp",
chartjs: "bin/project/configs/chartjs.jsonp"
// ... other imports
}
});

The builder resolves configs by following the imports chain starting from package.conf.jsonp. Any .jsonp file not reachable through this chain is invisible to the build process.

Missing import = silent failure

If you forget this step, the build succeeds without errors but the library files are missing at runtime, causing ReferenceError: LibName is not defined.

After adding the import, run oidis install to trigger CDI downloads, then oidis dev to build.

Step 3: Loading in FrontEndLoader​

After the builder makes the files available as static resources, the library must be loaded in the browser. There are two approaches:

Solution Project — Direct Loading​

For solution/customer projects, add script loading directly in the project's FrontEndLoader.setContent():

import { StaticPageContentManager } from "@io-oidis-gui/Io/Oidis/Gui/Utils/StaticPageContentManager.js";

@Resolver("/")
export class FrontEndLoader extends Parent {
protected setContent() : void {
super.setContent();
StaticPageContentManager.Language("cs");
StaticPageContentManager.HeadScriptAppend(
`resource/libs/chartjs/chart.umd.min.js?v=${this.getEnvironmentArgs().getProjectConfig().build.timestamp}`
);
}
}

Cache busting: Append ?v={buildTimestamp} to force browser re-download after deployments.

CSS loading: For stylesheets, use HeadLinkAppend:

StaticPageContentManager.HeadLinkAppend("resource/libs/graphiql/graphiql.min.css");

CORE Package — PageContentBundles​

For libraries in CORE packages (shared across all projects), register them in the PageContentBundles enum and Apply() method:

// In io-oidis-gui PageContentBundles.ts
export enum PageContentBundleType {
OIDIS,
BOOTSTRAP,
BARCODE,
// ... add new bundle type here
}

// In Apply() method
case PageContentBundleType.BARCODE:
StaticPageContentManager.HeadScriptAppend(
"resource/libs/jsBarcode/JsBarcode.all.min.js?v=" + this.buildTime
);
break;

Then apply in Hub's FrontEndLoader:

PageContentBundles.getInstance().Apply(PageContentBundleType.BARCODE);

Lazy Loading — On Demand​

For libraries only needed by specific components, load them at render time:

export class MyComponent extends GuiCommons {
private static dependencyLoaded : boolean = false;

protected innerCode() : string {
if (!MyComponent.dependencyLoaded) {
this.getEvents().setOnComplete(() : void => {
if (!MyComponent.dependencyLoaded) {
MyComponent.dependencyLoaded = true;
StaticPageContentManager.HeadScriptAppend(
"/resource/libs/myLib/myLib.min.js?v=" +
this.getEnvironmentArgs().getProjectConfig().build.timestamp,
"module"
);
}
});
}
return super.innerCode();
}
}

Key points:

  • Static flag prevents duplicate loading
  • "module" parameter loads as ES module (type="module" on script tag)
  • onComplete event fires after the component renders, ensuring DOM is ready

Step 4: Runtime Access​

Third-party libraries loaded via <script> tags expose globals on window. Access them using TypeScript declare:

declare const Chart : any;
declare const JsBarcode : any;
declare const Html5Qrcode : any;

export class MyController extends BasePanelController<MyPanel> {
private renderChart($canvas : HTMLCanvasElement) : void {
new Chart($canvas, {
type: "bar",
data: { ... },
options: { ... }
});
}
}

Safety Check​

Verify the library is loaded before use:

if (ObjectValidator.IsEmptyOrNull(Chart)) {
throw new Error("Chart.js requires chartjs.jsonp config and FrontEndLoader integration.");
}

Content Security Policy (CSP)​

Libraries that require relaxed CSP (e.g., unsafe-eval) must declare policies in their JSONP config:

domain: {
csp: {
policies: {
hubConfig: {
graphiql: {
enabled: true,
pattern: "*/graphiql",
policy: {
"default-src": "none",
"script-src": ["unsafe-eval", "unsafe-inline", "self"],
"style-src": ["unsafe-inline", "self"]
}
}
}
}
}
}

License Requirements​

All third-party libraries must be BSD-3-Clause compatible:

AcceptableReject
MIT, ISC, BSD-2-Clause, BSD-3-ClauseGPL, LGPL, AGPL, SSPL
Apache-2.0, 0BSD, Unlicense, SIL OFLAny copyleft license

The licensesRegister section in JSONP is mandatory — the builder validates license compatibility.

Quick Reference​

WhatWhere
JSONP configbin/project/configs/{libName}.jsonp
Config registrationpackage.conf.jsonp → imports.{libName}
Downloaded filesdependencies/{libName}/ (CDI) or dependencies/nodejs/build/node_modules/ (npm)
Built outputbuild/target/resource/libs/{libName}/
HTTP route/resource/libs/{libName}/*
Script loading (solution)Project FrontEndLoader.setContent()
Script loading (CORE)PageContentBundles.Apply()
Runtime accessdeclare const LibName : any;

See also: HTML & FrontEndLoader | JSONP System | Architecture Overview