In my Blazor app I'm using Plotly.Blazor for showing some graphs.
I have recently added BlazorMonaco, but once added - Plotly.Blazor
stopped working.
In the DevTools console I get the following error:
Error: Microsoft.JSInterop.JSException: Cannot read properties of
undefined (reading 'newPlot') TypeError: Cannot read properties of
undefined (reading 'newPlot')
at Module.newPlot (https://localhost:5001/_content/Plotly.Blazor/plotly-interop.js:4:19)
at https://localhost:5001/_framework/blazor.server.js:1:3244
...
After exploring a bit:
Monaco's
_content/BlazorMonaco/lib/monaco-editor/min/vs/loader.js
file, Plotly
works just fine (but than of course Monaco wont work).Plotly's
js it seems that window.Plotly
is not defined.My conclusion is that Monaco
is probably polluting the global namespace, but I cannot find hard evidence for that...
Any suggestions how I can work around this issue?
Additional information:
3.2.0
4.3.0
The issue is that the importScript
function in plotly-interop-5.4.0.js
conflicts with AMD (Asynchronous Module Definition) loaders, such as RequireJS, which might be active in your Blazor environment (such as used in Blazor.Monaco).
Plotly tries to define itself as an anonymous module, but AMD doesn't support multiple anonymous define calls in the same script so when onload
the window.Plotly
is undefined as you've seen.
Update: Fixed released 5.4.1
To resolve this issue, I submitted a pull request, but in the meantime, you can do this workaround.
Create two js scripts in separate folder if using RCL or in the index.html
function disableAMD() {
if (typeof Plotly !== "undefined") {
return;
}
if (typeof window.define === 'function' && window.define.amd) {
window._originalDefine = define;
window.define = undefined; // Temporarily disable AMD
}
}
function enableAMD() {
if (window._originalDefine) {
window.define = window._originalDefine; // Restore the original define function
delete window._originalDefine;
}
}
Then call them in the OnInitializedAsync() when your form that uses Plotly.Blazor
protected override async Task OnInitializedAsync()
{
var module = await Module;
await module.InvokeVoidAsync("disableAMD");
await base.OnInitializedAsync();
}
Then restore amd when you close the form:
public async ValueTask DisposeAsync()
{
_chart?.Purge();
var module = await Module;
await module.InvokeVoidAsync("enableAMD");
await module.DisposeAsync();
}