Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

external js script are loaded but not recognized #190

Open
DonatoD opened this issue May 29, 2024 · 6 comments
Open

external js script are loaded but not recognized #190

DonatoD opened this issue May 29, 2024 · 6 comments

Comments

@DonatoD
Copy link

DonatoD commented May 29, 2024

Using htmlgraphics panel, from grafana10.4 to 11 several js script, even loaded locally, are yes correctly loaded but then the object itself is not recognized. The problem is that this is happening with several script, pdf-lib.min.js just to name one.

You can reproduce it by loading this script https://cdn.jsdelivr.net/npm/pdf-lib/dist/pdf-lib.min.js into the oninit section and check for the PDFLib object. It will be undefined

@ZuperZee
Copy link
Contributor

Could you provide an example with the panel options, panel json or dashboard json?

Here's how to copy the panel options https://gapit-htmlgraphics-panel.gapit.io/docs/guides/how-to-import-export/#copy-from-one-panel-to-another.
Here's how to get the dashboard json https://grafana.com/docs/grafana/latest/dashboards/share-dashboards-panels/#export-a-dashboard-as-json

@DonatoD
Copy link
Author

DonatoD commented May 29, 2024

{
"calcsMutation": "standard",
"reduceOptions": {
"calcs": [
"lastNotNull",
"last",
"firstNotNull",
"first",
"min",
"max",
"mean",
"sum",
"count",
"range",
"delta",
"step",
"diff",
"logmin",
"allIsZero",
"allIsNull",
"diffperc"
]
},
"add100Percentage": false,
"centerAlignContent": false,
"overflow": "visible",
"useGrafanaScrollbar": false,
"SVGBaseFix": true,
"codeData": "",
"rootCSS": "",
"css": "",
"html": "",
"renderOnMount": true,
"onRender": "",
"panelupdateOnMount": true,
"dynamicHtmlGraphics": false,
"dynamicData": false,
"dynamicFieldDisplayValues": false,
"dynamicProps": false,
"onInitOnResize": false,
"onInit": "var scriptList = [\n\t{id:"PDFscriptA",url:"https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.14.305/pdf.min.js"},\n\t{id:"PDFscriptB",url:"https://cdn.jsdelivr.net/npm/pdf-lib/dist/pdf-lib.min.js"},\n\t{id:"MQTTscriptA",url:"https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.1.0/paho-mqtt.min.js"},\n\t{id:"MQTTscriptB",url:"https://unpkg.com/mqtt/dist/mqtt.min.js"},\n\t{id:"myGlobalScript",text:"var myGlobal = 33;"}];\nloadScripts(scriptList)\n\t\t.then(function(){\n\t\t\ttry{console.log("PDFa",pdfjsLib);}catch(err){console.log(err);}\n\t\t\ttry{console.log("PDFb",PDFLib);}catch(err){console.log(err);}\n\t\t\ttry{console.log("MQTTa",Paho);}catch(err){console.log(err);}\n\t\t\ttry{console.log("MQTTb",mqtt);}catch(err){console.log(err);}\n\t\t\tconsole.log("myGlobal = ",myGlobal);\n\t\t});\n\nfunction loadScripts(scriptList){\n\treturn new Promise(async function(resolve,reject){\n\t\tvar app;\n\t\tvar loaded = 0;\n\t\tfor(i in scriptList){\n\t\t\ttry{\n\t\t\t\tapp = await loadScript(scriptList[i]);\n\t\t\t\tconsole.log(app);\n\t\t\t\tloaded++;\n\t\t\t}catch(e){\n\t\t\t\tconsole.log(e);\n\t\t\t\treject('Script loaded: '+loaded+'/'+scriptList.length);\n\t\t\t}\n\t\t}\n\t\tresolve("OK");\n\t});\n\tfunction loadScript(obj){\n\t\treturn new Promise((resolve,reject) =>{\n\t\t\tvar el = null;\n\t\t\tif(!obj.id) reject('Id missing!');\n\t\t\tel = document.getElementById(obj.id);\n\t\t\tif(el) reject('Script not loaded: existing ID -> '+ obj.id);\n\t\t\telse{\n\t\t\t\tel = document.createElement("script");\n\t\t\t\tel.type = "text/javascript";\n\t\t\t\tif(obj.id) el.id = obj.id;\n\t\t\t\tif(obj.url) el.src = obj.url;\n\t\t\t\tif(obj.text){\n\t\t\t\t\tel.innerHTML = obj.text;\n\t\t\t\t\tresolve('Loaded OK -> '+ obj.id);\n\t\t\t\t}else{\n\t\t\t\t\tel.onload = () => resolve('Loaded OK -> '+ obj.id);\n\t\t\t\t\tel.onerror = () => reject('Loaded Error -> '+ obj.id);\n\t\t\t\t}\n\t\t\t\tdocument.head.appendChild(el);\n\t\t\t}\t\t\n\t\t});\n\t}\n}\n\n"
}

@DonatoD
Copy link
Author

DonatoD commented May 29, 2024

as you can see in these pictures, in grafana 10.1.4 it works
image
in grafana 11 it doesn't
image

@ZuperZee
Copy link
Contributor

Hmm, not sure. You could try using a bundler like https://github.com/gapitio/htmlgraphics-html-bundler-template
More info on the website https://gapit-htmlgraphics-panel.gapit.io/docs/projects/#bundlers.
I haven't used global scripts much in Grafana, so I'm a bit unfamiliar with why they stopped working in v11. I saw that the mqtt has a variable called mqtt, but the pdf-lib doesn't. Might it be something the package is doing?

@DonatoD
Copy link
Author

DonatoD commented Jun 3, 2024

I tried with bundler, but not always I was able on fix it.

@jackw
Copy link

jackw commented Jun 12, 2024

Loading external javascript within Grafana will always be tricky, especially if those scripts are placing objects on the global as new versions of Grafana or other plugins might interfere with those libraries or override them. If instead of creating script tags to load external code you use the same JS module loader Grafana uses (SystemJS) it will give back the packages objects allowing you to isolate your code from the outside world. It is worth noting that SystemJS is part of Grafana and is likely to receive updates across versions of Grafana which might require you to update your loading code. Below is an example of how this could be done based on the above onInit example.

const scriptsToLoad = [
  {
    id: "pdfjs",
    url: "https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.14.305/pdf.js",
  },
  {
    id: "pdflib",
    url: "https://cdn.jsdelivr.net/npm/pdf-lib/dist/pdf-lib.min.js",
  },
  {
    id: "paho-mqtt",
    url: "https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.1.0/paho-mqtt.min.js",
  },
  {
    id: "mqtt",
    url: "https://ga.system.jspm.io/npm:[email protected]/dist/mqtt.esm.js",
  },
];

const loadedScripts = {}

loadScripts(scriptsToLoad).then(() => {
  console.log("onInit", "scripts loaded!!!", loadedScripts);
  console.log(`pdfjs version: ${loadedScripts.pdfjs.version}`);
});

async function loadScripts(scriptList) {
  for (const script of scriptList) {
    try {
      const module = await loadScript(script.url);
      loadedScripts[script.id] = module;
    } catch (e) {
      console.log(e);
    }
  }
}

function loadScript(url) {
  return System.import(url).then((m) => (m.default ? m.default : m));
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants