microsoft / ApplicationInsights-node.js

Microsoft Application Insights SDK for Node.js
MIT License
320 stars 138 forks source link

aplicationinsights package incompatibilities with ESM #1354

Open thekip opened 2 days ago

thekip commented 2 days ago

Describe the bug applicationinsights doesn't work properly in ESM environment

This issue is possibly a duplicate of https://github.com/microsoft/ApplicationInsights-node.js/issues/1205 but with more details and workaround.

To Reproduce Steps to reproduce the behavior:

  1. Set "type": "module", in package.json
  2. Add

    import { setup, defaultClient } from 'applicationinsights';
    setup().start();
    
    console.log(defaultClient); 
  3. Run the app and check the console output, defaultClient would be undefined.

Expected behavior defaultClient should be fulfilled

Additional context This happened because of the differences how native ESM and transpiled to CJS modules works.

If you look to the entry point of the 'applicationinsights' package you will see:

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

exports.dispose =
  exports.TelemetryClient =
    exports.DistributedTracingModes =
      exports.Contracts = exports.defaultClient =
        exports.Configuration = exports.wrapWithCorrelationContext =
          exports.startOperation = exports.getCorrelationContext = exports.start = exports.setup = void 0;

var applicationinsights_1 = require("./src/shim/applicationinsights");
Object.defineProperty(exports, "setup", { enumerable: true, get: function () { return applicationinsights_1.setup; } });
Object.defineProperty(exports, "defaultClient", { enumerable: true, get: function () { return applicationinsights_1.defaultClient; } });
// ... other exports

When this package would be requested in CJS context, those getters would be invoked only when user's code will actually access them, but in ESM context, ESM loader enumerate all properties which are exported from the package and save result internally, so getter for defaultClient is executed only once and before this client ever initialized.

There is no simple way to fix this, other than don't use late-binding at all. So instead of defaultClient expose a function getDefaultClient()

To workaround the issue, i created a cjs file which is called from my ESM modules with the following content:

// telemetry.cjs
const applicationinsights = require('applicationinsights');
applicationinsights.setup().start();

module.exports = {
  telemetryClient: applicationinsights.defaultClient
}