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:
| Section | Purpose |
|---|---|
dependencies.{name}.location | Source: 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.
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)onCompleteevent 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:
| Acceptable | Reject |
|---|---|
| MIT, ISC, BSD-2-Clause, BSD-3-Clause | GPL, LGPL, AGPL, SSPL |
| Apache-2.0, 0BSD, Unlicense, SIL OFL | Any copyleft license |
The licensesRegister section in JSONP is mandatory — the builder validates license compatibility.
Quick Reference
| What | Where |
|---|---|
| JSONP config | bin/project/configs/{libName}.jsonp |
| Config registration | package.conf.jsonp → imports.{libName} |
| Downloaded files | dependencies/{libName}/ (CDI) or dependencies/nodejs/build/node_modules/ (npm) |
| Built output | build/target/resource/libs/{libName}/ |
| HTTP route | /resource/libs/{libName}/* |
| Script loading (solution) | Project FrontEndLoader.setContent() |
| Script loading (CORE) | PageContentBundles.Apply() |
| Runtime access | declare const LibName : any; |
See also: HTML & FrontEndLoader | JSONP System | Architecture Overview