In Odoo OWL components, you may want to dynamically load external JS or CSS libraries (such as Chart.js) only when a component is used. This helps reduce initial page load time and optimize performance.
This article shows two common ways to dynamically load assets inside a component:
Method 1: Using loadBundle
Odoo allows you to define bundled assets in the __manifest__.py
, and then load them on-demand in your component using loadBundle
.
1. Define a Bundle in __manifest__.py
# __manifest__.py
{
"name": "Web",
"version": "1.0",
"depends": ["base"],
"auto_install": True,
"assets": {
"web.chartjs_lib": [
"/web/static/lib/Chart/Chart.js",
"/web/static/lib/chartjs-adapter-luxon/chartjs-adapter-luxon.js",
]
},
}
2. Define a JournalDashboardGraph.js
/** @odoo-module **/
import { loadBundle } from "@web/core/assets";
import { Component, onWillStart, useRef } from "@odoo/owl";
import { standardFieldProps } from "../standard_field_props";
export class JournalDashboardGraphField extends Component {
static template = "web.JournalDashboardGraphField";
static props = {
...standardFieldProps,
graphType: String,
};
setup() {
this.chart = null;
this.canvasRef = useRef("canvas");
onWillStart(async () => {
await loadBundle("web.chartjs_lib");
});
}
}
Method 2: Manually Injecting Assets (Custom loadAssets)
If you want more control or load assets that are not defined in a bundle, you can inject <script>
and <link>
tags dynamically.
// DashboardKPI.js
/** @odoo-module **/
import { Component, onWillStart, useState } from "@odoo/owl";
import { useService } from "@web/core/utils/hooks";
async function loadAssets({ jsLibs = [], cssLibs = [] }) {
await Promise.all([
...cssLibs.map((href) => {
if (document.querySelector(`link[href="${href}"]`)) return Promise.resolve();
return new Promise((resolve, reject) => {
const link = document.createElement("link");
link.rel = "stylesheet";
link.href = href;
link.onload = resolve;
link.onerror = reject;
document.head.appendChild(link);
});
}),
...jsLibs.map((src) => {
if (document.querySelector(`script[src="${src}"]`)) return Promise.resolve();
return new Promise((resolve, reject) => {
const script = document.createElement("script");
script.src = src;
script.onload = resolve;
script.onerror = reject;
document.head.appendChild(script);
});
}),
]);
}
export class DashboardKPI extends Component {
setup() {
this.orm = useService("orm");
this.state = useState({});
onWillStart(async () => {
await loadAssets({
jsLibs: [
"/your module/static/src/lib/chartjs/chart.umd.min.js",
],
cssLibs: [],
});
});
}
}
Reply