Using a complex Widget inside react results in "Uncaught ReferenceError: webix is not defined"

Hello dear Webix community,

I want to integrate the Spreadsheet-ComplexWidget in a React app with Typescript.
My dependencies are as simple as possible:

 "@xbs/spreadsheet": "^10.2.1",
  "@xbs/webix-pro": "^10.2.1",
  "react": "^18.2.0",
  "react-dom": "^18.2.0"

When I try to include a Spreadsheet View, I get the following error message:

spreadsheet.js:355 Uncaught ReferenceError: webix is not defined
    at spreadsheet.js:355:2
    at spreadsheet.js:10:65
    at node_modules/@xbs/spreadsheet/spreadsheet.js (spreadsheet.js:13:1)
    at __require (chunk-76J2PTFD.js?v=1b8c8e08:3:50)
    at spreadsheet.js:17800:3

My react component is defined as follows:

import Webix from "./Webix.tsx";
import {ui} from "@xbs/webix-pro";
import '@xbs/spreadsheet/spreadsheet.min.css'
import '@xbs/spreadsheet/spreadsheet.js'

function webixConfig(): ui.layoutConfig{
    return {
        cols: [
            { view:"spreadsheet", id: "spreadsheet-123"}
        ]
    };
}
export default function WebixView() {
    return (
        <div style={{height: "100vh", width: '100vw'}}>
            <Webix ui={webixConfig()}/>
        </div>
    )
}

The used ‘Webix’ component has been taken from the Webix-React integration example. I had to modify it slightly in order to support a newer version of react and avoid deprecations.
Non-complex widgets work without any errors.

Does anybody have a clue and may give me some advice?

In case that it may be important i’m providing the source of the ‘Webix’ component as well:

import {Component, createRef} from 'react';

import '@xbs/webix-pro/webix.min.css'

import {ui} from "@xbs/webix-pro";

export type WebixProperties = {
    ui: ui.baseviewConfig,
    data?: any,
    select?: any

}
class Webix<S> extends Component<WebixProperties, S> {

    private ref = createRef<HTMLDivElement>();
    private ui: ui.baseview | null = null;

    render() {
        return (
            <div style={{height: '100%', width: '100%', padding: '0px', margin:'0px', border: 'none', display: 'block'}} ref={this.ref}></div>
        );
    }

    public setWebixData(data: any){
        const ui: any = this.ui;
        if (ui.setValues)
            ui.setValues(data);
        else if (ui.parse)
            ui.parse(data)
        else if (ui.setValue)
            ui.setValue(data);
    }

    public componentWillUnmount(){
        if(this.ui){
            this.ui.destructor();
            this.ui = null;
        }
    }

    public componentDidUpdate(props: WebixProperties){
        if (props.data)
            this.setWebixData(props.data);
        if (props.select && this.ui){
            const ui:any = this.ui;
            ui.select(props.select);
        }
    }

    public componentDidMount(){
        this.ui = ui(
            this.props.ui,
            this.ref.current!
        );
        this.componentDidUpdate(this.props);
    }

}

export default Webix;

Good day @Lul4n ,

All of our complex widgets require for the webix variable to be available in the global context. This means that if you are planning on using imports, you will need to define that variable in some way.

Generally speaking, there are 2 main ways in which you can include the required sources:

  1. Include the required dependencies via the script tag on some page (e.g., index.html )
  2. Import the required dependencies. Please note that this approach requires for the webix variable to be defined in the global scope (as I’ve mentioned above) - this facilitates the following:
  • A basic (yet a bit rough) solution is to manually assign webix to a global variable, then use webix.ui() to init the necessary complex widget (in this case, Spreadsheet). For example:
//index.js
import * as webix from "@xbs/webix-pro";
window.webix = webix;

//SpreadsheetView.js
webix.ready(() => {
  require("@xbs/spreadsheet");
  this.ui = webix.ui({
    view: "spreadsheet",
    ...
  });
});
  • In some cases, it is possible to use external tools like the ProvidePlugin for Webpack, which makes webix available for all includes (including Spreadsheet and other complex widgets). For example, you can add the next section in webpack.config.js :
plugins: [
  new webpack.ProvidePlugin({
  // SET PATH TO WEBIX HERE
  webix: path.join(__dirname, "node_modules", "@xbs", "webix-pro") // or wherever else it is located
}),

So that the webix will be available in all modules.
If you use ESLint with the no-undef rule, you’ll also need to extend these settings with the following statement, as ProvidePlugin allows to refer to a global value without importing/defining webix in a module:

"globals": {
   "webix": "readonly"
}
  • Or you can simply include just the core library as a global script and import only the complex widgets.

I would also like to note that, normally, we recommend including the core Webix library as a global script (through the script tag), as it is fairly large. The library will work faster due to caching, and your dev. toolchain will work faster as well (it will also make it easier to work with complex widgets due to the presence of the global webix variable). So, if possible, you should consider including everything through the script tag, or just the core library and import the rest.

Additionally, please, have a look at our demo of importing Webix Complex Widgets into a React App: demo link . Notice that there are several branches in the demo showing the several ways of importing the widgets.

Hope these examples will be helpful.