# Conflicting dependencies

**URL:** <https://forum.inductiveautomation.com/t/conflicting-dependencies/100510>\
**Category:** Module Development\
**Tags:** ignition81, perspective\
**Created:** [January 6, 2025, 11:10pm UTC](https://forum.inductiveautomation.com/t/conflicting-dependencies/100510 "2025-01-06T23:10:22Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![Grace\_Gan](https://avatars.discourse-cdn.com/v4/letter/g/e5b9ba/32.png) [@Grace\_Gan](https://forum.inductiveautomation.com/u/Grace_Gan)\
**Post date:** [January 6, 2025, 11:10pm UTC](https://forum.inductiveautomation.com/t/conflicting-dependencies/100510/1 "2025-01-06T23:10:22Z")

</div>

Hi,

I am building a perspective component module that uses apex chart as a dependencies. Everything works fine when I installed the module to the gateway, however, the chart fails to render if the [Kyvis-Labs apex charts components module](https://github.com/Kyvis-Labs/ignition-apexcharts-module) is also installed on the same gateway.

I think the error is due to the different versions used in the two module as I am using the latest version of `apexcharts` `4.3.0` but the Kyvis-Labs is using version `3.54.1`. When i use the version `3.54.1` in my module, the chart renders fine.

I've tried isolating the dependencies but running into some bottlenecks.

I didn't include `apexcharts` in the `externals` of webpack so the library is bundled which I can see from my output file. I don't want to depend on the apexchart installed in the Kyvis-Labs library because the user may not have that module installed.

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/9/1/914c6e6f7638996686d7e3625b21044a906a6b7d.png)

The following is how the apex charts is imported in the output file

```python
const apexcharts_1 = __importDefault(__webpack_require__(/*! apexcharts */ "../../node_modules/apexcharts/dist/apexcharts.common.js"));

```

I've noticed that the Kyvis-Labs component sets the ApexCharts globally  
`window["ApexCharts"] = ApexCharts;` which I'm not sure might be causing conflicts with the dependencies? I did try setting `window["ApexCharts"] = ApexCharts;` in my module as well but that doesn't fix the issue. The Kyvis-Labs library component seems to render fine but my chart component fail to render.

Am I missing steps here?

---

<div class="post-metadata">

**Author:** ![bmusson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bmusson/32/87530_2.png) [@bmusson](https://forum.inductiveautomation.com/u/bmusson)\
**Post date:** [January 7, 2025, 4:02am UTC](https://forum.inductiveautomation.com/t/conflicting-dependencies/100510/2 "2025-01-07T04:02:30Z")

</div>

> [@Grace\_Gan](#):
>
> I did try setting `window["ApexCharts"] = ApexCharts;` in my module as well but that doesn't fix the issue

You want the opposite of this; you explicitly _don’t_ want to collide with the ApexCharts implementation provided by the KyvisLabs module.

Maybe something here, maybe `output.uniquename` (I don’t use webpack 🤮)?

> **[Output | webpack](https://webpack.js.org/configuration/output/#outputuniquename)**
>
> webpack is a module bundler. Its main purpose is to bundle JavaScript files for usage in a browser, yet it is also capable of transforming, bundling, or packaging just about any resource or asset.

---

<div class="post-metadata">

**Author:** ![Grace\_Gan](https://avatars.discourse-cdn.com/v4/letter/g/e5b9ba/32.png) [@Grace\_Gan](https://forum.inductiveautomation.com/u/Grace_Gan)\
**Post date:** [January 7, 2025, 7:13pm UTC](https://forum.inductiveautomation.com/t/conflicting-dependencies/100510/3 "2025-01-07T19:13:03Z")

</div>

I wonder if the error was not caused by global version collision because setting the unique name doesn't help as I still get the same error which should solve the problem according to the docs 🤔

For more information the module installs fine it's just when I am using the component and triggers `chart.render()` then it'll error and fail to render chart

---

<div class="post-metadata">

**Author:** ![bmusson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bmusson/32/87530_2.png) [@bmusson](https://forum.inductiveautomation.com/u/bmusson)\
**Post date:** [January 7, 2025, 7:40pm UTC](https://forum.inductiveautomation.com/t/conflicting-dependencies/100510/4 "2025-01-07T19:40:46Z")

</div>

Post some code/configs? 🤷‍♂️

---

<div class="post-metadata">

**Author:** ![Grace\_Gan](https://avatars.discourse-cdn.com/v4/letter/g/e5b9ba/32.png) [@Grace\_Gan](https://forum.inductiveautomation.com/u/Grace_Gan)\
**Post date:** [January 8, 2025, 2:36am UTC](https://forum.inductiveautomation.com/t/conflicting-dependencies/100510/5 "2025-01-08T02:36:58Z")

</div>

`mesh-oee/web/packages/client/package.json`

```python
  "dependencies": {
    "@inductiveautomation/perspective-client": "2.1.16",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "apexcharts": "4.3.0"
  },

```

`mesh-oee/web/packages/client/webpack.config.js`

```python
const config = {
...

  output: {
    library: [LibName], // name as it will be accessible by on the webpack when linked as a script
    path: path.join(__dirname, "dist"),
    filename: `${LibName}.js`,
    libraryTarget: "umd",
    umdNamedDefine: true,
  },
}
...
 resolve: {
    extensions: [".jsx", ".js", ".ts", ".tsx", ".d.ts", ".css", ".scss"],
    modules: [
      path.resolve(__dirname, "../../node_modules"), // look at the local as well as shared node modules when resolving dependencies
      path.resolve(__dirname, "node_modules"), // Local node_modules in /web
    ],
  }
...
 

```

`mesh-oee/web/pacakages/client/typescript/components/MESHOEESummary.tsx`

```python
import ApexCharts from "apexcharts";
...
  private chartRef: React.RefObject<HTMLDivElement> = React.createRef();
  private chart: ApexCharts | null = null;
...
 if (!this.chart && this.chartRef.current) {
      this.chart = new ApexCharts(this.chartRef.current, {
        series: chartSeries,
        chart: {
          type: "line",
          height: "50%",
          width: "100%",
          useCanvas: true,
          stacked: true,
          toolbar: { show: false },
          animations: { enabled: false }, // Turn off animations for better performance
          zoom: { enabled: false },
        },
        grid: { show: false },
        xaxis: {
          type: "datetime",
          labels: {
            datetimeUTC: false,
            format: "HH:mm",
          },
        },
        stroke: {
          curve: "smooth",
          width: [2, 2, 0, 0],
        },
        yaxis: [
          {
            show: false,
            max: 100,
            min: 0,
            seriesName: ["Speed (%)", "Yield (%)"],
          },
          {
            show: false,
            opposite: true,
            max: 100,
            min: 0,
            seriesName: ["Available (%)", "Not Available (%)"],
          },
        ],
        tooltip: {
          enabled: true,
          x: { format: "HH:mm" },
        },
        plotOptions: {
          bar: {
            columnWidth: "100%",
            borderRadius: 0,
            stacked: true,
          },
        },
        dataLabels: { enabled: false },
      });
      this.chart.render().catch((e) => {
        console.log(e, "error init chart");
      });
    }

```

Chart render fine without the ApexCharts Module from Kyvis Labs installed but with it installed during the `this.chart.render()` call it throws an error saying `TypeError: t.put is not a function error init chart`

---

<div class="post-metadata">

**Author:** ![bmusson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bmusson/32/87530_2.png) [@bmusson](https://forum.inductiveautomation.com/u/bmusson)\
**Post date:** [January 8, 2025, 2:50am UTC](https://forum.inductiveautomation.com/t/conflicting-dependencies/100510/6 "2025-01-08T02:50:36Z")

</div>

> [@Grace\_Gan](#):
>
> mesh-oee/web/packages/client/webpack.config.js

Do you have any externals or globals configured? Showing this full file would be the most useful.

---

<div class="post-metadata">

**Author:** ![Grace\_Gan](https://avatars.discourse-cdn.com/v4/letter/g/e5b9ba/32.png) [@Grace\_Gan](https://forum.inductiveautomation.com/u/Grace_Gan)\
**Post date:** [January 8, 2025, 2:51am UTC](https://forum.inductiveautomation.com/t/conflicting-dependencies/100510/7 "2025-01-08T02:51:35Z")

</div>

Here's the full file

```python
/**
 * Webpack build configuration file. Uses generic configuration that is appropriate for development. Depending on
 * the needs of your module, you'll likely want to add appropriate 'production' configuration to this file in order
 * do do things such as minify, postcss, etc.
 *
 * To learn more about webpack, visit https://webpack.js.org/
 */

const webpack = require("webpack"),
  path = require("path"),
  fs = require("fs"),
  MiniCssExtractPlugin = require("mini-css-extract-plugin"),
  AfterBuildPlugin = require("@fiverr/afterbuild-webpack-plugin");

const LibName = "MESHOEEComponents";

// function that copies the result of the webpack from the dist/ folder into the generated-resources folder which
// ultimately gets included in a 'web.jar'. This jar is included in the module's gateway scope, and its contents are
// accessible as classpath resources just as if they were included in the gateway jar itself.
function copyToResources() {
  const generatedResourcesDir = path.resolve(
    __dirname,
    "../../../",
    "gateway/src/main/resources/mounted/"
  );
  const jsToCopy = path.resolve(__dirname, "dist/", `${LibName}.js`);
  const cssToCopy = path.resolve(__dirname, "dist/", `${LibName}.css`);
  const jSResourcePath = path.resolve(generatedResourcesDir, `${LibName}.js`);
  const cssResourcePath = path.resolve(generatedResourcesDir, `${LibName}.css`);

  const toCopy = [
    { from: jsToCopy, to: jSResourcePath },
    { from: cssToCopy, to: cssResourcePath },
  ];

  // if the desired folder doesn't exist, create it
  if (!fs.existsSync(generatedResourcesDir)) {
    fs.mkdirSync(generatedResourcesDir, { recursive: true });
  }

  toCopy.forEach((file) => {
    console.log(`copying ${file} into ${generatedResourcesDir}...`);

    try {
      fs.access(file.from, fs.constants.R_OK, (err) => {
        if (!err) {
          fs.createReadStream(file.from).pipe(fs.createWriteStream(file.to));
        } else {
          console.log(
            `Error when attempting to copy ${file.from} into ${file.to}`
          );
        }
      });
    } catch (err) {
      console.error(err);
      // rethrow to fail build
      throw err;
    }
  });
}

const config = {
  // define our entry point, from which we build our source tree for bundling
  entry: {
    MESHOEEComponents: path.join(
      __dirname,
      "./typescript/mesh-oee-client-component.ts"
    ),
  },

  output: {
    library: [LibName], // name as it will be accessible by on the webpack when linked as a script
    path: path.join(__dirname, "dist"),
    filename: `${LibName}.js`,
    libraryTarget: "umd",
    umdNamedDefine: true,
  },

  // Enable sourcemaps for debugging webpack's output. Should be changed for production builds.
  devtool: "source-map",

  resolve: {
    extensions: [".jsx", ".js", ".ts", ".tsx", ".d.ts", ".css", ".scss"],
    modules: [
      path.resolve(__dirname, "../../node_modules"), // look at the local as well as shared node modules when resolving dependencies
      path.resolve(__dirname, "node_modules"), // Local node_modules in /web
    ],
  },

  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: {
          loader: "ts-loader",
          options: {
            transpileOnly: false,
          },
        },
        exclude: /node_modules/,
      },
      {
        test: /\.css$|.scss$/,
        use: [
          MiniCssExtractPlugin.loader,
          {
            loader: "css-loader",
            options: {
              // tells css-loader not to treat `url('/some/path')` as things that need to resolve at build time
              // in other words, the url value is simply passed-through as written in the css/sass
              url: false,
            },
          },
          {
            loader: "sass-loader",
          },
        ],
      },
    ],
  },
  plugins: [
    new AfterBuildPlugin(function (stats) {
      copyToResources();
    }),
    // pulls CSS out into a single file instead of dynamically inlining it
    new MiniCssExtractPlugin({
      filename: "[name].css",
    }),
  ],

  // IMPORTANT -- this tells the webpack build tooling "don't include these things as part of the webpack bundle".
  // They are 'provided' 'externally' via perspective/ignition at runtime, and we don't want multiple copies in the
  // browser. Any libraries used that are also used in perspective should be excluded.
  externals: {
    react: "React",
    "react-dom": "ReactDOM",
    mobx: "mobx",
    "mobx-react": "mobxReact",
    "@inductiveautomation/perspective-client": "PerspectiveClient",
  },
  optimization: {
    splitChunks: {
      cacheGroups: {
        styles: {
          name: "styles",
          test: /\.css$/,
          chunks: "all",
          enforce: true,
        },
      },
    },
  },
};

module.exports = () => config;

```

---

<div class="post-metadata">

**Author:** ![Grace\_Gan](https://avatars.discourse-cdn.com/v4/letter/g/e5b9ba/32.png) [@Grace\_Gan](https://forum.inductiveautomation.com/u/Grace_Gan)\
**Post date:** [January 20, 2025, 1:50am UTC](https://forum.inductiveautomation.com/t/conflicting-dependencies/100510/8 "2025-01-20T01:50:06Z")

</div>

Tried a few more things but still have no luck on this unfortunately. But here's a summary of what I tried.

Instead of installing Kyvis Lab apex chart module and my module which uses apex charts, I've created a second module that also uses apex chart to do more testing.

When I set the version of apexcharts in the two module to be the same (either v3.54.1 or v.4.3.0), chart renders fine, but when they are different, the chart in the module that uses v4.3.0 fails to render, and the other one renders fine. Since I get the same kind of error in my own modules, i suspect it has nothing to do with Kyvis Lab setting ApexCharts globally.

The import statement of apexcharts in the js file generated by the webpack is as follows

`const apexcharts_1 = __importDefault(__webpack_require__(/*! apexcharts */ "../../node_modules/apexcharts/dist/apexcharts.common.js"));`

I'm wondering if in theory it is possible to have two modules bundling their own apexcharts and using different version without causing conflicts with how perspective components runs in ignition designer - I don't know much about this so I could be wrong.
